changeset 1444:0ebed2045ec5

cdefer: Use C array instead of Python list for callbacks.
author Marcel Keller <mkeller@cs.au.dk>
date Sun, 13 Jun 2010 14:36:06 +0200
parents 9f696c3308d5
children efe63f85605a
files viff/cdefer.c
diffstat 1 files changed, 47 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/viff/cdefer.c	Fri Jun 11 18:51:25 2010 +0200
+++ b/viff/cdefer.c	Sun Jun 13 14:36:06 2010 +0200
@@ -10,6 +10,8 @@
 #include <Python.h>
 #include "structmember.h"
 
+#define MAX_CALLBACKS 100
+
 /* Py_VISIT and Py_CLEAR are defined here to be compatible with Python 2.3 */
 
 #ifndef Py_VISIT
@@ -43,7 +45,7 @@
     PyObject_HEAD
     PyObject *result;
     int paused;
-    PyObject *callbacks;
+    PyObject *callbacks[MAX_CALLBACKS][3];
     PyObject *debuginfo;
     int called;
     /* Current callback index in the callbacks list to run. This
@@ -52,6 +54,7 @@
      * runCallbacks can be called reentrantly, and must not repeat the
      * previously-called callbacks. */
     int callback_index;
+    int n_callbacks;
 } cdefer_Deferred;
 
 /* Prototypes */
@@ -160,30 +163,39 @@
 }
 
 static void cdefer_Deferred_dealloc(PyObject *o) {
+    int i,j;
     cdefer_Deferred *self;
     self = (cdefer_Deferred *)o;
     PyObject_GC_UnTrack(self);
     Py_XDECREF(self->result);
     Py_XDECREF(self->debuginfo);
-    Py_XDECREF(self->callbacks);
+    for (i = self->callback_index; i < self->n_callbacks; i++)
+	for (j = 0; j < 3; j++)
+	    Py_XDECREF(self->callbacks[i][j]);
     (*o->ob_type->tp_free)(o);
 }
 
 static int cdefer_Deferred_traverse(PyObject *o, visitproc visit, void *arg) {
+    int i,j;
     cdefer_Deferred *self;
     self = (cdefer_Deferred *)o;
     Py_VISIT(self->result);
     Py_VISIT(self->debuginfo);
-    Py_VISIT(self->callbacks);
+    for (i = self->callback_index; i < self->n_callbacks; i++)
+	for (j = 0; j < 3; j++)
+	    Py_VISIT(self->callbacks[i][j]);
     return 0;
 }
 
 static int cdefer_Deferred_clear(PyObject *o) {
+    int i,j;
     cdefer_Deferred *self;
     self = (cdefer_Deferred *)o;
     Py_CLEAR(self->result);
     Py_CLEAR(self->debuginfo);
-    Py_CLEAR(self->callbacks);
+    for (i = self->callback_index; i < self->n_callbacks; i++)
+	for (j = 0; j < 3; j++)
+	    Py_CLEAR(self->callbacks[i][j]);
     return 0;
 }
 
@@ -229,10 +241,8 @@
 
     self->paused = 0;
     self->callback_index = 0;
-    self->callbacks = PyList_New(0);
-    if (!self->callbacks) {
-        return -1;
-    }
+    memset(self->callbacks, 0, sizeof(self->callbacks));
+    self->n_callbacks = 0;
     return 0;
 }
 
@@ -241,8 +251,6 @@
         PyObject *callbackKeywords, PyObject *errbackArgs,
         PyObject *errbackKeywords) {
     PyObject *result;
-    PyObject *cbs = 0;
-    int rc;
 
     if (callback != Py_None) {
         if (!PyCallable_Check(callback)) {
@@ -250,24 +258,27 @@
             return NULL;
         }
     }
+    /*
     if (errback != Py_None) {
         if (!PyCallable_Check(errback)) {
             PyErr_SetNone(PyExc_AssertionError);
             return NULL;
         }
     }
+    */
 
-    cbs = Py_BuildValue("(OOOOOO)", callback, callbackArgs, callbackKeywords,
-                                    errback, errbackArgs, errbackKeywords);
-    if (!cbs) {
-        return NULL;
+    if (self->n_callbacks == MAX_CALLBACKS) {
+	PyErr_SetString(PyExc_RuntimeError, "Maximal number of callbacks reached.");
+	return NULL;
     }
 
-    rc = PyList_Append(self->callbacks, cbs);
-    Py_CLEAR(cbs);
-    if (rc == -1) {
-        return NULL;
-    }
+    self->callbacks[self->n_callbacks][0] = callback;
+    self->callbacks[self->n_callbacks][1] = callbackArgs;
+    self->callbacks[self->n_callbacks][2] = callbackKeywords;
+    Py_INCREF(callback);
+    Py_INCREF(callbackArgs);
+    Py_INCREF(callbackKeywords);
+    self->n_callbacks++;
 
     if (self->called) {
         if (cdefer_Deferred__runCallbacks(self) == NULL) {
@@ -482,8 +493,6 @@
 
 
 static PyObject *cdefer_Deferred__runCallbacks(cdefer_Deferred *self) {
-    PyObject *cb;
-    PyObject *item;
     PyObject *callback;
     PyObject *args;
     PyObject *newArgs;
@@ -493,48 +502,40 @@
     PyObject *type, *value, *traceback;
     PyObject *tmp;
     PyObject *result;
-    int size;
-    int offset;
+    int j;
 
     if (!self->paused) {
-        cb = self->callbacks;
         for (;;) {
-            size = PyList_GET_SIZE(cb);
-            if (size == -1) {
-                return NULL;
-            }
-            if (self->callback_index >= size) {
+            if (self->callback_index >= self->n_callbacks) {
                 break;
             }
 
-            item = PyList_GET_ITEM(cb, self->callback_index);
-            if (!item) {
-                return NULL;
-            }
-
-            offset = 0;
 	    /*
             if (PyObject_IsInstance(self->result, failure_class)) {
-                offset = 3;
             }
 	    */
 
-            callback = PyTuple_GET_ITEM(item, offset + 0);
+	    callback = self->callbacks[self->callback_index][0];
             if (!callback) {
+		PyErr_SetString(PyExc_RuntimeError, "NULL callback.");
                 return NULL;
             }
             if (callback == Py_None) {
+		Py_DECREF(Py_None);
+		self->callbacks[self->callback_index][0] = NULL;
                 ++self->callback_index;
                 continue;
             }
 
-            args = PyTuple_GET_ITEM(item, offset + 1);
+	    args = self->callbacks[self->callback_index][1];
             if (!args) {
+		PyErr_SetString(PyExc_RuntimeError, "NULL args.");
                 return NULL;
             }
 
-            kwargs = PyTuple_GET_ITEM(item, offset + 2);
+	    kwargs = self->callbacks[self->callback_index][2];
             if (!kwargs) {
+		PyErr_SetString(PyExc_RuntimeError, "NULL kwargs.");
                 return NULL;
             }
 
@@ -554,7 +555,6 @@
                 newArgs = NULL;
             }
 
-            ++self->callback_index;
             if (kwargs == Py_None) {
                 tmp = PyObject_Call(callback, newArgs2, NULL);
             } else {
@@ -565,6 +565,13 @@
 
             Py_CLEAR(newArgs2);
 
+	    for (j = 0; j < 3; j++) {
+		Py_DECREF(self->callbacks[self->callback_index][j]);
+		self->callbacks[self->callback_index][j] = NULL;
+	    }
+
+            ++self->callback_index;
+
             if (!self->result) {
 		return NULL;
 		/*
@@ -588,11 +595,6 @@
             }
             Py_INCREF(self->result);
             if (PyObject_TypeCheck(self->result, &cdefer_DeferredType)) {
-                if (PyList_SetSlice(cb, 0, self->callback_index, NULL) == -1) {
-                    return NULL;
-                }
-                self->callback_index = 0;
-
                 result = PyObject_CallMethod((PyObject *)self, "pause", NULL);
                 if (!result) {
                     return NULL;
@@ -621,10 +623,6 @@
                 goto endLabel;
             }
         }
-        if (PyList_SetSlice(cb, 0, PyList_GET_SIZE(cb), NULL) == -1) {
-            return NULL;
-        }
-        self->callback_index = 0;
     }
 endLabel:;
     /*
@@ -775,7 +773,6 @@
   {"result", T_OBJECT_EX, offsetof(cdefer_Deferred, result), 0, 0},
   {"paused", T_INT, offsetof(cdefer_Deferred, paused), READONLY, 0},
   {"called", T_INT, offsetof(cdefer_Deferred, called), READONLY, 0},
-  {"callbacks", T_OBJECT, offsetof(cdefer_Deferred, callbacks), READONLY, 0},
   {0, 0, 0, 0, 0}
 };