[Python-checkins] r81174 - in python/branches/py3k-jit: Include/ceval.h Makefile.pre.in Python/ceval.c Python/ceval_gil.h Python/pythonrun.c Unittests/ThreadTest.cc

jeffrey.yasskin python-checkins at python.org
Fri May 14 20:51:40 CEST 2010


Author: jeffrey.yasskin
Date: Fri May 14 20:51:40 2010
New Revision: 81174

Log:
Fix a problem where initializing threads and then finalizing and
re-initializing the interpreter would cause any use of the gil to crash.


Added:
   python/branches/py3k-jit/Unittests/ThreadTest.cc
Modified:
   python/branches/py3k-jit/Include/ceval.h
   python/branches/py3k-jit/Makefile.pre.in
   python/branches/py3k-jit/Python/ceval.c
   python/branches/py3k-jit/Python/ceval_gil.h
   python/branches/py3k-jit/Python/pythonrun.c

Modified: python/branches/py3k-jit/Include/ceval.h
==============================================================================
--- python/branches/py3k-jit/Include/ceval.h	(original)
+++ python/branches/py3k-jit/Include/ceval.h	Fri May 14 20:51:40 2010
@@ -165,6 +165,7 @@
 PyAPI_FUNC(void) PyEval_AcquireThread(PyThreadState *tstate);
 PyAPI_FUNC(void) PyEval_ReleaseThread(PyThreadState *tstate);
 PyAPI_FUNC(void) PyEval_ReInitThreads(void);
+PyAPI_FUNC(void) PyEval_UnInitThreads(void);
 
 PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds);
 PyAPI_FUNC(unsigned long) _PyEval_GetSwitchInterval(void);

Modified: python/branches/py3k-jit/Makefile.pre.in
==============================================================================
--- python/branches/py3k-jit/Makefile.pre.in	(original)
+++ python/branches/py3k-jit/Makefile.pre.in	Fri May 14 20:51:40 2010
@@ -751,6 +751,7 @@
 		$(srcdir)/Unittests/GetArgsTest.cc \
 		$(srcdir)/Unittests/ListTest.cc \
 		$(srcdir)/Unittests/ObjectTest.cc \
+		$(srcdir)/Unittests/ThreadTest.cc \
 		$(srcdir)/Unittests/UnicodeTest.cc \
 		$(srcdir)/Unittests/pytest_main.cc \
 		$(@LLVM_UNITTEST_SRCS@) \

Modified: python/branches/py3k-jit/Python/ceval.c
==============================================================================
--- python/branches/py3k-jit/Python/ceval.c	(original)
+++ python/branches/py3k-jit/Python/ceval.c	Fri May 14 20:51:40 2010
@@ -389,6 +389,16 @@
     Py_DECREF(threading);
 }
 
+/* This function is called from Py_Finalize to destroy the gil.  No
+   other threads may be running when it is called. */
+void
+PyEval_UnInitThreads(void)
+{
+    if (!gil_created())
+        return;
+    destroy_gil();
+}
+
 #else
 static _Py_atomic_int eval_breaker = {0};
 static _Py_atomic_int gil_drop_request = {0};

Modified: python/branches/py3k-jit/Python/ceval_gil.h
==============================================================================
--- python/branches/py3k-jit/Python/ceval_gil.h	(original)
+++ python/branches/py3k-jit/Python/ceval_gil.h	Fri May 14 20:51:40 2010
@@ -95,6 +95,9 @@
 #define MUTEX_INIT(mut) \
     if (pthread_mutex_init(&mut, NULL)) { \
         Py_FatalError("pthread_mutex_init(" #mut ") failed"); };
+#define MUTEX_DESTROY(mut) \
+    if (pthread_mutex_destroy(&mut)) { \
+        Py_FatalError("pthread_mutex_destroy(" #mut ") failed"); };
 #define MUTEX_LOCK(mut) \
     if (pthread_mutex_lock(&mut)) { \
         Py_FatalError("pthread_mutex_lock(" #mut ") failed"); };
@@ -106,6 +109,9 @@
 #define COND_INIT(cond) \
     if (pthread_cond_init(&cond, NULL)) { \
         Py_FatalError("pthread_cond_init(" #cond ") failed"); };
+#define COND_DESTROY(cond) \
+    if (pthread_cond_destroy(&cond)) { \
+        Py_FatalError("pthread_cond_destroy(" #cond ") failed"); };
 #define COND_RESET(cond)
 #define COND_SIGNAL(cond) \
     if (pthread_cond_signal(&cond)) { \
@@ -145,6 +151,9 @@
 #define MUTEX_INIT(mut) \
     if (!(mut = CreateMutex(NULL, FALSE, NULL))) { \
         Py_FatalError("CreateMutex(" #mut ") failed"); };
+#define MUTEX_DESTROY(mut) \
+    if (!CloseHandle(mut)) { \
+        Py_FatalError("CloseHandle(" #mut ") failed to destroy mutex"); };
 #define MUTEX_LOCK(mut) \
     if (WaitForSingleObject(mut, INFINITE) != WAIT_OBJECT_0) { \
         Py_FatalError("WaitForSingleObject(" #mut ") failed"); };
@@ -172,6 +181,9 @@
     /* auto-reset, non-signalled */ \
     if (!(cond = CreateEvent(NULL, FALSE, FALSE, NULL))) { \
         Py_FatalError("CreateMutex(" #cond ") failed"); };
+#define COND_DESTROY(cond) \
+    if (!CloseHandle(cond)) { \
+        Py_FatalError("CloseHandle(" #cond ") failed to destroy event"); };
 #define COND_RESET(cond) \
     if (!ResetEvent(cond)) { \
         Py_FatalError("ResetEvent(" #cond ") failed"); };
@@ -256,6 +268,21 @@
     create_gil();
 }
 
+/* Requires that no other threads are running anymore. */
+static void destroy_gil(void)
+{
+    MUTEX_DESTROY(gil_mutex);
+#ifdef FORCE_SWITCHING
+    MUTEX_DESTROY(switch_mutex);
+#endif
+    COND_DESTROY(gil_cond);
+#ifdef FORCE_SWITCHING
+    COND_DESTROY(switch_cond);
+#endif
+    _Py_atomic_store_relaxed(&gil_locked, -1);
+    _Py_ANNOTATE_RWLOCK_DESTROY(&gil_locked);
+}
+
 static void drop_gil(PyThreadState *tstate)
 {
     /* NOTE: tstate is allowed to be NULL. */

Modified: python/branches/py3k-jit/Python/pythonrun.c
==============================================================================
--- python/branches/py3k-jit/Python/pythonrun.c	(original)
+++ python/branches/py3k-jit/Python/pythonrun.c	Fri May 14 20:51:40 2010
@@ -478,6 +478,7 @@
     /* Delete current thread */
     PyThreadState_Swap(NULL);
     PyInterpreterState_Delete(interp);
+    PyEval_UnInitThreads();
 
     /* Sundry finalizers */
     PyMethod_Fini();

Added: python/branches/py3k-jit/Unittests/ThreadTest.cc
==============================================================================
--- (empty file)
+++ python/branches/py3k-jit/Unittests/ThreadTest.cc	Fri May 14 20:51:40 2010
@@ -0,0 +1,28 @@
+#include "Python.h"
+
+#include "gtest/gtest.h"
+#include "pytest.h"
+
+namespace {
+
+class ThreadTest : public ::testing::Test {
+    PythonSetupTeardown setup_teardown_;
+};
+
+TEST_F(ThreadTest, InitThreadsAcrossFinalize)
+{
+    PyEval_InitThreads();
+
+    Py_Finalize();
+    // Make it more likely that we get a different address for the
+    // PyThreadState in the new interpreter.
+    void *p = malloc(sizeof(PyThreadState));
+    Py_Initialize();
+    free(p);
+
+    PyEval_InitThreads();
+    Py_BEGIN_ALLOW_THREADS;  // Used to crash.
+    Py_END_ALLOW_THREADS;
+}
+
+}  // anonymous namespace


More information about the Python-checkins mailing list