summaryrefslogtreecommitdiffstats
path: root/Python/pystate.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/pystate.c')
-rw-r--r--Python/pystate.c204
1 files changed, 21 insertions, 183 deletions
diff --git a/Python/pystate.c b/Python/pystate.c
index 394b12d..b17efdb 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -565,124 +565,6 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime)
#endif
-//---------------
-// global objects
-//---------------
-
-/* The global objects thread state is meant to be used in a very limited
- way and should not be used to actually run any Python code. */
-
-static PyThreadState *
-bind_global_objects_state(_PyRuntimeState *runtime)
-{
- PyThreadState *main_tstate = &runtime->cached_objects.main_tstate;
-
- bind_tstate(main_tstate);
- /* Unlike _PyThreadState_Bind(), we do not modify gilstate TSS. */
-
- return main_tstate;
-}
-
-static void
-unbind_global_objects_state(_PyRuntimeState *runtime)
-{
- PyThreadState *main_tstate = &runtime->cached_objects.main_tstate;
- assert(tstate_is_alive(main_tstate));
- assert(!main_tstate->_status.active);
- assert(gilstate_tss_get(runtime) != main_tstate);
-
- unbind_tstate(main_tstate);
-
- /* This thread state may be bound/unbound repeatedly,
- so we must erase evidence that it was ever bound (or unbound). */
- main_tstate->_status.bound = 0;
- main_tstate->_status.unbound = 0;
-
- /* We must fully unlink the thread state from any OS thread,
- to allow it to be bound more than once. */
- main_tstate->thread_id = 0;
-#ifdef PY_HAVE_THREAD_NATIVE_ID
- main_tstate->native_thread_id = 0;
-#endif
-}
-
-static inline void
-acquire_global_objects_lock(_PyRuntimeState *runtime)
-{
- /* For now we can rely on the GIL, so we don't actually
- acquire a global lock here. */
- assert(current_fast_get(runtime) != NULL);
-}
-
-static inline void
-release_global_objects_lock(_PyRuntimeState *runtime)
-{
- /* For now we can rely on the GIL, so we don't actually
- release a global lock here. */
- assert(current_fast_get(runtime) != NULL);
-}
-
-PyObject *
-_Py_AddToGlobalDict(PyObject *dict, PyObject *key, PyObject *value)
-{
- assert(dict != NULL);
- assert(PyDict_CheckExact(dict));
-
- /* All global objects are stored in _PyRuntime
- and owned by the main interpreter. */
- _PyRuntimeState *runtime = &_PyRuntime;
- PyThreadState *curts = current_fast_get(runtime);
- PyInterpreterState *interp = curts->interp;
- assert(interp != NULL); // The GIL must be held.
-
- /* Due to interpreter isolation we must hold a global lock,
- starting at this point and ending before we return.
- Note that the operations in this function are very fucused
- and we should not expect any reentrancy. */
- acquire_global_objects_lock(runtime);
-
- /* Swap to the main interpreter, if necessary. */
- PyThreadState *oldts = NULL;
- if (!_Py_IsMainInterpreter(interp)) {
- PyThreadState *main_tstate = bind_global_objects_state(runtime);
-
- oldts = _PyThreadState_Swap(runtime, main_tstate);
- assert(oldts != NULL);
- assert(!_Py_IsMainInterpreter(oldts->interp));
-
- /* The limitations of the global objects thread state apply
- from this point to the point we swap back to oldts. */
- }
-
- /* This might trigger a resize, which is why we must "acquire"
- the global object state. Also note that PyDict_SetDefault()
- must be compatible with our reentrancy and global objects state
- constraints. */
- PyObject *actual = PyDict_SetDefault(dict, key, value);
- if (actual == NULL) {
- /* Raising an exception from one interpreter in another
- is problematic, so we clear it and let the caller deal
- with the returned NULL. */
- assert(PyErr_ExceptionMatches(PyExc_MemoryError));
- PyErr_Clear();
- }
-
- /* Swap back, it it wasn't in the main interpreter already. */
- if (oldts != NULL) {
- // The returned tstate should be _PyRuntime.cached_objects.main_tstate.
- _PyThreadState_Swap(runtime, oldts);
-
- unbind_global_objects_state(runtime);
- }
-
- release_global_objects_lock(runtime);
-
- // XXX Immortalize the key and value.
-
- return actual;
-}
-
-
/*************************************/
/* the per-interpreter runtime state */
/*************************************/
@@ -1335,7 +1217,8 @@ free_threadstate(PyThreadState *tstate)
static void
init_threadstate(PyThreadState *tstate,
- PyInterpreterState *interp, uint64_t id)
+ PyInterpreterState *interp, uint64_t id,
+ PyThreadState *next)
{
if (tstate->_status.initialized) {
Py_FatalError("thread state already initialized");
@@ -1344,13 +1227,18 @@ init_threadstate(PyThreadState *tstate,
assert(interp != NULL);
tstate->interp = interp;
- // next/prev are set in add_threadstate().
- assert(tstate->next == NULL);
- assert(tstate->prev == NULL);
-
assert(id > 0);
tstate->id = id;
+ assert(interp->threads.head == tstate);
+ assert((next != NULL && id != 1) || (next == NULL && id == 1));
+ if (next != NULL) {
+ assert(next->prev == NULL || next->prev == tstate);
+ next->prev = tstate;
+ }
+ tstate->next = next;
+ assert(tstate->prev == NULL);
+
// thread_id and native_thread_id are set in bind_tstate().
tstate->py_recursion_limit = interp->ceval.recursion_limit,
@@ -1371,22 +1259,6 @@ init_threadstate(PyThreadState *tstate,
tstate->_status.initialized = 1;
}
-static void
-add_threadstate(PyInterpreterState *interp, PyThreadState *tstate,
- PyThreadState *next)
-{
- assert(interp->threads.head != tstate);
- assert((next != NULL && tstate->id != 1) ||
- (next == NULL && tstate->id == 1));
- if (next != NULL) {
- assert(next->prev == NULL || next->prev == tstate);
- next->prev = tstate;
- }
- tstate->next = next;
- assert(tstate->prev == NULL);
- interp->threads.head = tstate;
-}
-
static PyThreadState *
new_threadstate(PyInterpreterState *interp)
{
@@ -1426,9 +1298,9 @@ new_threadstate(PyInterpreterState *interp)
&initial._main_interpreter._initial_thread,
sizeof(*tstate));
}
+ interp->threads.head = tstate;
- init_threadstate(tstate, interp, id);
- add_threadstate(interp, tstate, old_head);
+ init_threadstate(tstate, interp, id, old_head);
HEAD_UNLOCK(runtime);
if (!used_newtstate) {
@@ -1476,33 +1348,6 @@ _PyThreadState_Init(PyThreadState *tstate)
}
void
-_PyThreadState_InitDetached(PyThreadState *tstate, PyInterpreterState *interp)
-{
- _PyRuntimeState *runtime = interp->runtime;
-
- HEAD_LOCK(runtime);
- interp->threads.next_unique_id += 1;
- uint64_t id = interp->threads.next_unique_id;
- HEAD_UNLOCK(runtime);
-
- init_threadstate(tstate, interp, id);
- // We do not call add_threadstate().
-}
-
-
-static void
-clear_datastack(PyThreadState *tstate)
-{
- _PyStackChunk *chunk = tstate->datastack_chunk;
- tstate->datastack_chunk = NULL;
- while (chunk != NULL) {
- _PyStackChunk *prev = chunk->previous;
- _PyObject_VirtualFree(chunk, chunk->size);
- chunk = prev;
- }
-}
-
-void
PyThreadState_Clear(PyThreadState *tstate)
{
assert(tstate->_status.initialized && !tstate->_status.cleared);
@@ -1576,6 +1421,7 @@ PyThreadState_Clear(PyThreadState *tstate)
// XXX Do it as early in the function as possible.
}
+
/* Common code for PyThreadState_Delete() and PyThreadState_DeleteCurrent() */
static void
tstate_delete_common(PyThreadState *tstate)
@@ -1608,25 +1454,17 @@ tstate_delete_common(PyThreadState *tstate)
unbind_tstate(tstate);
// XXX Move to PyThreadState_Clear()?
- clear_datastack(tstate);
+ _PyStackChunk *chunk = tstate->datastack_chunk;
+ tstate->datastack_chunk = NULL;
+ while (chunk != NULL) {
+ _PyStackChunk *prev = chunk->previous;
+ _PyObject_VirtualFree(chunk, chunk->size);
+ chunk = prev;
+ }
tstate->_status.finalized = 1;
}
-void
-_PyThreadState_ClearDetached(PyThreadState *tstate)
-{
- assert(!tstate->_status.bound);
- assert(!tstate->_status.bound_gilstate);
- assert(tstate->datastack_chunk == NULL);
- assert(tstate->thread_id == 0);
- assert(tstate->native_thread_id == 0);
- assert(tstate->next == NULL);
- assert(tstate->prev == NULL);
-
- PyThreadState_Clear(tstate);
- clear_datastack(tstate);
-}
static void
zapthreads(PyInterpreterState *interp)