@@ -122,6 +122,7 @@ typedef struct {
122
122
PyTypeObject * siginfo_type ;
123
123
} _signal_module_state ;
124
124
125
+ static _PyMutex signal_mutex ;
125
126
126
127
Py_LOCAL_INLINE (PyObject * )
127
128
get_handler (int i )
@@ -437,9 +438,11 @@ signal_raise_signal_impl(PyObject *module, int signalnum)
437
438
{
438
439
int err ;
439
440
Py_BEGIN_ALLOW_THREADS
441
+ _PyMutex_lock (& signal_mutex );
440
442
_Py_BEGIN_SUPPRESS_IPH
441
443
err = raise (signalnum );
442
444
_Py_END_SUPPRESS_IPH
445
+ _PyMutex_unlock (& signal_mutex );
443
446
Py_END_ALLOW_THREADS
444
447
445
448
if (err ) {
@@ -479,6 +482,7 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler)
479
482
_signal_module_state * modstate = get_signal_state (module );
480
483
PyObject * old_handler ;
481
484
void (* func )(int );
485
+ PyOS_sighandler_t e ;
482
486
#ifdef MS_WINDOWS
483
487
/* Validate that signalnum is one of the allowable signals */
484
488
switch (signalnum ) {
@@ -528,7 +532,14 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler)
528
532
if (_PyErr_CheckSignalsTstate (tstate )) {
529
533
return NULL ;
530
534
}
531
- if (PyOS_setsig (signalnum , func ) == SIG_ERR ) {
535
+
536
+ // On macOS, sigaction isn't thread-safe with concurrent calls to raise(),
537
+ // so we use a mutex to prevent concurrent calls to raise() and sigaction().
538
+ _PyMutex_lock (& signal_mutex );
539
+ e = PyOS_setsig (signalnum , func );
540
+ _PyMutex_unlock (& signal_mutex );
541
+
542
+ if (e == SIG_ERR ) {
532
543
PyErr_SetFromErrno (PyExc_OSError );
533
544
return NULL ;
534
545
}
0 commit comments