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);
}