On Apr 10, 2012, at 10:25 AM, Nadav Horesh wrote:

> Sorry for being slow.
> There is (I think) a related question I raised on the skimage list:
> I have a cython function that calls a C callback function in a loop (one call 
> for each pixel in an image). The C function in compiled in a different shared 
> library (a simple C library, not a python module). I would like a python 
> script to get the address of the C function and pass it on to the cython 
> function as the pointer for the callback function.
> 
> As I understand Travis' isue starts ones the callback address is obtained, 
> but, is there a direct method to retrieve the address from the shared library?


There are several ways to do this.   But, ctypes makes it fairly 
straightforward: 

Example:

lib = ctypes.CDLL('libm.dylib')
address_as_integer = ctypes.cast(lib.sin, ctypes.c_void_p).value

Basically, what we are talking about is a lighter weight way to do hand this 
address around instead of using ctypes objects including it's heavy-weight 
method of creating signatures. 

During the lengthy PEP 3118 discussions, this question of whether to use NumPy 
dtypes or ctypes classes was debated in terms of how to represent "data-types" 
in the buffer protocol.   Guido wisely decided to use the struct-module method 
of "strings" duly extended to cover more cases.      I think this is definitely 
the way to go.   I also noticed that the dyncall library (http://dyncall.org/) 
also uses strings to represent signatures (althought it uses a ")" to indicate 
the boundary between inputs and outputs). 

-Travis




> 
>   Nadav.
> ________________________________________
> From: numpy-discussion-boun...@scipy.org [numpy-discussion-boun...@scipy.org] 
> On Behalf Of Travis Oliphant [teoliph...@gmail.com]
> Sent: 10 April 2012 03:11
> To: Discussion of Numerical Python
> Subject: [Numpy-discussion] Getting C-function pointers from Python to C
> 
> Hi all,
> 
> Some of you are aware of Numba.   Numba allows you to create the equivalent 
> of C-function's dynamically from Python.   One purpose of this system is to 
> allow NumPy to take these functions and use them in operations like ufuncs, 
> generalized ufuncs, file-reading, fancy-indexing, and so forth.  There are 
> actually many use-cases that one can imagine for such things.
> 
> One question is how do you pass this function pointer to the C-side.    On 
> the Python side, Numba allows you to get the raw integer address of the 
> equivalent C-function pointer that it just created out of the Python code.    
> One can think of this as a 32- or 64-bit integer that you can cast to a 
> C-function pointer.
> 
> Now, how should this C-function pointer be passed from Python to NumPy?   One 
> approach is just to pass it as an integer --- in other words have an API in C 
> that accepts an integer as the first argument that the internal function 
> interprets as a C-function pointer.
> 
> This is essentially what ctypes does when creating a ctypes function pointer 
> out of:
> 
>  func = ctypes.CFUNCTYPE(restype, *argtypes)(integer)
> 
> Of course the problem with this is that you can easily hand it integers which 
> don't make sense and which will cause a segfault when control is passed to 
> this "function"
> 
> We could also piggy-back on-top of Ctypes and assume that a ctypes 
> function-pointer object is passed in.   This allows some error-checking at 
> least and also has the benefit that one could use ctypes to access a 
> c-function library where these functions were defined. I'm leaning towards 
> this approach.
> 
> Now, the issue is how to get the C-function pointer (that npy_intp integer) 
> back and hand it off internally.   Unfortunately, ctypes does not make it 
> very easy to get this address (that I can see).    There is no ctypes C-API, 
> for example.    There are two potential options:
> 
>        1) Create an API for such Ctypes function pointers in NumPy and use 
> the ctypes object structure.  If ctypes were to ever change it's object 
> structure we would have to adapt this API.
> 
>        Something like this is what is envisioned here:
> 
>             typedef struct {
>                        PyObject_HEAD
>                        char *b_ptr;
>             } _cfuncptr_object;
> 
>        then the function pointer is:
> 
>            (*((void **)(((_sp_cfuncptr_object *)(obj))->b_ptr)))
> 
>        which could be wrapped-up into a nice little NumPy C-API call like
> 
>        void * Npy_ctypes_funcptr(obj)
> 
> 
>        2) Use the Python API of ctypes to do the same thing.   This has the 
> advantage of not needing to mirror the simple _cfuncptr_object structure in 
> NumPy but it is *much* slower to get the address.   It basically does the 
> equivalent of
> 
>        ctypes.cast(obj, ctypes.c_void_p).value
> 
> 
>        There is working code for this in the ctypes_callback branch of my 
> scipy fork on github.
> 
> 
> I would like to propose two things:
> 
>        * creating a Npy_ctypes_funcptr(obj) function in the C-API of NumPy and
>        * implement it with the simple pointer dereference above (option #1)
> 
> 
> Thoughts?
> 
> -Travis
> 
> 
> 
> 
> 
> 
> 
> _______________________________________________
> NumPy-Discussion mailing list
> NumPy-Discussion@scipy.org
> http://mail.scipy.org/mailman/listinfo/numpy-discussion
> _______________________________________________
> NumPy-Discussion mailing list
> NumPy-Discussion@scipy.org
> http://mail.scipy.org/mailman/listinfo/numpy-discussion

_______________________________________________
NumPy-Discussion mailing list
NumPy-Discussion@scipy.org
http://mail.scipy.org/mailman/listinfo/numpy-discussion

Reply via email to