CPython is notorious for the Global Interpreter Lock (GIL). You have to release the GIL whenever you do blocking I/O and re-obtain it when you are done. With a callback it's a little different, you want to acquire the lock, call Python and release it again when your back in C-land.
Starting off, my .i file looked something like this:
Essentially what I'm doing here is defining a new function alt_start() to replace the API Start() function. A well known callback (api_start_callback) is then handed off the the real Start(). api_start_callback() does the heavy lifting of assembling the arguments, acquiring the GIL, calling the Python callback and then giving the GIL back to Python.
%module probe
%{
#include "myapi.h"
%}
%include "windows.i"
typedef void __stdcall (*HandleDataCallBack)(char*, int);
int Start(HandleDataCallBack);
int Stop();
int SendInquiry();
%{
PyObject* python_callback = 0;
void __stdcall api_start_callback(char* foo, int blah)
{
PyObject *arglist;
PyObject *result;
PyGILState_STATE gstate;
if (!PyCallable_Check(python_callback))
{
PyErr_SetString(PyExc_TypeError, "Python callback must be callable");
return;
}
arglist = Py_BuildValue("(si)", foo, blah);
gstate = PyGILState_Ensure();
result = PyEval_CallObject(python_callback, arglist);
Py_XDECREF(arglist);
Py_XDECREF(result);
PyGILState_Release(gstate);
}
void alt_start(PyObject *pyfunc)
{
python_callback = pyfunc;
Start(api_start_callback);
Py_INCREF(pyfunc);
}
%}
void alt_start(PyObject*);
For other places where the threading is an issue, SWIG can take of this itself when you run Swig with the -threads option. In my case: swig -python -threads probe.i
The simplified Python code for calling this looks something like this:
import probeSomeday perhaps, I'll be able to call Start() directly and pass my Python callback handler without the need for this special handling code. Until then, the work around isn't too horrible.
import time
def ProbeCallback(foo, blah):
....print "Foo: %s, Blah: %d" % (foo, blah)
probe.alt_start(ProbeCallback)
probe.SendInquiry()
time.sleep(60)
probe.Stop()
4 comments:
Interesting.
Is it possible PyGILState_Ensure(); should be called higher up though? There's other c-api calls above.
Kenny
Good point. Certainly couldn't hurt to move it up, but I don't think it's going to be an issue since it's not running the interpreter, just executing some helper functions.
Thx!
Hi,
I was impressed with the details here, can you please help me answer below query -
I would like to know hot to pass address reference to ‘c’ function through python. I am using swig for ‘c’ anf python interfacing
Interface file : stud.i
***************************************************
%module stud
%header%{
#include "stud.h"
%}
%include "stud.h"
%array_functions(char *,charp );
%inline %{
extern int parse1(char *,char *,char **);
%}
%inline %{
int print_args(char **argv) {
int i = 0;
for(i=0;i<=180;i++) {
printf("argv[%d] = %c\n", i,*(argv[i]));
i++;
}
return i;
}
%}
**********************************************************
Stud.c
======================================
#include string.h
#include stdio.h
/*the angular braces are removed as here as they were causing issues in posting*/
#include "stud.h"
int parse1(char *s, char *p,char **t)
{
strcat(p,s);
*t=&p[0];
}
**********************************************************
Stud.h
===================================
int parse1(char *,char *,char **);
**************************************************
>>> from stud import *
>>> a='rajashree'
>>> c='thoratf'
>>> d=new_charp(1000)
>>> parse1(a,c,d)
2300188
>>> d
Swig Object of type 'char **' at 0x28aca0
Now I want read value of d in python… How do I do it.
Any type of help is appreciated.
Thanks,
Rajashree.
rthorat@starentnetworks.com
Thanks Rajashree,
I suspect you'll need a typemap to tell Swig how to handle the char**. Looks like it doesn't know how to deal with the pointer and is keeping it as a Swig Object.
http://www.swig.org/Doc1.3/Python.html#Python_nn59
Alternatively you could wrap the char * in a simple struct and see if Swig likes that better.
Hope it helps!
-S
Post a Comment