So, I want to call a Python callback function from C.
At some point, the function is sent to C and packed into a tuple like this
PyObject *userData = Py_BuildValue("Oi",py_callback,some_number);
Somewhere in that area, I do Py_INCREF(py_callback)
, too.
PyObject *py_callback;
int some_number;
PyArg_ParseTuple((PyObject*)userData,"Oi",&py_callback,&some_number); // returns true
PyObject *py_result = PyObject_CallFunctionObjArgs(py_callback,
/* ... */
NULL);
and that last call throws a segmentation fault. Do you have any idea, why it would do such a thing?
When getting weird behaviour from the Python C API, it is always worth double checking that you are managing the state of the Global Interpreter Lock (aka "the GIL") correctly: http://docs.python.org/c-api/init.html#thread-state-and-the-global-interpreter-lock
I'm not sure why everyone is talking about the GIL here. Are you releasing it anywhere? I notice a few possible trouble points which I'll list below. It's intermingled with suggestions.
I notice that you're not incrementing the reference count of userData
. Why not? You are storing it aren't you? Why do you want to store it in the tuple? Why not just keep two variables (for callback and data) and then increment their refcounts so that you own a reference?
First of all, check the return values of all your functions to see if they're NULL
. This will let you make sure that you're actually running properly. It's also probably a good idea to use PyObject_Print
to print the objects you're interested in at all the points in the code to make sure things are going as you expect.
From your comment on where the segfault happens, my guess is that you're passing the wrong number of parameters to your callback function when you call it with PyObject_CallFunctionObjArgs
. Can you double check it? Maybe show us your callback function definition and then check the invocation again.
Another possible issue I see is that from the naming, py_some_number
sounds like you expect a Python integer object. This is not the case. After the PyArg_ParseTuple
, it will contain an integer.
精彩评论