mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
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).
This commit is contained in:
parent
501b324d3a
commit
76d5abc868
40 changed files with 2727 additions and 1327 deletions
|
@ -8,13 +8,6 @@ PyDoc_STRVAR(warnings__doc__,
|
|||
MODULE_NAME " provides basic warning filtering support.\n"
|
||||
"It is a helper module to speed up interpreter start-up.");
|
||||
|
||||
/* Both 'filters' and 'onceregistry' can be set in warnings.py;
|
||||
get_warnings_attr() will reset these variables accordingly. */
|
||||
static PyObject *_filters; /* List */
|
||||
static PyObject *_once_registry; /* Dict */
|
||||
static PyObject *_default_action; /* String */
|
||||
static long _filters_version;
|
||||
|
||||
_Py_IDENTIFIER(argv);
|
||||
_Py_IDENTIFIER(stderr);
|
||||
|
||||
|
@ -53,7 +46,7 @@ get_warnings_attr(const char *attr, int try_import)
|
|||
}
|
||||
|
||||
/* don't try to import after the start of the Python finallization */
|
||||
if (try_import && _Py_Finalizing == NULL) {
|
||||
if (try_import && !_Py_IS_FINALIZING()) {
|
||||
warnings_module = PyImport_Import(warnings_str);
|
||||
if (warnings_module == NULL) {
|
||||
/* Fallback to the C implementation if we cannot get
|
||||
|
@ -90,10 +83,10 @@ get_once_registry(void)
|
|||
if (registry == NULL) {
|
||||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
return _once_registry;
|
||||
return _PyRuntime.warnings.once_registry;
|
||||
}
|
||||
Py_DECREF(_once_registry);
|
||||
_once_registry = registry;
|
||||
Py_DECREF(_PyRuntime.warnings.once_registry);
|
||||
_PyRuntime.warnings.once_registry = registry;
|
||||
return registry;
|
||||
}
|
||||
|
||||
|
@ -108,11 +101,11 @@ get_default_action(void)
|
|||
if (PyErr_Occurred()) {
|
||||
return NULL;
|
||||
}
|
||||
return _default_action;
|
||||
return _PyRuntime.warnings.default_action;
|
||||
}
|
||||
|
||||
Py_DECREF(_default_action);
|
||||
_default_action = default_action;
|
||||
Py_DECREF(_PyRuntime.warnings.default_action);
|
||||
_PyRuntime.warnings.default_action = default_action;
|
||||
return default_action;
|
||||
}
|
||||
|
||||
|
@ -132,23 +125,24 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno,
|
|||
return NULL;
|
||||
}
|
||||
else {
|
||||
Py_DECREF(_filters);
|
||||
_filters = warnings_filters;
|
||||
Py_DECREF(_PyRuntime.warnings.filters);
|
||||
_PyRuntime.warnings.filters = warnings_filters;
|
||||
}
|
||||
|
||||
if (_filters == NULL || !PyList_Check(_filters)) {
|
||||
PyObject *filters = _PyRuntime.warnings.filters;
|
||||
if (filters == NULL || !PyList_Check(filters)) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
MODULE_NAME ".filters must be a list");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* _filters could change while we are iterating over it. */
|
||||
for (i = 0; i < PyList_GET_SIZE(_filters); i++) {
|
||||
/* _PyRuntime.warnings.filters could change while we are iterating over it. */
|
||||
for (i = 0; i < PyList_GET_SIZE(filters); i++) {
|
||||
PyObject *tmp_item, *action, *msg, *cat, *mod, *ln_obj;
|
||||
Py_ssize_t ln;
|
||||
int is_subclass, good_msg, good_mod;
|
||||
|
||||
tmp_item = PyList_GET_ITEM(_filters, i);
|
||||
tmp_item = PyList_GET_ITEM(filters, i);
|
||||
if (!PyTuple_Check(tmp_item) || PyTuple_GET_SIZE(tmp_item) != 5) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
MODULE_NAME ".filters item %zd isn't a 5-tuple", i);
|
||||
|
@ -220,9 +214,9 @@ already_warned(PyObject *registry, PyObject *key, int should_set)
|
|||
version_obj = _PyDict_GetItemId(registry, &PyId_version);
|
||||
if (version_obj == NULL
|
||||
|| !PyLong_CheckExact(version_obj)
|
||||
|| PyLong_AsLong(version_obj) != _filters_version) {
|
||||
|| PyLong_AsLong(version_obj) != _PyRuntime.warnings.filters_version) {
|
||||
PyDict_Clear(registry);
|
||||
version_obj = PyLong_FromLong(_filters_version);
|
||||
version_obj = PyLong_FromLong(_PyRuntime.warnings.filters_version);
|
||||
if (version_obj == NULL)
|
||||
return -1;
|
||||
if (_PyDict_SetItemId(registry, &PyId_version, version_obj) < 0) {
|
||||
|
@ -520,7 +514,7 @@ warn_explicit(PyObject *category, PyObject *message,
|
|||
if (registry == NULL)
|
||||
goto cleanup;
|
||||
}
|
||||
/* _once_registry[(text, category)] = 1 */
|
||||
/* _PyRuntime.warnings.once_registry[(text, category)] = 1 */
|
||||
rc = update_registry(registry, text, category, 0);
|
||||
}
|
||||
else if (_PyUnicode_EqualToASCIIString(action, "module")) {
|
||||
|
@ -910,7 +904,7 @@ warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds)
|
|||
static PyObject *
|
||||
warnings_filters_mutated(PyObject *self, PyObject *args)
|
||||
{
|
||||
_filters_version++;
|
||||
_PyRuntime.warnings.filters_version++;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
@ -1160,7 +1154,8 @@ create_filter(PyObject *category, const char *action)
|
|||
}
|
||||
|
||||
/* This assumes the line number is zero for now. */
|
||||
return PyTuple_Pack(5, action_obj, Py_None, category, Py_None, _PyLong_Zero);
|
||||
return PyTuple_Pack(5, action_obj, Py_None,
|
||||
category, Py_None, _PyLong_Zero);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -1228,33 +1223,35 @@ _PyWarnings_Init(void)
|
|||
if (m == NULL)
|
||||
return NULL;
|
||||
|
||||
if (_filters == NULL) {
|
||||
_filters = init_filters();
|
||||
if (_filters == NULL)
|
||||
if (_PyRuntime.warnings.filters == NULL) {
|
||||
_PyRuntime.warnings.filters = init_filters();
|
||||
if (_PyRuntime.warnings.filters == NULL)
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(_filters);
|
||||
if (PyModule_AddObject(m, "filters", _filters) < 0)
|
||||
Py_INCREF(_PyRuntime.warnings.filters);
|
||||
if (PyModule_AddObject(m, "filters", _PyRuntime.warnings.filters) < 0)
|
||||
return NULL;
|
||||
|
||||
if (_once_registry == NULL) {
|
||||
_once_registry = PyDict_New();
|
||||
if (_once_registry == NULL)
|
||||
if (_PyRuntime.warnings.once_registry == NULL) {
|
||||
_PyRuntime.warnings.once_registry = PyDict_New();
|
||||
if (_PyRuntime.warnings.once_registry == NULL)
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(_once_registry);
|
||||
if (PyModule_AddObject(m, "_onceregistry", _once_registry) < 0)
|
||||
Py_INCREF(_PyRuntime.warnings.once_registry);
|
||||
if (PyModule_AddObject(m, "_onceregistry",
|
||||
_PyRuntime.warnings.once_registry) < 0)
|
||||
return NULL;
|
||||
|
||||
if (_default_action == NULL) {
|
||||
_default_action = PyUnicode_FromString("default");
|
||||
if (_default_action == NULL)
|
||||
if (_PyRuntime.warnings.default_action == NULL) {
|
||||
_PyRuntime.warnings.default_action = PyUnicode_FromString("default");
|
||||
if (_PyRuntime.warnings.default_action == NULL)
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(_default_action);
|
||||
if (PyModule_AddObject(m, "_defaultaction", _default_action) < 0)
|
||||
Py_INCREF(_PyRuntime.warnings.default_action);
|
||||
if (PyModule_AddObject(m, "_defaultaction",
|
||||
_PyRuntime.warnings.default_action) < 0)
|
||||
return NULL;
|
||||
|
||||
_filters_version = 0;
|
||||
_PyRuntime.warnings.filters_version = 0;
|
||||
return m;
|
||||
}
|
||||
|
|
190
Python/ceval.c
190
Python/ceval.c
|
@ -36,7 +36,8 @@ extern int _PyObject_GetMethod(PyObject *, PyObject *, PyObject **);
|
|||
typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *);
|
||||
|
||||
/* Forward declarations */
|
||||
Py_LOCAL_INLINE(PyObject *) call_function(PyObject ***, Py_ssize_t, PyObject *);
|
||||
Py_LOCAL_INLINE(PyObject *) call_function(PyObject ***, Py_ssize_t,
|
||||
PyObject *);
|
||||
static PyObject * do_call_core(PyObject *, PyObject *, PyObject *);
|
||||
|
||||
#ifdef LLTRACE
|
||||
|
@ -52,13 +53,15 @@ static int call_trace_protected(Py_tracefunc, PyObject *,
|
|||
static void call_exc_trace(Py_tracefunc, PyObject *,
|
||||
PyThreadState *, PyFrameObject *);
|
||||
static int maybe_call_line_trace(Py_tracefunc, PyObject *,
|
||||
PyThreadState *, PyFrameObject *, int *, int *, int *);
|
||||
PyThreadState *, PyFrameObject *,
|
||||
int *, int *, int *);
|
||||
static void maybe_dtrace_line(PyFrameObject *, int *, int *, int *);
|
||||
static void dtrace_function_entry(PyFrameObject *);
|
||||
static void dtrace_function_return(PyFrameObject *);
|
||||
|
||||
static PyObject * cmp_outcome(int, PyObject *, PyObject *);
|
||||
static PyObject * import_name(PyFrameObject *, PyObject *, PyObject *, PyObject *);
|
||||
static PyObject * import_name(PyFrameObject *, PyObject *, PyObject *,
|
||||
PyObject *);
|
||||
static PyObject * import_from(PyObject *, PyObject *);
|
||||
static int import_all_from(PyObject *, PyObject *);
|
||||
static void format_exc_check_arg(PyObject *, const char *, PyObject *);
|
||||
|
@ -88,7 +91,7 @@ static long dxp[256];
|
|||
#endif
|
||||
|
||||
#ifdef WITH_THREAD
|
||||
#define GIL_REQUEST _Py_atomic_load_relaxed(&gil_drop_request)
|
||||
#define GIL_REQUEST _Py_atomic_load_relaxed(&_PyRuntime.ceval.gil_drop_request)
|
||||
#else
|
||||
#define GIL_REQUEST 0
|
||||
#endif
|
||||
|
@ -98,22 +101,22 @@ static long dxp[256];
|
|||
the GIL eventually anyway. */
|
||||
#define COMPUTE_EVAL_BREAKER() \
|
||||
_Py_atomic_store_relaxed( \
|
||||
&eval_breaker, \
|
||||
&_PyRuntime.ceval.eval_breaker, \
|
||||
GIL_REQUEST | \
|
||||
_Py_atomic_load_relaxed(&pendingcalls_to_do) | \
|
||||
pending_async_exc)
|
||||
_Py_atomic_load_relaxed(&_PyRuntime.ceval.pending.calls_to_do) | \
|
||||
_PyRuntime.ceval.pending.async_exc)
|
||||
|
||||
#ifdef WITH_THREAD
|
||||
|
||||
#define SET_GIL_DROP_REQUEST() \
|
||||
do { \
|
||||
_Py_atomic_store_relaxed(&gil_drop_request, 1); \
|
||||
_Py_atomic_store_relaxed(&eval_breaker, 1); \
|
||||
_Py_atomic_store_relaxed(&_PyRuntime.ceval.gil_drop_request, 1); \
|
||||
_Py_atomic_store_relaxed(&_PyRuntime.ceval.eval_breaker, 1); \
|
||||
} while (0)
|
||||
|
||||
#define RESET_GIL_DROP_REQUEST() \
|
||||
do { \
|
||||
_Py_atomic_store_relaxed(&gil_drop_request, 0); \
|
||||
_Py_atomic_store_relaxed(&_PyRuntime.ceval.gil_drop_request, 0); \
|
||||
COMPUTE_EVAL_BREAKER(); \
|
||||
} while (0)
|
||||
|
||||
|
@ -122,47 +125,35 @@ static long dxp[256];
|
|||
/* Pending calls are only modified under pending_lock */
|
||||
#define SIGNAL_PENDING_CALLS() \
|
||||
do { \
|
||||
_Py_atomic_store_relaxed(&pendingcalls_to_do, 1); \
|
||||
_Py_atomic_store_relaxed(&eval_breaker, 1); \
|
||||
_Py_atomic_store_relaxed(&_PyRuntime.ceval.pending.calls_to_do, 1); \
|
||||
_Py_atomic_store_relaxed(&_PyRuntime.ceval.eval_breaker, 1); \
|
||||
} while (0)
|
||||
|
||||
#define UNSIGNAL_PENDING_CALLS() \
|
||||
do { \
|
||||
_Py_atomic_store_relaxed(&pendingcalls_to_do, 0); \
|
||||
_Py_atomic_store_relaxed(&_PyRuntime.ceval.pending.calls_to_do, 0); \
|
||||
COMPUTE_EVAL_BREAKER(); \
|
||||
} while (0)
|
||||
|
||||
#define SIGNAL_ASYNC_EXC() \
|
||||
do { \
|
||||
pending_async_exc = 1; \
|
||||
_Py_atomic_store_relaxed(&eval_breaker, 1); \
|
||||
_PyRuntime.ceval.pending.async_exc = 1; \
|
||||
_Py_atomic_store_relaxed(&_PyRuntime.ceval.eval_breaker, 1); \
|
||||
} while (0)
|
||||
|
||||
#define UNSIGNAL_ASYNC_EXC() \
|
||||
do { pending_async_exc = 0; COMPUTE_EVAL_BREAKER(); } while (0)
|
||||
do { \
|
||||
_PyRuntime.ceval.pending.async_exc = 0; \
|
||||
COMPUTE_EVAL_BREAKER(); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* This single variable consolidates all requests to break out of the fast path
|
||||
in the eval loop. */
|
||||
static _Py_atomic_int eval_breaker = {0};
|
||||
/* Request for running pending calls. */
|
||||
static _Py_atomic_int pendingcalls_to_do = {0};
|
||||
/* Request for looking at the `async_exc` field of the current thread state.
|
||||
Guarded by the GIL. */
|
||||
static int pending_async_exc = 0;
|
||||
|
||||
#ifdef WITH_THREAD
|
||||
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include "pythread.h"
|
||||
|
||||
static PyThread_type_lock pending_lock = 0; /* for pending calls */
|
||||
static unsigned long main_thread = 0;
|
||||
/* Request for dropping the GIL */
|
||||
static _Py_atomic_int gil_drop_request = {0};
|
||||
|
||||
#include "ceval_gil.h"
|
||||
|
||||
int
|
||||
|
@ -178,9 +169,9 @@ PyEval_InitThreads(void)
|
|||
return;
|
||||
create_gil();
|
||||
take_gil(PyThreadState_GET());
|
||||
main_thread = PyThread_get_thread_ident();
|
||||
if (!pending_lock)
|
||||
pending_lock = PyThread_allocate_lock();
|
||||
_PyRuntime.ceval.pending.main_thread = PyThread_get_thread_ident();
|
||||
if (!_PyRuntime.ceval.pending.lock)
|
||||
_PyRuntime.ceval.pending.lock = PyThread_allocate_lock();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -248,9 +239,9 @@ PyEval_ReInitThreads(void)
|
|||
if (!gil_created())
|
||||
return;
|
||||
recreate_gil();
|
||||
pending_lock = PyThread_allocate_lock();
|
||||
_PyRuntime.ceval.pending.lock = PyThread_allocate_lock();
|
||||
take_gil(current_tstate);
|
||||
main_thread = PyThread_get_thread_ident();
|
||||
_PyRuntime.ceval.pending.main_thread = PyThread_get_thread_ident();
|
||||
|
||||
/* Destroy all threads except the current one */
|
||||
_PyThreadState_DeleteExcept(current_tstate);
|
||||
|
@ -294,7 +285,7 @@ PyEval_RestoreThread(PyThreadState *tstate)
|
|||
int err = errno;
|
||||
take_gil(tstate);
|
||||
/* _Py_Finalizing is protected by the GIL */
|
||||
if (_Py_Finalizing && tstate != _Py_Finalizing) {
|
||||
if (_Py_IS_FINALIZING() && !_Py_CURRENTLY_FINALIZING(tstate)) {
|
||||
drop_gil(tstate);
|
||||
PyThread_exit_thread();
|
||||
assert(0); /* unreachable */
|
||||
|
@ -346,19 +337,11 @@ _PyEval_SignalReceived(void)
|
|||
callback.
|
||||
*/
|
||||
|
||||
#define NPENDINGCALLS 32
|
||||
static struct {
|
||||
int (*func)(void *);
|
||||
void *arg;
|
||||
} pendingcalls[NPENDINGCALLS];
|
||||
static int pendingfirst = 0;
|
||||
static int pendinglast = 0;
|
||||
|
||||
int
|
||||
Py_AddPendingCall(int (*func)(void *), void *arg)
|
||||
{
|
||||
int i, j, result=0;
|
||||
PyThread_type_lock lock = pending_lock;
|
||||
PyThread_type_lock lock = _PyRuntime.ceval.pending.lock;
|
||||
|
||||
/* try a few times for the lock. Since this mechanism is used
|
||||
* for signal handling (on the main thread), there is a (slim)
|
||||
|
@ -380,14 +363,14 @@ Py_AddPendingCall(int (*func)(void *), void *arg)
|
|||
return -1;
|
||||
}
|
||||
|
||||
i = pendinglast;
|
||||
i = _PyRuntime.ceval.pending.last;
|
||||
j = (i + 1) % NPENDINGCALLS;
|
||||
if (j == pendingfirst) {
|
||||
if (j == _PyRuntime.ceval.pending.first) {
|
||||
result = -1; /* Queue full */
|
||||
} else {
|
||||
pendingcalls[i].func = func;
|
||||
pendingcalls[i].arg = arg;
|
||||
pendinglast = j;
|
||||
_PyRuntime.ceval.pending.calls[i].func = func;
|
||||
_PyRuntime.ceval.pending.calls[i].arg = arg;
|
||||
_PyRuntime.ceval.pending.last = j;
|
||||
}
|
||||
/* signal main loop */
|
||||
SIGNAL_PENDING_CALLS();
|
||||
|
@ -405,16 +388,19 @@ Py_MakePendingCalls(void)
|
|||
|
||||
assert(PyGILState_Check());
|
||||
|
||||
if (!pending_lock) {
|
||||
if (!_PyRuntime.ceval.pending.lock) {
|
||||
/* initial allocation of the lock */
|
||||
pending_lock = PyThread_allocate_lock();
|
||||
if (pending_lock == NULL)
|
||||
_PyRuntime.ceval.pending.lock = PyThread_allocate_lock();
|
||||
if (_PyRuntime.ceval.pending.lock == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* only service pending calls on main thread */
|
||||
if (main_thread && PyThread_get_thread_ident() != main_thread)
|
||||
if (_PyRuntime.ceval.pending.main_thread &&
|
||||
PyThread_get_thread_ident() != _PyRuntime.ceval.pending.main_thread)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/* don't perform recursive pending calls */
|
||||
if (busy)
|
||||
return 0;
|
||||
|
@ -436,16 +422,16 @@ Py_MakePendingCalls(void)
|
|||
void *arg = NULL;
|
||||
|
||||
/* pop one item off the queue while holding the lock */
|
||||
PyThread_acquire_lock(pending_lock, WAIT_LOCK);
|
||||
j = pendingfirst;
|
||||
if (j == pendinglast) {
|
||||
PyThread_acquire_lock(_PyRuntime.ceval.pending.lock, WAIT_LOCK);
|
||||
j = _PyRuntime.ceval.pending.first;
|
||||
if (j == _PyRuntime.ceval.pending.last) {
|
||||
func = NULL; /* Queue empty */
|
||||
} else {
|
||||
func = pendingcalls[j].func;
|
||||
arg = pendingcalls[j].arg;
|
||||
pendingfirst = (j + 1) % NPENDINGCALLS;
|
||||
func = _PyRuntime.ceval.pending.calls[j].func;
|
||||
arg = _PyRuntime.ceval.pending.calls[j].arg;
|
||||
_PyRuntime.ceval.pending.first = (j + 1) % NPENDINGCALLS;
|
||||
}
|
||||
PyThread_release_lock(pending_lock);
|
||||
PyThread_release_lock(_PyRuntime.ceval.pending.lock);
|
||||
/* having released the lock, perform the callback */
|
||||
if (func == NULL)
|
||||
break;
|
||||
|
@ -489,14 +475,6 @@ error:
|
|||
The two threads could theoretically wiggle around the "busy" variable.
|
||||
*/
|
||||
|
||||
#define NPENDINGCALLS 32
|
||||
static struct {
|
||||
int (*func)(void *);
|
||||
void *arg;
|
||||
} pendingcalls[NPENDINGCALLS];
|
||||
static volatile int pendingfirst = 0;
|
||||
static volatile int pendinglast = 0;
|
||||
|
||||
int
|
||||
Py_AddPendingCall(int (*func)(void *), void *arg)
|
||||
{
|
||||
|
@ -506,15 +484,15 @@ Py_AddPendingCall(int (*func)(void *), void *arg)
|
|||
if (busy)
|
||||
return -1;
|
||||
busy = 1;
|
||||
i = pendinglast;
|
||||
i = _PyRuntime.ceval.pending.last;
|
||||
j = (i + 1) % NPENDINGCALLS;
|
||||
if (j == pendingfirst) {
|
||||
if (j == _PyRuntime.ceval.pending.first) {
|
||||
busy = 0;
|
||||
return -1; /* Queue full */
|
||||
}
|
||||
pendingcalls[i].func = func;
|
||||
pendingcalls[i].arg = arg;
|
||||
pendinglast = j;
|
||||
_PyRuntime.ceval.pending.calls[i].func = func;
|
||||
_PyRuntime.ceval.pending.calls[i].arg = arg;
|
||||
_PyRuntime.ceval.pending.last = j;
|
||||
|
||||
SIGNAL_PENDING_CALLS();
|
||||
busy = 0;
|
||||
|
@ -543,12 +521,12 @@ Py_MakePendingCalls(void)
|
|||
int i;
|
||||
int (*func)(void *);
|
||||
void *arg;
|
||||
i = pendingfirst;
|
||||
if (i == pendinglast)
|
||||
i = _PyRuntime.ceval.pending.first;
|
||||
if (i == _PyRuntime.ceval.pending.last)
|
||||
break; /* Queue empty */
|
||||
func = pendingcalls[i].func;
|
||||
arg = pendingcalls[i].arg;
|
||||
pendingfirst = (i + 1) % NPENDINGCALLS;
|
||||
func = _PyRuntime.ceval.pending.calls[i].func;
|
||||
arg = _PyRuntime.ceval.pending.calls[i].arg;
|
||||
_PyRuntime.ceval.pending.first = (i + 1) % NPENDINGCALLS;
|
||||
if (func(arg) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
@ -570,20 +548,32 @@ error:
|
|||
#ifndef Py_DEFAULT_RECURSION_LIMIT
|
||||
#define Py_DEFAULT_RECURSION_LIMIT 1000
|
||||
#endif
|
||||
static int recursion_limit = Py_DEFAULT_RECURSION_LIMIT;
|
||||
int _Py_CheckRecursionLimit = Py_DEFAULT_RECURSION_LIMIT;
|
||||
|
||||
void
|
||||
_PyEval_Initialize(struct _ceval_runtime_state *state)
|
||||
{
|
||||
state->recursion_limit = Py_DEFAULT_RECURSION_LIMIT;
|
||||
state->check_recursion_limit = Py_DEFAULT_RECURSION_LIMIT;
|
||||
_gil_initialize(&state->gil);
|
||||
}
|
||||
|
||||
int
|
||||
_PyEval_CheckRecursionLimit(void)
|
||||
{
|
||||
return _PyRuntime.ceval.check_recursion_limit;
|
||||
}
|
||||
|
||||
int
|
||||
Py_GetRecursionLimit(void)
|
||||
{
|
||||
return recursion_limit;
|
||||
return _PyRuntime.ceval.recursion_limit;
|
||||
}
|
||||
|
||||
void
|
||||
Py_SetRecursionLimit(int new_limit)
|
||||
{
|
||||
recursion_limit = new_limit;
|
||||
_Py_CheckRecursionLimit = recursion_limit;
|
||||
_PyRuntime.ceval.recursion_limit = new_limit;
|
||||
_PyRuntime.ceval.check_recursion_limit = _PyRuntime.ceval.recursion_limit;
|
||||
}
|
||||
|
||||
/* the macro Py_EnterRecursiveCall() only calls _Py_CheckRecursiveCall()
|
||||
|
@ -595,6 +585,7 @@ int
|
|||
_Py_CheckRecursiveCall(const char *where)
|
||||
{
|
||||
PyThreadState *tstate = PyThreadState_GET();
|
||||
int recursion_limit = _PyRuntime.ceval.recursion_limit;
|
||||
|
||||
#ifdef USE_STACKCHECK
|
||||
if (PyOS_CheckStack()) {
|
||||
|
@ -603,7 +594,7 @@ _Py_CheckRecursiveCall(const char *where)
|
|||
return -1;
|
||||
}
|
||||
#endif
|
||||
_Py_CheckRecursionLimit = recursion_limit;
|
||||
_PyRuntime.ceval.check_recursion_limit = recursion_limit;
|
||||
if (tstate->recursion_critical)
|
||||
/* Somebody asked that we don't check for recursion. */
|
||||
return 0;
|
||||
|
@ -642,13 +633,7 @@ static void restore_and_clear_exc_state(PyThreadState *, PyFrameObject *);
|
|||
static int do_raise(PyObject *, PyObject *);
|
||||
static int unpack_iterable(PyObject *, int, int, PyObject **);
|
||||
|
||||
/* Records whether tracing is on for any thread. Counts the number of
|
||||
threads for which tstate->c_tracefunc is non-NULL, so if the value
|
||||
is 0, we know we don't have to check this thread's c_tracefunc.
|
||||
This speeds up the if statement in PyEval_EvalFrameEx() after
|
||||
fast_next_opcode*/
|
||||
static int _Py_TracingPossible = 0;
|
||||
|
||||
#define _Py_TracingPossible _PyRuntime.ceval.tracing_possible
|
||||
|
||||
|
||||
PyObject *
|
||||
|
@ -779,7 +764,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
|
|||
|
||||
#define DISPATCH() \
|
||||
{ \
|
||||
if (!_Py_atomic_load_relaxed(&eval_breaker)) { \
|
||||
if (!_Py_atomic_load_relaxed(&_PyRuntime.ceval.eval_breaker)) { \
|
||||
FAST_DISPATCH(); \
|
||||
} \
|
||||
continue; \
|
||||
|
@ -827,7 +812,8 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
|
|||
/* Code access macros */
|
||||
|
||||
/* The integer overflow is checked by an assertion below. */
|
||||
#define INSTR_OFFSET() (sizeof(_Py_CODEUNIT) * (int)(next_instr - first_instr))
|
||||
#define INSTR_OFFSET() \
|
||||
(sizeof(_Py_CODEUNIT) * (int)(next_instr - first_instr))
|
||||
#define NEXTOPARG() do { \
|
||||
_Py_CODEUNIT word = *next_instr; \
|
||||
opcode = _Py_OPCODE(word); \
|
||||
|
@ -1080,7 +1066,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
|
|||
async I/O handler); see Py_AddPendingCall() and
|
||||
Py_MakePendingCalls() above. */
|
||||
|
||||
if (_Py_atomic_load_relaxed(&eval_breaker)) {
|
||||
if (_Py_atomic_load_relaxed(&_PyRuntime.ceval.eval_breaker)) {
|
||||
if (_Py_OPCODE(*next_instr) == SETUP_FINALLY ||
|
||||
_Py_OPCODE(*next_instr) == YIELD_FROM) {
|
||||
/* Two cases where we skip running signal handlers and other
|
||||
|
@ -1097,12 +1083,16 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
|
|||
*/
|
||||
goto fast_next_opcode;
|
||||
}
|
||||
if (_Py_atomic_load_relaxed(&pendingcalls_to_do)) {
|
||||
if (_Py_atomic_load_relaxed(
|
||||
&_PyRuntime.ceval.pending.calls_to_do))
|
||||
{
|
||||
if (Py_MakePendingCalls() < 0)
|
||||
goto error;
|
||||
}
|
||||
#ifdef WITH_THREAD
|
||||
if (_Py_atomic_load_relaxed(&gil_drop_request)) {
|
||||
if (_Py_atomic_load_relaxed(
|
||||
&_PyRuntime.ceval.gil_drop_request))
|
||||
{
|
||||
/* Give another thread a chance */
|
||||
if (PyThreadState_Swap(NULL) != tstate)
|
||||
Py_FatalError("ceval: tstate mix-up");
|
||||
|
@ -1113,7 +1103,9 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
|
|||
take_gil(tstate);
|
||||
|
||||
/* Check if we should make a quick exit. */
|
||||
if (_Py_Finalizing && _Py_Finalizing != tstate) {
|
||||
if (_Py_IS_FINALIZING() &&
|
||||
!_Py_CURRENTLY_FINALIZING(tstate))
|
||||
{
|
||||
drop_gil(tstate);
|
||||
PyThread_exit_thread();
|
||||
}
|
||||
|
|
|
@ -8,20 +8,13 @@
|
|||
|
||||
/* First some general settings */
|
||||
|
||||
/* microseconds (the Python API uses seconds, though) */
|
||||
#define DEFAULT_INTERVAL 5000
|
||||
static unsigned long gil_interval = DEFAULT_INTERVAL;
|
||||
#define INTERVAL (gil_interval >= 1 ? gil_interval : 1)
|
||||
|
||||
/* Enable if you want to force the switching of threads at least every `gil_interval` */
|
||||
#undef FORCE_SWITCHING
|
||||
#define FORCE_SWITCHING
|
||||
#define INTERVAL (_PyRuntime.ceval.gil.interval >= 1 ? _PyRuntime.ceval.gil.interval : 1)
|
||||
|
||||
|
||||
/*
|
||||
Notes about the implementation:
|
||||
|
||||
- The GIL is just a boolean variable (gil_locked) whose access is protected
|
||||
- The GIL is just a boolean variable (locked) whose access is protected
|
||||
by a mutex (gil_mutex), and whose changes are signalled by a condition
|
||||
variable (gil_cond). gil_mutex is taken for short periods of time,
|
||||
and therefore mostly uncontended.
|
||||
|
@ -48,7 +41,7 @@ static unsigned long gil_interval = DEFAULT_INTERVAL;
|
|||
- When a thread releases the GIL and gil_drop_request is set, that thread
|
||||
ensures that another GIL-awaiting thread gets scheduled.
|
||||
It does so by waiting on a condition variable (switch_cond) until
|
||||
the value of gil_last_holder is changed to something else than its
|
||||
the value of last_holder is changed to something else than its
|
||||
own thread state pointer, indicating that another thread was able to
|
||||
take the GIL.
|
||||
|
||||
|
@ -60,11 +53,7 @@ static unsigned long gil_interval = DEFAULT_INTERVAL;
|
|||
*/
|
||||
|
||||
#include "condvar.h"
|
||||
#ifndef Py_HAVE_CONDVAR
|
||||
#error You need either a POSIX-compatible or a Windows system!
|
||||
#endif
|
||||
|
||||
#define MUTEX_T PyMUTEX_T
|
||||
#define MUTEX_INIT(mut) \
|
||||
if (PyMUTEX_INIT(&(mut))) { \
|
||||
Py_FatalError("PyMUTEX_INIT(" #mut ") failed"); };
|
||||
|
@ -78,7 +67,6 @@ static unsigned long gil_interval = DEFAULT_INTERVAL;
|
|||
if (PyMUTEX_UNLOCK(&(mut))) { \
|
||||
Py_FatalError("PyMUTEX_UNLOCK(" #mut ") failed"); };
|
||||
|
||||
#define COND_T PyCOND_T
|
||||
#define COND_INIT(cond) \
|
||||
if (PyCOND_INIT(&(cond))) { \
|
||||
Py_FatalError("PyCOND_INIT(" #cond ") failed"); };
|
||||
|
@ -103,48 +91,36 @@ static unsigned long gil_interval = DEFAULT_INTERVAL;
|
|||
} \
|
||||
|
||||
|
||||
#define DEFAULT_INTERVAL 5000
|
||||
|
||||
/* Whether the GIL is already taken (-1 if uninitialized). This is atomic
|
||||
because it can be read without any lock taken in ceval.c. */
|
||||
static _Py_atomic_int gil_locked = {-1};
|
||||
/* Number of GIL switches since the beginning. */
|
||||
static unsigned long gil_switch_number = 0;
|
||||
/* Last PyThreadState holding / having held the GIL. This helps us know
|
||||
whether anyone else was scheduled after we dropped the GIL. */
|
||||
static _Py_atomic_address gil_last_holder = {0};
|
||||
|
||||
/* This condition variable allows one or several threads to wait until
|
||||
the GIL is released. In addition, the mutex also protects the above
|
||||
variables. */
|
||||
static COND_T gil_cond;
|
||||
static MUTEX_T gil_mutex;
|
||||
|
||||
#ifdef FORCE_SWITCHING
|
||||
/* This condition variable helps the GIL-releasing thread wait for
|
||||
a GIL-awaiting thread to be scheduled and take the GIL. */
|
||||
static COND_T switch_cond;
|
||||
static MUTEX_T switch_mutex;
|
||||
#endif
|
||||
|
||||
static void _gil_initialize(struct _gil_runtime_state *state)
|
||||
{
|
||||
_Py_atomic_int uninitialized = {-1};
|
||||
state->locked = uninitialized;
|
||||
state->interval = DEFAULT_INTERVAL;
|
||||
}
|
||||
|
||||
static int gil_created(void)
|
||||
{
|
||||
return _Py_atomic_load_explicit(&gil_locked, _Py_memory_order_acquire) >= 0;
|
||||
return (_Py_atomic_load_explicit(&_PyRuntime.ceval.gil.locked,
|
||||
_Py_memory_order_acquire)
|
||||
) >= 0;
|
||||
}
|
||||
|
||||
static void create_gil(void)
|
||||
{
|
||||
MUTEX_INIT(gil_mutex);
|
||||
MUTEX_INIT(_PyRuntime.ceval.gil.mutex);
|
||||
#ifdef FORCE_SWITCHING
|
||||
MUTEX_INIT(switch_mutex);
|
||||
MUTEX_INIT(_PyRuntime.ceval.gil.switch_mutex);
|
||||
#endif
|
||||
COND_INIT(gil_cond);
|
||||
COND_INIT(_PyRuntime.ceval.gil.cond);
|
||||
#ifdef FORCE_SWITCHING
|
||||
COND_INIT(switch_cond);
|
||||
COND_INIT(_PyRuntime.ceval.gil.switch_cond);
|
||||
#endif
|
||||
_Py_atomic_store_relaxed(&gil_last_holder, 0);
|
||||
_Py_ANNOTATE_RWLOCK_CREATE(&gil_locked);
|
||||
_Py_atomic_store_explicit(&gil_locked, 0, _Py_memory_order_release);
|
||||
_Py_atomic_store_relaxed(&_PyRuntime.ceval.gil.last_holder, 0);
|
||||
_Py_ANNOTATE_RWLOCK_CREATE(&_PyRuntime.ceval.gil.locked);
|
||||
_Py_atomic_store_explicit(&_PyRuntime.ceval.gil.locked, 0,
|
||||
_Py_memory_order_release);
|
||||
}
|
||||
|
||||
static void destroy_gil(void)
|
||||
|
@ -152,54 +128,62 @@ static void destroy_gil(void)
|
|||
/* some pthread-like implementations tie the mutex to the cond
|
||||
* and must have the cond destroyed first.
|
||||
*/
|
||||
COND_FINI(gil_cond);
|
||||
MUTEX_FINI(gil_mutex);
|
||||
COND_FINI(_PyRuntime.ceval.gil.cond);
|
||||
MUTEX_FINI(_PyRuntime.ceval.gil.mutex);
|
||||
#ifdef FORCE_SWITCHING
|
||||
COND_FINI(switch_cond);
|
||||
MUTEX_FINI(switch_mutex);
|
||||
COND_FINI(_PyRuntime.ceval.gil.switch_cond);
|
||||
MUTEX_FINI(_PyRuntime.ceval.gil.switch_mutex);
|
||||
#endif
|
||||
_Py_atomic_store_explicit(&gil_locked, -1, _Py_memory_order_release);
|
||||
_Py_ANNOTATE_RWLOCK_DESTROY(&gil_locked);
|
||||
_Py_atomic_store_explicit(&_PyRuntime.ceval.gil.locked, -1,
|
||||
_Py_memory_order_release);
|
||||
_Py_ANNOTATE_RWLOCK_DESTROY(&_PyRuntime.ceval.gil.locked);
|
||||
}
|
||||
|
||||
static void recreate_gil(void)
|
||||
{
|
||||
_Py_ANNOTATE_RWLOCK_DESTROY(&gil_locked);
|
||||
_Py_ANNOTATE_RWLOCK_DESTROY(&_PyRuntime.ceval.gil.locked);
|
||||
/* XXX should we destroy the old OS resources here? */
|
||||
create_gil();
|
||||
}
|
||||
|
||||
static void drop_gil(PyThreadState *tstate)
|
||||
{
|
||||
if (!_Py_atomic_load_relaxed(&gil_locked))
|
||||
if (!_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked))
|
||||
Py_FatalError("drop_gil: GIL is not locked");
|
||||
/* tstate is allowed to be NULL (early interpreter init) */
|
||||
if (tstate != NULL) {
|
||||
/* Sub-interpreter support: threads might have been switched
|
||||
under our feet using PyThreadState_Swap(). Fix the GIL last
|
||||
holder variable so that our heuristics work. */
|
||||
_Py_atomic_store_relaxed(&gil_last_holder, (uintptr_t)tstate);
|
||||
_Py_atomic_store_relaxed(&_PyRuntime.ceval.gil.last_holder,
|
||||
(uintptr_t)tstate);
|
||||
}
|
||||
|
||||
MUTEX_LOCK(gil_mutex);
|
||||
_Py_ANNOTATE_RWLOCK_RELEASED(&gil_locked, /*is_write=*/1);
|
||||
_Py_atomic_store_relaxed(&gil_locked, 0);
|
||||
COND_SIGNAL(gil_cond);
|
||||
MUTEX_UNLOCK(gil_mutex);
|
||||
MUTEX_LOCK(_PyRuntime.ceval.gil.mutex);
|
||||
_Py_ANNOTATE_RWLOCK_RELEASED(&_PyRuntime.ceval.gil.locked, /*is_write=*/1);
|
||||
_Py_atomic_store_relaxed(&_PyRuntime.ceval.gil.locked, 0);
|
||||
COND_SIGNAL(_PyRuntime.ceval.gil.cond);
|
||||
MUTEX_UNLOCK(_PyRuntime.ceval.gil.mutex);
|
||||
|
||||
#ifdef FORCE_SWITCHING
|
||||
if (_Py_atomic_load_relaxed(&gil_drop_request) && tstate != NULL) {
|
||||
MUTEX_LOCK(switch_mutex);
|
||||
if (_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil_drop_request) &&
|
||||
tstate != NULL)
|
||||
{
|
||||
MUTEX_LOCK(_PyRuntime.ceval.gil.switch_mutex);
|
||||
/* Not switched yet => wait */
|
||||
if ((PyThreadState*)_Py_atomic_load_relaxed(&gil_last_holder) == tstate) {
|
||||
if (((PyThreadState*)_Py_atomic_load_relaxed(
|
||||
&_PyRuntime.ceval.gil.last_holder)
|
||||
) == tstate)
|
||||
{
|
||||
RESET_GIL_DROP_REQUEST();
|
||||
/* NOTE: if COND_WAIT does not atomically start waiting when
|
||||
releasing the mutex, another thread can run through, take
|
||||
the GIL and drop it again, and reset the condition
|
||||
before we even had a chance to wait for it. */
|
||||
COND_WAIT(switch_cond, switch_mutex);
|
||||
COND_WAIT(_PyRuntime.ceval.gil.switch_cond,
|
||||
_PyRuntime.ceval.gil.switch_mutex);
|
||||
}
|
||||
MUTEX_UNLOCK(switch_mutex);
|
||||
MUTEX_UNLOCK(_PyRuntime.ceval.gil.switch_mutex);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -211,60 +195,65 @@ static void take_gil(PyThreadState *tstate)
|
|||
Py_FatalError("take_gil: NULL tstate");
|
||||
|
||||
err = errno;
|
||||
MUTEX_LOCK(gil_mutex);
|
||||
MUTEX_LOCK(_PyRuntime.ceval.gil.mutex);
|
||||
|
||||
if (!_Py_atomic_load_relaxed(&gil_locked))
|
||||
if (!_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked))
|
||||
goto _ready;
|
||||
|
||||
while (_Py_atomic_load_relaxed(&gil_locked)) {
|
||||
while (_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked)) {
|
||||
int timed_out = 0;
|
||||
unsigned long saved_switchnum;
|
||||
|
||||
saved_switchnum = gil_switch_number;
|
||||
COND_TIMED_WAIT(gil_cond, gil_mutex, INTERVAL, timed_out);
|
||||
saved_switchnum = _PyRuntime.ceval.gil.switch_number;
|
||||
COND_TIMED_WAIT(_PyRuntime.ceval.gil.cond, _PyRuntime.ceval.gil.mutex,
|
||||
INTERVAL, timed_out);
|
||||
/* If we timed out and no switch occurred in the meantime, it is time
|
||||
to ask the GIL-holding thread to drop it. */
|
||||
if (timed_out &&
|
||||
_Py_atomic_load_relaxed(&gil_locked) &&
|
||||
gil_switch_number == saved_switchnum) {
|
||||
_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked) &&
|
||||
_PyRuntime.ceval.gil.switch_number == saved_switchnum) {
|
||||
SET_GIL_DROP_REQUEST();
|
||||
}
|
||||
}
|
||||
_ready:
|
||||
#ifdef FORCE_SWITCHING
|
||||
/* This mutex must be taken before modifying gil_last_holder (see drop_gil()). */
|
||||
MUTEX_LOCK(switch_mutex);
|
||||
/* This mutex must be taken before modifying
|
||||
_PyRuntime.ceval.gil.last_holder (see drop_gil()). */
|
||||
MUTEX_LOCK(_PyRuntime.ceval.gil.switch_mutex);
|
||||
#endif
|
||||
/* We now hold the GIL */
|
||||
_Py_atomic_store_relaxed(&gil_locked, 1);
|
||||
_Py_ANNOTATE_RWLOCK_ACQUIRED(&gil_locked, /*is_write=*/1);
|
||||
_Py_atomic_store_relaxed(&_PyRuntime.ceval.gil.locked, 1);
|
||||
_Py_ANNOTATE_RWLOCK_ACQUIRED(&_PyRuntime.ceval.gil.locked, /*is_write=*/1);
|
||||
|
||||
if (tstate != (PyThreadState*)_Py_atomic_load_relaxed(&gil_last_holder)) {
|
||||
_Py_atomic_store_relaxed(&gil_last_holder, (uintptr_t)tstate);
|
||||
++gil_switch_number;
|
||||
if (tstate != (PyThreadState*)_Py_atomic_load_relaxed(
|
||||
&_PyRuntime.ceval.gil.last_holder))
|
||||
{
|
||||
_Py_atomic_store_relaxed(&_PyRuntime.ceval.gil.last_holder,
|
||||
(uintptr_t)tstate);
|
||||
++_PyRuntime.ceval.gil.switch_number;
|
||||
}
|
||||
|
||||
#ifdef FORCE_SWITCHING
|
||||
COND_SIGNAL(switch_cond);
|
||||
MUTEX_UNLOCK(switch_mutex);
|
||||
COND_SIGNAL(_PyRuntime.ceval.gil.switch_cond);
|
||||
MUTEX_UNLOCK(_PyRuntime.ceval.gil.switch_mutex);
|
||||
#endif
|
||||
if (_Py_atomic_load_relaxed(&gil_drop_request)) {
|
||||
if (_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil_drop_request)) {
|
||||
RESET_GIL_DROP_REQUEST();
|
||||
}
|
||||
if (tstate->async_exc != NULL) {
|
||||
_PyEval_SignalAsyncExc();
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gil_mutex);
|
||||
MUTEX_UNLOCK(_PyRuntime.ceval.gil.mutex);
|
||||
errno = err;
|
||||
}
|
||||
|
||||
void _PyEval_SetSwitchInterval(unsigned long microseconds)
|
||||
{
|
||||
gil_interval = microseconds;
|
||||
_PyRuntime.ceval.gil.interval = microseconds;
|
||||
}
|
||||
|
||||
unsigned long _PyEval_GetSwitchInterval()
|
||||
{
|
||||
return gil_interval;
|
||||
return _PyRuntime.ceval.gil.interval;
|
||||
}
|
||||
|
|
|
@ -37,27 +37,16 @@
|
|||
* Condition Variable.
|
||||
*/
|
||||
|
||||
#ifndef _CONDVAR_H_
|
||||
#define _CONDVAR_H_
|
||||
#ifndef _CONDVAR_IMPL_H_
|
||||
#define _CONDVAR_IMPL_H_
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
#ifndef _POSIX_THREADS
|
||||
/* This means pthreads are not implemented in libc headers, hence the macro
|
||||
not present in unistd.h. But they still can be implemented as an external
|
||||
library (e.g. gnu pth in pthread emulation) */
|
||||
# ifdef HAVE_PTHREAD_H
|
||||
# include <pthread.h> /* _POSIX_THREADS */
|
||||
# endif
|
||||
#endif
|
||||
#include "internal/_condvar.h"
|
||||
|
||||
#ifdef _POSIX_THREADS
|
||||
/*
|
||||
* POSIX support
|
||||
*/
|
||||
#define Py_HAVE_CONDVAR
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#define PyCOND_ADD_MICROSECONDS(tv, interval) \
|
||||
do { /* TODO: add overflow and truncation checks */ \
|
||||
|
@ -74,13 +63,11 @@ do { /* TODO: add overflow and truncation checks */ \
|
|||
#endif
|
||||
|
||||
/* The following functions return 0 on success, nonzero on error */
|
||||
#define PyMUTEX_T pthread_mutex_t
|
||||
#define PyMUTEX_INIT(mut) pthread_mutex_init((mut), NULL)
|
||||
#define PyMUTEX_FINI(mut) pthread_mutex_destroy(mut)
|
||||
#define PyMUTEX_LOCK(mut) pthread_mutex_lock(mut)
|
||||
#define PyMUTEX_UNLOCK(mut) pthread_mutex_unlock(mut)
|
||||
|
||||
#define PyCOND_T pthread_cond_t
|
||||
#define PyCOND_INIT(cond) pthread_cond_init((cond), NULL)
|
||||
#define PyCOND_FINI(cond) pthread_cond_destroy(cond)
|
||||
#define PyCOND_SIGNAL(cond) pthread_cond_signal(cond)
|
||||
|
@ -116,45 +103,11 @@ PyCOND_TIMEDWAIT(PyCOND_T *cond, PyMUTEX_T *mut, long long us)
|
|||
* Emulated condition variables ones that work with XP and later, plus
|
||||
* example native support on VISTA and onwards.
|
||||
*/
|
||||
#define Py_HAVE_CONDVAR
|
||||
|
||||
|
||||
/* include windows if it hasn't been done before */
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
/* options */
|
||||
/* non-emulated condition variables are provided for those that want
|
||||
* to target Windows Vista. Modify this macro to enable them.
|
||||
*/
|
||||
#ifndef _PY_EMULATED_WIN_CV
|
||||
#define _PY_EMULATED_WIN_CV 1 /* use emulated condition variables */
|
||||
#endif
|
||||
|
||||
/* fall back to emulation if not targeting Vista */
|
||||
#if !defined NTDDI_VISTA || NTDDI_VERSION < NTDDI_VISTA
|
||||
#undef _PY_EMULATED_WIN_CV
|
||||
#define _PY_EMULATED_WIN_CV 1
|
||||
#endif
|
||||
|
||||
|
||||
#if _PY_EMULATED_WIN_CV
|
||||
|
||||
/* The mutex is a CriticalSection object and
|
||||
The condition variables is emulated with the help of a semaphore.
|
||||
Semaphores are available on Windows XP (2003 server) and later.
|
||||
We use a Semaphore rather than an auto-reset event, because although
|
||||
an auto-resent event might appear to solve the lost-wakeup bug (race
|
||||
condition between releasing the outer lock and waiting) because it
|
||||
maintains state even though a wait hasn't happened, there is still
|
||||
a lost wakeup problem if more than one thread are interrupted in the
|
||||
critical place. A semaphore solves that, because its state is counted,
|
||||
not Boolean.
|
||||
Because it is ok to signal a condition variable with no one
|
||||
waiting, we need to keep track of the number of
|
||||
waiting threads. Otherwise, the semaphore's state could rise
|
||||
without bound. This also helps reduce the number of "spurious wakeups"
|
||||
that would otherwise happen.
|
||||
|
||||
This implementation still has the problem that the threads woken
|
||||
with a "signal" aren't necessarily those that are already
|
||||
|
@ -168,8 +121,6 @@ PyCOND_TIMEDWAIT(PyCOND_T *cond, PyMUTEX_T *mut, long long us)
|
|||
http://www.cse.wustl.edu/~schmidt/win32-cv-1.html
|
||||
*/
|
||||
|
||||
typedef CRITICAL_SECTION PyMUTEX_T;
|
||||
|
||||
Py_LOCAL_INLINE(int)
|
||||
PyMUTEX_INIT(PyMUTEX_T *cs)
|
||||
{
|
||||
|
@ -198,15 +149,6 @@ PyMUTEX_UNLOCK(PyMUTEX_T *cs)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* The ConditionVariable object. From XP onwards it is easily emulated with
|
||||
* a Semaphore
|
||||
*/
|
||||
|
||||
typedef struct _PyCOND_T
|
||||
{
|
||||
HANDLE sem;
|
||||
int waiting; /* to allow PyCOND_SIGNAL to be a no-op */
|
||||
} PyCOND_T;
|
||||
|
||||
Py_LOCAL_INLINE(int)
|
||||
PyCOND_INIT(PyCOND_T *cv)
|
||||
|
@ -304,12 +246,7 @@ PyCOND_BROADCAST(PyCOND_T *cv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Use native Win7 primitives if build target is Win7 or higher */
|
||||
|
||||
/* SRWLOCK is faster and better than CriticalSection */
|
||||
typedef SRWLOCK PyMUTEX_T;
|
||||
#else /* !_PY_EMULATED_WIN_CV */
|
||||
|
||||
Py_LOCAL_INLINE(int)
|
||||
PyMUTEX_INIT(PyMUTEX_T *cs)
|
||||
|
@ -339,8 +276,6 @@ PyMUTEX_UNLOCK(PyMUTEX_T *cs)
|
|||
}
|
||||
|
||||
|
||||
typedef CONDITION_VARIABLE PyCOND_T;
|
||||
|
||||
Py_LOCAL_INLINE(int)
|
||||
PyCOND_INIT(PyCOND_T *cv)
|
||||
{
|
||||
|
@ -387,4 +322,4 @@ PyCOND_BROADCAST(PyCOND_T *cv)
|
|||
|
||||
#endif /* _POSIX_THREADS, NT_THREADS */
|
||||
|
||||
#endif /* _CONDVAR_H_ */
|
||||
#endif /* _CONDVAR_IMPL_H_ */
|
||||
|
|
|
@ -77,6 +77,30 @@ extern void _PyGILState_Init(PyInterpreterState *, PyThreadState *);
|
|||
extern void _PyGILState_Fini(void);
|
||||
#endif /* WITH_THREAD */
|
||||
|
||||
_PyRuntimeState _PyRuntime = {};
|
||||
|
||||
void
|
||||
_PyRuntime_Initialize(void)
|
||||
{
|
||||
/* XXX We only initialize once in the process, which aligns with
|
||||
the static initialization of the former globals now found in
|
||||
_PyRuntime. However, _PyRuntime *should* be initialized with
|
||||
every Py_Initialize() call, but doing so breaks the runtime.
|
||||
This is because the runtime state is not properly finalized
|
||||
currently. */
|
||||
static int initialized = 0;
|
||||
if (initialized)
|
||||
return;
|
||||
initialized = 1;
|
||||
_PyRuntimeState_Init(&_PyRuntime);
|
||||
}
|
||||
|
||||
void
|
||||
_PyRuntime_Finalize(void)
|
||||
{
|
||||
_PyRuntimeState_Fini(&_PyRuntime);
|
||||
}
|
||||
|
||||
/* Global configuration variable declarations are in pydebug.h */
|
||||
/* XXX (ncoghlan): move those declarations to pylifecycle.h? */
|
||||
int Py_DebugFlag; /* Needed by parser.c */
|
||||
|
@ -100,8 +124,6 @@ int Py_LegacyWindowsFSEncodingFlag = 0; /* Uses mbcs instead of utf-8 */
|
|||
int Py_LegacyWindowsStdioFlag = 0; /* Uses FileIO instead of WindowsConsoleIO */
|
||||
#endif
|
||||
|
||||
PyThreadState *_Py_Finalizing = NULL;
|
||||
|
||||
/* Hack to force loading of object files */
|
||||
int (*_PyOS_mystrnicmp_hack)(const char *, const char *, Py_ssize_t) = \
|
||||
PyOS_mystrnicmp; /* Python/pystrcmp.o */
|
||||
|
@ -119,19 +141,17 @@ PyModule_GetWarningsModule(void)
|
|||
*
|
||||
* Can be called prior to Py_Initialize.
|
||||
*/
|
||||
int _Py_CoreInitialized = 0;
|
||||
int _Py_Initialized = 0;
|
||||
|
||||
int
|
||||
_Py_IsCoreInitialized(void)
|
||||
{
|
||||
return _Py_CoreInitialized;
|
||||
return _PyRuntime.core_initialized;
|
||||
}
|
||||
|
||||
int
|
||||
Py_IsInitialized(void)
|
||||
{
|
||||
return _Py_Initialized;
|
||||
return _PyRuntime.initialized;
|
||||
}
|
||||
|
||||
/* Helper to allow an embedding application to override the normal
|
||||
|
@ -544,14 +564,16 @@ void _Py_InitializeCore(const _PyCoreConfig *config)
|
|||
_PyCoreConfig core_config = _PyCoreConfig_INIT;
|
||||
_PyMainInterpreterConfig preinit_config = _PyMainInterpreterConfig_INIT;
|
||||
|
||||
_PyRuntime_Initialize();
|
||||
|
||||
if (config != NULL) {
|
||||
core_config = *config;
|
||||
}
|
||||
|
||||
if (_Py_Initialized) {
|
||||
if (_PyRuntime.initialized) {
|
||||
Py_FatalError("Py_InitializeCore: main interpreter already initialized");
|
||||
}
|
||||
if (_Py_CoreInitialized) {
|
||||
if (_PyRuntime.core_initialized) {
|
||||
Py_FatalError("Py_InitializeCore: runtime core already initialized");
|
||||
}
|
||||
|
||||
|
@ -564,7 +586,14 @@ void _Py_InitializeCore(const _PyCoreConfig *config)
|
|||
* threads still hanging around from a previous Py_Initialize/Finalize
|
||||
* pair :(
|
||||
*/
|
||||
_Py_Finalizing = NULL;
|
||||
_PyRuntime.finalizing = NULL;
|
||||
|
||||
if (_PyMem_SetupAllocators(core_config.allocator) < 0) {
|
||||
fprintf(stderr,
|
||||
"Error in PYTHONMALLOC: unknown allocator \"%s\"!\n",
|
||||
core_config.allocator);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
/* Passing "" to setlocale() on Android requests the C locale rather
|
||||
|
@ -606,7 +635,7 @@ void _Py_InitializeCore(const _PyCoreConfig *config)
|
|||
Py_HashRandomizationFlag = 1;
|
||||
}
|
||||
|
||||
_PyInterpreterState_Init();
|
||||
_PyInterpreterState_Enable(&_PyRuntime);
|
||||
interp = PyInterpreterState_New();
|
||||
if (interp == NULL)
|
||||
Py_FatalError("Py_InitializeCore: can't make main interpreter");
|
||||
|
@ -698,7 +727,7 @@ void _Py_InitializeCore(const _PyCoreConfig *config)
|
|||
}
|
||||
|
||||
/* Only when we get here is the runtime core fully initialized */
|
||||
_Py_CoreInitialized = 1;
|
||||
_PyRuntime.core_initialized = 1;
|
||||
}
|
||||
|
||||
/* Read configuration settings from standard locations
|
||||
|
@ -739,10 +768,10 @@ int _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config)
|
|||
PyInterpreterState *interp;
|
||||
PyThreadState *tstate;
|
||||
|
||||
if (!_Py_CoreInitialized) {
|
||||
if (!_PyRuntime.core_initialized) {
|
||||
Py_FatalError("Py_InitializeMainInterpreter: runtime core not initialized");
|
||||
}
|
||||
if (_Py_Initialized) {
|
||||
if (_PyRuntime.initialized) {
|
||||
Py_FatalError("Py_InitializeMainInterpreter: main interpreter already initialized");
|
||||
}
|
||||
|
||||
|
@ -763,7 +792,7 @@ int _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config)
|
|||
* This means anything which needs support from extension modules
|
||||
* or pure Python code in the standard library won't work.
|
||||
*/
|
||||
_Py_Initialized = 1;
|
||||
_PyRuntime.initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
/* TODO: Report exceptions rather than fatal errors below here */
|
||||
|
@ -808,7 +837,7 @@ int _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config)
|
|||
Py_XDECREF(warnings_module);
|
||||
}
|
||||
|
||||
_Py_Initialized = 1;
|
||||
_PyRuntime.initialized = 1;
|
||||
|
||||
if (!Py_NoSiteFlag)
|
||||
initsite(); /* Module site */
|
||||
|
@ -924,7 +953,7 @@ Py_FinalizeEx(void)
|
|||
PyThreadState *tstate;
|
||||
int status = 0;
|
||||
|
||||
if (!_Py_Initialized)
|
||||
if (!_PyRuntime.initialized)
|
||||
return status;
|
||||
|
||||
wait_for_thread_shutdown();
|
||||
|
@ -946,9 +975,9 @@ Py_FinalizeEx(void)
|
|||
|
||||
/* Remaining threads (e.g. daemon threads) will automatically exit
|
||||
after taking the GIL (in PyEval_RestoreThread()). */
|
||||
_Py_Finalizing = tstate;
|
||||
_Py_Initialized = 0;
|
||||
_Py_CoreInitialized = 0;
|
||||
_PyRuntime.finalizing = tstate;
|
||||
_PyRuntime.initialized = 0;
|
||||
_PyRuntime.core_initialized = 0;
|
||||
|
||||
/* Flush sys.stdout and sys.stderr */
|
||||
if (flush_std_files() < 0) {
|
||||
|
@ -1110,6 +1139,7 @@ Py_FinalizeEx(void)
|
|||
#endif
|
||||
|
||||
call_ll_exitfuncs();
|
||||
_PyRuntime_Finalize();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -1139,7 +1169,7 @@ Py_NewInterpreter(void)
|
|||
PyThreadState *tstate, *save_tstate;
|
||||
PyObject *bimod, *sysmod;
|
||||
|
||||
if (!_Py_Initialized)
|
||||
if (!_PyRuntime.initialized)
|
||||
Py_FatalError("Py_NewInterpreter: call Py_Initialize first");
|
||||
|
||||
#ifdef WITH_THREAD
|
||||
|
@ -1854,20 +1884,19 @@ exit:
|
|||
# include "pythread.h"
|
||||
#endif
|
||||
|
||||
static void (*pyexitfunc)(void) = NULL;
|
||||
/* For the atexit module. */
|
||||
void _Py_PyAtExit(void (*func)(void))
|
||||
{
|
||||
pyexitfunc = func;
|
||||
_PyRuntime.pyexitfunc = func;
|
||||
}
|
||||
|
||||
static void
|
||||
call_py_exitfuncs(void)
|
||||
{
|
||||
if (pyexitfunc == NULL)
|
||||
if (_PyRuntime.pyexitfunc == NULL)
|
||||
return;
|
||||
|
||||
(*pyexitfunc)();
|
||||
(*_PyRuntime.pyexitfunc)();
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
|
@ -1900,22 +1929,19 @@ wait_for_thread_shutdown(void)
|
|||
}
|
||||
|
||||
#define NEXITFUNCS 32
|
||||
static void (*exitfuncs[NEXITFUNCS])(void);
|
||||
static int nexitfuncs = 0;
|
||||
|
||||
int Py_AtExit(void (*func)(void))
|
||||
{
|
||||
if (nexitfuncs >= NEXITFUNCS)
|
||||
if (_PyRuntime.nexitfuncs >= NEXITFUNCS)
|
||||
return -1;
|
||||
exitfuncs[nexitfuncs++] = func;
|
||||
_PyRuntime.exitfuncs[_PyRuntime.nexitfuncs++] = func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
call_ll_exitfuncs(void)
|
||||
{
|
||||
while (nexitfuncs > 0)
|
||||
(*exitfuncs[--nexitfuncs])();
|
||||
while (_PyRuntime.nexitfuncs > 0)
|
||||
(*_PyRuntime.exitfuncs[--_PyRuntime.nexitfuncs])();
|
||||
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
|
|
194
Python/pystate.c
194
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)
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
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");
|
||||
|
|
|
@ -519,8 +519,6 @@ Return the profiling function set with sys.setprofile.\n\
|
|||
See the profiler chapter in the library manual."
|
||||
);
|
||||
|
||||
static int _check_interval = 100;
|
||||
|
||||
static PyObject *
|
||||
sys_setcheckinterval(PyObject *self, PyObject *args)
|
||||
{
|
||||
|
@ -529,7 +527,8 @@ sys_setcheckinterval(PyObject *self, PyObject *args)
|
|||
"are deprecated. Use sys.setswitchinterval() "
|
||||
"instead.", 1) < 0)
|
||||
return NULL;
|
||||
if (!PyArg_ParseTuple(args, "i:setcheckinterval", &_check_interval))
|
||||
PyInterpreterState *interp = PyThreadState_GET()->interp;
|
||||
if (!PyArg_ParseTuple(args, "i:setcheckinterval", &interp->check_interval))
|
||||
return NULL;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
@ -549,7 +548,8 @@ sys_getcheckinterval(PyObject *self, PyObject *args)
|
|||
"are deprecated. Use sys.getswitchinterval() "
|
||||
"instead.", 1) < 0)
|
||||
return NULL;
|
||||
return PyLong_FromLong(_check_interval);
|
||||
PyInterpreterState *interp = PyThreadState_GET()->interp;
|
||||
return PyLong_FromLong(interp->check_interval);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(getcheckinterval_doc,
|
||||
|
@ -1339,7 +1339,7 @@ Clear the internal type lookup cache.");
|
|||
static PyObject *
|
||||
sys_is_finalizing(PyObject* self, PyObject* args)
|
||||
{
|
||||
return PyBool_FromLong(_Py_Finalizing != NULL);
|
||||
return PyBool_FromLong(_Py_IS_FINALIZING());
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(is_finalizing_doc,
|
||||
|
@ -1479,11 +1479,24 @@ list_builtin_module_names(void)
|
|||
return list;
|
||||
}
|
||||
|
||||
static PyObject *warnoptions = NULL;
|
||||
static PyObject *
|
||||
get_warnoptions(void)
|
||||
{
|
||||
PyObject *warnoptions = PyThreadState_GET()->interp->warnoptions;
|
||||
if (warnoptions == NULL || !PyList_Check(warnoptions)) {
|
||||
Py_XDECREF(warnoptions);
|
||||
warnoptions = PyList_New(0);
|
||||
if (warnoptions == NULL)
|
||||
return NULL;
|
||||
PyThreadState_GET()->interp->warnoptions = warnoptions;
|
||||
}
|
||||
return warnoptions;
|
||||
}
|
||||
|
||||
void
|
||||
PySys_ResetWarnOptions(void)
|
||||
{
|
||||
PyObject *warnoptions = PyThreadState_GET()->interp->warnoptions;
|
||||
if (warnoptions == NULL || !PyList_Check(warnoptions))
|
||||
return;
|
||||
PyList_SetSlice(warnoptions, 0, PyList_GET_SIZE(warnoptions), NULL);
|
||||
|
@ -1492,12 +1505,9 @@ PySys_ResetWarnOptions(void)
|
|||
void
|
||||
PySys_AddWarnOptionUnicode(PyObject *unicode)
|
||||
{
|
||||
if (warnoptions == NULL || !PyList_Check(warnoptions)) {
|
||||
Py_XDECREF(warnoptions);
|
||||
warnoptions = PyList_New(0);
|
||||
if (warnoptions == NULL)
|
||||
return;
|
||||
}
|
||||
PyObject *warnoptions = get_warnoptions();
|
||||
if (warnoptions == NULL)
|
||||
return;
|
||||
PyList_Append(warnoptions, unicode);
|
||||
}
|
||||
|
||||
|
@ -1515,17 +1525,20 @@ PySys_AddWarnOption(const wchar_t *s)
|
|||
int
|
||||
PySys_HasWarnOptions(void)
|
||||
{
|
||||
PyObject *warnoptions = PyThreadState_GET()->interp->warnoptions;
|
||||
return (warnoptions != NULL && (PyList_Size(warnoptions) > 0)) ? 1 : 0;
|
||||
}
|
||||
|
||||
static PyObject *xoptions = NULL;
|
||||
|
||||
static PyObject *
|
||||
get_xoptions(void)
|
||||
{
|
||||
PyObject *xoptions = PyThreadState_GET()->interp->xoptions;
|
||||
if (xoptions == NULL || !PyDict_Check(xoptions)) {
|
||||
Py_XDECREF(xoptions);
|
||||
xoptions = PyDict_New();
|
||||
if (xoptions == NULL)
|
||||
return NULL;
|
||||
PyThreadState_GET()->interp->xoptions = xoptions;
|
||||
}
|
||||
return xoptions;
|
||||
}
|
||||
|
@ -2130,17 +2143,15 @@ _PySys_EndInit(PyObject *sysdict)
|
|||
SET_SYS_FROM_STRING_INT_RESULT("base_exec_prefix",
|
||||
PyUnicode_FromWideChar(Py_GetExecPrefix(), -1));
|
||||
|
||||
if (warnoptions == NULL) {
|
||||
warnoptions = PyList_New(0);
|
||||
if (warnoptions == NULL)
|
||||
return -1;
|
||||
}
|
||||
PyObject *warnoptions = get_warnoptions();
|
||||
if (warnoptions == NULL)
|
||||
return -1;
|
||||
SET_SYS_FROM_STRING_BORROW_INT_RESULT("warnoptions", warnoptions);
|
||||
|
||||
SET_SYS_FROM_STRING_INT_RESULT("warnoptions",
|
||||
PyList_GetSlice(warnoptions,
|
||||
0, Py_SIZE(warnoptions)));
|
||||
|
||||
SET_SYS_FROM_STRING_BORROW_INT_RESULT("_xoptions", get_xoptions());
|
||||
PyObject *xoptions = get_xoptions();
|
||||
if (xoptions == NULL)
|
||||
return -1;
|
||||
SET_SYS_FROM_STRING_BORROW_INT_RESULT("_xoptions", xoptions);
|
||||
|
||||
if (PyErr_Occurred())
|
||||
return -1;
|
||||
|
|
|
@ -76,11 +76,6 @@ PyThread_init_thread(void)
|
|||
PyThread__init_thread();
|
||||
}
|
||||
|
||||
/* Support for runtime thread stack size tuning.
|
||||
A value of 0 means using the platform's default stack size
|
||||
or the size specified by the THREAD_STACK_SIZE macro. */
|
||||
static size_t _pythread_stacksize = 0;
|
||||
|
||||
#if defined(_POSIX_THREADS)
|
||||
# define PYTHREAD_NAME "pthread"
|
||||
# include "thread_pthread.h"
|
||||
|
@ -96,7 +91,7 @@ static size_t _pythread_stacksize = 0;
|
|||
size_t
|
||||
PyThread_get_stacksize(void)
|
||||
{
|
||||
return _pythread_stacksize;
|
||||
return PyThreadState_GET()->interp->pythread_stacksize;
|
||||
}
|
||||
|
||||
/* Only platforms defining a THREAD_SET_STACKSIZE() macro
|
||||
|
|
|
@ -189,9 +189,10 @@ PyThread_start_new_thread(void (*func)(void *), void *arg)
|
|||
return PYTHREAD_INVALID_THREAD_ID;
|
||||
obj->func = func;
|
||||
obj->arg = arg;
|
||||
PyThreadState *tstate = PyThreadState_GET();
|
||||
size_t stacksize = tstate ? tstate->interp->pythread_stacksize : 0;
|
||||
hThread = (HANDLE)_beginthreadex(0,
|
||||
Py_SAFE_DOWNCAST(_pythread_stacksize,
|
||||
Py_ssize_t, unsigned int),
|
||||
Py_SAFE_DOWNCAST(stacksize, Py_ssize_t, unsigned int),
|
||||
bootstrap, obj,
|
||||
0, &threadID);
|
||||
if (hThread == 0) {
|
||||
|
@ -332,13 +333,13 @@ _pythread_nt_set_stacksize(size_t size)
|
|||
{
|
||||
/* set to default */
|
||||
if (size == 0) {
|
||||
_pythread_stacksize = 0;
|
||||
PyThreadState_GET()->interp->pythread_stacksize = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* valid range? */
|
||||
if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) {
|
||||
_pythread_stacksize = size;
|
||||
PyThreadState_GET()->interp->pythread_stacksize = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -205,8 +205,9 @@ PyThread_start_new_thread(void (*func)(void *), void *arg)
|
|||
return PYTHREAD_INVALID_THREAD_ID;
|
||||
#endif
|
||||
#if defined(THREAD_STACK_SIZE)
|
||||
tss = (_pythread_stacksize != 0) ? _pythread_stacksize
|
||||
: THREAD_STACK_SIZE;
|
||||
PyThreadState *tstate = PyThreadState_GET();
|
||||
size_t stacksize = tstate ? tstate->interp->pythread_stacksize : 0;
|
||||
tss = (stacksize != 0) ? stacksize : THREAD_STACK_SIZE;
|
||||
if (tss != 0) {
|
||||
if (pthread_attr_setstacksize(&attrs, tss) != 0) {
|
||||
pthread_attr_destroy(&attrs);
|
||||
|
@ -578,7 +579,7 @@ _pythread_pthread_set_stacksize(size_t size)
|
|||
|
||||
/* set to default */
|
||||
if (size == 0) {
|
||||
_pythread_stacksize = 0;
|
||||
PyThreadState_GET()->interp->pythread_stacksize = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -595,7 +596,7 @@ _pythread_pthread_set_stacksize(size_t size)
|
|||
rc = pthread_attr_setstacksize(&attrs, size);
|
||||
pthread_attr_destroy(&attrs);
|
||||
if (rc == 0) {
|
||||
_pythread_stacksize = size;
|
||||
PyThreadState_GET()->interp->pythread_stacksize = size;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue