bpo-31370: Remove support for threads-less builds (#3385)

* Remove Setup.config
* Always define WITH_THREAD for compatibility.
This commit is contained in:
Antoine Pitrou 2017-09-07 18:56:24 +02:00 committed by Victor Stinner
parent 1f06a680de
commit a6a4dc816d
135 changed files with 2472 additions and 4377 deletions

View file

@ -87,11 +87,7 @@ static long dxp[256];
#endif
#endif
#ifdef WITH_THREAD
#define GIL_REQUEST _Py_atomic_load_relaxed(&gil_drop_request)
#else
#define GIL_REQUEST 0
#endif
/* This can set eval_breaker to 0 even though gil_drop_request became
1. We believe this is all right because the eval loop will release
@ -103,8 +99,6 @@ static long dxp[256];
_Py_atomic_load_relaxed(&pendingcalls_to_do) | \
pending_async_exc)
#ifdef WITH_THREAD
#define SET_GIL_DROP_REQUEST() \
do { \
_Py_atomic_store_relaxed(&gil_drop_request, 1); \
@ -117,8 +111,6 @@ static long dxp[256];
COMPUTE_EVAL_BREAKER(); \
} while (0)
#endif
/* Pending calls are only modified under pending_lock */
#define SIGNAL_PENDING_CALLS() \
do { \
@ -151,8 +143,6 @@ static _Py_atomic_int pendingcalls_to_do = {0};
Guarded by the GIL. */
static int pending_async_exc = 0;
#ifdef WITH_THREAD
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
@ -256,8 +246,6 @@ PyEval_ReInitThreads(void)
_PyThreadState_DeleteExcept(current_tstate);
}
#endif /* WITH_THREAD */
/* This function is used to signal that async exceptions are waiting to be
raised, therefore it is also useful in non-threaded builds. */
@ -277,10 +265,8 @@ PyEval_SaveThread(void)
PyThreadState *tstate = PyThreadState_Swap(NULL);
if (tstate == NULL)
Py_FatalError("PyEval_SaveThread: NULL tstate");
#ifdef WITH_THREAD
if (gil_created())
drop_gil(tstate);
#endif
return tstate;
}
@ -289,7 +275,6 @@ PyEval_RestoreThread(PyThreadState *tstate)
{
if (tstate == NULL)
Py_FatalError("PyEval_RestoreThread: NULL tstate");
#ifdef WITH_THREAD
if (gil_created()) {
int err = errno;
take_gil(tstate);
@ -301,7 +286,6 @@ PyEval_RestoreThread(PyThreadState *tstate)
}
errno = err;
}
#endif
PyThreadState_Swap(tstate);
}
@ -320,14 +304,12 @@ PyEval_RestoreThread(PyThreadState *tstate)
Note that because registry may occur from within signal handlers,
or other asynchronous events, calling malloc() is unsafe!
#ifdef WITH_THREAD
Any thread can schedule pending calls, but only the main thread
will execute them.
There is no facility to schedule calls to a particular thread, but
that should be easy to change, should that ever be required. In
that case, the static variables here should go into the python
threadstate.
#endif
*/
void
@ -339,9 +321,7 @@ _PyEval_SignalReceived(void)
SIGNAL_PENDING_CALLS();
}
#ifdef WITH_THREAD
/* The WITH_THREAD implementation is thread-safe. It allows
/* This implementation is thread-safe. It allows
scheduling to be made from any thread, and even from an executing
callback.
*/
@ -464,106 +444,6 @@ error:
return -1;
}
#else /* if ! defined WITH_THREAD */
/*
WARNING! ASYNCHRONOUSLY EXECUTING CODE!
This code is used for signal handling in python that isn't built
with WITH_THREAD.
Don't use this implementation when Py_AddPendingCalls() can happen
on a different thread!
There are two possible race conditions:
(1) nested asynchronous calls to Py_AddPendingCall()
(2) AddPendingCall() calls made while pending calls are being processed.
(1) is very unlikely because typically signal delivery
is blocked during signal handling. So it should be impossible.
(2) is a real possibility.
The current code is safe against (2), but not against (1).
The safety against (2) is derived from the fact that only one
thread is present, interrupted by signals, and that the critical
section is protected with the "busy" variable. On Windows, which
delivers SIGINT on a system thread, this does not hold and therefore
Windows really shouldn't use this version.
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)
{
static volatile int busy = 0;
int i, j;
/* XXX Begin critical section */
if (busy)
return -1;
busy = 1;
i = pendinglast;
j = (i + 1) % NPENDINGCALLS;
if (j == pendingfirst) {
busy = 0;
return -1; /* Queue full */
}
pendingcalls[i].func = func;
pendingcalls[i].arg = arg;
pendinglast = j;
SIGNAL_PENDING_CALLS();
busy = 0;
/* XXX End critical section */
return 0;
}
int
Py_MakePendingCalls(void)
{
static int busy = 0;
if (busy)
return 0;
busy = 1;
/* unsignal before starting to call callbacks, so that any callback
added in-between re-signals */
UNSIGNAL_PENDING_CALLS();
/* Python signal handler doesn't really queue a callback: it only signals
that a signal was received, see _PyEval_SignalReceived(). */
if (PyErr_CheckSignals() < 0) {
goto error;
}
for (;;) {
int i;
int (*func)(void *);
void *arg;
i = pendingfirst;
if (i == pendinglast)
break; /* Queue empty */
func = pendingcalls[i].func;
arg = pendingcalls[i].arg;
pendingfirst = (i + 1) % NPENDINGCALLS;
if (func(arg) < 0) {
goto error;
}
}
busy = 0;
return 0;
error:
busy = 0;
SIGNAL_PENDING_CALLS(); /* We're not done yet */
return -1;
}
#endif /* WITH_THREAD */
/* The interpreter's recursion limit */
@ -1101,7 +981,6 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
if (Py_MakePendingCalls() < 0)
goto error;
}
#ifdef WITH_THREAD
if (_Py_atomic_load_relaxed(&gil_drop_request)) {
/* Give another thread a chance */
if (PyThreadState_Swap(NULL) != tstate)
@ -1121,7 +1000,6 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
if (PyThreadState_Swap(tstate) != NULL)
Py_FatalError("ceval: orphan tstate");
}
#endif
/* Check for asynchronous exceptions. */
if (tstate->async_exc != NULL) {
PyObject *exc = tstate->async_exc;

View file

@ -680,9 +680,7 @@ _Py_fstat(int fd, struct _Py_stat_struct *status)
{
int res;
#ifdef WITH_THREAD
assert(PyGILState_Check());
#endif
Py_BEGIN_ALLOW_THREADS
res = _Py_fstat_noraise(fd, status);
@ -999,10 +997,8 @@ _Py_open_impl(const char *pathname, int flags, int gil_held)
int
_Py_open(const char *pathname, int flags)
{
#ifdef WITH_THREAD
/* _Py_open() must be called with the GIL held. */
assert(PyGILState_Check());
#endif
return _Py_open_impl(pathname, flags, 1);
}
@ -1095,9 +1091,7 @@ _Py_fopen_obj(PyObject *path, const char *mode)
wchar_t wmode[10];
int usize;
#ifdef WITH_THREAD
assert(PyGILState_Check());
#endif
if (!PyUnicode_Check(path)) {
PyErr_Format(PyExc_TypeError,
@ -1125,9 +1119,7 @@ _Py_fopen_obj(PyObject *path, const char *mode)
PyObject *bytes;
char *path_bytes;
#ifdef WITH_THREAD
assert(PyGILState_Check());
#endif
if (!PyUnicode_FSConverter(path, &bytes))
return NULL;
@ -1177,9 +1169,7 @@ _Py_read(int fd, void *buf, size_t count)
int err;
int async_err = 0;
#ifdef WITH_THREAD
assert(PyGILState_Check());
#endif
/* _Py_read() must not be called with an exception set, otherwise the
* caller may think that read() was interrupted by a signal and the signal
@ -1318,9 +1308,7 @@ _Py_write_impl(int fd, const void *buf, size_t count, int gil_held)
Py_ssize_t
_Py_write(int fd, const void *buf, size_t count)
{
#ifdef WITH_THREAD
assert(PyGILState_Check());
#endif
/* _Py_write() must not be called with an exception set, otherwise the
* caller may think that write() was interrupted by a signal and the signal
@ -1471,9 +1459,7 @@ _Py_dup(int fd)
DWORD ftype;
#endif
#ifdef WITH_THREAD
assert(PyGILState_Check());
#endif
#ifdef MS_WINDOWS
_Py_BEGIN_SUPPRESS_IPH

View file

@ -142,8 +142,6 @@ _PyImportZip_Init(void)
in different threads to return with a partially loaded module.
These calls are serialized by the global interpreter lock. */
#ifdef WITH_THREAD
#include "pythread.h"
static PyThread_type_lock import_lock = 0;
@ -224,8 +222,6 @@ _PyImport_ReInitLock(void)
}
}
#endif
/*[clinic input]
_imp.lock_held
@ -238,11 +234,7 @@ static PyObject *
_imp_lock_held_impl(PyObject *module)
/*[clinic end generated code: output=8b89384b5e1963fc input=9b088f9b217d9bdf]*/
{
#ifdef WITH_THREAD
return PyBool_FromLong(import_lock_thread != PYTHREAD_INVALID_THREAD_ID);
#else
Py_RETURN_FALSE;
#endif
}
/*[clinic input]
@ -258,9 +250,7 @@ static PyObject *
_imp_acquire_lock_impl(PyObject *module)
/*[clinic end generated code: output=1aff58cb0ee1b026 input=4a2d4381866d5fdc]*/
{
#ifdef WITH_THREAD
_PyImport_AcquireLock();
#endif
Py_RETURN_NONE;
}
@ -276,13 +266,11 @@ static PyObject *
_imp_release_lock_impl(PyObject *module)
/*[clinic end generated code: output=7faab6d0be178b0a input=934fb11516dd778b]*/
{
#ifdef WITH_THREAD
if (_PyImport_ReleaseLock() < 0) {
PyErr_SetString(PyExc_RuntimeError,
"not holding the import lock");
return NULL;
}
#endif
Py_RETURN_NONE;
}
@ -290,12 +278,10 @@ void
_PyImport_Fini(void)
{
Py_CLEAR(extensions);
#ifdef WITH_THREAD
if (import_lock != NULL) {
PyThread_free_lock(import_lock);
import_lock = NULL;
}
#endif
}
/* Helper for sys */

View file

@ -1,7 +1,7 @@
#include "Python.h"
#if defined(__sgi) && defined(WITH_THREAD) && !defined(_SGI_MP_SOURCE)
#if defined(__sgi) && !defined(_SGI_MP_SOURCE)
#define _SGI_MP_SOURCE
#endif

View file

@ -72,10 +72,8 @@ extern int _PyTraceMalloc_Init(void);
extern int _PyTraceMalloc_Fini(void);
extern void _Py_ReadyTypes(void);
#ifdef WITH_THREAD
extern void _PyGILState_Init(PyInterpreterState *, PyThreadState *);
extern void _PyGILState_Fini(void);
#endif /* WITH_THREAD */
/* Global configuration variable declarations are in pydebug.h */
/* XXX (ncoghlan): move those declarations to pylifecycle.h? */
@ -618,7 +616,6 @@ void _Py_InitializeCore(const _PyCoreConfig *config)
Py_FatalError("Py_InitializeCore: can't make first thread");
(void) PyThreadState_Swap(tstate);
#ifdef WITH_THREAD
/* We can't call _PyEval_FiniThreads() in Py_FinalizeEx because
destroying the GIL might fail when it is being referenced from
another running thread (see issue #9901).
@ -627,7 +624,6 @@ void _Py_InitializeCore(const _PyCoreConfig *config)
_PyEval_FiniThreads();
/* Auto-thread-state API */
_PyGILState_Init(interp, tstate);
#endif /* WITH_THREAD */
_Py_ReadyTypes();
@ -1084,9 +1080,7 @@ Py_FinalizeEx(void)
PyGrammar_RemoveAccelerators(&_PyParser_Grammar);
/* Cleanup auto-thread-state */
#ifdef WITH_THREAD
_PyGILState_Fini();
#endif /* WITH_THREAD */
/* Delete current thread. After this, many C API calls become crashy. */
PyThreadState_Swap(NULL);
@ -1142,11 +1136,9 @@ Py_NewInterpreter(void)
if (!_Py_Initialized)
Py_FatalError("Py_NewInterpreter: call Py_Initialize first");
#ifdef WITH_THREAD
/* Issue #10915, #15751: The GIL API doesn't work with multiple
interpreters: disable PyGILState_Check(). */
_PyGILState_check_enabled = 0;
#endif
interp = PyInterpreterState_New();
if (interp == NULL)
@ -1850,9 +1842,7 @@ exit:
/* Clean up and exit */
#ifdef WITH_THREAD
# include "pythread.h"
#endif
static void (*pyexitfunc)(void) = NULL;
/* For the atexit module. */
@ -1878,7 +1868,6 @@ call_py_exitfuncs(void)
static void
wait_for_thread_shutdown(void)
{
#ifdef WITH_THREAD
_Py_IDENTIFIER(_shutdown);
PyObject *result;
PyObject *threading = _PyImport_GetModuleId(&PyId_threading);
@ -1896,7 +1885,6 @@ wait_for_thread_shutdown(void)
Py_DECREF(result);
}
Py_DECREF(threading);
#endif
}
#define NEXITFUNCS 32

View file

@ -36,7 +36,6 @@ extern "C" {
int _PyGILState_check_enabled = 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()))
@ -49,11 +48,6 @@ static PyThread_type_lock head_mutex = NULL; /* Protects interp->tstate_head */
/* TODO: Given interp_main, it may be possible to kill this ref */
static PyInterpreterState *autoInterpreterState = NULL;
static int autoTLSkey = -1;
#else
#define HEAD_INIT() /* Nothing */
#define HEAD_LOCK() /* Nothing */
#define HEAD_UNLOCK() /* Nothing */
#endif
static PyInterpreterState *interp_head = NULL;
static PyInterpreterState *interp_main = NULL;
@ -63,9 +57,7 @@ static PyInterpreterState *interp_main = NULL;
_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
@ -93,10 +85,8 @@ PyInterpreterState_New(void)
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;
@ -206,12 +196,10 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
}
HEAD_UNLOCK();
PyMem_RawFree(interp);
#ifdef WITH_THREAD
if (interp_head == NULL && head_mutex != NULL) {
PyThread_free_lock(head_mutex);
head_mutex = NULL;
}
#endif
}
@ -252,11 +240,7 @@ new_threadstate(PyInterpreterState *interp, int init)
tstate->use_tracing = 0;
tstate->gilstate_counter = 0;
tstate->async_exc = NULL;
#ifdef WITH_THREAD
tstate->thread_id = PyThread_get_thread_ident();
#else
tstate->thread_id = 0;
#endif
tstate->dict = NULL;
@ -314,9 +298,7 @@ _PyThreadState_Prealloc(PyInterpreterState *interp)
void
_PyThreadState_Init(PyThreadState *tstate)
{
#ifdef WITH_THREAD
_PyGILState_NoteThreadState(tstate);
#endif
}
PyObject*
@ -498,15 +480,12 @@ 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);
#endif /* WITH_THREAD */
tstate_delete_common(tstate);
}
#ifdef WITH_THREAD
void
PyThreadState_DeleteCurrent()
{
@ -520,7 +499,6 @@ PyThreadState_DeleteCurrent()
SET_TSTATE(NULL);
PyEval_ReleaseLock();
}
#endif /* WITH_THREAD */
/*
@ -588,7 +566,7 @@ PyThreadState_Swap(PyThreadState *newts)
to be used for a thread. Check this the best we can in debug
builds.
*/
#if defined(Py_DEBUG) && defined(WITH_THREAD)
#if defined(Py_DEBUG)
if (newts) {
/* This can be called from PyEval_RestoreThread(). Similar
to it, we need to ensure errno doesn't change.
@ -749,7 +727,6 @@ _PyThread_CurrentFrames(void)
}
/* Python "auto thread state" API. */
#ifdef WITH_THREAD
/* Keep this as a static, as it is not reliable! It can only
ever be compared to the state for the *current* thread.
@ -805,10 +782,8 @@ _PyGILState_Fini(void)
void
_PyGILState_Reinit(void)
{
#ifdef WITH_THREAD
head_mutex = NULL;
HEAD_INIT();
#endif
PyThreadState *tstate = PyGILState_GetThisThreadState();
PyThread_delete_key(autoTLSkey);
if ((autoTLSkey = PyThread_create_key()) == -1)
@ -960,10 +935,7 @@ PyGILState_Release(PyGILState_STATE oldstate)
PyEval_SaveThread();
}
#endif /* WITH_THREAD */
#ifdef __cplusplus
}
#endif

View file

@ -556,7 +556,6 @@ PyDoc_STRVAR(getcheckinterval_doc,
"getcheckinterval() -> current check interval; see setcheckinterval()."
);
#ifdef WITH_THREAD
static PyObject *
sys_setswitchinterval(PyObject *self, PyObject *args)
{
@ -594,8 +593,6 @@ PyDoc_STRVAR(getswitchinterval_doc,
"getswitchinterval() -> current thread switch interval; see setswitchinterval()."
);
#endif /* WITH_THREAD */
static PyObject *
sys_setrecursionlimit(PyObject *self, PyObject *args)
{
@ -1418,12 +1415,10 @@ static PyMethodDef sys_methods[] = {
setcheckinterval_doc},
{"getcheckinterval", sys_getcheckinterval, METH_NOARGS,
getcheckinterval_doc},
#ifdef WITH_THREAD
{"setswitchinterval", sys_setswitchinterval, METH_VARARGS,
setswitchinterval_doc},
{"getswitchinterval", sys_getswitchinterval, METH_NOARGS,
getswitchinterval_doc},
#endif
#ifdef HAVE_DLOPEN
{"setdlopenflags", sys_setdlopenflags, METH_VARARGS,
setdlopenflags_doc},
@ -2055,9 +2050,7 @@ _PySys_BeginInit(void)
PyUnicode_FromString("legacy"));
#endif
#ifdef WITH_THREAD
SET_SYS_FROM_STRING("thread_info", PyThread_GetInfo());
#endif
/* initialize asyncgen_hooks */
if (AsyncGenHooksType.tp_name == NULL) {

View file

@ -749,7 +749,6 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
PyThreadState *tstate;
unsigned int nthreads;
#ifdef WITH_THREAD
if (current_tstate == NULL) {
/* _Py_DumpTracebackThreads() is called from signal handlers by
faulthandler.
@ -777,21 +776,6 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
interp = current_tstate->interp;
}
}
#else
if (current_tstate == NULL) {
/* Call _PyThreadState_UncheckedGet() instead of PyThreadState_Get()
to not fail with a fatal error if the thread state is NULL. */
current_tstate = _PyThreadState_UncheckedGet();
}
if (interp == NULL) {
if (current_tstate == NULL) {
/* We need the interpreter state to get Python threads */
return "unable to get the interpreter state";
}
interp = current_tstate->interp;
}
#endif
assert(interp != NULL);
/* Get the current interpreter from the current thread */