summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorMark Hammond <mhammond@skippinet.com.au>2003-04-19 15:41:53 (GMT)
committerMark Hammond <mhammond@skippinet.com.au>2003-04-19 15:41:53 (GMT)
commit8d98d2cb95ac37147a4de5a119869211e8351324 (patch)
tree8175d77139194bffa61b79d19544525927a13fc5 /Modules
parente36b6900878b8715c37bfa241381dddb82cda386 (diff)
downloadcpython-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.c47
-rw-r--r--Modules/posixmodule.c56
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;
}