Commit cd0cb8cc authored by Victor Stinner's avatar Victor Stinner

Close #19787: PyThread_set_key_value() now always set the value. In Python 3.3,

the function did nothing if the key already exists (if the current value is a
non-NULL pointer).

_testcapi.run_in_subinterp() now correctly sets the new Python thread state of
the current thread when a subinterpreter is created.
parent 24bd0280
...@@ -1068,3 +1068,8 @@ that may require changes to your code. ...@@ -1068,3 +1068,8 @@ that may require changes to your code.
working directory will also now have an absolute path, including when using working directory will also now have an absolute path, including when using
``-m`` with the interpreter (this does not influence when the path to a file ``-m`` with the interpreter (this does not influence when the path to a file
is specified on the command-line). is specified on the command-line).
* (C API) :c:func:`PyThread_set_key_value` now always set the value. In Python
3.3, the function did nothing if the key already exists (if the current
value is a non-NULL pointer).
...@@ -10,6 +10,10 @@ Release date: 2014-01-05 ...@@ -10,6 +10,10 @@ Release date: 2014-01-05
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #19787: PyThread_set_key_value() now always set the value. In Python
3.3, the function did nothing if the key already exists (if the current value
is a non-NULL pointer).
- Issue #14432: Remove the thread state field from the frame structure. Fix a - Issue #14432: Remove the thread state field from the frame structure. Fix a
crash when a generator is created in a C thread that is destroyed while the crash when a generator is created in a C thread that is destroyed while the
generator is still used. The issue was that a generator contains a frame, and generator is still used. The issue was that a generator contains a frame, and
......
...@@ -2511,6 +2511,10 @@ run_in_subinterp(PyObject *self, PyObject *args) ...@@ -2511,6 +2511,10 @@ run_in_subinterp(PyObject *self, PyObject *args)
r = PyRun_SimpleString(code); r = PyRun_SimpleString(code);
Py_EndInterpreter(substate); Py_EndInterpreter(substate);
/* restore previous thread safe. It was replaced by Py_NewInterpreter()
which creates a new thread state. */
_PyThreadState_Init(mainstate);
PyThreadState_Swap(mainstate); PyThreadState_Swap(mainstate);
return PyLong_FromLong(r); return PyLong_FromLong(r);
......
...@@ -168,14 +168,11 @@ set_reentrant(int reentrant) ...@@ -168,14 +168,11 @@ set_reentrant(int reentrant)
assert(reentrant == 0 || reentrant == 1); assert(reentrant == 0 || reentrant == 1);
if (reentrant) { if (reentrant) {
assert(PyThread_get_key_value(tracemalloc_reentrant_key) == NULL); assert(PyThread_get_key_value(tracemalloc_reentrant_key) == NULL);
PyThread_set_key_value(tracemalloc_reentrant_key, PyThread_set_key_value(tracemalloc_reentrant_key, REENTRANT);
REENTRANT);
} }
else { else {
/* FIXME: PyThread_set_key_value() cannot be used to set the flag assert(PyThread_get_key_value(tracemalloc_reentrant_key) == REENTRANT);
to zero, because it does nothing if the variable has already PyThread_set_key_value(tracemalloc_reentrant_key, NULL);
a value set. */
PyThread_delete_key_value(tracemalloc_reentrant_key);
} }
} }
......
...@@ -205,7 +205,7 @@ static int nkeys = 0; /* PyThread_create_key() hands out nkeys+1 next */ ...@@ -205,7 +205,7 @@ static int nkeys = 0; /* PyThread_create_key() hands out nkeys+1 next */
* segfaults. Now we lock the whole routine. * segfaults. Now we lock the whole routine.
*/ */
static struct key * static struct key *
find_key(int key, void *value) find_key(int key, int update, void *value)
{ {
struct key *p, *prev_p; struct key *p, *prev_p;
long id = PyThread_get_thread_ident(); long id = PyThread_get_thread_ident();
...@@ -215,8 +215,11 @@ find_key(int key, void *value) ...@@ -215,8 +215,11 @@ find_key(int key, void *value)
PyThread_acquire_lock(keymutex, 1); PyThread_acquire_lock(keymutex, 1);
prev_p = NULL; prev_p = NULL;
for (p = keyhead; p != NULL; p = p->next) { for (p = keyhead; p != NULL; p = p->next) {
if (p->id == id && p->key == key) if (p->id == id && p->key == key) {
if (update)
p->value = value;
goto Done; goto Done;
}
/* Sanity check. These states should never happen but if /* Sanity check. These states should never happen but if
* they do we must abort. Otherwise we'll end up spinning in * they do we must abort. Otherwise we'll end up spinning in
* in a tight loop with the lock held. A similar check is done * in a tight loop with the lock held. A similar check is done
...@@ -227,7 +230,7 @@ find_key(int key, void *value) ...@@ -227,7 +230,7 @@ find_key(int key, void *value)
if (p->next == keyhead) if (p->next == keyhead)
Py_FatalError("tls find_key: circular list(!)"); Py_FatalError("tls find_key: circular list(!)");
} }
if (value == NULL) { if (!update && value == NULL) {
assert(p == NULL); assert(p == NULL);
goto Done; goto Done;
} }
...@@ -279,19 +282,12 @@ PyThread_delete_key(int key) ...@@ -279,19 +282,12 @@ PyThread_delete_key(int key)
PyThread_release_lock(keymutex); PyThread_release_lock(keymutex);
} }
/* Confusing: If the current thread has an association for key,
* value is ignored, and 0 is returned. Else an attempt is made to create
* an association of key to value for the current thread. 0 is returned
* if that succeeds, but -1 is returned if there's not enough memory
* to create the association. value must not be NULL.
*/
int int
PyThread_set_key_value(int key, void *value) PyThread_set_key_value(int key, void *value)
{ {
struct key *p; struct key *p;
assert(value != NULL); p = find_key(key, 1, value);
p = find_key(key, value);
if (p == NULL) if (p == NULL)
return -1; return -1;
else else
...@@ -304,7 +300,7 @@ PyThread_set_key_value(int key, void *value) ...@@ -304,7 +300,7 @@ PyThread_set_key_value(int key, void *value)
void * void *
PyThread_get_key_value(int key) PyThread_get_key_value(int key)
{ {
struct key *p = find_key(key, NULL); struct key *p = find_key(key, 0, NULL);
if (p == NULL) if (p == NULL)
return NULL; return NULL;
......
...@@ -389,20 +389,11 @@ PyThread_delete_key(int key) ...@@ -389,20 +389,11 @@ PyThread_delete_key(int key)
TlsFree(key); TlsFree(key);
} }
/* We must be careful to emulate the strange semantics implemented in thread.c,
* where the value is only set if it hasn't been set before.
*/
int int
PyThread_set_key_value(int key, void *value) PyThread_set_key_value(int key, void *value)
{ {
BOOL ok; BOOL ok;
void *oldvalue;
assert(value != NULL);
oldvalue = TlsGetValue(key);
if (oldvalue != NULL)
/* ignore value if already set */
return 0;
ok = TlsSetValue(key, value); ok = TlsSetValue(key, value);
if (!ok) if (!ok)
return -1; return -1;
......
...@@ -627,9 +627,6 @@ int ...@@ -627,9 +627,6 @@ int
PyThread_set_key_value(int key, void *value) PyThread_set_key_value(int key, void *value)
{ {
int fail; int fail;
void *oldValue = pthread_getspecific(key);
if (oldValue != NULL)
return 0;
fail = pthread_setspecific(key, value); fail = pthread_setspecific(key, value);
return fail ? -1 : 0; return fail ? -1 : 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment