Index: Lib/test/test_capi.py =================================================================== --- Lib/test/test_capi.py (revision 67120) +++ Lib/test/test_capi.py (working copy) @@ -35,6 +35,49 @@ raise test_support.TestFailed, \ "Couldn't find main thread correctly in the list" + def TestPendingCalls_Submit(l, n): + def callback(): + l[0] += 1 + + _testcapi._pending_threadfunc(callback, n); + + def TestPendingCalls_Wait(l, n): + #now, stick around until l[0] has grown to 10 + count = 0; + while l[0] != n: + #this busy loop is where we expect to be interrupted to + #run our callbacks. Note that callbacks are only run on the + #main thread + if test_support.verbose: + print "(%i)"%(l[0],), + for i in xrange(1000): + a = i*i + count += 1 + if count > 10000: + raise test_support.TestFailed, \ + "timeout waiting for %i callbacks, got %i"%(n, count) + if test_support.verbose: + print "(%i)"%(l[0],) + + def TestPendingCalls(): + if test_support.verbose: + print "pending-calls" + l = [0] + n = 5 + import threading + t = threading.Thread(target=TestPendingCalls_Submit, args = (l, n)) + t.start() + TestPendingCalls_Wait(l, n) + t.join() + + #again, just using the main thread, likely they will all be dispathced at + #once. We must be careful not to ask for too many. The queue can handle + #at most 32 and since we are on a single thread, we would wait forever + #for the queue to become free + l[0] = 0 + TestPendingCalls_Submit(l, n) + TestPendingCalls_Wait(l, n) + try: _testcapi._test_thread_state have_thread_state = True Index: Modules/_testcapimodule.c =================================================================== --- Modules/_testcapimodule.c (revision 67120) +++ Modules/_testcapimodule.c (working copy) @@ -709,6 +709,50 @@ return NULL; Py_RETURN_NONE; } + +/* test Py_AddPendingCalls using threads */ +static int _pending_callback(void *arg) +{ + /* we assume the argument is callable object to which we own a reference */ + PyObject *callable = (PyObject *)arg; + PyObject *r = PyObject_CallObject(callable, NULL); + Py_DECREF(callable); + Py_DECREF(r); + return r != NULL ? 0 : -1; +} + +/* The following requests n callbacks to _pending_callback. It can be + * run from any python thread. + */ +PyObject *pending_threadfunc(PyObject *self, PyObject *arg) +{ + PyObject *callable; + int n; + int i, j, k; + if (PyArg_ParseTuple(arg, "Oi", &callable, &n) == 0) + return NULL; + + /* create references upfront, while we hold the lock */ + for(i = 0; i