changeset 1449:d6bd88318fc6

cdefer: Replaced C array for callbacks by linked list.
author Marcel Keller <mkeller@cs.au.dk>
date Mon, 19 Jul 2010 18:23:13 +0200
parents 6b3ea4d579d6
children d611209ceeaa
files viff/cdefer.c
diffstat 1 files changed, 64 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- a/viff/cdefer.c	Mon Jul 19 17:02:41 2010 +0200
+++ b/viff/cdefer.c	Mon Jul 19 18:23:13 2010 +0200
@@ -10,8 +10,6 @@
 #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
@@ -47,20 +45,23 @@
 PyObject * debuginfo_class = NULL;
 PyObject * format_stack = NULL;
 
+struct cdefer_Callback_ {
+    PyObject *func;
+    PyObject *args;
+    PyObject *kwargs;
+    struct cdefer_Callback_ *next;
+};
+
+typedef struct cdefer_Callback_ cdefer_Callback;
+
 typedef struct {
     PyObject_HEAD
     PyObject *result;
     int paused;
-    PyObject *callbacks[MAX_CALLBACKS][3];
+    cdefer_Callback *callbacks;
+    cdefer_Callback *last_callback;
     PyObject *debuginfo;
     int called;
-    /* Current callback index in the callbacks list to run. This
-     * allows clearing the list once per runCallbacks rather than
-     * popping every item. It has to be per-deferred, because
-     * runCallbacks can be called reentrantly, and must not repeat the
-     * previously-called callbacks. */
-    int callback_index;
-    int n_callbacks;
 } cdefer_Deferred;
 
 /* Prototypes */
@@ -168,40 +169,56 @@
     return (PyObject *)self;
 }
 
+inline cdefer_Callback* cdefer_Callback_free(cdefer_Callback *callback) {
+    cdefer_Callback* next = callback->next;
+    Py_DECREF(callback->func);
+    Py_DECREF(callback->args);
+    Py_DECREF(callback->kwargs);
+    free(callback);
+    return next;
+}
+
 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);
-    for (i = self->callback_index; i < self->n_callbacks; i++)
-	for (j = 0; j < 3; j++)
-	    Py_XDECREF(self->callbacks[i][j]);
+    while (self->callbacks)
+	self->callbacks = cdefer_Callback_free(self->callbacks);
     (*o->ob_type->tp_free)(o);
 }
 
 static int cdefer_Deferred_traverse(PyObject *o, visitproc visit, void *arg) {
-    int i,j;
     cdefer_Deferred *self;
+    cdefer_Callback *cb;
     self = (cdefer_Deferred *)o;
     Py_VISIT(self->result);
     Py_VISIT(self->debuginfo);
-    for (i = self->callback_index; i < self->n_callbacks; i++)
-	for (j = 0; j < 3; j++)
-	    Py_VISIT(self->callbacks[i][j]);
+    cb = self->callbacks;
+    while (cb) {
+	Py_VISIT(cb->func);
+	Py_VISIT(cb->args);
+	Py_VISIT(cb->kwargs);
+	cb = cb->next;
+    }
     return 0;
 }
 
 static int cdefer_Deferred_clear(PyObject *o) {
-    int i,j;
     cdefer_Deferred *self;
+    cdefer_Callback *next;
     self = (cdefer_Deferred *)o;
     Py_CLEAR(self->result);
     Py_CLEAR(self->debuginfo);
-    for (i = self->callback_index; i < self->n_callbacks; i++)
-	for (j = 0; j < 3; j++)
-	    Py_CLEAR(self->callbacks[i][j]);
+    while (self->callbacks) {
+	Py_CLEAR(self->callbacks->func);
+	Py_CLEAR(self->callbacks->args);
+	Py_CLEAR(self->callbacks->kwargs);
+	next = self->callbacks->next;
+	free(self->callbacks);
+	self->callbacks = next;
+    }
     return 0;
 }
 
@@ -248,9 +265,8 @@
     }
 
     self->paused = 0;
-    self->callback_index = 0;
-    memset(self->callbacks, 0, sizeof(self->callbacks));
-    self->n_callbacks = 0;
+    self->callbacks = NULL;
+    self->last_callback = NULL;
     return 0;
 }
 
@@ -259,6 +275,7 @@
         PyObject *callbackKeywords, PyObject *errbackArgs,
         PyObject *errbackKeywords) {
     PyObject *result;
+    cdefer_Callback *cb;
 
     if (callback != Py_None) {
         if (!PyCallable_Check(callback)) {
@@ -275,18 +292,21 @@
     }
     */
 
-    if (self->n_callbacks == MAX_CALLBACKS) {
-	PyErr_SetString(PyExc_RuntimeError, "Maximal number of callbacks reached.");
-	return NULL;
-    }
-
-    self->callbacks[self->n_callbacks][0] = callback;
-    self->callbacks[self->n_callbacks][1] = callbackArgs;
-    self->callbacks[self->n_callbacks][2] = callbackKeywords;
+    cb = (cdefer_Callback*) malloc(sizeof(cdefer_Callback));
+    cb->next = NULL;
+    cb->func = callback;
+    cb->args = callbackArgs;
+    cb->kwargs = callbackKeywords;
     Py_INCREF(callback);
     Py_INCREF(callbackArgs);
     Py_INCREF(callbackKeywords);
-    self->n_callbacks++;
+
+    if (self->last_callback)
+	self->last_callback->next = cb;
+    else
+	self->callbacks = cb;
+
+    self->last_callback = cb;
 
     if (self->called) {
         if (cdefer_Deferred__runCallbacks(self) == NULL) {
@@ -510,38 +530,33 @@
     PyObject *type, *value, *traceback;
     PyObject *tmp;
     PyObject *result;
-    int j;
 
     if (!self->paused) {
-        for (;;) {
-            if (self->callback_index >= self->n_callbacks) {
-                break;
-            }
-
+        while(self->callbacks) {
 	    /*
             if (PyObject_IsInstance(self->result, failure_class)) {
             }
 	    */
 
-	    callback = self->callbacks[self->callback_index][0];
+	    callback = self->callbacks->func;
             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;
+		self->callbacks->func = NULL;
+                self->callbacks = self->callbacks->next;
                 continue;
             }
 
-	    args = self->callbacks[self->callback_index][1];
+	    args = self->callbacks->args;
             if (!args) {
 		PyErr_SetString(PyExc_RuntimeError, "NULL args.");
                 return NULL;
             }
 
-	    kwargs = self->callbacks[self->callback_index][2];
+	    kwargs = self->callbacks->kwargs;
             if (!kwargs) {
 		PyErr_SetString(PyExc_RuntimeError, "NULL kwargs.");
                 return NULL;
@@ -573,12 +588,10 @@
 
             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->callbacks = cdefer_Callback_free(self->callbacks);
 
-            ++self->callback_index;
+	    if (!self->callbacks)
+		self->last_callback = NULL;
 
             if (!self->result) {
 		return NULL;
@@ -781,7 +794,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},
-  {"n_callbacks", T_INT, offsetof(cdefer_Deferred, n_callbacks), READONLY, 0},
   {0, 0, 0, 0, 0}
 };
 
@@ -942,7 +954,7 @@
     if(PyArg_UnpackTuple(args, "split_result", 2, 2, &result, &clone) < 0)
 	return NULL;
 
-    res = cdefer_Deferred__startRunCallbacks(clone, result);
+    res = cdefer_Deferred__startRunCallbacks((cdefer_Deferred*)clone, result);
 
     if (!res)
 	return NULL;