[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