diff options
Diffstat (limited to 'Python/pystate.c')
-rw-r--r-- | Python/pystate.c | 152 |
1 files changed, 110 insertions, 42 deletions
diff --git a/Python/pystate.c b/Python/pystate.c index 772aa53168..2ac2fd5274 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -6,11 +6,11 @@ /* -------------------------------------------------------------------------- CAUTION -Always use malloc() and free() directly in this file. A number of these -functions are advertised as safe to call when the GIL isn't held, and in -a debug build Python redirects (e.g.) PyMem_NEW (etc) to Python's debugging -obmalloc functions. Those aren't thread-safe (they rely on the GIL to avoid -the expense of doing their own locking). +Always use PyMem_RawMalloc() and PyMem_RawFree() directly in this file. A +number of these functions are advertised as safe to call when the GIL isn't +held, and in a debug build Python redirects (e.g.) PyMem_NEW (etc) to Python's +debugging obmalloc functions. Those aren't thread-safe (they rely on the GIL +to avoid the expense of doing their own locking). -------------------------------------------------------------------------- */ #ifdef HAVE_DLOPEN @@ -60,7 +60,7 @@ PyInterpreterState * PyInterpreterState_New(void) { PyInterpreterState *interp = (PyInterpreterState *) - malloc(sizeof(PyInterpreterState)); + PyMem_RawMalloc(sizeof(PyInterpreterState)); if (interp != NULL) { HEAD_INIT(); @@ -72,6 +72,7 @@ PyInterpreterState_New(void) interp->modules_by_index = NULL; interp->sysdict = NULL; interp->builtins = NULL; + interp->builtins_copy = NULL; interp->tstate_head = NULL; interp->codec_search_path = NULL; interp->codec_search_cache = NULL; @@ -115,6 +116,7 @@ PyInterpreterState_Clear(PyInterpreterState *interp) Py_CLEAR(interp->modules_by_index); Py_CLEAR(interp->sysdict); Py_CLEAR(interp->builtins); + Py_CLEAR(interp->builtins_copy); Py_CLEAR(interp->importlib); } @@ -148,7 +150,7 @@ PyInterpreterState_Delete(PyInterpreterState *interp) Py_FatalError("PyInterpreterState_Delete: remaining threads"); *p = interp->next; HEAD_UNLOCK(); - free(interp); + PyMem_RawFree(interp); #ifdef WITH_THREAD if (interp_head == NULL && head_mutex != NULL) { PyThread_free_lock(head_mutex); @@ -168,7 +170,7 @@ threadstate_getframe(PyThreadState *self) static PyThreadState * new_threadstate(PyInterpreterState *interp, int init) { - PyThreadState *tstate = (PyThreadState *)malloc(sizeof(PyThreadState)); + PyThreadState *tstate = (PyThreadState *)PyMem_RawMalloc(sizeof(PyThreadState)); if (_PyThreadState_GetFrame == NULL) _PyThreadState_GetFrame = threadstate_getframe; @@ -182,7 +184,6 @@ new_threadstate(PyInterpreterState *interp, int init) tstate->recursion_critical = 0; tstate->tracing = 0; tstate->use_tracing = 0; - tstate->tick_counter = 0; tstate->gilstate_counter = 0; tstate->async_exc = NULL; #ifdef WITH_THREAD @@ -208,12 +209,17 @@ new_threadstate(PyInterpreterState *interp, int init) tstate->trash_delete_nesting = 0; tstate->trash_delete_later = NULL; + tstate->on_delete = NULL; + tstate->on_delete_data = NULL; if (init) _PyThreadState_Init(tstate); HEAD_LOCK(); + tstate->prev = NULL; tstate->next = interp->tstate_head; + if (tstate->next) + tstate->next->prev = tstate; interp->tstate_head = tstate; HEAD_UNLOCK(); } @@ -317,6 +323,31 @@ PyState_RemoveModule(struct PyModuleDef* def) return PyList_SetItem(state->modules_by_index, index, Py_None); } +/* used by import.c:PyImport_Cleanup */ +void +_PyState_ClearModules(void) +{ + PyInterpreterState *state = PyThreadState_GET()->interp; + if (state->modules_by_index) { + Py_ssize_t i; + for (i = 0; i < PyList_GET_SIZE(state->modules_by_index); i++) { + PyObject *m = PyList_GET_ITEM(state->modules_by_index, i); + if (PyModule_Check(m)) { + /* cleanup the saved copy of module dicts */ + PyModuleDef *md = PyModule_GetDef(m); + if (md) + Py_CLEAR(md->m_base.m_copy); + } + } + /* Setting modules_by_index to NULL could be dangerous, so we + clear the list instead. */ + if (PyList_SetSlice(state->modules_by_index, + 0, PyList_GET_SIZE(state->modules_by_index), + NULL)) + PyErr_WriteUnraisable(state->modules_by_index); + } +} + void PyThreadState_Clear(PyThreadState *tstate) { @@ -349,37 +380,23 @@ static void tstate_delete_common(PyThreadState *tstate) { PyInterpreterState *interp; - PyThreadState **p; - PyThreadState *prev_p = NULL; if (tstate == NULL) Py_FatalError("PyThreadState_Delete: NULL tstate"); interp = tstate->interp; if (interp == NULL) Py_FatalError("PyThreadState_Delete: NULL interp"); HEAD_LOCK(); - for (p = &interp->tstate_head; ; p = &(*p)->next) { - if (*p == NULL) - Py_FatalError( - "PyThreadState_Delete: invalid tstate"); - if (*p == tstate) - break; - /* Sanity check. These states should never happen but if - * 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 thread.c find_key(). */ - if (*p == prev_p) - Py_FatalError( - "PyThreadState_Delete: small circular list(!)" - " and tstate not found."); - prev_p = *p; - if ((*p)->next == interp->tstate_head) - Py_FatalError( - "PyThreadState_Delete: circular list(!) and" - " tstate not found."); - } - *p = tstate->next; + if (tstate->prev) + tstate->prev->next = tstate->next; + else + interp->tstate_head = tstate->next; + if (tstate->next) + tstate->next->prev = tstate->prev; HEAD_UNLOCK(); - free(tstate); + if (tstate->on_delete != NULL) { + tstate->on_delete(tstate->on_delete_data); + } + PyMem_RawFree(tstate); } @@ -414,6 +431,43 @@ PyThreadState_DeleteCurrent() #endif /* WITH_THREAD */ +/* + * Delete all thread states except the one passed as argument. + * Note that, if there is a current thread state, it *must* be the one + * passed as argument. Also, this won't touch any other interpreters + * than the current one, since we don't know which thread state should + * be kept in those other interpreteres. + */ +void +_PyThreadState_DeleteExcept(PyThreadState *tstate) +{ + PyInterpreterState *interp = tstate->interp; + PyThreadState *p, *next, *garbage; + HEAD_LOCK(); + /* Remove all thread states, except tstate, from the linked list of + thread states. This will allow calling PyThreadState_Clear() + without holding the lock. */ + garbage = interp->tstate_head; + if (garbage == tstate) + garbage = tstate->next; + if (tstate->prev) + tstate->prev->next = tstate->next; + if (tstate->next) + tstate->next->prev = tstate->prev; + tstate->prev = tstate->next = NULL; + interp->tstate_head = tstate; + HEAD_UNLOCK(); + /* Clear and deallocate all stale thread states. Even if this + executes Python code, we should be safe since it executes + in the current thread, not one of the stale threads. */ + for (p = garbage; p; p = next) { + next = p->next; + PyThreadState_Clear(p); + PyMem_RawFree(p); + } +} + + PyThreadState * PyThreadState_Get(void) { @@ -671,18 +725,18 @@ _PyGILState_NoteThreadState(PyThreadState* tstate) The only situation where you can legitimately have more than one thread state for an OS level thread is when there are multiple - interpreters, when: + interpreters. - a) You shouldn't really be using the PyGILState_ APIs anyway, - and: + You shouldn't really be using the PyGILState_ APIs anyway (see issues + #10915 and #15751). - b) The slightly odd way PyThread_set_key_value works (see - comments by its implementation) means that the first thread - state created for that given OS level thread will "win", - which seems reasonable behaviour. + The first thread state created for that given OS level thread will + "win", which seems reasonable behaviour. */ - if (PyThread_set_key_value(autoTLSkey, (void *)tstate) < 0) - Py_FatalError("Couldn't create autoTLSkey mapping"); + if (PyThread_get_key_value(autoTLSkey) == NULL) { + if (PyThread_set_key_value(autoTLSkey, (void *)tstate) < 0) + Py_FatalError("Couldn't create autoTLSkey mapping"); + } /* PyGILState_Release must not try to delete this thread state. */ tstate->gilstate_counter = 1; @@ -697,6 +751,15 @@ PyGILState_GetThisThreadState(void) return (PyThreadState *)PyThread_get_key_value(autoTLSkey); } +int +PyGILState_Check(void) +{ + /* can't use PyThreadState_Get() since it will assert that it has the GIL */ + PyThreadState *tstate = (PyThreadState*)_Py_atomic_load_relaxed( + &_PyThreadState_Current); + return tstate && (tstate == PyGILState_GetThisThreadState()); +} + PyGILState_STATE PyGILState_Ensure(void) { @@ -710,6 +773,11 @@ PyGILState_Ensure(void) assert(autoInterpreterState); /* Py_Initialize() hasn't been called! */ tcur = (PyThreadState *)PyThread_get_key_value(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 + GIL. */ + PyEval_InitThreads(); + /* Create a new thread state for this thread */ tcur = PyThreadState_New(autoInterpreterState); if (tcur == NULL) |