[Pyrex] Callback help
Dale Cieslak
dcieslak at yahoo.com
Wed Apr 21 18:44:16 CEST 2010
>> Hi all,
>>
>> I apologize if this has already been answered or if it's a dumb question...I tried looking through the archives and haven't found
>> anything similar so far. I'm trying to wrap a C API that makes use of
>> callbacks, and I looked at the cheesefinder callback demo code in the
>> Pyrex distribution. If I write my code to match the cheesefinder
>> example, it works fine. However, it appears that the cheesefinder
>> example passes the Python function pointer as the user_data itself, but
>> what if I want to ALSO pass user data to my Python callback? I should
>> point out that it's been several years since I did any serious C coding
>> (which is why I'm trying to wrap the thing in Python), so I'm hoping
>> it's just a simple n00b-level solution. I tried various permutations
>> of using PyCObject_AsVoidPtr instead of just casts, but to no avail.
>> Essentially it compiles fine, but Bus Errors/Seg Faults when it goes to call the python callback.
>If you're casting Python objects to void*, you need to make sure you're holding onto a reference of them elsewhere (e.g. as an object, in a list, ...). Otherwise they'll be garbage collected and the void* you stored will become meaningless (hence the segfaults).
Thanks, Robert! It turns out that it wasn't a void*-cast Python object that was being garbage-collected, in fact, but that did point me in the right direction. I realized that the reference to my user data was just plain old-fashioned going out-of-scope. In conjunction with Greg's solution of using a nested function, everything is now working exactly as expected.
I was doing this:
test.py
----------
import testcb
data = {}
data['one'] = 1
data['two'] = 2
def pyCallbackOuter(userData):
def
nestedCallback(unusedVar):
print userData.keys()
return nestedCallback
err = testcb.pyFunction(pyCallbackOuter,
data)
test.pyx
----------
...
cdef void
callback(void *userData):
(<object>userData)(1)
def
pyFunction(pyCallbackOuter, data):
cb = pyCallbackOuter(data)
# test callback
cb(1) ###### <- this prints
['one', 'two'] as expected
err = c_function(callback,
<void *>cb) # <-- when the callback runs via this function,
# it
gives a Bus Error on the "print userData.keys()"
# line...as if userData is
undefined or a bogus
# pointer or something
but I realized thanks to your hint that the reference to "data" was going away. Now that I moved the creation of the nested function outside the above function, it works like a charm!
Thanks again, Robert and Greg! Also, Greg, thanks for Pyrex itself. Aside from my temporary confusion, it's amazingly easy to use. I've become a huge fan!
~Dale
More information about the Pyrex
mailing list