The GIL, callbacks, and GPFs

  • Thread starter Francois De Serres
  • Start date
F

Francois De Serres

Hello,

I'm chasing a GPF in the interpreter when running my extension module.
It's not very elaborated, but uses a system (threaded) callback, and
therefore the GIL.
Help would be mucho appreciated. Here's the rough picture:

win32_spam.c
------------
/* code here is unit-tested OK */

typedef struct Bag {
char data[128];
site_t size;
} Bag;
typedef void (*PCallback)(const Bag * const bag);

Bag bag;
PCallback user_callback = NULL;

/* called by windoz */
static void CALLBACK win32_call_me(void) {
memcpy(bag.data, somestuff, 100);
bag.size = 100;
SPAWN_THREAD(user_callback, & bag);//pseudo-code
}



spam_module.c
-------------
/* most of the code here is pasted from doc */

static PyObject * my_callback = NULL;

static PyObject *
setCallback(PyObject *dummy, PyObject *args) {
PyObject *result = NULL;
PyObject *temp;
if (PyArg_ParseTuple(args, "O:miSetCallback", &temp)) {
if ((temp != Py_None) && (!PyCallable_Check(temp))) {
PyErr_SetString(PyExc_TypeError, "parameter must be callable");
return NULL;
}
Py_XINCREF(temp);
Py_XDECREF(my_callback);
my_callback = temp;
Py_INCREF(Py_None);
result = Py_None;

/* set the actual callback in win32_spam.c */
user_callback = & external_callback;
}
return result;
}

static void external_callback(const Bag * const bag) {
if (my_callback && (my_callback != Py_None)) {
PyObject * arglist = NULL;
PyObject * result = NULL;
arglist = Py_BuildValue("(s#)", bag->data, bag->size);

/* do it */
PyGILState_STATE gil = PyGILState_Ensure();
result = PyEval_CallObject(my_callback, arglist);
PyGILState_Release(gil);

Py_DECREF(arglist);
Py_DECREF(result);
}
}


blowup_spam1.py
-------------
# This throws a GPF on callback.
# Why, since the GIL is acquired by the callback?

import spam.py

def callback(stuff):
print stuff

if __name__ == '__main__':
spam.setCallback(callback)
raw_input()


blowup_spam2.py
-------------
# This throws a GPF as well
# Why, since we're using a threadsafe queue?

import spam
import Queue

q = Queue.Queue()

def callback(stuff):
q.put(stuff)

if __name__ == '__main__':
spam.setCallback(callback)
while True:
print q.get()



nice_spam.py
-------------
# This works
# Why, since the rest did not?

import spam
import Queue
import threading

q = Queue.Queue()

def callback(stuff):
q.put(stuff)

def job():
while True:
print q.get()

if __name__ == '__main__':
spam.setCallback(callback)
t = threading.Thread(job)
t.start()
raw_input()



Please point me to what I'm doing wrong...

TIA,
Francois


PS: I've already submitted my issue under "(Win32 API) callback to
Python, threading hiccups", but I guess it was poorly formulated.
 
T

Thomas Heller

Francois De Serres said:
Hello,

I'm chasing a GPF in the interpreter when running my extension module.
It's not very elaborated, but uses a system (threaded) callback, and
therefore the GIL.
Help would be mucho appreciated. Here's the rough picture:
static void external_callback(const Bag * const bag) { if
(my_callback && (my_callback != Py_None)) {
PyObject * arglist = NULL;
PyObject * result = NULL;
arglist = Py_BuildValue("(s#)", bag->data, bag->size);
/* do it */
PyGILState_STATE gil = PyGILState_Ensure();

You're calling Py_BuildValue without holding the GIL. Not sure if
that's the reason for your problems, but I don't think its ok.
result = PyEval_CallObject(my_callback, arglist);
PyGILState_Release(gil);
Py_DECREF(arglist);
Py_DECREF(result); }
}

Thomas
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,708
Latest member
SherleneF1

Latest Threads

Top