diff options
author | Mark Hammond <mhammond@skippinet.com.au> | 2003-04-19 15:41:53 (GMT) |
---|---|---|
committer | Mark Hammond <mhammond@skippinet.com.au> | 2003-04-19 15:41:53 (GMT) |
commit | 8d98d2cb95ac37147a4de5a119869211e8351324 (patch) | |
tree | 8175d77139194bffa61b79d19544525927a13fc5 /Modules | |
parent | e36b6900878b8715c37bfa241381dddb82cda386 (diff) | |
download | cpython-8d98d2cb95ac37147a4de5a119869211e8351324.zip cpython-8d98d2cb95ac37147a4de5a119869211e8351324.tar.gz cpython-8d98d2cb95ac37147a4de5a119869211e8351324.tar.bz2 |
New PyGILState_ API - implements pep 311, from patch 684256.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_testcapimodule.c | 47 | ||||
-rw-r--r-- | Modules/posixmodule.c | 56 |
2 files changed, 53 insertions, 50 deletions
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index b3da398..b52e965 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -7,6 +7,10 @@ #include "Python.h" +#ifdef WITH_THREAD +#include "pythread.h" +#endif /* WITH_THREAD */ + static PyObject *TestError; /* set to exception object in init */ /* Raise TestError with test_name + ": " + msg, and return NULL. */ @@ -535,6 +539,46 @@ raise_exception(PyObject *self, PyObject *args) return NULL; } +#ifdef WITH_THREAD + +void _make_call(void *callable) +{ + PyObject *rc; + PyGILState_STATE s = PyGILState_Ensure(); + rc = PyObject_CallFunction(callable, ""); + Py_XDECREF(rc); + PyGILState_Release(s); +} + +static PyObject * +test_thread_state(PyObject *self, PyObject *args) +{ + PyObject *fn; + if (!PyArg_ParseTuple(args, "O:test_thread_state", &fn)) + return NULL; + /* Ensure Python is setup for threading */ + PyEval_InitThreads(); + /* Start a new thread for our callback. */ + PyThread_start_new_thread( _make_call, fn); + /* Make the callback with the thread lock held by this thread */ + _make_call(fn); + /* Do it all again, but this time with the thread-lock released */ + Py_BEGIN_ALLOW_THREADS + _make_call(fn); + 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, fn); + _make_call(fn); + Py_END_ALLOW_THREADS + Py_INCREF(Py_None); + return Py_None; +} +#endif + static PyMethodDef TestMethods[] = { {"raise_exception", raise_exception, METH_VARARGS}, {"test_config", (PyCFunction)test_config, METH_NOARGS}, @@ -554,6 +598,9 @@ static PyMethodDef TestMethods[] = { #ifdef Py_USING_UNICODE {"test_u_code", (PyCFunction)test_u_code, METH_NOARGS}, #endif +#ifdef WITH_THREAD + {"_test_thread_state", (PyCFunction)test_thread_state, METH_VARARGS}, +#endif {NULL, NULL} /* sentinel */ }; diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 9bf52f3..d34756a 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -4354,22 +4354,11 @@ _PyPopen(char *cmdstring, int mode, int n) * exit code as the result of the close() operation. This permits the * files to be closed in any order - it is always the close() of the * final handle that will return the exit code. + * + * NOTE: This function is currently called with the GIL released. + * hence we use the GILState API to manage our state. */ - /* RED_FLAG 31-Aug-2000 Tim - * This is always called (today!) between a pair of - * Py_BEGIN_ALLOW_THREADS/ Py_END_ALLOW_THREADS - * macros. So the thread running this has no valid thread state, as - * far as Python is concerned. However, this calls some Python API - * functions that cannot be called safely without a valid thread - * state, in particular PyDict_GetItem. - * As a temporary hack (although it may last for years ...), we - * *rely* on not having a valid thread state in this function, in - * order to create our own "from scratch". - * This will deadlock if _PyPclose is ever called by a thread - * holding the global lock. - */ - static int _PyPclose(FILE *file) { int result; @@ -4378,40 +4367,16 @@ static int _PyPclose(FILE *file) PyObject *procObj, *hProcessObj, *intObj, *fileObj; long file_count; #ifdef WITH_THREAD - PyInterpreterState* pInterpreterState; - PyThreadState* pThreadState; + PyGILState_STATE state; #endif /* Close the file handle first, to ensure it can't block the * child from exiting if it's the last handle. */ result = fclose(file); - #ifdef WITH_THREAD - /* Bootstrap a valid thread state into existence. */ - pInterpreterState = PyInterpreterState_New(); - if (!pInterpreterState) { - /* Well, we're hosed now! We don't have a thread - * state, so can't call a nice error routine, or raise - * an exception. Just die. - */ - Py_FatalError("unable to allocate interpreter state " - "when closing popen object"); - return -1; /* unreachable */ - } - pThreadState = PyThreadState_New(pInterpreterState); - if (!pThreadState) { - Py_FatalError("unable to allocate thread state " - "when closing popen object"); - return -1; /* unreachable */ - } - /* Grab the global lock. Note that this will deadlock if the - * current thread already has the lock! (see RED_FLAG comments - * before this function) - */ - PyEval_RestoreThread(pThreadState); + state = PyGILState_Ensure(); #endif - if (_PyPopenProcs) { if ((fileObj = PyLong_FromVoidPtr(file)) != NULL && (procObj = PyDict_GetItem(_PyPopenProcs, @@ -4470,17 +4435,8 @@ static int _PyPclose(FILE *file) } /* if _PyPopenProcs */ #ifdef WITH_THREAD - /* Tear down the thread & interpreter states. - * Note that interpreter state clear & delete functions automatically - * call the thread clear & delete functions, and indeed insist on - * doing that themselves. The lock must be held during the clear, but - * need not be held during the delete. - */ - PyInterpreterState_Clear(pInterpreterState); - PyEval_ReleaseThread(pThreadState); - PyInterpreterState_Delete(pInterpreterState); + PyGILState_Release(state); #endif - return result; } |