http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80e25b46/tools/bin/pythonSrc/PSI-0.3b2_gp/src/process.c ---------------------------------------------------------------------- diff --git a/tools/bin/pythonSrc/PSI-0.3b2_gp/src/process.c b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/process.c new file mode 100644 index 0000000..555f004 --- /dev/null +++ b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/process.c @@ -0,0 +1,981 @@ +/* The MIT License + * + * Copyright (C) 2007 Chris Miles + * + * Copyright (C) 2008-2009 Floris Bruynooghe + * + * Copyright (C) 2008-2009 Abilisoft Ltd. + * + * Copyright (C) 2009 Erick Tryzelaar + * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** psi.process.Process class + * + * This file contains the common support for the psi.process.Process class. + */ + + +#include <Python.h> + +#include <errno.h> +#include <signal.h> +#include <string.h> +#include <sys/types.h> +#include <time.h> + +#include "psi.h" +#include "process.h" + + +/** The Python Process object + * + * `pid' and `proci' are filled in by the init method. All the python objects + * are filled lazily when they are accessed. They exist so that accessing + * them twice returns a new reference to the same objects instead of creating + * new objects. Just like in the psi_process structure some of these pointers + * might never be used on some platforms, e.g. zoneid is Solaris-only. + */ +typedef struct { + PyObject_HEAD + pid_t pid; + struct psi_process *proci; +} PsiProcessObject; + + +/***** Local declarations *****/ + +static int check_init(PsiProcessObject *obj); + + +/***** Local functions *****/ + +void * +psi_free_process(struct psi_process *proci) +{ + int i; + + psi_FREE(proci->name); + psi_FREE(proci->exe); + if (proci->argv != NULL) + for (i = 0; i < proci->argc; i++) + psi_free(proci->argv[i]); + psi_FREE(proci->argv); + psi_FREE(proci->command); + for (i = 0; i < proci->envc; i++) + psi_free(proci->envv[i]); + psi_FREE(proci->envv); + psi_FREE(proci->cwd); + psi_FREE(proci->terminal); + psi_FREE(proci->zonename); + psi_free(proci); + return NULL; +} + + +/** Create a hash from a proci structure + * + * This is the implementation of Process.__hash__() really but without + * needeing a full PsiProcessObject so it can be used easier in + * various places. + */ +static long +hash_proci(const pid_t pid, const struct psi_process *proci) +{ + PyObject *tuple; + PyObject *pypid; + PyObject *starttime; + long hash; + +#ifdef LINUX + if (psi_checkattr("Process.jiffies", proci->jiffies_status) < 0) + return -1; +#else + if (psi_checkattr("Process.start_time", proci->start_time_status) < 0) + return -1; +#endif + pypid = PyLong_FromLong(pid); + if (pypid == NULL) + return -1; +#ifdef LINUX + starttime = PyLong_FromLong(proci->jiffies); +#else + starttime = PsiTimeSpec_New(&proci->start_time); +#endif + if (starttime == NULL) { + Py_DECREF(pypid); + return -1; + } + if ((tuple = PyTuple_New(2)) == NULL) { + Py_DECREF(pypid); + Py_DECREF(starttime); + return -1; + } + PyTuple_SET_ITEM(tuple, 0, pypid); + PyTuple_SET_ITEM(tuple, 1, starttime); + hash = PyObject_Hash(tuple); + Py_DECREF(tuple); + return hash; +} + + +static int +Process_init(PsiProcessObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"pid", NULL}; + pid_t pid; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &pid)) + return -1; + self->pid = pid; + self->proci = psi_arch_process(pid); + if (self->proci == NULL) + return -1; + return 0; +} + + +static void +Process_dealloc(PsiProcessObject *self) +{ + if (self == NULL) + return; + if (self->proci != NULL) + psi_free_process(self->proci); + Py_TYPE(self)->tp_free((PyObject*)self); +} + + +static PyObject * +Process_repr(PsiProcessObject *self) +{ + return PyStr_FromFormat("%s(pid=%d)", + Py_TYPE(self)->tp_name, (int)self->pid); +} + + +static long +Process_hash(PsiProcessObject *self) +{ + return hash_proci(self->pid, self->proci); +} + + +static PyObject * +Process_richcompare(PyObject *v, PyObject *w, int op) +{ + PsiProcessObject *vo, *wo; + PyObject *result; + int istrue; + + if (!PyObject_TypeCheck(v, &PsiProcess_Type) + || !PyObject_TypeCheck(w, &PsiProcess_Type)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + vo = (PsiProcessObject *)v; + wo = (PsiProcessObject *)w; + switch (op) { + case Py_EQ: + istrue = vo->pid == wo->pid; + break; + case Py_NE: + istrue = vo->pid != wo->pid; + break; + case Py_LE: + istrue = vo->pid <= wo->pid; + break; + case Py_GE: + istrue = vo->pid >= wo->pid; + break; + case Py_LT: + istrue = vo->pid < wo->pid; + break; + case Py_GT: + istrue = vo->pid > wo->pid; + break; + default: + assert(!"op unknown"); + istrue = 0; /* To shut up compiler */ + } + result = istrue ? Py_True : Py_False; + Py_INCREF(result); + return result; +} + + +/** Check if object is initialised + * + * Small helper function that checks if an object is properly initialised. + * + * XXX: Maybe this should go into util.c in some from. + */ +static int +check_init(PsiProcessObject *obj) +{ + if (obj->proci == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "Instance has not been initialised properly"); + return -1; + } + return 0; +} + + +static PyObject * +Process_get_pid(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + return PyLong_FromLong(self->pid); +} + + +static PyObject * +Process_get_name(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.name", + self->proci->name_status) < 0) + return NULL; + return PyStr_FromString(self->proci->name); +} + + +static PyObject * +Process_get_exe(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.exe", self->proci->exe_status) < 0) + return NULL; + return PyStr_FromString(self->proci->exe); +} + + +/** Create a tuple from the argv vector in the psi_process structure + * + * Each element in argv is allowed to be NULL in which case a None object + * should be added to the tuple. + */ +static PyObject * +Process_get_args(PsiProcessObject *self, void *closure) +{ + PyObject *args; + PyObject *arg; + int i; + + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.args", self->proci->argc_status) < 0 + || psi_checkattr("Process.args", self->proci->argv_status) < 0) + return NULL; + args = PyTuple_New((Py_ssize_t)self->proci->argc); + if (args == NULL) + return NULL; + for (i = 0; i < self->proci->argc; i++) { + arg = PyStr_FromString(self->proci->argv[i]); + if (arg == NULL) { + Py_DECREF(args); + return NULL; + } + PyTuple_SET_ITEM(args, i, arg); + } + return args; +} + + +static PyObject * +Process_get_argc(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.argc", self->proci->argc_status) < 0) + return NULL; + return PyLong_FromLong(self->proci->argc); +} + + +/** Return the command + * + * Note that implementations are allowed to return an empty string for this in + * which case we need to get the name attribute instead. + */ +static PyObject * +Process_get_command(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.command", self->proci->command_status) < 0) + return NULL; + if (strlen(self->proci->command) == 0) { + if (psi_checkattr("Process.command", self->proci->name_status) < 0) + return NULL; + return PyStr_FromString(self->proci->name); + } else + return PyStr_FromString(self->proci->command); +} + + +static PyObject * +Process_get_env(PsiProcessObject *self, void *closure) +{ + PyObject *env; + PyObject *val; + char *key; + char *s; + char *equals; + int i; + int r; + + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.env", self->proci->envc_status) < 0 + || psi_checkattr("Process.env", self->proci->envv_status) < 0) + return NULL; + env = PyDict_New(); + if (env == NULL) + return NULL; + s = (char *)self->proci->envv; + for (i = 0; i < self->proci->envc; i++) { + key = self->proci->envv[i]; + equals = strchr(key, '='); + if (!equals) + continue; /* This is possible on at least Linux */ + *equals = '\0'; + val = PyStr_FromString(equals + 1); + if (val == NULL) { + Py_DECREF(env); + return NULL; + } + r = PyDict_SetItemString(env, key, val); + Py_DECREF(val); + if (r == -1) + return NULL; + } + return env; +} + + +#if ! (defined(SUNOS5) && SUNOS5_MINOR < 10) +static PyObject * +Process_get_cwd(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.cwd", self->proci->cwd_status) < 0) + return NULL; + return PyStr_FromString(self->proci->cwd); +} +#endif + + +static PyObject * +Process_get_euid(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.uid", self->proci->euid_status) < 0) + return NULL; + return PyLong_FromLong(self->proci->euid); +} + + +static PyObject * +Process_get_egid(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.gid", self->proci->egid_status) < 0) + return NULL; + return PyLong_FromLong(self->proci->egid); +} + + +static PyObject * +Process_get_ruid(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.real_uid", self->proci->ruid_status) < 0) + return NULL; + return PyLong_FromLong(self->proci->ruid); +} + + +static PyObject * +Process_get_rgid(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.real_gid", self->proci->rgid_status) < 0) + return NULL; + return PyLong_FromLong(self->proci->rgid); +} + + +#if defined(SUNOS5) && SUNOS5_MINOR >= 10 +static PyObject * +Process_get_zoneid(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.zoneid", self->proci->zoneid_status) < 0) + return NULL; + return PyLong_FromLong(self->proci->zoneid); +} +#endif + + +#if defined(SUNOS5) && SUNOS5_MINOR >= 10 +static PyObject * +Process_get_zonename(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.zonename", self->proci->zonename_status) < 0) + return NULL; + return PyStr_FromString(self->proci->zonename); +} +#endif + + +static PyObject * +Process_get_ppid(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.ppid", self->proci->ppid_status) < 0) + return NULL; + return PyLong_FromLong((long)self->proci->ppid); +} + + +static PyObject * +Process_get_sid(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.sid", self->proci->sid_status) < 0) + return NULL; + return PyLong_FromLong(self->proci->sid); +} + + +static PyObject * +Process_get_pgrp(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.pgrp", self->proci->pgrp_status) < 0) + return NULL; + return PyLong_FromLong(self->proci->pgrp); +} + + +static PyObject * +Process_get_priority(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.priority", self->proci->priority_status) < 0) + return NULL; + return PyLong_FromLong((long)self->proci->priority); +} + + +static PyObject * +Process_get_nice(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.nice", self->proci->nice_status) < 0) + return NULL; + return PyLong_FromLong((long)self->proci->nice); +} + + +static PyObject * +Process_get_start_time(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.start_time", self->proci->start_time_status) < 0) + return NULL; + return PsiTimeSpec_New(&self->proci->start_time); +} + + +#ifdef LINUX +static PyObject * +Process_get_jiffies(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.jiffies", self->proci->jiffies_status) < 0) + return NULL; + return PyLong_FromLong(self->proci->jiffies); +} +#endif + + +static PyObject * +Process_get_status(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.status", self->proci->status_status) < 0) + return NULL; + return PyLong_FromLong((long)self->proci->status); +} + + +#ifndef LINUX2_4 +static PyObject * +Process_get_nthreads(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.nthreads", self->proci->nthreads_status) < 0) + return NULL; + return PyLong_FromLong((long)self->proci->nthreads); +} +#endif + + +#if ! (defined(SUNOS5) && SUNOS5_MINOR < 10) +static PyObject * +Process_get_terminal(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.terminal", self->proci->terminal_status) < 0) + return NULL; + if (self->proci->terminal == '\0') { + Py_INCREF(Py_None); + return Py_None; + } else + return PyStr_FromString(self->proci->terminal); +} +#endif + + +static PyObject * +Process_get_utime(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.utime", self->proci->utime_status) < 0) + return NULL; + return PsiTimeSpec_New(&self->proci->utime); +} + + +static PyObject * +Process_get_stime(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.stime", self->proci->stime_status) < 0) + return NULL; + return PsiTimeSpec_New(&self->proci->stime); +} + + +static PyObject * +Process_get_cputime(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.cputime", self->proci->cputime_status) < 0) + return NULL; + return PsiTimeSpec_New(&self->proci->cputime); +} + + +static PyObject * +Process_get_rss(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.rss", self->proci->rss_status) < 0) + return NULL; + return PyLong_FromLong(self->proci->rss); +} + + +static PyObject * +Process_get_vsz(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.vsz", self->proci->vsz_status) < 0) + return NULL; + return PyLong_FromLong(self->proci->vsz); +} + + +#if !defined(LINUX) && !defined(AIX) +static PyObject * +Process_get_pcpu(PsiProcessObject *self, void *closure) +{ + if (check_init(self) < 0) + return NULL; + if (psi_checkattr("Process.pcpu", self->proci->pcpu_status) < 0) + return NULL; + return PyFloat_FromDouble(self->proci->pcpu); +} +#endif + + +PyDoc_STRVAR(Process_refresh__doc, "\ +Process.refresh()\n\ +\n\ +Refresh all data of the attributes. This allows you to get new data\n\ +without having to create a new Process instance.\n\ +"); +static PyObject * +Process_refresh(PsiProcessObject *self) +{ + struct psi_process *new_proci; + long old_hash; + long new_hash; + + if (check_init(self) < 0) + return NULL; + old_hash = hash_proci(self->pid, self->proci); + if (old_hash == -1) + return NULL; + new_proci = psi_arch_process(self->pid); + if (new_proci == NULL) { + PyErr_SetString(PsiExc_NoSuchProcessError, "Process no longer exists"); + return NULL; + } + new_hash = hash_proci(self->pid, new_proci); + if (new_hash == -1) { + psi_free_process(new_proci); + return NULL; + } + if (new_hash == old_hash) { + psi_free_process(self->proci); + self->proci = new_proci; + Py_RETURN_NONE; + } else { + psi_free_process(new_proci); + PyErr_SetString(PsiExc_NoSuchProcessError, "Process no longer exists"); + return NULL; + } +} + + +PyDoc_STRVAR(Process_exists__doc, "\ +Process.exists() -> True or False\n\ +\n\ +Test if a process still exists. This might not mean it is alive, it\n\ +could be in a zombie state or similar.\ +"); +static PyObject * +Process_exists(PsiProcessObject *self) +{ + struct psi_process *new_proci; + long old_hash; + long new_hash; + + PyErr_WarnEx(PyExc_FutureWarning, "Experimental method", 1); + if (check_init(self) < 0) + return NULL; + old_hash = hash_proci(self->pid, self->proci); + if (old_hash == -1) + return NULL; + new_proci = psi_arch_process(self->pid); + if (new_proci == NULL) { + PyErr_Clear(); + Py_RETURN_FALSE; + } + new_hash = hash_proci(self->pid, new_proci); + psi_free_process(new_proci); + if (new_hash == -1) { + psi_free_process(new_proci); + return NULL; + } + if (new_hash == old_hash) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + + +PyDoc_STRVAR(Process_children__doc, "\ +Process.children() -> [child, ...]\n\ +\n\ +This returns a (possibly empty) list of children of the process. Each\n\ +child will be the corresponding Process instance.\n\ +"); +static PyObject * +Process_children(PsiProcessObject *self) +{ + PyObject *isalive; + PyObject *ptable; + PyObject *children; + PsiProcessObject *proc; + PyObject *pyproc; + Py_ssize_t pos = 0; + + PyErr_WarnEx(PyExc_FutureWarning, "Experimental method", 1); + isalive = Process_exists(self); + if (isalive != Py_True) { + PyErr_SetString(PsiExc_NoSuchProcessError, "Process no longer exists"); + return NULL; + } + children = PyList_New(0); + if (children == NULL) + return NULL; + ptable = PsiProcessTable_New(); + if (ptable == NULL) { + Py_DECREF(children); + return NULL; + } + while (PyDict_Next(ptable, &pos, NULL, &pyproc)) { + proc = (PsiProcessObject *)pyproc; + if (proc->proci->ppid == self->pid) + if (PyList_Append(children, (PyObject *)proc) == -1) { + Py_DECREF(children); + Py_DECREF(ptable); + return NULL; + } + } + Py_DECREF(ptable); + return children; +} + + +PyDoc_STRVAR(Process_kill__doc, "\ +Process.kill(signal)\n\ +\n\ +Send a signal to the process. `signal` is an integer signal number\n\ +as defined by the OS, use one of the signal.SIG* constants.\n\ +"); +static PyObject * +Process_kill(PsiProcessObject* self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"sig", NULL}; + PyObject *isalive; + int sig = SIGTERM; + int r; + + PyErr_WarnEx(PyExc_FutureWarning, "Experimental method", 1); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &sig)) + return NULL; + isalive = Process_exists(self); + if (isalive != Py_True) { + PyErr_SetString(PsiExc_NoSuchProcessError, "Process no longer exists"); + return NULL; + } + r = kill(self->pid, sig); + if (r == -1) + if (errno == EINVAL) { + PyErr_Format(PyExc_ValueError, "Invalid signal: %d", sig); + return NULL; + } else if (errno == EPERM) { + PyErr_Format(PsiExc_InsufficientPrivsError, + "No permission to send signal %d to process %ld", + sig, (long)self->pid); + return NULL; + } else if (errno == ESRCH) { + PyErr_SetString(PsiExc_NoSuchProcessError, + "Process no longer exists"); + return NULL; + } else { + PyErr_Format(PyExc_SystemError, "Unexpected errno: %d", errno); + return NULL; + } + else + Py_RETURN_NONE; +} + + +static PyGetSetDef Process_getseters[] = { + {"pid", (getter)Process_get_pid, (setter)NULL, + "Process PID", NULL}, + {"name", (getter)Process_get_name, (setter)NULL, + "Name of the process, accounting name if defined", NULL}, + {"exe", (getter)Process_get_exe, (setter)NULL, + "Absolute pathname to the executable of the process", NULL}, + {"args", (getter)Process_get_args, (setter)NULL, + "List of the command and it's arguments\n" + "\n" + "On some systems (e.g. SunOS, AIX) it possible that this is not\n" + "available due to privileges. The `command' attribute should still\n" + "be available in those cases.", NULL}, + {"argc", (getter)Process_get_argc, (setter)NULL, + "Argument count", NULL}, + {"command", (getter)Process_get_command, (setter)NULL, + "Command and arguments as a string\n" + "\n" + "On some systems (e.g. SunOS, AIX) this might be truncated to a limited\n" + "length. On those systems this will always be available however, while\n" + "the `args' attribute might not be.", NULL}, + {"env", (getter)Process_get_env, (setter)NULL, + "The environment of the process as a dictionary", NULL}, +#if ! (defined(SUNOS5) && SUNOS5_MINOR < 10) + {"cwd", (getter)Process_get_cwd, (setter)NULL, + "Current working directory", NULL}, +#endif + {"euid", (getter)Process_get_euid, (setter)NULL, + "Current UID", NULL}, + {"egid", (getter)Process_get_egid, (setter)NULL, + "Current GID", NULL}, + {"ruid", (getter)Process_get_ruid, (setter)NULL, + "Real UID", NULL}, + {"rgid", (getter)Process_get_rgid, (setter)NULL, + "Real GID", NULL}, +#if defined(SUNOS5) && SUNOS5_MINOR >= 10 + {"zoneid", (getter)Process_get_zoneid, (setter)NULL, + "ID of the Solaris zone the process is running in", NULL}, + {"zonename", (getter)Process_get_zonename, (setter)NULL, + "Name of the Solaris zone the process is running in", NULL}, +#endif + {"ppid", (getter)Process_get_ppid, (setter)NULL, + "Parent PID", NULL}, + {"pgrp", (getter)Process_get_pgrp, (setter)NULL, + "Process group ID aka PID of process group leader", NULL}, + {"sid", (getter)Process_get_sid, (setter)NULL, + "Session ID of the process", NULL}, + {"priority", (getter)Process_get_priority, (setter)NULL, + "Priority of the process", NULL}, + {"nice", (getter)Process_get_nice, (setter)NULL, + "Nice value of the process", NULL}, + {"start_time", (getter)Process_get_start_time, (setter)NULL, + "Start time of process as datetime.datetime object\n\n" + "Use .strftime('%s') to get seconds since epoch", + NULL}, +#ifdef LINUX + {"jiffies", (getter)Process_get_jiffies, (setter)NULL, + "Number of jiffies of the start of the process since boot", NULL}, +#endif + {"status", (getter)Process_get_status, (setter)NULL, + "Process status\n\n" + "A value matching one of the psi.process.PROC_STATUS_* constants", NULL}, +#ifndef LINUX2_4 + {"nthreads", (getter)Process_get_nthreads, (setter)NULL, + "Number of threads used by this process", NULL}, +#endif +#if ! (defined(SUNOS5) && SUNOS5_MINOR < 10) + {"terminal", (getter)Process_get_terminal, (setter)NULL, + "Owning terminal or None", NULL}, +#endif + {"utime", (getter)Process_get_utime, (setter)NULL, + "Time the process has spent in user mode (datetime.timedelta)", NULL}, + {"stime", (getter)Process_get_stime, (setter)NULL, + "Time the process has spend in system mode (datetime.timedelta)", NULL}, + {"cputime", (getter)Process_get_cputime, (setter)NULL, + "Total CPU time of the process (datetime.timedelta)", NULL}, + {"rss", (getter)Process_get_rss, (setter)NULL, + "Resident memory size (RSS) in bytes", NULL}, + {"vsz", (getter)Process_get_vsz, (setter)NULL, + "Virtual memory size in bytes", NULL}, +#if !defined(LINUX) && !defined(AIX) + {"pcpu", (getter)Process_get_pcpu, (setter)NULL, + "%% CPU usage, instantaneous", NULL}, +#endif + {NULL} /* Sentinel */ +}; + + +static PyMethodDef Process_methods[] = { + {"refresh", (PyCFunction)Process_refresh, + METH_NOARGS, Process_refresh__doc}, + {"exists", (PyCFunction)Process_exists, + METH_NOARGS, Process_exists__doc}, + {"children", (PyCFunction)Process_children, + METH_NOARGS, Process_children__doc}, + {"kill", (PyCFunction)Process_kill, + METH_VARARGS | METH_KEYWORDS, Process_kill__doc}, + {NULL} /* Sentinel */ +}; + + +PyTypeObject PsiProcess_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "psi.process.Process", /* tp_name */ + sizeof(PsiProcessObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)Process_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)Process_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)Process_hash, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "Process(pid=x) -> Process object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + (richcmpfunc)Process_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Process_methods, /* tp_methods */ + 0, /* tp_members */ + Process_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Process_init, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ +}; + + +/** Create a new PsiProcessObject + * + * Create a new PsiProcessObject for a pid. + * + * Returns a new reference to a PsiProcessObject or NULL in case of an error. + */ +PyObject * +PsiProcess_New(pid_t pid) +{ + PsiProcessObject *obj; + + obj = (PsiProcessObject *)PyType_GenericNew(&PsiProcess_Type, NULL, NULL); + if (obj == NULL) + return NULL; + + /* Skip calling .__init__() */ + obj->pid = pid; + obj->proci = psi_arch_process(pid); + if (obj->proci == NULL) + return NULL; + return (PyObject *)obj; +}
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80e25b46/tools/bin/pythonSrc/PSI-0.3b2_gp/src/processmodule.c ---------------------------------------------------------------------- diff --git a/tools/bin/pythonSrc/PSI-0.3b2_gp/src/processmodule.c b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/processmodule.c new file mode 100644 index 0000000..7970c86 --- /dev/null +++ b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/processmodule.c @@ -0,0 +1,208 @@ +/* The MIT License + * + * Copyright (C) 2008-2009 Floris Bruynooghe + * + * Copyright (C) 2008-2009 Abilisoft Ltd. + * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* The psi.process module */ + + +#include <Python.h> + +#include "psi.h" +#include "process.h" + + +/* Declarations (we need these since we use -Wmissing-declarations) */ +#ifdef PY3K +PyMODINIT_FUNC PyInit_process(void); +#else +PyMODINIT_FUNC initprocess(void); +#endif + + +/* Re-declare these as non-extern since we're providing the symbols */ +PyObject *PsiExc_AttrNotAvailableError = NULL; +PyObject *PsiExc_AttrInsufficientPrivsError = NULL; +PyObject *PsiExc_AttrNotImplementedError = NULL; +PyObject *PsiExc_MissingResourceError = NULL; +PyObject *PsiExc_NoSuchProcessError = NULL; +PyObject *PsiExc_InsufficientPrivsError = NULL; + + +/* More constants */ +static char MODULE_NAME[] = "psi.process"; +PyDoc_STRVAR(MODULE_DOC, "Module for process information"); + + +/** Finalise the types + * + * Calls PyType_Ready() and increases their reference count. + */ +static int +prepare_types(void) +{ + if (PyType_Ready(&PsiProcess_Type) < 0) + return -1; + if (PyType_Ready(&PsiProcessTable_Type) < 0) + return -1; + Py_INCREF(&PsiProcess_Type); + Py_INCREF(&PsiProcessTable_Type); + return 0; +} + + +/** Initialise the global exceptions + * + * If this function fails the modinit function will Py_XDECREF the exceptions, + * so no need to do that here. + */ +static int +init_exceptions(void) +{ + PyObject *_psimod; + + _psimod = PyImport_ImportModule("psi._psi"); + if (_psimod == NULL) + return -1; + PsiExc_AttrNotAvailableError = PyObject_GetAttrString( + _psimod, "AttrNotAvailableError"); + if (PsiExc_AttrNotAvailableError == NULL) + goto error; + PsiExc_AttrInsufficientPrivsError = PyObject_GetAttrString( + _psimod, "AttrInsufficientPrivsError"); + if (PsiExc_AttrInsufficientPrivsError == NULL) + goto error; + PsiExc_AttrNotImplementedError = PyObject_GetAttrString( + _psimod, "AttrNotImplementedError"); + if (PsiExc_AttrNotImplementedError == NULL) + goto error; + PsiExc_MissingResourceError = PyObject_GetAttrString( + _psimod, "MissingResourceError"); + if (PsiExc_MissingResourceError == NULL) + goto error; + PsiExc_InsufficientPrivsError = PyObject_GetAttrString( + _psimod, "InsufficientPrivsError"); + if (PsiExc_InsufficientPrivsError == NULL) + goto error; + PsiExc_NoSuchProcessError = PyErr_NewException( + "psi.process.NoSuchProcessError", PsiExc_MissingResourceError, NULL); + if (PsiExc_NoSuchProcessError == NULL) + goto error; + Py_DECREF(_psimod); + return 0; + + error: + Py_DECREF(_psimod); + return -1; +} + + +/* Add all objects to the module */ +static int +add_module_objects(PyObject *module) +{ + struct psi_flag *flag; + + flag = psi_arch_proc_status_flags; + while (flag->name != NULL) { + if (PyModule_AddIntConstant(module, flag->name, flag->val) == -1) + return -1; + flag++; + } + if (PyModule_AddObject(module, "Process", + (PyObject *)&PsiProcess_Type) < 0) + return -1; + if (PyModule_AddObject(module, "ProcessTable", + (PyObject *)&PsiProcessTable_Type) < 0) + return -1; + if (PyModule_AddObject(module, "NoSuchProcessError", + PsiExc_NoSuchProcessError) < 0) + return -1; + return 0; +} + + +static PyMethodDef process_methods[] = { + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + + +#ifdef PY3K +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, /* m_base */ + MODULE_NAME, /* m_name */ + MODULE_DOC, /* m_doc */ + -1, /* m_size */ + process_methods, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ +}; +#endif + + +/* Some defines to make the module init function readable */ +#ifdef PY3K +#define MODFUNC PyInit_process +#define RETURN(VAR) return VAR +#else +#define MODFUNC initprocess +#define RETURN(VAR) return +#endif + + +/* Returns the psi.process module */ +PyMODINIT_FUNC +MODFUNC(void) +{ + PyObject *mod = NULL; + + if (prepare_types() < 0) + RETURN(NULL); + if (init_exceptions() < 0) + goto error; +#ifdef PY3K + mod = PyModule_Create(&moduledef); +#else + mod = Py_InitModule3(MODULE_NAME, process_methods, MODULE_DOC); +#endif + if (mod == NULL) + goto error; + if (add_module_objects(mod) < 0) + goto error; + RETURN(mod); + + error: + Py_XDECREF(mod); + Py_XDECREF(PsiExc_AttrNotAvailableError); + Py_XDECREF(PsiExc_AttrInsufficientPrivsError); + Py_XDECREF(PsiExc_AttrNotImplementedError); + Py_XDECREF(PsiExc_MissingResourceError); + Py_XDECREF(PsiExc_InsufficientPrivsError); + Py_XDECREF(PsiExc_NoSuchProcessError); + Py_DECREF((PyObject*)&PsiProcess_Type); + Py_DECREF((PyObject*)&PsiProcessTable_Type); + RETURN(NULL); +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80e25b46/tools/bin/pythonSrc/PSI-0.3b2_gp/src/processtable.c ---------------------------------------------------------------------- diff --git a/tools/bin/pythonSrc/PSI-0.3b2_gp/src/processtable.c b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/processtable.c new file mode 100644 index 0000000..81cee6f --- /dev/null +++ b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/processtable.c @@ -0,0 +1,240 @@ +/* The MIT License + * + * Copyright (C) 2008-2009 Floris Bruynooghe + * + * Copyright (C) 2008-2009 Abilisoft Ltd. + * + * Copyright (C) 2009 Erick Tryzelaar + * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** psi.process.ProcessTable class + * + * This file contains the common support for the psi.process.ProcessTable + * class. + */ + + +#include <Python.h> + +#include "psi.h" +#include "process.h" + + +/* The ProcessTableObject. It has no extra fields. */ +typedef PyDictObject PsiProcessTableObject; + + +/* Declarations */ +static int add_procs_to_table(PsiProcessTableObject *pt, + const struct psi_proclist *prl); + + +/* ProcessTable methods */ + + +static int +ProcessTable_init(PsiProcessTableObject *self, PyObject *args, PyObject *kwds) +{ + struct psi_proclist *prl; + int r; + + if (args != NULL && PySequence_Length(args) > 0) { + PyErr_Format(PyExc_TypeError, + "__init__() takes no arguments (%d given)", + (int)PySequence_Length(args)); + return -1; + } + if (kwds != NULL && PyMapping_Length(kwds) > 0) { + PyErr_SetString(PyExc_TypeError, + "__init__() takes no keyword arguments"); + return -1; + } + if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0) + return -1; + prl = psi_arch_proclist(); + if (prl == NULL) + return -1; + r = add_procs_to_table(self, prl); + psi_free_proclist(prl); + return r; +} + + +static PyObject * +ProcessTable_repr(PsiProcessTableObject *self) +{ + return PyStr_FromString("psi.process.ProcessTable()"); +} + + +static int +ProcessTable_ass_subscript(PsiProcessTableObject *self, + PyObject *item, PyObject *value) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "ProcessTable does not support item deletion"); + } else { + PyErr_SetString(PyExc_TypeError, + "ProcessTable does not support item assignment"); + } + return -1; +} + + +static PyMappingMethods ProcessTable_as_mapping = { + 0, /* mp_length */ + 0, /* mp_subscript */ + (objobjargproc)ProcessTable_ass_subscript, /* mp_ass_subscript */ +}; + + +PyTypeObject PsiProcessTable_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "psi.process.ProcessTable", /* tp_name */ + sizeof(PsiProcessTableObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)ProcessTable_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + &ProcessTable_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "A dictionary of all processes (snapshot)", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PyDict_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)ProcessTable_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + + +/* Local functions */ + + +/* Always returns NULL */ +void * +psi_free_proclist(struct psi_proclist *prl) +{ + psi_free(prl->pids); + psi_free(prl); + return NULL; +} + + +/** Add Process objects to a PsiProcessTableObject + * + * This will create a Process object for each PID in the `prl' proclist + * structure and add it to the ProcessTable object `pt'. This will also reset + * `pt->count' to the value of `prl->count'. If a process listed in the + * proclist structure does no longer exist (newProcessObject() raise a + * NoSuchProcessError) it will be silently skipped and `pt->count' will be + * updated accordingly. + * + * Return 0 on success and -1 on failure. + */ +static int +add_procs_to_table(PsiProcessTableObject *pt, const struct psi_proclist *prl) +{ + PyObject *proc; + PyObject *key; + int i; + int r; + + for (i = 0; i < prl->count; i++) { + proc = PsiProcess_New(prl->pids[i]); + if (proc == NULL && PyErr_ExceptionMatches(PsiExc_NoSuchProcessError)) { + PyErr_Clear(); + continue; + } else if (proc == NULL) + return -1; + key = PyLong_FromLong(prl->pids[i]); + if (key == NULL) { + Py_DECREF(proc); + return -1; + } + r = PyDict_SetItem((PyObject*)pt, key, proc); + Py_DECREF(proc); + Py_DECREF(key); + if (r == -1) + return -1; + } + return 0; +} + + +/** Create a new ProcessTableObject + * + * The ugly part is that PyDict_Type.tp_init (called by ProcessTable_init()) + * does not cope with NULL as args or kwds. Oh well. + */ +PyObject * +PsiProcessTable_New(void) +{ + PyObject *args = NULL; + PyObject *kwds = NULL; + PyObject *obj; + + obj = PyDict_Type.tp_new(&PsiProcessTable_Type, NULL, NULL); + if (obj == NULL) + return NULL; + args = PyTuple_New(0); + if (args == NULL) + goto error; + kwds = PyDict_New(); + if (kwds == NULL) + goto error; + if (ProcessTable_init((PsiProcessTableObject *)obj, args, kwds) != 0) + goto error; + Py_DECREF(args); + Py_DECREF(kwds); + return obj; + + error: + Py_XDECREF(args); + Py_XDECREF(kwds); + Py_DECREF(obj); + return NULL; +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80e25b46/tools/bin/pythonSrc/PSI-0.3b2_gp/src/timespec.c ---------------------------------------------------------------------- diff --git a/tools/bin/pythonSrc/PSI-0.3b2_gp/src/timespec.c b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/timespec.c new file mode 100644 index 0000000..548886a --- /dev/null +++ b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/timespec.c @@ -0,0 +1,852 @@ +/* The MIT License + * + * Copyright (C) 2009 Floris Bruynooghe + * + * Copyright (C) 2009 Erick Tryzelaar + * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** _psi.TimeSpec class + * + * This file contains the TimeSpec class, the way psi represents time. + */ + + +#include <Python.h> + +#include <time.h> + +#include "psi.h" +#include "psifuncs.h" +#include "posix_utils.h" + + +#if PY_VERSION_HEX < 0x02030000 /* < 2.3 */ +#define HAVE_DATETIME 0 +#else +#define HAVE_DATETIME 1 +#endif + + +/** The Python TimeSpec object + * + * Note that since Python initialises all members to 0, even when this object + * did not have it's .__init__() method called it will be valid and useful. + */ +typedef struct { + PyObject_HEAD + struct timespec tv; +} PsiTimeSpecObject; + + +/***** Global Variables *****/ + +#if HAVE_DATETIME +/* datetime.datetime.fromtimestamp */ +static PyObject *FROMTIMESTAMP = NULL; +/* datetime.datetime.utcfromtimestamp */ +static PyObject *UTCFROMTIMESTAMP = NULL; +/* datetime.datetime.timedelta */ +static PyObject *TIMEDELTA = NULL; +#endif /* HAVE_DATETIME */ + + +/***** Local helper function *****/ + + +static void +norm_timespec(struct timespec *tv) +{ + if (tv->tv_nsec >= 1000000000) { + tv->tv_sec += tv->tv_nsec / 1000000000; + tv->tv_nsec = tv->tv_nsec % 1000000000; + } else if (tv->tv_nsec <= -1000000000) { + tv->tv_sec -= -(tv->tv_nsec) / 1000000000; + tv->tv_nsec = -(tv->tv_nsec) % 1000000000; + } + if (tv->tv_sec > 0 && tv->tv_nsec < 0) { + tv->tv_sec--; + tv->tv_nsec = 1000000000 + tv->tv_nsec; + } else if (tv->tv_sec < 0 && tv->tv_nsec > 0) { + tv->tv_sec++; + tv->tv_nsec = tv->tv_nsec - 1000000000; + } +} + + +/** Convert PsiTimeSpecObject to struct timespec + * + * Use any2timespec() instead. + */ +static struct timespec +timespec2timespec(const PsiTimeSpecObject *pyo) +{ + return pyo->tv; +} + + +/** Convert a PyTypleObject to struct timespec + * + * Use any2timespec() instead. + */ +static struct timespec +tuple2timespec(const PyObject *tuple) +{ + struct timespec tv = {0, 0}; + PyObject *pyo; + + if (!PyTuple_Check(tuple) || PyTuple_GET_SIZE(tuple) != 2) { + PyErr_SetString(PyExc_TypeError, "Not tuple or size != 2"); + return tv; + } + pyo = PyTuple_GET_ITEM(tuple, 0); + if (PyLong_Check(pyo)) + tv.tv_sec = PyLong_AsLong(pyo); +#ifndef PY3K + else if (PyInt_Check(pyo)) + tv.tv_sec = PyInt_AsLong(pyo); +#endif + else { + PyErr_SetString(PyExc_TypeError, "Non-number inside tuple"); + return tv; + } + if (PyErr_Occurred() != NULL) + return tv; + pyo = PyTuple_GET_ITEM(tuple, 1); + if (PyLong_Check(pyo)) + tv.tv_nsec = PyLong_AsLong(pyo); +#ifndef PY3K + else if (PyInt_Check(pyo)) + tv.tv_nsec = PyInt_AsLong(pyo); +#endif + else { + PyErr_SetString(PyExc_TypeError, "Non-number inside tuple"); + return tv; + } + return tv; +} + + +/** Convert a Python int to a struct timespec + * + * Use any2timespec() instead. + */ +#ifndef PY3K +static struct timespec +int2timespec(const PyObject *obj) +{ + struct timespec tv; + + if (!PyInt_Check(obj)) + PyErr_SetString(PyExc_TypeError, "Not an integer object"); + else { + tv.tv_sec = PyInt_AS_LONG(obj); + tv.tv_nsec = 0; + } + return tv; +} +#endif + + +/** Convert a Python long to a struct timespec + * + * Use any2timespec() instead. + */ +static struct timespec +long2timespec(PyObject *obj) +{ + struct timespec tv; + + if (!PyLong_Check(obj)) + PyErr_SetString(PyExc_TypeError, "Not a long object"); + else { + tv.tv_sec = PyLong_AsLong(obj); + tv.tv_nsec = 0; + } + return tv; +} + + +/** Convert a Python float to a struct timespec + * + * Use any2timespec() instead. + */ +static struct timespec +float2timespec(PyObject *obj) +{ + struct timespec tv; + + if (!PyFloat_Check(obj)) + PyErr_SetString(PyExc_TypeError, "Not a float object"); + else + /* Don't use PyFloat_AS_DOUBLE() here as that macro causes alignment + * issues on SunOS 5.10 sun4v. */ + tv = posix_double2timespec(PyFloat_AsDouble(obj)); + return tv; +} + + +/** Convert any Python object to a struct timespec if possible + * + * This function will attempt to convert any Python object into a timespec + * structure. The objects that can be converted are: psi.TimeSpec, 2-tuple of + * integers, int or long and float. + * + * A TypeError will be raised if the object can't be converted, you must check + * this with PyErr_Occurred(). + */ +static struct timespec +any2timespec(PyObject *obj) +{ + struct timespec tv; + + if (PyObject_TypeCheck(obj, &PsiTimeSpec_Type)) + tv = timespec2timespec((PsiTimeSpecObject *)obj); + else if (PyTuple_Check(obj)) + tv = tuple2timespec(obj); + else if (PyFloat_Check(obj)) + tv = float2timespec(obj); +#ifndef PY3K + else if (PyInt_Check(obj)) + tv = int2timespec(obj); +#endif + else if (PyLong_Check(obj)) + tv = long2timespec(obj); + else + PyErr_SetString(PyExc_TypeError, + "Unable to convert object to timespec structure"); + if (PyErr_Occurred() == NULL) + norm_timespec(&tv); + return tv; +} + + +/** Import and return the time module + * + * This will import the time module and return it. Returns a borrowed + * reference or NULL on failure. + */ +static PyObject * +import_time(void) +{ + static PyObject *time = NULL; + + if (time != NULL) + return time; + time = PyImport_ImportModuleNoBlock("time"); + return time; +} + + +#if HAVE_DATETIME + +/** Initialise datetime module + * + * This initialises the UTCFROMTIMESTAMP, FROMTIMESTAMP and TIMEDELTA global + * variables. + */ +static int +init_datetime(void) +{ + PyObject *mod; + PyObject *dt; + + mod = PyImport_ImportModuleNoBlock("datetime"); + if (mod == NULL) + return -1; + dt = PyObject_GetAttrString(mod, "datetime"); + if (dt == NULL) { + Py_DECREF(mod); + return -1; + } + FROMTIMESTAMP = PyObject_GetAttrString(dt, "fromtimestamp"); + if (FROMTIMESTAMP == NULL) { + Py_DECREF(mod); + return -1; + } + UTCFROMTIMESTAMP = PyObject_GetAttrString(dt, "utcfromtimestamp"); + Py_DECREF(dt); + if (UTCFROMTIMESTAMP == NULL) { + Py_DECREF(FROMTIMESTAMP); + Py_DECREF(mod); + return -1; + } + TIMEDELTA = PyObject_GetAttrString(mod, "timedelta"); + Py_DECREF(mod); + if (TIMEDELTA == NULL) { + Py_CLEAR(FROMTIMESTAMP); + Py_CLEAR(UTCFROMTIMESTAMP); + return -1; + } + return 0; +} + + +/* Can't use PyDateTime_IMPORT and all API things associated with it since + * that was only introduced in python 2.4 and we support 2.3 as a minimum. + * Even if we could it would be pain to use for this. */ +static PyObject * +timespec2datetime(const struct timespec *tspec) +{ + PyObject *datetime; + PyObject *timedelta; + PyObject *ret; + + if (FROMTIMESTAMP == NULL || TIMEDELTA == NULL) + if (init_datetime() < 0) + return NULL; + datetime = PyObject_CallFunction(FROMTIMESTAMP, "(l)", tspec->tv_sec); + if (datetime == NULL) + return NULL; + timedelta = PyObject_CallFunction(TIMEDELTA, "(iil)", + 0, 0, tspec->tv_nsec/1000); + if (timedelta == NULL) { + Py_DECREF(datetime); + return NULL; + } + ret = PyObject_CallMethod(datetime, "__add__", "(O)", timedelta); + Py_DECREF(datetime); + Py_DECREF(timedelta); + return ret; +} + + +static PyObject * +timespec2utcdatetime(const struct timespec *tspec) +{ + PyObject *datetime; + PyObject *timedelta; + PyObject *ret; + + if (UTCFROMTIMESTAMP == NULL || TIMEDELTA == NULL) + if (init_datetime() < 0) + return NULL; + datetime = PyObject_CallFunction(UTCFROMTIMESTAMP, "(l)", tspec->tv_sec); + if (datetime == NULL) + return NULL; + timedelta = PyObject_CallFunction(TIMEDELTA, "(iil)", + 0, 0, tspec->tv_nsec/1000); + if (timedelta == NULL) { + Py_DECREF(datetime); + return NULL; + } + ret = PyObject_CallMethod(datetime, "__add__", "(O)", timedelta); + Py_DECREF(datetime); + Py_DECREF(timedelta); + return ret; +} + + +static PyObject * +timespec2timedelta(const struct timespec *tspec) +{ + if (TIMEDELTA == NULL) + if (init_datetime() < 0) + return NULL; + return PyObject_CallFunction(TIMEDELTA, "(ill)", + 0, tspec->tv_sec, tspec->tv_nsec/1000); +} + +#endif /* HAVE_DATETIME */ + + +/***** TimeSpec methods *****/ + + +static int +TimeSpec_init(PsiTimeSpecObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"tv_sec", "tv_nsec", NULL}; + long tv_sec = 0; + long tv_nsec = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ll", kwlist, + &tv_sec, &tv_nsec)) + return -1; + self->tv.tv_sec = tv_sec; + self->tv.tv_nsec = tv_nsec; + norm_timespec(&self->tv); + return 0; +} + + +static PyObject * +TimeSpec_repr(PsiTimeSpecObject *self) +{ + return PyStr_FromFormat("%s(tv_sec=%ld, tv_nsec=%ld)", + Py_TYPE(self)->tp_name, + (long)self->tv.tv_sec, + (long)self->tv.tv_nsec); +} + + +static PyObject * +TimeSpec_get_tv_sec(PsiTimeSpecObject *self, void *closure) +{ + return PyLong_FromLong(self->tv.tv_sec); +} + + +static PyObject * +TimeSpec_get_tv_nsec(PsiTimeSpecObject *self, void *closure) +{ + return PyLong_FromLong(self->tv.tv_nsec); +} + + +static PyObject * +TimeSpec_getitem(PsiTimeSpecObject *self, Py_ssize_t i) +{ + if (i == 0) + return PyLong_FromLong(self->tv.tv_sec); + else if (i == 1) + return PyLong_FromLong(self->tv.tv_nsec); + else { + PyErr_SetString(PyExc_IndexError, "index out of range"); + return NULL; + } +} + + +static long +TimeSpec_hash(PsiTimeSpecObject *self) +{ + PyObject *tuple; + PyObject *item; + long hash = -1; + + if ((tuple = PyTuple_New(2)) == NULL) + return -1; + + item = PyLong_FromLong(self->tv.tv_sec); + if (item == NULL) + goto end; + PyTuple_SET_ITEM(tuple, 0, item); + item = PyLong_FromLong(self->tv.tv_nsec); + if (item == NULL) + goto end; + PyTuple_SET_ITEM(tuple, 1, item); + hash = PyObject_Hash(tuple); + + end: + Py_DECREF(tuple); + return hash; +} + + +static PyObject * +TimeSpec_richcompare(PyObject *v, PyObject *w, int op) +{ + struct timespec vo, wo; + PyObject *result; + int istrue; + + vo = any2timespec(v); + if (PyErr_Occurred() != NULL) + goto error; + wo = any2timespec(w); + if (PyErr_Occurred() != NULL) + goto error; + + /* Note that vo and wo are normalised so simple comparison is fine. */ + switch (op) { + case Py_EQ: + istrue = vo.tv_sec == wo.tv_sec && vo.tv_nsec == wo.tv_nsec; + break; + case Py_NE: + istrue = vo.tv_sec != wo.tv_sec || vo.tv_nsec != wo.tv_nsec; + break; + case Py_LE: + istrue = vo.tv_sec <= wo.tv_sec && vo.tv_nsec <= wo.tv_nsec; + break; + case Py_GE: + istrue = vo.tv_sec >= wo.tv_sec && vo.tv_nsec >= wo.tv_nsec; + break; + case Py_LT: + if (vo.tv_sec != wo.tv_sec) + istrue = vo.tv_sec < wo.tv_sec; + else + istrue = vo.tv_nsec < wo.tv_nsec; + break; + case Py_GT: + if (vo.tv_sec != wo.tv_sec) + istrue = vo.tv_sec > wo.tv_sec; + else + istrue = vo.tv_nsec > wo.tv_nsec; + break; + default: + assert(!"op unknown"); + istrue = 0; /* To shut up compiler */ + } + result = istrue ? Py_True : Py_False; + Py_INCREF(result); + return result; + + error: + PyErr_Clear(); + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + + +static PyObject * +TimeSpec_add(PyObject *v, PyObject *w) +{ + struct timespec vo, wo; + + vo = any2timespec(v); + if (PyErr_Occurred() != NULL) + goto error; + wo = any2timespec(w); + if (PyErr_Occurred() != NULL) + goto error; + + vo.tv_sec += wo.tv_sec; + vo.tv_nsec += wo.tv_nsec; + /* PsiTimeSpec_InternalNew() does normalise the members for us. */ + return PsiTimeSpec_InternalNew(&vo); + + error: + PyErr_Clear(); + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + + +static PyObject * +TimeSpec_subtract(PyObject *v, PyObject *w) +{ + struct timespec vo, wo; + + vo = any2timespec(v); + if (PyErr_Occurred() != NULL) + goto error; + wo = any2timespec(w); + if (PyErr_Occurred() != NULL) + goto error; + + vo.tv_sec -= wo.tv_sec; + vo.tv_nsec -= wo.tv_nsec; + /* PsiTimeSpec_InternalNew() does normalise the members for us. */ + return PsiTimeSpec_InternalNew(&vo); + + error: + PyErr_Clear(); + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + + +static int +TimeSpec_bool(PsiTimeSpecObject *self) +{ + return self->tv.tv_sec != 0 || self->tv.tv_nsec != 0; +} + + +PyDoc_STRVAR(TimeSpec_timestamp__doc, "\ +TimeSpec.timestamp() -> float\n\ +\n\ +Convert a TimeSpec into a UNIX timestamp from the unix EPOCH. If you\n\ +wanted the integer timestamp just use the tv_sec attribute.\ +"); +PyDoc_STRVAR(TimeSpec_float__doc, "\ +TimeSpec.float() -> float\n\ +\n\ +Alias for .timestamp(), but this may be more natural when working with\n\ +durations.\ +"); +static PyObject * +TimeSpec_timestamp(PsiTimeSpecObject *self) +{ + double d = (double)self->tv.tv_sec + ((double)self->tv.tv_nsec * 1.0e-9); + return PyFloat_FromDouble(d); +} + + +PyDoc_STRVAR(TimeSpec_mktime__doc, "\ +TimeSpec.mktime() -> float\n\ +\n\ +Return the time as a floating point, but converted to the local\n\ +timezone. The returned time is not a UNIX or POSIX timestamp.\ +"); +static PyObject * +TimeSpec_mktime(PsiTimeSpecObject *self) +{ + PyObject *time; + PyObject *obj; + double d; + long l = self->tv.tv_sec; + + time = import_time(); + if (time == NULL) + return NULL; + + /* Add timezone difference */ + obj = PyObject_GetAttrString(time, "timezone"); + if (obj == NULL) + return NULL; + if (PyLong_Check(obj)) + l += PyLong_AsLong(obj); +#ifndef PY3K + else if (PyInt_Check(obj)) + l += PyInt_AsLong(obj); +#endif + Py_DECREF(obj); + if (PyErr_Occurred()) + return NULL; + + /* Add DST difference */ + obj = PyObject_GetAttrString(time, "altzone"); + if (obj == NULL) + return NULL; + if (PyLong_Check(obj)) + l += PyLong_AsLong(obj); +#ifndef PY3K + else if (PyInt_Check(obj)) + l += PyInt_AsLong(obj); +#endif + Py_DECREF(obj); + if (PyErr_Occurred()) + return NULL; + + d = (double)l + ((double)self->tv.tv_nsec * 1.0e-9); + return PyFloat_FromDouble(d); +} + + +PyDoc_STRVAR(TimeSpec_timetuple__doc, "\ +TimeSpec.timetuple() -> time.struct_time\n\ +\n\ +Returns a time.struct_time instance in UTC.\ +"); +PyDoc_STRVAR(TimeSpec_gmtime__doc, "\ +TimeSpec.gmtime() -> time.struct_time\n\ +\n\ +Alias for TimeSpec.timetuple()\ +"); +static PyObject * +TimeSpec_timetuple(PsiTimeSpecObject *self) +{ + PyObject *time; + PyObject *timetuple; + + time = import_time(); + if (time == NULL) + return NULL; + timetuple = PyObject_CallMethod(time, "gmtime", "(l)", self->tv.tv_sec); + return timetuple; +} + + +PyDoc_STRVAR(TimeSpec_localtime__doc, "\ +TimeSpec.localtime() -> time.struct_time\n\ +\n\ +Returns a time.struct_time instance in the local timezone.\ +"); +static PyObject * +TimeSpec_localtime(PsiTimeSpecObject *self) +{ + PyObject *time; + PyObject *localtime; + + time = import_time(); + if (time == NULL) + return NULL; + localtime = PyObject_CallMethod(time, "localtime", "(l)", self->tv.tv_sec); + return localtime; +} + + +#if HAVE_DATETIME + +PyDoc_STRVAR(TimeSpec_utcdatetime__doc, "\ +TimeSpec.utcdatetime()\n\ +\n\ +Returns a datetime.datetime instance representing the time in UTC.\ +"); +static PyObject * +TimeSpec_utcdatetime(PsiTimeSpecObject *self) +{ + return timespec2utcdatetime(&self->tv); +} + + +PyDoc_STRVAR(TimeSpec_datetime__doc, "\ +TimeSpec.datetime() -> datetime.datetime\n\ +\n\ +Returns a datetime.datetime instance representing the time in the local\n\ +timezone. Note that the tzinfo of the datetime object will be unset.\ +"); +static PyObject * +TimeSpec_datetime(PsiTimeSpecObject *self) +{ + return timespec2datetime(&self->tv); +} + + +PyDoc_STRVAR(TimeSpec_timedelta__doc, "\ +TimeSpec.timedelta() -> datetime.timedelta\n\ +\n\ +Retruns a datetime.timedelta instance representing the time as a duration.\ +"); +static PyObject * +TimeSpec_timedelta(PsiTimeSpecObject *self) +{ + return timespec2timedelta(&self->tv); +} + +#endif /* HAVE_DATETIME */ + + +static PyGetSetDef TimeSpec_getseters[] = { + {"tv_sec", (getter)TimeSpec_get_tv_sec, (setter)NULL, + "Seconds", NULL}, + {"tv_nsec", (getter)TimeSpec_get_tv_nsec, (setter)NULL, + "Nanoseconds", NULL}, + {NULL} /* Sentinel */ +}; + + +static PyNumberMethods TimeSpec_as_number = { + (binaryfunc)TimeSpec_add, /* nb_add */ + (binaryfunc)TimeSpec_subtract, /* nb_subtract */ + 0, /* nb_multiply */ +#ifndef PY3K + 0, /* nb_divide */ +#endif + 0, /* nb_remainder */ + 0, /* nb_divmod */ + 0, /* nb_power */ + 0, /* nb_negative */ + 0, /* nb_posistive */ + 0, /* nb_absolute */ + (inquiry)TimeSpec_bool, /* nb_nonzero(2.X)/nb_bool(3.X) */ +}; + + +static PySequenceMethods TimeSpec_as_sequence = { + 0, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + (ssizeargfunc)TimeSpec_getitem, /* sq_item */ + 0, /* sq_ass_item */ + 0, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ +}; + + +static PyMethodDef TimeSpec_methods[] = { + {"timestamp", (PyCFunction)TimeSpec_timestamp, + METH_NOARGS, TimeSpec_timestamp__doc}, + {"float", (PyCFunction)TimeSpec_timestamp, + METH_NOARGS, TimeSpec_float__doc}, + {"mktime", (PyCFunction)TimeSpec_mktime, + METH_NOARGS, TimeSpec_mktime__doc}, + {"timetuple", (PyCFunction)TimeSpec_timetuple, + METH_NOARGS, TimeSpec_timetuple__doc}, + {"gmtime", (PyCFunction)TimeSpec_timetuple, + METH_NOARGS, TimeSpec_gmtime__doc}, + {"localtime", (PyCFunction)TimeSpec_localtime, + METH_NOARGS, TimeSpec_localtime__doc}, +#if HAVE_DATETIME + {"utcdatetime", (PyCFunction)TimeSpec_utcdatetime, + METH_NOARGS, TimeSpec_utcdatetime__doc}, + {"datetime", (PyCFunction)TimeSpec_datetime, + METH_NOARGS, TimeSpec_datetime__doc}, + {"timedelta", (PyCFunction)TimeSpec_timedelta, + METH_NOARGS, TimeSpec_timedelta__doc}, +#endif /* HAVE_DATETIME */ + {NULL} /* Sentinel */ +}; + + +PyDoc_STRVAR(TimeSpec__doc, "\ +TimeSpec(tv_sec=x, tv_nsec=y) -> TimeSpec object\n\ +\n\ +This represents either absolute time since the epoch\n\ +(00:00 1 January 1970 UTC) in seconds and nanosecods,\n\ +or relative time in seconds and nanoseconds.\n\ +\n\ +It behaves a little bit like a tuple, but only index 0 and 1\n\ +are allowed, negative indexes don't work and neither does len().\n\ +Comparison with a tuple of lenght 2 works too.\n\ +"); +PyTypeObject PsiTimeSpec_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "psi.TimeSpec", /* tp_name */ + sizeof(PsiTimeSpecObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)TimeSpec_repr, /* tp_repr */ + &TimeSpec_as_number, /* tp_as_number */ + &TimeSpec_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)TimeSpec_hash, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE /* tp_flags */ +#ifndef PY3K + | Py_TPFLAGS_CHECKTYPES +#endif + , + TimeSpec__doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + (richcmpfunc)TimeSpec_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + TimeSpec_methods, /* tp_methods */ + 0, /* tp_members */ + TimeSpec_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)TimeSpec_init, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ +}; + + +PyObject * +PsiTimeSpec_InternalNew(const struct timespec *tv) +{ + PsiTimeSpecObject *obj; + + obj = (PsiTimeSpecObject*)PyType_GenericNew(&PsiTimeSpec_Type, NULL, NULL); + if (obj == NULL) + return NULL; + obj->tv = *tv; /* Skip calling the .__init__() method */ + norm_timespec(&obj->tv); + return (PyObject*)obj; +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80e25b46/tools/bin/pythonSrc/PSI-0.3b2_gp/src/util.c ---------------------------------------------------------------------- diff --git a/tools/bin/pythonSrc/PSI-0.3b2_gp/src/util.c b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/util.c new file mode 100644 index 0000000..5da6320 --- /dev/null +++ b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/util.c @@ -0,0 +1,604 @@ +/* The MIT License + * + * Copyright (C) 2008-2009 Floris Bruynooghe + * + * Copyright (C) 2008-2009 Abilisoft Ltd. + * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <Python.h> + +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include "psi.h" + + +/***** Global Variables *****/ + +/* psi._psi._C_API */ +static PyObject *(*TIMESPEC)(const struct timespec *) = NULL; + + +/***** Functions *****/ + + +int +psi_checkattr(const char *name, const int status) +{ + if (status == PSI_STATUS_OK) + return 0; + else if (status == PSI_STATUS_NI) + PyErr_Format(PsiExc_AttrNotImplementedError, + "%s is not implemented on this system", name); + else if (status == PSI_STATUS_NA) + PyErr_Format(PsiExc_AttrNotAvailableError, + "%s is not available for this process", name); + else if (status == PSI_STATUS_PRIVS) + PyErr_Format(PsiExc_AttrInsufficientPrivsError, + "Insufficient privileges for %s", name); + return -1; +} + + +void * +psi_malloc(size_t size) +{ + void *value; + +#ifdef PYMALLOC + value = PyMem_Malloc(size); +#else + value = malloc(size); +#endif + if (value == NULL) + PyErr_NoMemory(); + return value; +} + + +void * +psi_realloc(void *ptr, size_t size) +{ + void *value; + +#ifdef PYMALLOC + value = PyMem_Realloc(ptr, size); +#else + value = realloc(ptr, size); +#endif + if (value == NULL) + PyErr_NoMemory(); + return value; +} + + +void +psi_free(void *ptr) +{ +#ifdef PYMALLOC + PyMem_Free(ptr); +#else + free(ptr); +#endif +} + + +void * +psi_calloc(size_t size) +{ + void *value; + + value = psi_malloc(size); + if (value == NULL) + return NULL; + memset(value, 0, size); + return value; +} + + +char * +psi_strdup(const char *str) +{ + char *to; + + to = psi_malloc((size_t)(strlen(str)+1)); + if (to == NULL) + return NULL; + return strcpy(to, str); +} + + +char * +psi_strndup(const char *str, size_t n) +{ + char *to; + + to = psi_malloc((size_t)(n+1)); + if (to == NULL) + return NULL; + to[n] = '\0'; + return strncpy(to, str, n); +} + + +int +psi_asprintf(char **ptr, const char *template, ...) +{ + va_list ap; + int r; + size_t size = 128; + char *ptr2; + + *ptr = (char *)psi_malloc(size); + if (*ptr == NULL) { + PyErr_NoMemory(); + return -1; + } + va_start(ap, template); + r = PyOS_vsnprintf(*ptr, size, template, ap); + va_end(ap); + if (r < 0) { + psi_free(*ptr); + *ptr = NULL; + PyErr_Format(PyExc_OSError, + "PyOS_vsnprintf returned error code: %d", r); + return -1; + } + else if (r > (int)size) { + size = (size_t)r + 1; + ptr2 = (char *)psi_realloc(*ptr, size); + if (ptr2 == NULL) { + psi_free(*ptr); + ptr = NULL; + PyErr_NoMemory(); + return -1; + } + *ptr = ptr2; + va_start(ap, template); + r = PyOS_vsnprintf(*ptr, size, template, ap); + va_end(ap); + if (r < 0 || r > (int)size) { + psi_free(*ptr); + *ptr = NULL; + if (r < 0) + PyErr_Format(PyExc_OSError, + "PyOS_vsnprintf returned error code: %d", r); + else + PyErr_SetString(PyExc_OSError, + "Required size from PyOS_vsnprintf was wrong!"); + return -1; + } + } + return size; +} + + +int +psi_read_file(char **buf, char *path) +{ + char *p, *startp; + FILE *file; + int n; + int bufsize = 2048; + int count = 0; + int endoffile = 0; + + errno = 0; + file = fopen(path, "r"); + if (file == NULL) { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, path); + if (errno == EACCES || errno == EPERM) + return -2; + else + return -1; + } + startp = p = (char*) psi_malloc(bufsize + 1); + if (p == NULL) + return -1; + while ((n = fread(p, sizeof(char), 2048, file)) > 0) { + count += n; + if (n < 2048) + break; + /* We didn't have a big enough buffer so allocate some more. */ + bufsize += 2048; + startp = psi_realloc(startp, bufsize + 1); + if (startp == NULL) { + fclose(file); + return -1; + } + + /* Update our pointer to the end of the buffer */ + p = startp + count; + } + endoffile = feof(file); + fclose(file); + + if (!endoffile) { /* read error */ + psi_free(startp); + return -2; /* XXX: Should be more specific here. */ + } + + /* Make sure the last character is null. */ + startp[count] = '\0'; + *buf = startp; + return count; +} + + +int +psi_readlink(char **target, char *link) +{ + void *ptr; + size_t size = 128; + int r; + + *target = (char *)psi_malloc(size); + if (*target == NULL) + return -1; + errno = 0; + r = readlink(link, *target, size-1); + while ((size_t)r == size-1) { + size += 128; + ptr = (char *)psi_realloc(*target, size); + if (ptr == NULL) { + psi_free(*target); + *target = NULL; + return -1; + } + *target = ptr; + errno = 0; + r = readlink(link, *target, size-1); + } + if (r == -1) { + psi_free(*target); + *target = NULL; + PyErr_SetFromErrnoWithFilename(PyExc_OSError, link); + if (errno == EACCES || errno == EPERM) + return -2; + else + return -1; + } + (*target)[r] = '\0'; + return 0; +} + + +int +psi_strings_count(const char *cmdl, const int size) +{ + int i = 0; + int n = 0; + + while (i < size) { + if (cmdl[i] == '\0') + n += 1; + i++; + } + return n; +} + + +char ** +psi_strings_to_array(char *buf, const int count) +{ + char **array; + char *ptr; + int i; + int j; + int l; + + array = psi_malloc(count * sizeof(char*)); + if (array == NULL) + return NULL; + ptr = buf; + for (i = 0; i < count; i++) { + l = strlen(ptr) + 1; + array[i] = psi_malloc(l); + if (array[i] == NULL) { + for (j = 0; j < i; j++) + psi_free(array[j]); + psi_free(array); + return NULL; + } + memcpy(array[i], ptr, l); + ptr += l; + } + return array; +} + + +PyObject * +PsiTimeSpec_New(const struct timespec *tv) +{ + if (TIMESPEC == NULL) { + PyObject *mod; + PyObject *c_api; + + mod = PyImport_ImportModuleNoBlock("psi._psi"); + if (mod == NULL) + return NULL; + c_api = PyObject_GetAttrString(mod, "_C_API"); + if (c_api == NULL) { + Py_DECREF(mod); + return NULL; + } + TIMESPEC = PyCObject_AsVoidPtr(c_api); + } + return (*TIMESPEC)(tv); +} + + +#if PY_VERSION_HEX < 0x02040000 /* < 2.4 */ + +/* This is copied from Python 2.6 sources. */ + +#include <locale.h> + +/* ascii character tests (as opposed to locale tests) */ +#define ISSPACE(c) ((c) == ' ' || (c) == '\f' || (c) == '\n' || \ + (c) == '\r' || (c) == '\t' || (c) == '\v') +#define ISDIGIT(c) ((c) >= '0' && (c) <= '9') + +/** + * PyOS_ascii_strtod: + * @nptr: the string to convert to a numeric value. + * @endptr: if non-%NULL, it returns the character after + * the last character used in the conversion. + * + * Converts a string to a #gdouble value. + * This function behaves like the standard strtod() function + * does in the C locale. It does this without actually + * changing the current locale, since that would not be + * thread-safe. + * + * This function is typically used when reading configuration + * files or other non-user input that should be locale independent. + * To handle input from the user you should normally use the + * locale-sensitive system strtod() function. + * + * If the correct value would cause overflow, plus or minus %HUGE_VAL + * is returned (according to the sign of the value), and %ERANGE is + * stored in %errno. If the correct value would cause underflow, + * zero is returned and %ERANGE is stored in %errno. + * If memory allocation fails, %ENOMEM is stored in %errno. + * + * This function resets %errno before calling strtod() so that + * you can reliably detect overflow and underflow. + * + * Return value: the #gdouble value. + **/ +double +PyOS_ascii_strtod(const char *nptr, char **endptr) +{ + char *fail_pos; + double val = -1.0; + struct lconv *locale_data; + const char *decimal_point; + size_t decimal_point_len; + const char *p, *decimal_point_pos; + const char *end = NULL; /* Silence gcc */ + const char *digits_pos = NULL; + int negate = 0; + + assert(nptr != NULL); + + fail_pos = NULL; + + locale_data = localeconv(); + decimal_point = locale_data->decimal_point; + decimal_point_len = strlen(decimal_point); + + assert(decimal_point_len != 0); + + decimal_point_pos = NULL; + + /* We process any leading whitespace and the optional sign manually, + then pass the remainder to the system strtod. This ensures that + the result of an underflow has the correct sign. (bug #1725) */ + + p = nptr; + /* Skip leading space */ + while (ISSPACE(*p)) + p++; + + /* Process leading sign, if present */ + if (*p == '-') { + negate = 1; + p++; + } else if (*p == '+') { + p++; + } + + /* What's left should begin with a digit, a decimal point, or one of + the letters i, I, n, N. It should not begin with 0x or 0X */ + if ((!ISDIGIT(*p) && + *p != '.' && *p != 'i' && *p != 'I' && *p != 'n' && *p != 'N') + || + (*p == '0' && (p[1] == 'x' || p[1] == 'X'))) + { + if (endptr) + *endptr = (char*)nptr; + errno = EINVAL; + return val; + } + digits_pos = p; + + if (decimal_point[0] != '.' || + decimal_point[1] != 0) + { + while (ISDIGIT(*p)) + p++; + + if (*p == '.') + { + decimal_point_pos = p++; + + while (ISDIGIT(*p)) + p++; + + if (*p == 'e' || *p == 'E') + p++; + if (*p == '+' || *p == '-') + p++; + while (ISDIGIT(*p)) + p++; + end = p; + } + else if (strncmp(p, decimal_point, decimal_point_len) == 0) + { + /* Python bug #1417699 */ + if (endptr) + *endptr = (char*)nptr; + errno = EINVAL; + return val; + } + /* For the other cases, we need not convert the decimal + point */ + } + + /* Set errno to zero, so that we can distinguish zero results + and underflows */ + errno = 0; + + if (decimal_point_pos) + { + char *copy, *c; + + /* We need to convert the '.' to the locale specific decimal + point */ + copy = (char *)PyMem_MALLOC(end - digits_pos + + 1 + decimal_point_len); + if (copy == NULL) { + if (endptr) + *endptr = (char *)nptr; + errno = ENOMEM; + return val; + } + + c = copy; + memcpy(c, digits_pos, decimal_point_pos - digits_pos); + c += decimal_point_pos - digits_pos; + memcpy(c, decimal_point, decimal_point_len); + c += decimal_point_len; + memcpy(c, decimal_point_pos + 1, + end - (decimal_point_pos + 1)); + c += end - (decimal_point_pos + 1); + *c = 0; + + val = strtod(copy, &fail_pos); + + if (fail_pos) + { + if (fail_pos > decimal_point_pos) + fail_pos = (char *)digits_pos + + (fail_pos - copy) - + (decimal_point_len - 1); + else + fail_pos = (char *)digits_pos + + (fail_pos - copy); + } + + PyMem_FREE(copy); + + } + else { + val = strtod(digits_pos, &fail_pos); + } + + if (fail_pos == digits_pos) + fail_pos = (char *)nptr; + + if (negate && fail_pos != nptr) + val = -val; + + if (endptr) + *endptr = fail_pos; + + return val; +} + +double +PyOS_ascii_atof(const char *nptr) +{ + return PyOS_ascii_strtod(nptr, NULL); +} + +#endif /* PY_VERSION_HEX < 0x02040000 */ + + +#if PY_VERSION_HEX < 0x03010000 /* < 3.1 */ + +/** Copied from Python 3.1 sources + * + * Only change was to use PyOS_ascii_strtod instead of _PyOS_ascii_strtod. + * + * Note that the PyFPE_*_PROTECT macros have been disabled. This is because + * they do a crazy thing with casts that will create a warning (they loose + * information) that doesn't matter (the information is not needed, this is + * merely used to trick the FPU from some arches into generating SIGFPE), see + * pyfpe.h for the details. + * + * The point is that commenting these macros out should not have any + * regressions, when we where using PyOS_ascii_strtod() directly we didn't use + * these macro's either. And if any of uptime or boottime (the only place + * this is used currently) do overflow I'm long dead anyway, unless something + * crazy happened to the world. + */ + +double +PyOS_string_to_double(const char *s, + char **endptr, + PyObject *overflow_exception) +{ + double x, result=-1.0; + char *fail_pos; + + errno = 0; +/* PyFPE_START_PROTECT("PyOS_string_to_double", return -1.0) */ + x = PyOS_ascii_strtod(s, &fail_pos); +/* PyFPE_END_PROTECT(x) */ + + if (errno == ENOMEM) { + PyErr_NoMemory(); + fail_pos = (char *)s; + } + else if (!endptr && (fail_pos == s || *fail_pos != '\0')) + PyErr_Format(PyExc_ValueError, + "could not convert string to float: %.200s", s); + else if (fail_pos == s) + PyErr_Format(PyExc_ValueError, + "could not convert string to float: %.200s", s); + else if (errno == ERANGE && fabs(x) >= 1.0 && overflow_exception) + PyErr_Format(overflow_exception, + "value too large to convert to float: %.200s", s); + else + result = x; + + if (endptr != NULL) + *endptr = fail_pos; + return result; +} + +#endif /* PY_VERSION_HEX < 0x03010000 */
