summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Misc/NEWS6
-rw-r--r--Modules/threadmodule.c9
-rw-r--r--Python/pystate.c68
3 files changed, 65 insertions, 18 deletions
diff --git a/Misc/NEWS b/Misc/NEWS
index ed4c8de..cc2ac30 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -40,6 +40,12 @@ What's New in Python 2.4.2c1
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).
+
- On 64-bit platforms, when __len__() returns a value that cannot be
represented as a C int, raise OverflowError.
diff --git a/Modules/threadmodule.c b/Modules/threadmodule.c
index cba01fa..052262c 100644
--- a/Modules/threadmodule.c
+++ b/Modules/threadmodule.c
@@ -425,10 +425,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) {
@@ -453,7 +455,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();
}
diff --git a/Python/pystate.c b/Python/pystate.c
index abca8dd..9d0ba31 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -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)