static PyObject * test_thread_state(PyObject *self, PyObject *args) { PyObject *fn; int success = 1; if (!PyArg_ParseTuple(args, "O:test_thread_state", &fn)) return NULL; if (!PyCallable_Check(fn)) { PyErr_Format(PyExc_TypeError, "'%s' object is not callable", fn->ob_type->tp_name); return NULL; } /* Ensure Python is set up for threading */ PyEval_InitThreads(); thread_done = PyThread_allocate_lock(); if (thread_done == NULL) return PyErr_NoMemory(); PyThread_acquire_lock(thread_done, 1); /* Start a new thread with our callback. */ PyThread_start_new_thread(_make_call_from_thread, fn); /* Make the callback with the thread lock held by this thread */ success &= _make_call(fn); /* Do it all again, but this time with the thread-lock released */ Py_BEGIN_ALLOW_THREADS success &= _make_call(fn); PyThread_acquire_lock(thread_done, 1); /* wait for thread to finish */ Py_END_ALLOW_THREADS /* And once more with and without a thread XXX - should use a lock and work out exactly what we are trying to test <wink> */ Py_BEGIN_ALLOW_THREADS PyThread_start_new_thread(_make_call_from_thread, fn); success &= _make_call(fn); PyThread_acquire_lock(thread_done, 1); /* wait for thread to finish */ Py_END_ALLOW_THREADS /* Release lock we acquired above. This is required on HP-UX. */ PyThread_release_lock(thread_done); PyThread_free_lock(thread_done); if (!success) return NULL; Py_RETURN_NONE; }
/* Same thing, but releases `thread_done` when it returns. This variant * should be called only from threads spawned by test_thread_state(). */ static void _make_call_from_thread(void *callable) { _make_call(callable); PyThread_release_lock(thread_done); }