mirror of
https://github.com/python/cpython
synced 2026-11-06 09:02:40 +03:00
Make _PyThreadState_ResumeDetached() waiter-aware and use it from start_the_world(), matching main branch. Remove tstate_resume().
381 lines
13 KiB
C
381 lines
13 KiB
C
#ifndef Py_INTERNAL_PYSTATE_H
|
|
#define Py_INTERNAL_PYSTATE_H
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#ifndef Py_BUILD_CORE
|
|
# error "this header requires Py_BUILD_CORE define"
|
|
#endif
|
|
|
|
#include "pycore_pythonrun.h" // _PyOS_STACK_MARGIN_SHIFT
|
|
#include "pycore_typedefs.h" // _PyRuntimeState
|
|
#include "pycore_tstate.h"
|
|
|
|
|
|
// Values for PyThreadState.state. A thread must be in the "attached" state
|
|
// before calling most Python APIs. If the GIL is enabled, then "attached"
|
|
// implies that the thread holds the GIL and "detached" implies that the
|
|
// thread does not hold the GIL (or is in the process of releasing it). In
|
|
// `--disable-gil` builds, multiple threads may be "attached" to the same
|
|
// interpreter at the same time. Only the "bound" thread may perform the
|
|
// transitions between "attached" and "detached" on its own PyThreadState.
|
|
//
|
|
// The "suspended" states are used to implement stop-the-world pauses in
|
|
// `--disable-gil` builds.
|
|
// They are similar to the "detached" state in that the thread is not allowed
|
|
// to call most Python APIs. A suspended thread trying to attach marks itself
|
|
// as "suspended-waiting". Only the thread responsible for suspending it may
|
|
// resume it, moving it to "detached" or "detached-waiting".
|
|
// A "detached-waiting" thread must attach before it can be suspended again.
|
|
//
|
|
// The "shutting down" state is used when the interpreter is being finalized.
|
|
// Threads in this state can't do anything other than block the OS thread.
|
|
// (See _PyThreadState_HangThread).
|
|
//
|
|
// State transitions:
|
|
// Bound thread: attached <-> detached
|
|
// attached -> suspended
|
|
// suspended -> suspended-waiting
|
|
// detached-waiting -> attached
|
|
// Suspending thread: detached <-> suspended
|
|
// suspended-waiting -> detached-waiting
|
|
#define _Py_THREAD_DETACHED 0
|
|
#define _Py_THREAD_ATTACHED 1
|
|
#define _Py_THREAD_SUSPENDED 2
|
|
#define _Py_THREAD_SHUTTING_DOWN 3
|
|
#define _Py_THREAD_SUSPENDED_WAITING 4
|
|
#define _Py_THREAD_DETACHED_WAITING 5
|
|
|
|
|
|
/* Check if the current thread is the main thread.
|
|
Use _Py_IsMainInterpreter() to check if it's the main interpreter. */
|
|
extern int _Py_IsMainThread(void);
|
|
|
|
// Export for '_testinternalcapi' shared extension
|
|
PyAPI_FUNC(PyInterpreterState*) _PyInterpreterState_Main(void);
|
|
|
|
static inline int
|
|
_Py_IsMainInterpreter(PyInterpreterState *interp)
|
|
{
|
|
return (interp == _PyInterpreterState_Main());
|
|
}
|
|
|
|
extern int _Py_IsMainInterpreterFinalizing(PyInterpreterState *interp);
|
|
|
|
// Export for _interpreters module.
|
|
PyAPI_FUNC(PyObject *) _PyInterpreterState_GetIDObject(PyInterpreterState *);
|
|
|
|
// Export for _interpreters module.
|
|
PyAPI_FUNC(int) _PyInterpreterState_SetRunningMain(PyInterpreterState *);
|
|
PyAPI_FUNC(void) _PyInterpreterState_SetNotRunningMain(PyInterpreterState *);
|
|
PyAPI_FUNC(int) _PyInterpreterState_IsRunningMain(PyInterpreterState *);
|
|
PyAPI_FUNC(void) _PyErr_SetInterpreterAlreadyRunning(void);
|
|
|
|
extern int _PyThreadState_IsRunningMain(PyThreadState *);
|
|
extern void _PyInterpreterState_ReinitRunningMain(PyThreadState *);
|
|
extern const PyConfig* _Py_GetMainConfig(void);
|
|
|
|
|
|
/* Only handle signals on the main thread of the main interpreter. */
|
|
static inline int
|
|
_Py_ThreadCanHandleSignals(PyInterpreterState *interp)
|
|
{
|
|
return (_Py_IsMainThread() && _Py_IsMainInterpreter(interp));
|
|
}
|
|
|
|
|
|
/* Variable and static inline functions for in-line access to current thread
|
|
and interpreter state */
|
|
|
|
#if !defined(Py_BUILD_CORE_MODULE)
|
|
extern _Py_thread_local PyThreadState *_Py_tss_tstate;
|
|
extern _Py_thread_local PyInterpreterState *_Py_tss_interp;
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
extern int _PyThreadState_CheckConsistency(PyThreadState *tstate);
|
|
#endif
|
|
|
|
extern int _PyThreadState_MustExit(PyThreadState *tstate);
|
|
extern void _PyThreadState_HangThread(PyThreadState *tstate);
|
|
|
|
// Export for most shared extensions, used via _PyThreadState_GET() static
|
|
// inline function.
|
|
PyAPI_FUNC(PyThreadState *) _PyThreadState_GetCurrent(void);
|
|
|
|
/* Get the current Python thread state.
|
|
|
|
This function is unsafe: it does not check for error and it can return NULL.
|
|
|
|
The caller must hold the GIL.
|
|
|
|
See also PyThreadState_Get() and PyThreadState_GetUnchecked(). */
|
|
static inline PyThreadState*
|
|
_PyThreadState_GET(void)
|
|
{
|
|
#if !defined(Py_BUILD_CORE_MODULE)
|
|
return _Py_tss_tstate;
|
|
#else
|
|
return _PyThreadState_GetCurrent();
|
|
#endif
|
|
}
|
|
|
|
static inline int
|
|
_PyThreadState_IsAttached(PyThreadState *tstate)
|
|
{
|
|
return (_Py_atomic_load_int_relaxed(&tstate->state) == _Py_THREAD_ATTACHED);
|
|
}
|
|
|
|
// Attaches the current thread to the interpreter.
|
|
//
|
|
// This may block while acquiring the GIL (if the GIL is enabled) or while
|
|
// waiting for a stop-the-world pause (if the GIL is disabled).
|
|
//
|
|
// High-level code should generally call PyEval_RestoreThread() instead, which
|
|
// calls this function.
|
|
extern void _PyThreadState_Attach(PyThreadState *tstate);
|
|
|
|
// Detaches the current thread from the interpreter.
|
|
//
|
|
// High-level code should generally call PyEval_SaveThread() instead, which
|
|
// calls this function.
|
|
extern void _PyThreadState_Detach(PyThreadState *tstate);
|
|
|
|
// Detaches the current thread to the "suspended" state if a stop-the-world
|
|
// pause is in progress.
|
|
//
|
|
// If there is no stop-the-world pause in progress, then the thread switches
|
|
// to the "detached" state.
|
|
extern void _PyThreadState_Suspend(PyThreadState *tstate);
|
|
|
|
#ifdef Py_GIL_DISABLED
|
|
// Try to atomically transition a *different* thread's state from "detached"
|
|
// to "suspended". On success, the target thread cannot attach until
|
|
// _PyThreadState_ResumeDetached() is called, and the caller may safely
|
|
// perform operations that are normally only permitted for the owning thread
|
|
// (such as merging the biased reference counts of objects it owns).
|
|
//
|
|
// The caller must not run arbitrary Python code, allocate GC objects, or
|
|
// stop the world while holding the thread in the suspended state.
|
|
// Returns 1 on success, 0 if the thread was not in the "detached" state.
|
|
extern int _PyThreadState_TrySuspendDetached(PyThreadState *tstate);
|
|
|
|
// Resume a thread suspended by _PyThreadState_TrySuspendDetached() or a
|
|
// stop-the-world pause: switch it back to "detached" or "detached-waiting"
|
|
// and wake it if it is waiting to attach.
|
|
extern void _PyThreadState_ResumeDetached(PyThreadState *tstate);
|
|
#endif
|
|
|
|
// Mark the thread state as "shutting down". This is used during interpreter
|
|
// and runtime finalization. The thread may no longer attach to the
|
|
// interpreter and will instead block via _PyThreadState_HangThread().
|
|
extern void _PyThreadState_SetShuttingDown(PyThreadState *tstate);
|
|
|
|
// Perform a stop-the-world pause for all threads in the all interpreters.
|
|
//
|
|
// Threads in the "attached" state are paused and transitioned to the "GC"
|
|
// state. Threads in the "detached" state switch to the "GC" state, preventing
|
|
// them from reattaching until the stop-the-world pause is complete.
|
|
//
|
|
// NOTE: This is a no-op outside of Py_GIL_DISABLED builds.
|
|
extern void _PyEval_StopTheWorldAll(_PyRuntimeState *runtime);
|
|
extern void _PyEval_StartTheWorldAll(_PyRuntimeState *runtime);
|
|
|
|
// Perform a stop-the-world pause for threads in the specified interpreter.
|
|
//
|
|
// NOTE: This is a no-op outside of Py_GIL_DISABLED builds.
|
|
extern PyAPI_FUNC(void) _PyEval_StopTheWorld(PyInterpreterState *interp);
|
|
extern PyAPI_FUNC(void) _PyEval_StartTheWorld(PyInterpreterState *interp);
|
|
|
|
|
|
static inline void
|
|
_Py_EnsureFuncTstateNotNULL(const char *func, PyThreadState *tstate)
|
|
{
|
|
if (tstate == NULL) {
|
|
#ifndef Py_GIL_DISABLED
|
|
_Py_FatalErrorFunc(func,
|
|
"the function must be called with the GIL held, "
|
|
"after Python initialization and before Python finalization, "
|
|
"but the GIL is released (the current Python thread state is NULL)");
|
|
#else
|
|
_Py_FatalErrorFunc(func,
|
|
"the function must be called with an active thread state, "
|
|
"after Python initialization and before Python finalization, "
|
|
"but it was called without an active thread state. "
|
|
"Are you trying to call the C API inside of a Py_BEGIN_ALLOW_THREADS block?");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// Call Py_FatalError() if tstate is NULL
|
|
#define _Py_EnsureTstateNotNULL(tstate) \
|
|
_Py_EnsureFuncTstateNotNULL(__func__, (tstate))
|
|
|
|
|
|
/* Get the current interpreter state.
|
|
|
|
The function is unsafe: it does not check for error and it can return NULL.
|
|
|
|
The caller must hold the GIL.
|
|
|
|
See also PyInterpreterState_Get()
|
|
and _PyGILState_GetInterpreterStateUnsafe(). */
|
|
static inline PyInterpreterState* _PyInterpreterState_GET(void) {
|
|
#ifdef Py_DEBUG
|
|
PyThreadState *tstate = _PyThreadState_GET();
|
|
_Py_EnsureTstateNotNULL(tstate);
|
|
#endif
|
|
#if !defined(Py_BUILD_CORE_MODULE)
|
|
return _Py_tss_interp;
|
|
#else
|
|
return _PyThreadState_GET()->interp;
|
|
#endif
|
|
}
|
|
|
|
|
|
// PyThreadState functions
|
|
|
|
// Export for _testinternalcapi
|
|
PyAPI_FUNC(PyThreadState *) _PyThreadState_New(
|
|
PyInterpreterState *interp,
|
|
int whence);
|
|
extern void _PyThreadState_Bind(PyThreadState *tstate);
|
|
PyAPI_FUNC(PyThreadState *) _PyThreadState_NewBound(
|
|
PyInterpreterState *interp,
|
|
int whence);
|
|
extern PyThreadState * _PyThreadState_RemoveExcept(PyThreadState *tstate);
|
|
extern void _PyThreadState_DeleteList(PyThreadState *list, int is_after_fork);
|
|
extern void _PyThreadState_ClearMimallocHeaps(PyThreadState *tstate);
|
|
|
|
// Export for '_testinternalcapi' shared extension
|
|
PyAPI_FUNC(PyObject*) _PyThreadState_GetDict(PyThreadState *tstate);
|
|
|
|
/* The implementation of sys._current_exceptions() Returns a dict mapping
|
|
thread id to that thread's current exception.
|
|
*/
|
|
extern PyObject* _PyThread_CurrentExceptions(void);
|
|
|
|
|
|
/* Other */
|
|
|
|
extern PyThreadState * _PyThreadState_Swap(
|
|
_PyRuntimeState *runtime,
|
|
PyThreadState *newts);
|
|
|
|
extern PyStatus _PyInterpreterState_Enable(_PyRuntimeState *runtime);
|
|
|
|
#ifdef HAVE_FORK
|
|
extern PyStatus _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime);
|
|
extern void _PySignal_AfterFork(void);
|
|
#endif
|
|
|
|
// Export for the stable ABI
|
|
PyAPI_FUNC(int) _PyState_AddModule(
|
|
PyThreadState *tstate,
|
|
PyObject* module,
|
|
PyModuleDef* def);
|
|
|
|
|
|
extern int _PyOS_InterruptOccurred(PyThreadState *tstate);
|
|
|
|
#define HEAD_LOCK(runtime) \
|
|
PyMutex_LockFlags(&(runtime)->interpreters.mutex, _Py_LOCK_DONT_DETACH)
|
|
#define HEAD_UNLOCK(runtime) \
|
|
PyMutex_Unlock(&(runtime)->interpreters.mutex)
|
|
#define ASSERT_HEAD_IS_LOCKED(runtime) \
|
|
assert(PyMutex_IsLocked(&(runtime)->interpreters.mutex))
|
|
|
|
#define _Py_FOR_EACH_TSTATE_UNLOCKED(interp, t) \
|
|
for (PyThreadState *t = interp->threads.head; t; t = t->next)
|
|
#define _Py_FOR_EACH_TSTATE_BEGIN(interp, t) \
|
|
HEAD_LOCK(interp->runtime); \
|
|
_Py_FOR_EACH_TSTATE_UNLOCKED(interp, t)
|
|
#define _Py_FOR_EACH_TSTATE_END(interp) \
|
|
HEAD_UNLOCK(interp->runtime)
|
|
|
|
|
|
// Get the configuration of the current interpreter.
|
|
// The caller must hold the GIL.
|
|
// Export for test_peg_generator.
|
|
PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void);
|
|
|
|
// Get the single PyInterpreterState used by this process' GILState
|
|
// implementation.
|
|
//
|
|
// This function doesn't check for error. Return NULL before _PyGILState_Init()
|
|
// is called and after _PyGILState_Fini() is called.
|
|
//
|
|
// See also PyInterpreterState_Get() and _PyInterpreterState_GET().
|
|
extern PyInterpreterState* _PyGILState_GetInterpreterStateUnsafe(void);
|
|
|
|
extern PyObject * _Py_GetMainModule(PyThreadState *);
|
|
extern int _Py_CheckMainModule(PyObject *module);
|
|
|
|
#ifndef NDEBUG
|
|
/* Modern equivalent of assert(PyGILState_Check()) */
|
|
static inline void
|
|
_Py_AssertHoldsTstateFunc(const char *func)
|
|
{
|
|
PyThreadState *tstate = _PyThreadState_GET();
|
|
_Py_EnsureFuncTstateNotNULL(func, tstate);
|
|
}
|
|
#define _Py_AssertHoldsTstate() _Py_AssertHoldsTstateFunc(__func__)
|
|
#else
|
|
#define _Py_AssertHoldsTstate()
|
|
#endif
|
|
|
|
#if !_Py__has_builtin(__builtin_frame_address) && !defined(__GNUC__) && !defined(_MSC_VER)
|
|
static uintptr_t return_pointer_as_int(char* p) {
|
|
return (uintptr_t)p;
|
|
}
|
|
#endif
|
|
|
|
static inline uintptr_t
|
|
_Py_get_machine_stack_pointer(void) {
|
|
#if _Py__has_builtin(__builtin_frame_address) || defined(__GNUC__)
|
|
return (uintptr_t)__builtin_frame_address(0);
|
|
#elif defined(_MSC_VER)
|
|
return (uintptr_t)_AddressOfReturnAddress();
|
|
#else
|
|
char here;
|
|
/* Avoid compiler warning about returning stack address */
|
|
return return_pointer_as_int(&here);
|
|
#endif
|
|
}
|
|
|
|
static inline intptr_t
|
|
_Py_RecursionLimit_GetMargin(PyThreadState *tstate)
|
|
{
|
|
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
|
|
assert(_tstate->c_stack_hard_limit != 0);
|
|
intptr_t here_addr = _Py_get_machine_stack_pointer();
|
|
#if _Py_STACK_GROWS_DOWN
|
|
return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, here_addr - (intptr_t)_tstate->c_stack_soft_limit, _PyOS_STACK_MARGIN_SHIFT);
|
|
#else
|
|
return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, (intptr_t)_tstate->c_stack_soft_limit - here_addr, _PyOS_STACK_MARGIN_SHIFT);
|
|
#endif
|
|
}
|
|
|
|
/* PEP 788 structures. */
|
|
|
|
struct PyInterpreterGuard {
|
|
PyInterpreterState *interp;
|
|
};
|
|
|
|
struct PyInterpreterView {
|
|
int64_t id;
|
|
};
|
|
|
|
// Exports for '_testinternalcapi' shared extension
|
|
PyAPI_FUNC(Py_ssize_t) _PyInterpreterState_GuardCountdown(PyInterpreterState *interp);
|
|
PyAPI_FUNC(PyInterpreterState *) _PyInterpreterGuard_GetInterpreter(PyInterpreterGuard *guard);
|
|
|
|
extern int _PyInterpreterGuard_TryAcquire(PyInterpreterState *interp,
|
|
PyInterpreterGuard *guard);
|
|
extern void _PyInterpreterGuard_Release(PyInterpreterGuard *guard);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#endif /* !Py_INTERNAL_PYSTATE_H */
|