Re: Callback help
Dale Cieslak <[email protected]> Wed, 21 Apr 2010 09:44:16 -0700 (PDT)
| Newsgroups | gmane.comp.python.pyrex |
|---|---|
| Message-ID | <[email protected]> |
>> 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 ho=
lding 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 bec=
ome meaningless (hence the segfaults).
Thanks, Robert! It turns out that it wasn't a void*-cast Python object tha=
t 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 ol=
d-fashioned going out-of-scope. In conjunction with Greg's solution of usi=
ng a nested function, everything is now working exactly as expected.
I was doing this:
test.py
----------
import testcb
data =3D {}
data['one'] =3D 1
data['two'] =3D 2
def pyCallbackOuter(userData):
def =
nestedCallback(unusedVar):
print userData.keys()
=
return nestedCallback
err =3D testcb.pyFunction(pyCallbackOuter, =
data)
test.pyx
----------
...
cdef void =
callback(void *userData):
(<object>userData)(1)
def =
pyFunction(pyCallbackOuter, data):
cb =3D pyCallbackOuter(data)
# test callback
cb(1) ###### <- this prints =
['one', 'two'] as expected
err =3D 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 a=
way. Now that I moved the creation of the nested function outside the abov=
e 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 hu=
ge fan!
~Dale
=