mirror of
https://github.com/python/cpython.git
synced 2025-07-09 20:35:26 +00:00
bpo-25658: Implement PEP 539 for Thread Specific Storage (TSS) API (GH-1362)
See PEP 539 for details. Highlights of changes: - Add Thread Specific Storage (TSS) API - Document the Thread Local Storage (TLS) API as deprecated - Update code that used TLS API to use TSS API
This commit is contained in:
parent
b8ab9d3fc8
commit
731e189014
18 changed files with 651 additions and 108 deletions
|
@ -46,7 +46,12 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime)
|
|||
_PyEval_Initialize(&runtime->ceval);
|
||||
|
||||
runtime->gilstate.check_enabled = 1;
|
||||
runtime->gilstate.autoTLSkey = -1;
|
||||
/* A TSS key must be initialized with Py_tss_NEEDS_INIT
|
||||
in accordance with the specification. */
|
||||
{
|
||||
Py_tss_t initial = Py_tss_NEEDS_INIT;
|
||||
runtime->gilstate.autoTSSkey = initial;
|
||||
}
|
||||
|
||||
runtime->interpreters.mutex = PyThread_allocate_lock();
|
||||
if (runtime->interpreters.mutex == NULL)
|
||||
|
@ -485,9 +490,9 @@ PyThreadState_Delete(PyThreadState *tstate)
|
|||
if (tstate == GET_TSTATE())
|
||||
Py_FatalError("PyThreadState_Delete: tstate is still current");
|
||||
if (_PyRuntime.gilstate.autoInterpreterState &&
|
||||
PyThread_get_key_value(_PyRuntime.gilstate.autoTLSkey) == tstate)
|
||||
PyThread_tss_get(&_PyRuntime.gilstate.autoTSSkey) == tstate)
|
||||
{
|
||||
PyThread_delete_key_value(_PyRuntime.gilstate.autoTLSkey);
|
||||
PyThread_tss_set(&_PyRuntime.gilstate.autoTSSkey, NULL);
|
||||
}
|
||||
tstate_delete_common(tstate);
|
||||
}
|
||||
|
@ -502,9 +507,9 @@ PyThreadState_DeleteCurrent()
|
|||
"PyThreadState_DeleteCurrent: no current tstate");
|
||||
tstate_delete_common(tstate);
|
||||
if (_PyRuntime.gilstate.autoInterpreterState &&
|
||||
PyThread_get_key_value(_PyRuntime.gilstate.autoTLSkey) == tstate)
|
||||
PyThread_tss_get(&_PyRuntime.gilstate.autoTSSkey) == tstate)
|
||||
{
|
||||
PyThread_delete_key_value(_PyRuntime.gilstate.autoTLSkey);
|
||||
PyThread_tss_set(&_PyRuntime.gilstate.autoTSSkey, NULL);
|
||||
}
|
||||
SET_TSTATE(NULL);
|
||||
PyEval_ReleaseLock();
|
||||
|
@ -761,11 +766,11 @@ void
|
|||
_PyGILState_Init(PyInterpreterState *i, PyThreadState *t)
|
||||
{
|
||||
assert(i && t); /* must init with valid states */
|
||||
_PyRuntime.gilstate.autoTLSkey = PyThread_create_key();
|
||||
if (_PyRuntime.gilstate.autoTLSkey == -1)
|
||||
Py_FatalError("Could not allocate TLS entry");
|
||||
if (PyThread_tss_create(&_PyRuntime.gilstate.autoTSSkey) != 0) {
|
||||
Py_FatalError("Could not allocate TSS entry");
|
||||
}
|
||||
_PyRuntime.gilstate.autoInterpreterState = i;
|
||||
assert(PyThread_get_key_value(_PyRuntime.gilstate.autoTLSkey) == NULL);
|
||||
assert(PyThread_tss_get(&_PyRuntime.gilstate.autoTSSkey) == NULL);
|
||||
assert(t->gilstate_counter == 0);
|
||||
|
||||
_PyGILState_NoteThreadState(t);
|
||||
|
@ -780,14 +785,13 @@ _PyGILState_GetInterpreterStateUnsafe(void)
|
|||
void
|
||||
_PyGILState_Fini(void)
|
||||
{
|
||||
PyThread_delete_key(_PyRuntime.gilstate.autoTLSkey);
|
||||
_PyRuntime.gilstate.autoTLSkey = -1;
|
||||
PyThread_tss_delete(&_PyRuntime.gilstate.autoTSSkey);
|
||||
_PyRuntime.gilstate.autoInterpreterState = NULL;
|
||||
}
|
||||
|
||||
/* Reset the TLS key - called by PyOS_AfterFork_Child().
|
||||
/* Reset the TSS key - called by PyOS_AfterFork_Child().
|
||||
* This should not be necessary, but some - buggy - pthread implementations
|
||||
* don't reset TLS upon fork(), see issue #10517.
|
||||
* don't reset TSS upon fork(), see issue #10517.
|
||||
*/
|
||||
void
|
||||
_PyGILState_Reinit(void)
|
||||
|
@ -796,15 +800,18 @@ _PyGILState_Reinit(void)
|
|||
if (_PyRuntime.interpreters.mutex == NULL)
|
||||
Py_FatalError("Can't initialize threads for interpreter");
|
||||
PyThreadState *tstate = PyGILState_GetThisThreadState();
|
||||
PyThread_delete_key(_PyRuntime.gilstate.autoTLSkey);
|
||||
if ((_PyRuntime.gilstate.autoTLSkey = PyThread_create_key()) == -1)
|
||||
Py_FatalError("Could not allocate TLS entry");
|
||||
PyThread_tss_delete(&_PyRuntime.gilstate.autoTSSkey);
|
||||
if (PyThread_tss_create(&_PyRuntime.gilstate.autoTSSkey) != 0) {
|
||||
Py_FatalError("Could not allocate TSS entry");
|
||||
}
|
||||
|
||||
/* If the thread had an associated auto thread state, reassociate it with
|
||||
* the new key. */
|
||||
if (tstate && PyThread_set_key_value(_PyRuntime.gilstate.autoTLSkey,
|
||||
(void *)tstate) < 0)
|
||||
Py_FatalError("Couldn't create autoTLSkey mapping");
|
||||
if (tstate &&
|
||||
PyThread_tss_set(&_PyRuntime.gilstate.autoTSSkey, (void *)tstate) != 0)
|
||||
{
|
||||
Py_FatalError("Couldn't create autoTSSkey mapping");
|
||||
}
|
||||
}
|
||||
|
||||
/* When a thread state is created for a thread by some mechanism other than
|
||||
|
@ -815,13 +822,13 @@ _PyGILState_Reinit(void)
|
|||
static void
|
||||
_PyGILState_NoteThreadState(PyThreadState* tstate)
|
||||
{
|
||||
/* If autoTLSkey isn't initialized, this must be the very first
|
||||
/* If autoTSSkey isn't initialized, 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 (!_PyRuntime.gilstate.autoInterpreterState)
|
||||
return;
|
||||
|
||||
/* Stick the thread state for this thread in thread local storage.
|
||||
/* Stick the thread state for this thread in thread specific storage.
|
||||
|
||||
The only situation where you can legitimately have more than one
|
||||
thread state for an OS level thread is when there are multiple
|
||||
|
@ -833,12 +840,11 @@ _PyGILState_NoteThreadState(PyThreadState* tstate)
|
|||
The first thread state created for that given OS level thread will
|
||||
"win", which seems reasonable behaviour.
|
||||
*/
|
||||
if (PyThread_get_key_value(_PyRuntime.gilstate.autoTLSkey) == NULL) {
|
||||
if ((PyThread_set_key_value(_PyRuntime.gilstate.autoTLSkey,
|
||||
(void *)tstate)
|
||||
) < 0)
|
||||
if (PyThread_tss_get(&_PyRuntime.gilstate.autoTSSkey) == NULL) {
|
||||
if ((PyThread_tss_set(&_PyRuntime.gilstate.autoTSSkey, (void *)tstate)
|
||||
) != 0)
|
||||
{
|
||||
Py_FatalError("Couldn't create autoTLSkey mapping");
|
||||
Py_FatalError("Couldn't create autoTSSkey mapping");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -852,8 +858,7 @@ PyGILState_GetThisThreadState(void)
|
|||
{
|
||||
if (_PyRuntime.gilstate.autoInterpreterState == NULL)
|
||||
return NULL;
|
||||
return (PyThreadState *)PyThread_get_key_value(
|
||||
_PyRuntime.gilstate.autoTLSkey);
|
||||
return (PyThreadState *)PyThread_tss_get(&_PyRuntime.gilstate.autoTSSkey);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -864,8 +869,9 @@ PyGILState_Check(void)
|
|||
if (!_PyGILState_check_enabled)
|
||||
return 1;
|
||||
|
||||
if (_PyRuntime.gilstate.autoTLSkey == -1)
|
||||
if (!PyThread_tss_is_created(&_PyRuntime.gilstate.autoTSSkey)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
tstate = GET_TSTATE();
|
||||
if (tstate == NULL)
|
||||
|
@ -886,8 +892,7 @@ PyGILState_Ensure(void)
|
|||
*/
|
||||
/* Py_Initialize() hasn't been called! */
|
||||
assert(_PyRuntime.gilstate.autoInterpreterState);
|
||||
tcur = (PyThreadState *)PyThread_get_key_value(
|
||||
_PyRuntime.gilstate.autoTLSkey);
|
||||
tcur = (PyThreadState *)PyThread_tss_get(&_PyRuntime.gilstate.autoTSSkey);
|
||||
if (tcur == NULL) {
|
||||
/* At startup, Python has no concrete GIL. If PyGILState_Ensure() is
|
||||
called from a new thread for the first time, we need the create the
|
||||
|
@ -919,8 +924,8 @@ PyGILState_Ensure(void)
|
|||
void
|
||||
PyGILState_Release(PyGILState_STATE oldstate)
|
||||
{
|
||||
PyThreadState *tcur = (PyThreadState *)PyThread_get_key_value(
|
||||
_PyRuntime.gilstate.autoTLSkey);
|
||||
PyThreadState *tcur = (PyThreadState *)PyThread_tss_get(
|
||||
&_PyRuntime.gilstate.autoTSSkey);
|
||||
if (tcur == NULL)
|
||||
Py_FatalError("auto-releasing thread-state, "
|
||||
"but no thread-state for this thread");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue