Split python module. Added support for cyclic GC runs.
authorSven Trenkel <collectd@semidefinite.de>
Wed, 21 Oct 2009 14:08:30 +0000 (16:08 +0200)
committerSven Trenkel <collectd@semidefinite.de>
Wed, 21 Oct 2009 14:08:30 +0000 (16:08 +0200)
src/cpython.h [new file with mode: 0644]
src/pyconfig.c [new file with mode: 0644]
src/python.c

diff --git a/src/cpython.h b/src/cpython.h
new file mode 100644 (file)
index 0000000..9be5628
--- /dev/null
@@ -0,0 +1,50 @@
+/* These two macros are basicly Py_BEGIN_ALLOW_THREADS and Py_BEGIN_ALLOW_THREADS
+ * from the other direction. If a Python thread calls a C function
+ * Py_BEGIN_ALLOW_THREADS is used to allow other python threads to run because
+ * we don't intend to call any Python functions.
+ *
+ * These two macros are used whenever a C thread intends to call some Python
+ * function, usually because some registered callback was triggered.
+ * Just like Py_BEGIN_ALLOW_THREADS it opens a block so these macros have to be
+ * used in pairs. They aquire the GIL, create a new Python thread state and swap
+ * the current thread state with the new one. This means this thread is now allowed
+ * to execute Python code. */
+
+#define CPY_LOCK_THREADS {\
+       PyGILState_STATE gil_state;\
+       gil_state = PyGILState_Ensure();
+
+#define CPY_RELEASE_THREADS \
+       PyGILState_Release(gil_state);\
+}
+
+/* Python 2.4 has this macro, older versions do not. */
+#ifndef Py_VISIT
+#define Py_VISIT(o) do {\
+       int _vret;\
+       if ((o) != NULL) {\
+               _vret = visit((o), arg);\
+               if (_vret != 0)\
+               return _vret;\
+       }\
+} while (0)
+#endif
+
+/* Python 2.4 has this macro, older versions do not. */
+#ifndef Py_CLEAR
+#define Py_CLEAR(o) do {\
+       PyObject *tmp = o;\
+       (o) = NULL;\
+       Py_XDECREF(tmp);\
+} while (0)
+#endif
+
+typedef struct {
+       PyObject_HEAD      /* No semicolon! */
+       PyObject *parent;
+       PyObject *key;
+       PyObject *values;
+       PyObject *children;
+} Config;
+
+PyTypeObject ConfigType;
diff --git a/src/pyconfig.c b/src/pyconfig.c
new file mode 100644 (file)
index 0000000..a6b4469
--- /dev/null
@@ -0,0 +1,143 @@
+#include <Python.h>
+#include <structmember.h>
+
+#include "collectd.h"
+#include "common.h"
+
+#include "cpython.h"
+
+static PyObject *Config_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
+       Config *self;
+       
+       self = (Config *) type->tp_alloc(type, 0);
+       if (self == NULL)
+               return NULL;
+       
+       self->parent = NULL;
+       self->key = NULL;
+       self->values = NULL;
+       self->children = NULL;
+       return (PyObject *) self;
+}
+
+static int Config_init(PyObject *s, PyObject *args, PyObject *kwds) {
+       PyObject *key = NULL, *parent = NULL, *values = NULL, *children = NULL, *tmp;
+       Config *self = (Config *) s;
+       static char *kwlist[] = {"key", "parent", "values", "children", NULL};
+       
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "S|OOO", kwlist,
+                       &key, &parent, &values, &children))
+               return -1;
+       
+       if (values == NULL) {
+               values = PyTuple_New(0);
+               PyErr_Clear();
+       }
+       if (children == NULL) {
+               children = PyTuple_New(0);
+               PyErr_Clear();
+       }
+       tmp = self->key;
+       Py_INCREF(key);
+       self->key = key;
+       Py_XDECREF(tmp);
+       if (parent != NULL) {
+               tmp = self->parent;
+               Py_INCREF(parent);
+               self->parent = parent;
+               Py_XDECREF(tmp);
+       }
+       if (values != NULL) {
+               tmp = self->values;
+               Py_INCREF(values);
+               self->values = values;
+               Py_XDECREF(tmp);
+       }
+       if (children != NULL) {
+               tmp = self->children;
+               Py_INCREF(children);
+               self->children = children;
+               Py_XDECREF(tmp);
+       }
+       return 0;
+}
+
+static PyObject *Config_repr(PyObject *s) {
+       Config *self = (Config *) s;
+       
+       return PyString_FromFormat("<collectd.Config %snode %s>", self->parent == Py_None ? "root " : "", PyString_AsString(PyObject_Str(self->key)));
+}
+
+static int Config_traverse(PyObject *self, visitproc visit, void *arg) {
+       Config *c = (Config *) self;
+       Py_VISIT(c->parent);
+       Py_VISIT(c->key);
+       Py_VISIT(c->values);
+       Py_VISIT(c->children);
+       return 0;
+}
+
+static int Config_clear(PyObject *self) {
+       Config *c = (Config *) self;
+       Py_CLEAR(c->parent);
+       Py_CLEAR(c->key);
+       Py_CLEAR(c->values);
+       Py_CLEAR(c->children);
+       return 0;
+}
+
+static void Config_dealloc(PyObject *self) {
+       Config_clear(self);
+       self->ob_type->tp_free(self);
+}
+
+static PyMemberDef Config_members[] = {
+       {"Parent", T_OBJECT, offsetof(Config, parent), 0, "Parent node"},
+       {"Key", T_OBJECT_EX, offsetof(Config, key), 0, "Keyword of this node"},
+       {"Values", T_OBJECT_EX, offsetof(Config, values), 0, "Values after the key"},
+       {"Children", T_OBJECT_EX, offsetof(Config, children), 0, "Childnodes of this node"},
+       {NULL}
+};
+
+PyTypeObject ConfigType = {
+       PyObject_HEAD_INIT(NULL)
+       0,                         /* Always 0 */
+       "collectd.Config",         /* tp_name */
+       sizeof(Config),            /* tp_basicsize */
+       0,                         /* Will be filled in later */
+       Config_dealloc,            /* tp_dealloc */
+       0,                         /* tp_print */
+       0,                         /* tp_getattr */
+       0,                         /* tp_setattr */
+       0,                         /* tp_compare */
+       Config_repr,               /* tp_repr */
+       0,                         /* tp_as_number */
+       0,                         /* tp_as_sequence */
+       0,                         /* 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 | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
+       "Cool help text later",    /* tp_doc */
+       Config_traverse,           /* tp_traverse */
+       Config_clear,              /* tp_clear */
+       0,                         /* tp_richcompare */
+       0,                         /* tp_weaklistoffset */
+       0,                         /* tp_iter */
+       0,                         /* tp_iternext */
+       0,                         /* tp_methods */
+       Config_members,            /* tp_members */
+       0,                         /* tp_getset */
+       0,                         /* tp_base */
+       0,                         /* tp_dict */
+       0,                         /* tp_descr_get */
+       0,                         /* tp_descr_set */
+       0,                         /* tp_dictoffset */
+       Config_init,               /* tp_init */
+       0,                         /* tp_alloc */
+       Config_new                 /* tp_new */
+};
+
index 1fda642..dc8f957 100644 (file)
@@ -4,6 +4,8 @@
 #include "collectd.h"
 #include "common.h"
 
+#include "cpython.h"
+
 typedef struct cpy_callback_s {
        char *name;
        PyObject *callback;
@@ -18,34 +20,6 @@ typedef struct cpy_callback_s {
 
 static PyThreadState *state;
 
-/* Serves the same purpose as PyEval_ThreadsInitialized but doesn't require
- * Python 2.4. */
-static int cpy_have_threads;
-
-/* These two macros are basicly Py_BEGIN_ALLOW_THREADS and Py_BEGIN_ALLOW_THREADS
- * from the other direction. If a Python thread calls a C function
- * Py_BEGIN_ALLOW_THREADS is used to allow other python threads to run because
- * we don't intend to call any Python functions.
- *
- * These two macros are used whenever a C thread intends to call some Python
- * function, usually because some registered callback was triggered.
- * Just like Py_BEGIN_ALLOW_THREADS it opens a block so these macros have to be
- * used in pairs. They aquire the GIL, create a new Python thread state and swap
- * the current thread state with the new one. This means this thread is now allowed
- * to execute Python code. */
-
-#define CPY_LOCK_THREADS {\
-       PyGILState_STATE gil_state;\
-       if (cpy_have_threads)\
-               gil_state = PyGILState_Ensure();
-
-#define CPY_RELEASE_THREADS \
-       if (cpy_have_threads)\
-               PyGILState_Release(gil_state);\
-}
-
-
 static cpy_callback_t *cpy_config_callbacks;
 static cpy_callback_t *cpy_init_callbacks;
 static cpy_callback_t *cpy_shutdown_callbacks;
@@ -77,130 +51,6 @@ static void cpy_log_callback(int severity, const char *message, user_data_t *dat
        CPY_RELEASE_THREADS
 }
 
-typedef struct {
-       PyObject_HEAD      /* No semicolon! */
-       PyObject *parent;
-       PyObject *key;
-       PyObject *values;
-       PyObject *children;
-} Config;
-
-static void Config_dealloc(PyObject *s) {
-       Config *self = (Config *) s;
-       
-       Py_XDECREF(self->parent);
-       Py_XDECREF(self->key);
-       Py_XDECREF(self->values);
-       Py_XDECREF(self->children);
-       self->ob_type->tp_free(s);
-}
-
-static PyObject *Config_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
-       Config *self;
-       
-       self = (Config *) type->tp_alloc(type, 0);
-       if (self == NULL)
-               return NULL;
-       
-       self->parent = NULL;
-       self->key = NULL;
-       self->values = NULL;
-       self->children = NULL;
-       return (PyObject *) self;
-}
-
-static int Config_init(PyObject *s, PyObject *args, PyObject *kwds) {
-       PyObject *key = NULL, *parent = NULL, *values = NULL, *children = NULL, *tmp;
-       Config *self = (Config *) s;
-       static char *kwlist[] = {"key", "parent", "values", "children", NULL};
-       
-       if (!PyArg_ParseTupleAndKeywords(args, kwds, "S|OOO", kwlist,
-                       &key, &parent, &values, &children))
-               return -1;
-       
-       if (values == NULL) {
-               values = PyTuple_New(0);
-               PyErr_Clear();
-       }
-       if (children == NULL) {
-               children = PyTuple_New(0);
-               PyErr_Clear();
-       }
-       tmp = self->key;
-       Py_INCREF(key);
-       self->key = key;
-       Py_XDECREF(tmp);
-       if (parent != NULL) {
-               tmp = self->parent;
-               Py_INCREF(parent);
-               self->parent = parent;
-               Py_XDECREF(tmp);
-       }
-       if (values != NULL) {
-               tmp = self->values;
-               Py_INCREF(values);
-               self->values = values;
-               Py_XDECREF(tmp);
-       }
-       if (children != NULL) {
-               tmp = self->children;
-               Py_INCREF(children);
-               self->children = children;
-               Py_XDECREF(tmp);
-       }
-       return 0;
-}
-
-static PyMemberDef Config_members[] = {
-    {"Parent", T_OBJECT, offsetof(Config, parent), 0, "Parent node"},
-    {"Key", T_OBJECT_EX, offsetof(Config, key), 0, "Keyword of this node"},
-    {"Values", T_OBJECT_EX, offsetof(Config, values), 0, "Values after the key"},
-    {"Children", T_OBJECT_EX, offsetof(Config, children), 0, "Childnodes of this node"},
-    {NULL}
-};
-
-static PyTypeObject ConfigType = {
-    PyObject_HEAD_INIT(NULL)
-    0,                         /* Always 0 */
-    "collectd.Config",         /* tp_name */
-    sizeof(Config),            /* tp_basicsize */
-    0,                         /* Will be filled in later */
-    Config_dealloc,            /* tp_dealloc */
-    0,                         /* tp_print */
-    0,                         /* tp_getattr */
-    0,                         /* tp_setattr */
-    0,                         /* tp_compare */
-    0,                         /* tp_repr */
-    0,                         /* tp_as_number */
-    0,                         /* tp_as_sequence */
-    0,                         /* 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*/
-    "Cool help text later",    /* tp_doc */
-    0,                        /* tp_traverse */
-    0,                        /* tp_clear */
-    0,                        /* tp_richcompare */
-    0,                        /* tp_weaklistoffset */
-    0,                        /* tp_iter */
-    0,                        /* tp_iternext */
-    0,                         /* tp_methods */
-    Config_members,            /* tp_members */
-    0,                         /* tp_getset */
-    0,                         /* tp_base */
-    0,                         /* tp_dict */
-    0,                         /* tp_descr_get */
-    0,                         /* tp_descr_set */
-    0,                         /* tp_dictoffset */
-    Config_init,               /* tp_init */
-    0,                         /* tp_alloc */
-    Config_new                 /* tp_new */
-};
-
 static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
        cpy_callback_t *c;
        const char *name = NULL;
@@ -368,7 +218,6 @@ static int cpy_init(void) {
        PyObject *ret;
        
        PyEval_InitThreads();
-       cpy_have_threads = 1;
        /* Now it's finally OK to use python threads. */
        for (c = cpy_init_callbacks; c; c = c->next) {
                if (c->data == NULL)