summaryrefslogtreecommitdiffstats
path: root/Python/pystate.c
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2017-09-06 01:26:16 (GMT)
committerGitHub <noreply@github.com>2017-09-06 01:26:16 (GMT)
commit76d5abc8684bac4f2fc7cccfe2cd940923357351 (patch)
tree4ae6a3bd88bef1266a8d9723c589f925d90bf848 /Python/pystate.c
parent501b324d3a940d26e0021a38aae8d896a30fbcff (diff)
downloadcpython-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.c196
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");