Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

asynchronous callbacks

1 view
Skip to first unread message

hans

unread,
May 23, 2002, 2:25:49 PM5/23/02
to
I'm writing a Python extension module that has to handle asynchronous
callbacks. There have been some earlier posts about this, but so far
I haven't found a safe solution.

What I'm doing is this:

I have a global variable

PyInterpreterState* my_interp;

The initialization function of my extension module looks like:

void initmymodule(void) {

...

PyEval_InitThreads();
my_interp = PyThreadState_Get()->interp;
}

The callback functions look like:

static void cb_Fun(void* pyFun, T* data)
{
...
// convert data into a Python tuple: arg

ENTER_PY
res = PyEval_CallObject((PyObject*)pyFun, arg);
LEAVE_PY
...
}

where I'm using two macros:

#define ENTER_PY { PyThreadState* tstate = NULL;\
if (_PyThreadState_Current == NULL) {\
tstate = PyThreadState_New(my_interp);\
PyEval_AquireThread(tstate);\
}

#define LEAVE_PY if (tstate) {\
PyThreadState_Clear(tstate);\
PyThreadState_DeleteCurrent();}\
}

The callbacks function can be registered (to a C API) with pyFun
pointing to some Python function (defined in a script). (This Python
function can itself callback into the C API.) In the script, after
registering a function as callback, the main thread is simply looping
in

while running:
time.sleep(0)

Variable `running` can at some point be reset by the callback to break
out of the loop.

The problem is that I still get Fatal Python Errors, like
"PyThreadState_Get: no current thread", and sometimes "ceval: tstate
mix-up".
How is this possible? And how can I prevent those errors? What am I
missing?
(I'm working with Python 2.2 on a Win2000 OS.)

Hans

Chris Liechti

unread,
May 23, 2002, 3:35:02 PM5/23/02
to
hans....@scansoft.com (hans) wrote in
news:dae4590e.02052...@posting.google.com:

> I'm writing a Python extension module that has to handle asynchronous
> callbacks.

thats exactly what i did today! i found this aricle very useful:
http://www.linuxjournal.com/article.php?sid=3641

unfortunately (for you) i don't have the sources at hand right now they're
on a powered down machine 3km away and it's raining.... ;-)

>There have been some earlier posts about this, but so far
> I haven't found a safe solution.
>
> What I'm doing is this:
>
> I have a global variable
>
> PyInterpreterState* my_interp;
>
> The initialization function of my extension module looks like:
>
> void initmymodule(void) {
>
> ...
>
> PyEval_InitThreads();
> my_interp = PyThreadState_Get()->interp;
> }

i did this in the function where i register the callback. i also create my
PyThreadState here

--- from the article above
PyThreadState * mainThreadState = NULL;
// save a pointer to the main PyThreadState object
mainThreadState = PyThreadState_Get();
// get a reference to the PyInterpreterState
PyInterpreterState * mainInterpreterState = mainThreadState->interp;
// create a thread state object for this thread
PyThreadState * myThreadState = PyThreadState_New(mainInterpreterState);
----

i'm holding myThreadState in a global variable.

> The callback functions look like:
>
> static void cb_Fun(void* pyFun, T* data)
> {
> ...
> // convert data into a Python tuple: arg
>
> ENTER_PY
> res = PyEval_CallObject((PyObject*)pyFun, arg);
> LEAVE_PY
> ...
> }
>
> where I'm using two macros:
>
> #define ENTER_PY { PyThreadState* tstate = NULL;\
> if (_PyThreadState_Current == NULL) {\
> tstate = PyThreadState_New(my_interp);\
> PyEval_AquireThread(tstate);\
> }
>
> #define LEAVE_PY if (tstate) {\
> PyThreadState_Clear(tstate);\
> PyThreadState_DeleteCurrent();}\
> }

you should aquire the GIL with PyEval_AcquireLock() and do
PyEval_ReleaseLock() after interacting with python:


---- quote from the article above:
// grab the global interpreter lock
PyEval_AcquireLock();
// swap in my thread state
PyThreadState_Swap(myThreadState);
// execute some python code
PyEval_SimpleString("import sys
");
PyEval_SimpleString("sys.stdout.write('Hello from a C thread!
')
");
// clear the thread state
PyThreadState_Swap(NULL);
// release our hold on the global interpreter
PyEval_ReleaseLock();
----

> The callbacks function can be registered (to a C API) with pyFun
> pointing to some Python function (defined in a script). (This Python
> function can itself callback into the C API.) In the script, after
> registering a function as callback, the main thread is simply looping
> in
>
> while running:
> time.sleep(0)
>
> Variable `running` can at some point be reset by the callback to break
> out of the loop.
>
> The problem is that I still get Fatal Python Errors, like
> "PyThreadState_Get: no current thread", and sometimes "ceval: tstate
> mix-up".
> How is this possible? And how can I prevent those errors? What am I
> missing?
> (I'm working with Python 2.2 on a Win2000 OS.)
>
> Hans


HTH chris

--
Chris <clie...@gmx.net>

Duncan Grisby

unread,
May 28, 2002, 10:29:43 AM5/28/02
to
In article <dae4590e.02052...@posting.google.com>,
hans <hans....@scansoft.com> wrote:

>I'm writing a Python extension module that has to handle asynchronous
>callbacks. There have been some earlier posts about this, but so far
>I haven't found a safe solution.

omniORBpy has to do exactly this. When I first wrote it, I created a
new Python thread state on every call, but I discovered that that
imposes a huge overhead. I implemented a cache of thread states, which
halved the invocation time.

The code is in C++, but reading it might help you figure out something
useful to you. Look at pyThreadCache.h and pyThreadCache.cc in this
CVS directory:

http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/omniorb/omniORBpy/modules/?only_with_tag=omnipy2_develop

Cheers,

Duncan.

--
-- Duncan Grisby --
-- dun...@grisby.org --
-- http://www.grisby.org --

0 new messages