]> granicus.if.org Git - python/commitdiff
Fix bug:
authorMichael W. Hudson <mwh@python.net>
Mon, 20 Jun 2005 16:52:57 +0000 (16:52 +0000)
committerMichael W. Hudson <mwh@python.net>
Mon, 20 Jun 2005 16:52:57 +0000 (16:52 +0000)
1163563 ] Sub threads execute in restricted mode

basically by fixing bug 1010677 in a non-broken way.

Backport candidate.

Misc/NEWS
Modules/threadmodule.c
Python/pystate.c

index 4763598d3ae1e3cf552d93433ef732b84b2207bc..80f7dc79333ce227761c0d521ccdaf2b74f604e5 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,12 @@ What's New in Python 2.5 alpha 1?
 Core and builtins
 -----------------
 
+- SF bug #1163563: the original fix for bug #1010677 ("thread Module
+  Breaks PyGILState_Ensure()") broke badly in the case of multiple
+  interpreter states; back out that fix and do a better job (see
+  http://mail.python.org/pipermail/python-dev/2005-June/054258.html
+  for a longer write-up of the problem).
+
 - SF patch #1180995: marshal now uses a binary format by default when
   serializing floats.
 
index 098a78490d1fc8daf2741651c42a657a02601e0a..3025595df1b2a8f91afaec6abe15bab100e80086 100644 (file)
@@ -413,10 +413,12 @@ static void
 t_bootstrap(void *boot_raw)
 {
        struct bootstate *boot = (struct bootstate *) boot_raw;
-       PyGILState_STATE gstate;
+       PyThreadState *tstate;
        PyObject *res;
 
-       gstate = PyGILState_Ensure();
+       tstate = PyThreadState_New(boot->interp);
+
+       PyEval_AcquireThread(tstate);
        res = PyEval_CallObjectWithKeywords(
                boot->func, boot->args, boot->keyw);
        if (res == NULL) {
@@ -441,7 +443,8 @@ t_bootstrap(void *boot_raw)
        Py_DECREF(boot->args);
        Py_XDECREF(boot->keyw);
        PyMem_DEL(boot_raw);
-       PyGILState_Release(gstate);
+       PyThreadState_Clear(tstate);
+       PyThreadState_DeleteCurrent();
        PyThread_exit_thread();
 }
 
index e2cf7c564d5125ce731b4e9cd2352da8cf8c0d3c..3ac799ce8862560720f10d375e855e136bdb6719 100644 (file)
@@ -36,6 +36,12 @@ static PyThread_type_lock head_mutex = NULL; /* Protects interp->tstate_head */
 #define HEAD_INIT() (void)(head_mutex || (head_mutex = PyThread_allocate_lock()))
 #define HEAD_LOCK() PyThread_acquire_lock(head_mutex, WAIT_LOCK)
 #define HEAD_UNLOCK() PyThread_release_lock(head_mutex)
+
+/* The single PyInterpreterState used by this process'
+   GILState implementation
+*/
+static PyInterpreterState *autoInterpreterState = NULL;
+static int autoTLSkey = 0;
 #else
 #define HEAD_INIT() /* Nothing */
 #define HEAD_LOCK() /* Nothing */
@@ -47,6 +53,8 @@ static PyInterpreterState *interp_head = NULL;
 PyThreadState *_PyThreadState_Current = NULL;
 PyThreadFrameGetter _PyThreadState_GetFrame = NULL;
 
+static void _PyGILState_NoteThreadState(PyThreadState* tstate);
+
 
 PyInterpreterState *
 PyInterpreterState_New(void)
@@ -180,6 +188,8 @@ PyThreadState_New(PyInterpreterState *interp)
                tstate->c_profileobj = NULL;
                tstate->c_traceobj = NULL;
 
+               _PyGILState_NoteThreadState(tstate);
+
                HEAD_LOCK();
                tstate->next = interp->tstate_head;
                interp->tstate_head = tstate;
@@ -261,6 +271,8 @@ PyThreadState_DeleteCurrent()
                        "PyThreadState_DeleteCurrent: no current tstate");
        _PyThreadState_Current = NULL;
        tstate_delete_common(tstate);
+       if (autoTLSkey && PyThread_get_key_value(autoTLSkey) == tstate)
+               PyThread_delete_key_value(autoTLSkey);
        PyEval_ReleaseLock();
 }
 #endif /* WITH_THREAD */
@@ -393,12 +405,6 @@ PyThreadState_IsCurrent(PyThreadState *tstate)
        return tstate == _PyThreadState_Current;
 }
 
-/* The single PyInterpreterState used by this process'
-   GILState implementation
-*/
-static PyInterpreterState *autoInterpreterState = NULL;
-static int autoTLSkey = 0;
-
 /* Internal initialization/finalization functions called by
    Py_Initialize/Py_Finalize
 */
@@ -408,12 +414,10 @@ _PyGILState_Init(PyInterpreterState *i, PyThreadState *t)
        assert(i && t); /* must init with valid states */
        autoTLSkey = PyThread_create_key();
        autoInterpreterState = i;
-       /* Now stash the thread state for this thread in TLS */
        assert(PyThread_get_key_value(autoTLSkey) == NULL);
-       if (PyThread_set_key_value(autoTLSkey, (void *)t) < 0)
-               Py_FatalError("Couldn't create autoTLSkey mapping");
-       assert(t->gilstate_counter == 0); /* must be a new thread state */
-       t->gilstate_counter = 1;
+       assert(t->gilstate_counter == 0);
+
+       _PyGILState_NoteThreadState(t);
 }
 
 void
@@ -424,6 +428,41 @@ _PyGILState_Fini(void)
        autoInterpreterState = NULL;;
 }
 
+/* When a thread state is created for a thread by some mechanism other than
+   PyGILState_Ensure, it's important that the GILState machinery knows about
+   it so it doesn't try to create another thread state for the thread (this is
+   a better fix for SF bug #1010677 than the first one attempted).
+*/
+void
+_PyGILState_NoteThreadState(PyThreadState* tstate)
+{
+       /* If autoTLSkey is 0, this must be the very first threadstate created
+          in Py_Initialize().  Don't do anything for now (we'll be back here
+          when _PyGILState_Init is called). */
+       if (!autoTLSkey) 
+               return;
+       
+       /* Stick the thread state for this thread in thread local storage.
+
+          The only situation where you can legitimately have more than one
+          thread state for an OS level thread is when there are multiple
+          interpreters, when:
+              
+              a) You shouldn't really be using the PyGILState_ APIs anyway,
+                 and:
+
+              b) The slightly odd way PyThread_set_key_value works (see
+                 comments by its implementation) means that the first thread
+                 state created for that given OS level thread will "win",
+                 which seems reasonable behaviour.
+       */
+       if (PyThread_set_key_value(autoTLSkey, (void *)tstate) < 0)
+               Py_FatalError("Couldn't create autoTLSkey mapping");
+
+       /* PyGILState_Release must not try to delete this thread state. */
+       tstate->gilstate_counter = 1;
+}
+
 /* The public functions */
 PyThreadState *
 PyGILState_GetThisThreadState(void)
@@ -450,8 +489,9 @@ PyGILState_Ensure(void)
                tcur = PyThreadState_New(autoInterpreterState);
                if (tcur == NULL)
                        Py_FatalError("Couldn't create thread-state for new thread");
-               if (PyThread_set_key_value(autoTLSkey, (void *)tcur) < 0)
-                       Py_FatalError("Couldn't create autoTLSkey mapping");
+               /* This is our thread state!  We'll need to delete it in the
+                  matching call to PyGILState_Release(). */
+               tcur->gilstate_counter = 0;
                current = 0; /* new thread state is never current */
        }
        else
@@ -498,8 +538,6 @@ PyGILState_Release(PyGILState_STATE oldstate)
                 * habit of coming back).
                 */
                PyThreadState_DeleteCurrent();
-               /* Delete this thread from our TLS. */
-               PyThread_delete_key_value(autoTLSkey);
        }
        /* Release the lock if necessary */
        else if (oldstate == PyGILState_UNLOCKED)