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


      =