[Pyrex] Re: Re: callback

Pedro Rodriguez pedro_rodriguez at club-internet.fr
Tue Aug 19 13:15:31 CEST 2003


> 
> john, pedro,
> 
> thanks for your quick responses... i'm still having trouble with both of
> your suggestions.
> 
> 
> class Play
>     def status_callback(self, callback, user_data):
>         data = (callback, user_data)
>         set_status_callback(self.ctx, _callback_wrapper, <void*>data)
> 
> cdef int _callback_wrapper(void *data, long sec, long msec):
>     callback, user_data = <object>data # this is line 56
>     return callback(data, sec, msec)
> 
> when i compile this i get the following error
> C:\src>mpgedit.pyx:56:20: Cannot convert 'void (*)' to Python object
> 
> when i use the global variable technique as pedro suggested i get an
> additional error
> C:\src>mpgedit.pyx:49:8: '%s' redeclared
> C:\src>mpgedit.pyx:55:20: Cannot convert 'void (*)' to Python object
> 
> line 49 is the "global data" line
> 

I don't understand where those errors come from. The following standalone
code compiles just fine for me. My setup is :
    redhat 7.3
    python 2.2.2
    pyrex 0.8.2

and the commands I used:
    pyrexc t.pyx
    gcc -g -c -fPIC -I/mnt/wrk/python/include/python2.2 t.c
    gcc -g -shared t.o -lm -o t.so

# pyrex code
cdef extern from "../playif.h":
    ctypedef int (*status)(void *, long, long)
    void set_status_callback(int, status, void*)

data = None

class Play:
    def status_callback(self, callback, user_data):
        global data
        data = (callback, user_data)
        set_status_callback(self.ctx, _callback_wrapper, <void*>data)

cdef int _callback_wrapper(void *data, long sec, long msec):
    callback, user_data = <object>data
    return callback(user_data, sec, msec)


/* ../playif.h */
typedef int (*status)(void *, long, long);
void set_status_callback(int, status, void*);


> 
> john,
> 
> i would prefer to use your Py_INCREF and Py_DECREF since i'm used to using
> that when i write extesions manually.  but i don't see how use it in my
> case.  in my example, i don't see where to Py_INCREF or Py_DECREF.
> 

 
I hope you, John and Greg will correct me if I am wrong. Each time you
pass a python object that will be kept inside the C library, you'll
have to call Py_INCREF. In your first code, this will have to be done
on the callback, prior to set_status_callback. If you use Greg's hint
with an instance method, this may even more necessary since your object
may get garbage collected (question : is Py_INCREF on an instance method
sufficient to prevent the actual instance to be freed ?).

For the Py_DECREF call, it will mostly depends on the way the C library
releases the object passed. Your api 'set_status_callback' doesn't seem
to return the former object passed, so this means that you'll have to
do the tracking yourself (if it were returned, you just will have to do
a Py_DECREF on the returned value).

This is why I used the global value approach. I do the tracking at
Python's level, and this tracking mirrors the C library content. No need
to do Py_INC/DEC REF, since Python does it already.

There is still one last issue. In my example, once called the C library
will alway keep a Python object. If possible/necessary, a special case
should be considered. If removing the callback consists in just passing
a NULL pointer, it may be necessary to test if python's callback is None
and passing NULL in this case.

Hoping I am not on the wrong track...

-- 
Pedro

mirors the





More information about the Pyrex mailing list