diff options
author | Eric Snow <ericsnowcurrently@gmail.com> | 2017-09-06 01:26:16 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-06 01:26:16 (GMT) |
commit | 76d5abc8684bac4f2fc7cccfe2cd940923357351 (patch) | |
tree | 4ae6a3bd88bef1266a8d9723c589f925d90bf848 /Python/pystate.c | |
parent | 501b324d3a940d26e0021a38aae8d896a30fbcff (diff) | |
download | cpython-76d5abc8684bac4f2fc7cccfe2cd940923357351.zip cpython-76d5abc8684bac4f2fc7cccfe2cd940923357351.tar.gz cpython-76d5abc8684bac4f2fc7cccfe2cd940923357351.tar.bz2 |
bpo-30860: Consolidate stateful runtime globals. (#2594)
* group the (stateful) runtime globals into various topical structs
* consolidate the topical structs under a single top-level _PyRuntimeState struct
* add a check-c-globals.py script that helps identify runtime globals
Other globals are excluded (see globals.txt and check-c-globals.py).
Diffstat (limited to 'Python/pystate.c')
-rw-r--r-- | Python/pystate.c | 196 |
1 files changed, 108 insertions, 88 deletions
diff --git a/Python/pystate.c b/Python/pystate.c index 30a3722..3d32077 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -34,55 +34,66 @@ to avoid the expense of doing their own locking). extern "C" { #endif -int _PyGILState_check_enabled = 1; +void +_PyRuntimeState_Init(_PyRuntimeState *runtime) +{ + _PyRuntimeState initial = {}; + *runtime = initial; + + _PyObject_Initialize(&runtime->obj); + _PyMem_Initialize(&runtime->mem); + _PyGC_Initialize(&runtime->gc); + _PyEval_Initialize(&runtime->ceval); + + runtime->gilstate.check_enabled = 1; + runtime->gilstate.autoTLSkey = -1; #ifdef WITH_THREAD -#include "pythread.h" -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 -*/ -/* TODO: Given interp_main, it may be possible to kill this ref */ -static PyInterpreterState *autoInterpreterState = NULL; -static int autoTLSkey = -1; + runtime->interpreters.mutex = PyThread_allocate_lock(); + if (runtime->interpreters.mutex == NULL) + Py_FatalError("Can't initialize threads for interpreter"); +#endif + runtime->interpreters.next_id = -1; +} + +void +_PyRuntimeState_Fini(_PyRuntimeState *runtime) +{ +#ifdef WITH_THREAD + if (runtime->interpreters.mutex != NULL) { + PyThread_free_lock(runtime->interpreters.mutex); + runtime->interpreters.mutex = NULL; + } +#endif +} + +#ifdef WITH_THREAD +#define HEAD_LOCK() PyThread_acquire_lock(_PyRuntime.interpreters.mutex, \ + WAIT_LOCK) +#define HEAD_UNLOCK() PyThread_release_lock(_PyRuntime.interpreters.mutex) #else -#define HEAD_INIT() /* Nothing */ #define HEAD_LOCK() /* Nothing */ #define HEAD_UNLOCK() /* Nothing */ #endif -static PyInterpreterState *interp_head = NULL; -static PyInterpreterState *interp_main = NULL; - -/* Assuming the current thread holds the GIL, this is the - PyThreadState for the current thread. */ -_Py_atomic_address _PyThreadState_Current = {0}; -PyThreadFrameGetter _PyThreadState_GetFrame = NULL; - #ifdef WITH_THREAD static void _PyGILState_NoteThreadState(PyThreadState* tstate); #endif -/* _next_interp_id is an auto-numbered sequence of small integers. - It gets initialized in _PyInterpreterState_Init(), which is called - in Py_Initialize(), and used in PyInterpreterState_New(). A negative - interpreter ID indicates an error occurred. The main interpreter - will always have an ID of 0. Overflow results in a RuntimeError. - If that becomes a problem later then we can adjust, e.g. by using - a Python int. - - We initialize this to -1 so that the pre-Py_Initialize() value - results in an error. */ -static int64_t _next_interp_id = -1; - void -_PyInterpreterState_Init(void) +_PyInterpreterState_Enable(_PyRuntimeState *runtime) { - _next_interp_id = 0; + runtime->interpreters.next_id = 0; +#ifdef WITH_THREAD + /* Since we only call _PyRuntimeState_Init() once per process + (see _PyRuntime_Initialize()), we make sure the mutex is + initialized here. */ + if (runtime->interpreters.mutex == NULL) { + runtime->interpreters.mutex = PyThread_allocate_lock(); + if (runtime->interpreters.mutex == NULL) + Py_FatalError("Can't initialize threads for interpreter"); + } +#endif } PyInterpreterState * @@ -92,16 +103,16 @@ PyInterpreterState_New(void) PyMem_RawMalloc(sizeof(PyInterpreterState)); if (interp != NULL) { - HEAD_INIT(); -#ifdef WITH_THREAD - if (head_mutex == NULL) - Py_FatalError("Can't initialize threads for interpreter"); -#endif interp->modules_by_index = NULL; interp->sysdict = NULL; interp->builtins = NULL; interp->builtins_copy = NULL; interp->tstate_head = NULL; + interp->check_interval = 100; + interp->warnoptions = NULL; + interp->xoptions = NULL; + interp->num_threads = 0; + interp->pythread_stacksize = 0; interp->codec_search_path = NULL; interp->codec_search_cache = NULL; interp->codec_error_registry = NULL; @@ -125,19 +136,19 @@ PyInterpreterState_New(void) #endif HEAD_LOCK(); - interp->next = interp_head; - if (interp_main == NULL) { - interp_main = interp; + interp->next = _PyRuntime.interpreters.head; + if (_PyRuntime.interpreters.main == NULL) { + _PyRuntime.interpreters.main = interp; } - interp_head = interp; - if (_next_interp_id < 0) { + _PyRuntime.interpreters.head = interp; + if (_PyRuntime.interpreters.next_id < 0) { /* overflow or Py_Initialize() not called! */ PyErr_SetString(PyExc_RuntimeError, "failed to get an interpreter ID"); interp = NULL; } else { - interp->id = _next_interp_id; - _next_interp_id += 1; + interp->id = _PyRuntime.interpreters.next_id; + _PyRuntime.interpreters.next_id += 1; } HEAD_UNLOCK(); } @@ -189,7 +200,7 @@ PyInterpreterState_Delete(PyInterpreterState *interp) PyInterpreterState **p; zapthreads(interp); HEAD_LOCK(); - for (p = &interp_head; ; p = &(*p)->next) { + for (p = &_PyRuntime.interpreters.head; ; p = &(*p)->next) { if (*p == NULL) Py_FatalError( "PyInterpreterState_Delete: invalid interp"); @@ -199,19 +210,13 @@ PyInterpreterState_Delete(PyInterpreterState *interp) if (interp->tstate_head != NULL) Py_FatalError("PyInterpreterState_Delete: remaining threads"); *p = interp->next; - if (interp_main == interp) { - interp_main = NULL; - if (interp_head != NULL) + if (_PyRuntime.interpreters.main == interp) { + _PyRuntime.interpreters.main = NULL; + if (_PyRuntime.interpreters.head != NULL) Py_FatalError("PyInterpreterState_Delete: remaining subinterpreters"); } HEAD_UNLOCK(); PyMem_RawFree(interp); -#ifdef WITH_THREAD - if (interp_head == NULL && head_mutex != NULL) { - PyThread_free_lock(head_mutex); - head_mutex = NULL; - } -#endif } @@ -499,8 +504,11 @@ PyThreadState_Delete(PyThreadState *tstate) if (tstate == GET_TSTATE()) Py_FatalError("PyThreadState_Delete: tstate is still current"); #ifdef WITH_THREAD - if (autoInterpreterState && PyThread_get_key_value(autoTLSkey) == tstate) - PyThread_delete_key_value(autoTLSkey); + if (_PyRuntime.gilstate.autoInterpreterState && + PyThread_get_key_value(_PyRuntime.gilstate.autoTLSkey) == tstate) + { + PyThread_delete_key_value(_PyRuntime.gilstate.autoTLSkey); + } #endif /* WITH_THREAD */ tstate_delete_common(tstate); } @@ -515,8 +523,11 @@ PyThreadState_DeleteCurrent() Py_FatalError( "PyThreadState_DeleteCurrent: no current tstate"); tstate_delete_common(tstate); - if (autoInterpreterState && PyThread_get_key_value(autoTLSkey) == tstate) - PyThread_delete_key_value(autoTLSkey); + if (_PyRuntime.gilstate.autoInterpreterState && + PyThread_get_key_value(_PyRuntime.gilstate.autoTLSkey) == tstate) + { + PyThread_delete_key_value(_PyRuntime.gilstate.autoTLSkey); + } SET_TSTATE(NULL); PyEval_ReleaseLock(); } @@ -676,13 +687,13 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc) PyInterpreterState * PyInterpreterState_Head(void) { - return interp_head; + return _PyRuntime.interpreters.head; } PyInterpreterState * PyInterpreterState_Main(void) { - return interp_main; + return _PyRuntime.interpreters.main; } PyInterpreterState * @@ -722,7 +733,7 @@ _PyThread_CurrentFrames(void) * need to grab head_mutex for the duration. */ HEAD_LOCK(); - for (i = interp_head; i != NULL; i = i->next) { + for (i = _PyRuntime.interpreters.head; i != NULL; i = i->next) { PyThreadState *t; for (t = i->tstate_head; t != NULL; t = t->next) { PyObject *id; @@ -774,11 +785,11 @@ void _PyGILState_Init(PyInterpreterState *i, PyThreadState *t) { assert(i && t); /* must init with valid states */ - autoTLSkey = PyThread_create_key(); - if (autoTLSkey == -1) + _PyRuntime.gilstate.autoTLSkey = PyThread_create_key(); + if (_PyRuntime.gilstate.autoTLSkey == -1) Py_FatalError("Could not allocate TLS entry"); - autoInterpreterState = i; - assert(PyThread_get_key_value(autoTLSkey) == NULL); + _PyRuntime.gilstate.autoInterpreterState = i; + assert(PyThread_get_key_value(_PyRuntime.gilstate.autoTLSkey) == NULL); assert(t->gilstate_counter == 0); _PyGILState_NoteThreadState(t); @@ -787,15 +798,15 @@ _PyGILState_Init(PyInterpreterState *i, PyThreadState *t) PyInterpreterState * _PyGILState_GetInterpreterStateUnsafe(void) { - return autoInterpreterState; + return _PyRuntime.gilstate.autoInterpreterState; } void _PyGILState_Fini(void) { - PyThread_delete_key(autoTLSkey); - autoTLSkey = -1; - autoInterpreterState = NULL; + PyThread_delete_key(_PyRuntime.gilstate.autoTLSkey); + _PyRuntime.gilstate.autoTLSkey = -1; + _PyRuntime.gilstate.autoInterpreterState = NULL; } /* Reset the TLS key - called by PyOS_AfterFork_Child(). @@ -806,17 +817,19 @@ void _PyGILState_Reinit(void) { #ifdef WITH_THREAD - head_mutex = NULL; - HEAD_INIT(); + _PyRuntime.interpreters.mutex = PyThread_allocate_lock(); + if (_PyRuntime.interpreters.mutex == NULL) + Py_FatalError("Can't initialize threads for interpreter"); #endif PyThreadState *tstate = PyGILState_GetThisThreadState(); - PyThread_delete_key(autoTLSkey); - if ((autoTLSkey = PyThread_create_key()) == -1) + PyThread_delete_key(_PyRuntime.gilstate.autoTLSkey); + if ((_PyRuntime.gilstate.autoTLSkey = PyThread_create_key()) == -1) Py_FatalError("Could not allocate TLS entry"); /* If the thread had an associated auto thread state, reassociate it with * the new key. */ - if (tstate && PyThread_set_key_value(autoTLSkey, (void *)tstate) < 0) + if (tstate && PyThread_set_key_value(_PyRuntime.gilstate.autoTLSkey, + (void *)tstate) < 0) Py_FatalError("Couldn't create autoTLSkey mapping"); } @@ -831,7 +844,7 @@ _PyGILState_NoteThreadState(PyThreadState* tstate) /* If autoTLSkey 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 (!autoInterpreterState) + if (!_PyRuntime.gilstate.autoInterpreterState) return; /* Stick the thread state for this thread in thread local storage. @@ -846,9 +859,13 @@ _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(autoTLSkey) == NULL) { - if (PyThread_set_key_value(autoTLSkey, (void *)tstate) < 0) + if (PyThread_get_key_value(_PyRuntime.gilstate.autoTLSkey) == NULL) { + if ((PyThread_set_key_value(_PyRuntime.gilstate.autoTLSkey, + (void *)tstate) + ) < 0) + { Py_FatalError("Couldn't create autoTLSkey mapping"); + } } /* PyGILState_Release must not try to delete this thread state. */ @@ -859,9 +876,10 @@ _PyGILState_NoteThreadState(PyThreadState* tstate) PyThreadState * PyGILState_GetThisThreadState(void) { - if (autoInterpreterState == NULL) + if (_PyRuntime.gilstate.autoInterpreterState == NULL) return NULL; - return (PyThreadState *)PyThread_get_key_value(autoTLSkey); + return (PyThreadState *)PyThread_get_key_value( + _PyRuntime.gilstate.autoTLSkey); } int @@ -872,7 +890,7 @@ PyGILState_Check(void) if (!_PyGILState_check_enabled) return 1; - if (autoTLSkey == -1) + if (_PyRuntime.gilstate.autoTLSkey == -1) return 1; tstate = GET_TSTATE(); @@ -892,8 +910,10 @@ PyGILState_Ensure(void) spells out other issues. Embedders are expected to have called Py_Initialize() and usually PyEval_InitThreads(). */ - assert(autoInterpreterState); /* Py_Initialize() hasn't been called! */ - tcur = (PyThreadState *)PyThread_get_key_value(autoTLSkey); + /* Py_Initialize() hasn't been called! */ + assert(_PyRuntime.gilstate.autoInterpreterState); + tcur = (PyThreadState *)PyThread_get_key_value( + _PyRuntime.gilstate.autoTLSkey); 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 @@ -901,7 +921,7 @@ PyGILState_Ensure(void) PyEval_InitThreads(); /* Create a new thread state for this thread */ - tcur = PyThreadState_New(autoInterpreterState); + tcur = PyThreadState_New(_PyRuntime.gilstate.autoInterpreterState); if (tcur == NULL) Py_FatalError("Couldn't create thread-state for new thread"); /* This is our thread state! We'll need to delete it in the @@ -926,7 +946,7 @@ void PyGILState_Release(PyGILState_STATE oldstate) { PyThreadState *tcur = (PyThreadState *)PyThread_get_key_value( - autoTLSkey); + _PyRuntime.gilstate.autoTLSkey); if (tcur == NULL) Py_FatalError("auto-releasing thread-state, " "but no thread-state for this thread"); |