diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 0d3b7a3d12..29d420007b 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -122,6 +122,7 @@ typedef struct { PyTypeObject *siginfo_type; } _signal_module_state; +static _PyMutex signal_mutex; Py_LOCAL_INLINE(PyObject *) get_handler(int i) @@ -437,9 +438,11 @@ signal_raise_signal_impl(PyObject *module, int signalnum) { int err; Py_BEGIN_ALLOW_THREADS + _PyMutex_lock(&signal_mutex); _Py_BEGIN_SUPPRESS_IPH err = raise(signalnum); _Py_END_SUPPRESS_IPH + _PyMutex_unlock(&signal_mutex); Py_END_ALLOW_THREADS if (err) { @@ -479,6 +482,7 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler) _signal_module_state *modstate = get_signal_state(module); PyObject *old_handler; void (*func)(int); + PyOS_sighandler_t e; #ifdef MS_WINDOWS /* Validate that signalnum is one of the allowable signals */ switch (signalnum) { @@ -528,7 +532,14 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler) if (_PyErr_CheckSignalsTstate(tstate)) { return NULL; } - if (PyOS_setsig(signalnum, func) == SIG_ERR) { + + // On macOS, sigaction isn't thread-safe with concurrent calls to raise(), + // so we use a mutex to prevent concurrent calls to raise() and sigaction(). + _PyMutex_lock(&signal_mutex); + e = PyOS_setsig(signalnum, func); + _PyMutex_unlock(&signal_mutex); + + if (e == SIG_ERR) { PyErr_SetFromErrno(PyExc_OSError); return NULL; }