I&#39;m trying to wrapp a C callback system. I want to call python methods (with python arguments) passing them as function callbacks to C function. A simple example<br><br>###### foo.h #######<br><br>define MAX_FUNCS 4<br>
<br>typedef void(*VoidFunc)(void*);<br>&nbsp;<br>typedef struct FooStruct{<br>&nbsp; VoidFunc funcs[MAX_FUNCS];<br>&nbsp; void* data[MAX_FUNCS];<br>} FooStruct;<br><br>FooStruct* Foo_new(void);<br><br>int Foo_call(FooStruct* self, int indexFunc);<br>
<br>int Foo_addFunc(FooStruct* self, VoidFunc func, void* data);<br><br>int Foo_fire(FooStruct* self);<br><br>void Foo_destroy(FooStruct* self);<br><br><br>###### foo.c #######<br>#include &lt;stdlib.h&gt;<br>#include &lt;foo.h&gt;<br>
<br>FooStruct* Foo_new(void){<br>&nbsp; int i;<br>&nbsp; FooStruct* tmp = malloc(sizeof(FooStruct));<br>&nbsp; for (i=0; i&lt;MAX_FUNCS; i++){<br>&nbsp;&nbsp;&nbsp; tmp-&gt;funcs[i]=NULL;<br>&nbsp;&nbsp;&nbsp; tmp-&gt;data[i] = NULL;<br>&nbsp; }<br>&nbsp; return tmp;<br>}<br>
<br>int Foo_call(FooStruct* self, int indexFunc){<br>&nbsp; if (self)<br>&nbsp;&nbsp;&nbsp; if (indexFunc &lt; MAX_FUNCS &amp;&amp; indexFunc &gt;= 0 ){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*(self-&gt;funcs[indexFunc]))(self-&gt;data[indexFunc]);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
&nbsp;&nbsp;&nbsp; }<br>&nbsp; return 1;<br>}<br><br>int Foo_addFunc(FooStruct* self, VoidFunc func, void* data){<br>&nbsp; if (self){<br>&nbsp;&nbsp;&nbsp; int i;<br>&nbsp;&nbsp;&nbsp; for (i=0; i&lt;MAX_FUNCS; i++)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (self-&gt;funcs[i] == NULL){<br>&nbsp;&nbsp;&nbsp; self-&gt;funcs[i] = func;<br>
&nbsp;&nbsp;&nbsp; self-&gt;data[i] = data;<br>&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; if (i != MAX_FUNCS)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>&nbsp; }<br>&nbsp; return 1;<br>}<br><br>int Foo_fire(FooStruct* self){<br>&nbsp; if (self){<br>&nbsp;&nbsp;&nbsp; int i;<br>&nbsp;&nbsp;&nbsp; for (i=0; i&lt;MAX_FUNCS; i++)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (self-&gt;funcs[i])<br>&nbsp;&nbsp;&nbsp; (*(self-&gt;funcs[i]))(self-&gt;data[i]);<br>&nbsp;&nbsp;&nbsp; return 0;<br>&nbsp; }<br>&nbsp; return 1;<br>}<br><br>void Foo_destroy(FooStruct* self){<br>&nbsp; if (self)<br>&nbsp;&nbsp;&nbsp; free(self);<br>}<br><br><br>FooStruct structure stores a vector of void(*)(void*) function pointers and a vector of generic data (void pointers). The i function will be executed with the i data (void pointer) as argument. The Foo_fire method executes all function stored in a FooStruct instance with <span onclick="dr4sdgryt(event)">appropriate arguments. The bar.pyx wraps this functions in a pyrex extension PyFooStruct<br>
<br>cdef extern from &#39;foo.h&#39;:<br>&nbsp; struct FooStruct:<br>&nbsp;&nbsp;&nbsp; pass<br>&nbsp; FooStruct* Foo_new()<br>&nbsp; int Foo_call(FooStruct* self, int indexFunc)<br>&nbsp; int Foo_addFunc(FooStruct* self, void(*func)(void*), void* data)<br>
&nbsp; int Foo_fire(FooStruct* self)<br>&nbsp; void Foo_destroy(FooStruct* self)<br><br><br>cdef void PyCallback( object funcAndData):<br>&nbsp; cdef object func, data<br>&nbsp; func = funcAndData[0]<br>&nbsp; data = funcAndData[1]<br>&nbsp; func(*data)<br>
<br>cdef class PyFooStruct:<br>&nbsp; cdef FooStruct* selfPtr<br><br>&nbsp; def __init__(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.selfPtr = Foo_new()<br><br>&nbsp; def PyFoo_call(self, i):<br>&nbsp;&nbsp;&nbsp; return Foo_call(self.selfPtr, i)<br><br>&nbsp; def PyFoo_addFunc(self, func, data):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cdef object tmpFuncAndData<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmpFuncAndData = (func, data)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Foo_addFunc(self.selfPtr, &lt;void(*)(void*)&gt;PyCallback, \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;void*&gt;tmpFuncAndData)<br><br>&nbsp; def PyFoo_fire(self):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Foo_fire(self.selfPtr)<br><br>&nbsp; def __dealloc__(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Foo_destroy(self.selfPtr)<br><br><br>The PyCallback C function gets a tuple funcAndData as argument. The first element is a pointer to a Python function, the second is a tuple of generic data. PyCallback executes the function (first element of the tuple argument) with the data arguments (second item of the tuple argument). To add a python function reference to the PyFooStruct pyrex extension&nbsp; (using the Foo_addFunction C function), the PyFoo_addFunc pass the PyCallback method as the function pointer (casting its type to void(*)(void*)), and a tuple with two element as generic data (casting it to void*). This tuple (tmpFuncAndData), contains the python method reference as first argument (func) and the python func&#39;s argument as second argument (data). The steps through which a python function is executed by the C wrapped function are:<br>
<br>- PyFoo_addFunc store a callback to a func python function that use a tuple of data arguments, passing to Foo_addFunc PyCallback as the function pointer and a tuple (func, data) as argument (func is the python function, data the tuple of arguments);<br>
- when PyFoo_fire is called, all stored python function will be executed<br>- a generic i function is executed calling the PyCallback function with i void-casted data. <br>- PyCallback gets reference to python function and function data from the tuple argument, and call the function with the tuple argument.<br>
<br>I&#39;ve written this simple python test:<br><br>from bar import *<br><br>def printFoo(*notUsedArgs):<br>&nbsp; print &#39;foo&#39;<br><br>def printBar(*notUsedArgs):<br>&nbsp; print &#39;bar&#39;<br><br>def printFooBar(*notUsedArgs):<br>
&nbsp; print &#39;foobar&#39;<br><br>def printSomething( *tupleOfString ):<br>&nbsp; for foo in tupleOfString:<br>&nbsp;&nbsp;&nbsp; print foo<br><br>if __name__ == &#39;__main__&#39;:<br>&nbsp; foo = PyFooStruct()<br>&nbsp; foo.PyFoo_addFunc(printFoo, (None,))<br>
&nbsp; foo.PyFoo_addFunc(printBar, (None,))<br>&nbsp; foo.PyFoo_addFunc(printFooBar, (None,))<br>&nbsp; foo.PyFoo_addFunc(printSomething, (&#39;Foo&#39;, &#39;Bar&#39;, &#39;FooBar&#39;))<br>&nbsp; foo.PyFoo_fire()<br>&nbsp; <br>But when I execute the script, the interpreter raises those exceptions<br>
<br>python test.py<br>Exception exceptions.TypeError: &quot;&#39;tuple&#39; object is not callable&quot; in &#39;bar.PyCallback&#39; ignored<br>Exception exceptions.TypeError: &quot;&#39;tuple&#39; object is not callable&quot; in &#39;bar.PyCallback&#39; ignored<br>
Exception exceptions.TypeError: &quot;&#39;tuple&#39; object is not callable&quot; in &#39;bar.PyCallback&#39; ignored<br>Exception exceptions.TypeError: &quot;&#39;tuple&#39; object is not callable&quot; in &#39;bar.PyCallback&#39; ignored<br>
python: Objects/obmalloc.c:929: PyObject_Free: Assertion `pool-&gt;ref.count &gt; 0&#39; failed.<br>Abortito<br><br>What is the problem? Could be a problem </span><span onclick="dr4sdgryt(event)">inherent&nbsp; </span><span onclick="dr4sdgryt(event)">to local scope of t</span><span onclick="dr4sdgryt(event)">mpFuncAndData variable in </span><span onclick="dr4sdgryt(event)">PyFoo_addFunc method? I&#39;ve rewritten the wrapper importing the Py_XINCREF macro to increment the tmpFuncAndData reference count and all seems to work<br>
<br><br>######## bar.pyx with Py_XINCREF ######<br>cdef extern from &#39;Python.h&#39;:<br>&nbsp; struct PyObject:<br>&nbsp;&nbsp;&nbsp; pass<br>&nbsp; void Py_XINCREF(object)<br><br>cdef extern from &#39;foo.h&#39;:<br>&nbsp; struct FooStruct:<br>&nbsp;&nbsp;&nbsp; pass<br>
&nbsp; FooStruct* Foo_new()<br>&nbsp; int Foo_call(FooStruct* self, int indexFunc)<br>&nbsp; int Foo_addFunc(FooStruct* self, void(*func)(void*), void* data)<br>&nbsp; int Foo_fire(FooStruct* self)<br>&nbsp; void Foo_destroy(FooStruct* self)<br><br>
<br>cdef void PyCallback( object funcAndData):<br>&nbsp; cdef object func, data<br>&nbsp; func = funcAndData[0]<br>&nbsp; data = funcAndData[1]<br>&nbsp; func(*data)<br><br>cdef class PyFooStruct:<br>&nbsp; cdef FooStruct* selfPtr<br><br>&nbsp; def __init__(self):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.selfPtr = Foo_new()<br><br>&nbsp; def PyFoo_call(self, i):<br>&nbsp;&nbsp;&nbsp; return Foo_call(self.selfPtr, i)<br><br>&nbsp; def PyFoo_addFunc(self, func, data):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cdef object tmpFuncAndData<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmpFuncAndData = (func, data)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Py_XINCREF(tmpFuncAndData)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Foo_addFunc(self.selfPtr, &lt;void(*)(void*)&gt;PyCallback, \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;void*&gt;tmpFuncAndData)<br><br>&nbsp; def PyFoo_fire(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Foo_fire(self.selfPtr)<br>
<br>&nbsp; def __dealloc__(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Foo_destroy(self.selfPtr)<br><br>With the test script above, the interpreter gives me the correct output<br><br>python test.py<br>foo<br>bar<br>foobar<br>Foo<br>Bar<br>FooBar<br><br>Is there a way to solve the problem without importing anything from Python.h?<br>
</span>