Skip to content

Commit 57e836c

Browse files
authored
[3.6] bpo-30808: Use _Py_atomic API for concurrency-sensitive signal state (GH-2417) (#3007)
* Improve signal delivery Avoid using Py_AddPendingCall from signal handler, to avoid calling signal-unsafe functions. * Remove unused function * Improve comments * Use _Py_atomic API for concurrency-sensitive signal state * Add blurb (cherry picked from commit 2c8a5e4)
1 parent 9cd0ef8 commit 57e836c

File tree

2 files changed

+21
-18
lines changed

2 files changed

+21
-18
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Use _Py_atomic API for concurrency-sensitive signal state.

Modules/signalmodule.c

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ static pid_t main_pid;
9393
#endif
9494

9595
static volatile struct {
96-
sig_atomic_t tripped;
96+
_Py_atomic_int tripped;
9797
PyObject *func;
9898
} Handlers[NSIG];
9999

@@ -113,7 +113,7 @@ static volatile sig_atomic_t wakeup_fd = -1;
113113
#endif
114114

115115
/* Speed up sigcheck() when none tripped */
116-
static volatile sig_atomic_t is_tripped = 0;
116+
static _Py_atomic_int is_tripped;
117117

118118
static PyObject *DefaultHandler;
119119
static PyObject *IgnoreHandler;
@@ -240,11 +240,13 @@ trip_signal(int sig_num)
240240
int fd;
241241
Py_ssize_t rc;
242242

243-
Handlers[sig_num].tripped = 1;
243+
_Py_atomic_store_relaxed(&Handlers[sig_num].tripped, 1);
244244

245245
/* Set is_tripped after setting .tripped, as it gets
246246
cleared in PyErr_CheckSignals() before .tripped. */
247-
is_tripped = 1;
247+
_Py_atomic_store(&is_tripped, 1);
248+
249+
/* Notify ceval.c */
248250
_PyEval_SignalReceived();
249251

250252
/* And then write to the wakeup fd *after* setting all the globals and
@@ -465,7 +467,7 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler)
465467
return NULL;
466468
}
467469
old_handler = Handlers[signalnum].func;
468-
Handlers[signalnum].tripped = 0;
470+
_Py_atomic_store_relaxed(&Handlers[signalnum].tripped, 0);
469471
Py_INCREF(handler);
470472
Handlers[signalnum].func = handler;
471473
if (old_handler != NULL)
@@ -1264,11 +1266,11 @@ PyInit__signal(void)
12641266
goto finally;
12651267
Py_INCREF(IntHandler);
12661268

1267-
Handlers[0].tripped = 0;
1269+
_Py_atomic_store_relaxed(&Handlers[0].tripped, 0);
12681270
for (i = 1; i < NSIG; i++) {
12691271
void (*t)(int);
12701272
t = PyOS_getsig(i);
1271-
Handlers[i].tripped = 0;
1273+
_Py_atomic_store_relaxed(&Handlers[i].tripped, 0);
12721274
if (t == SIG_DFL)
12731275
Handlers[i].func = DefaultHandler;
12741276
else if (t == SIG_IGN)
@@ -1492,7 +1494,7 @@ finisignal(void)
14921494

14931495
for (i = 1; i < NSIG; i++) {
14941496
func = Handlers[i].func;
1495-
Handlers[i].tripped = 0;
1497+
_Py_atomic_store_relaxed(&Handlers[i].tripped, 0);
14961498
Handlers[i].func = NULL;
14971499
if (i != SIGINT && func != NULL && func != Py_None &&
14981500
func != DefaultHandler && func != IgnoreHandler)
@@ -1513,7 +1515,7 @@ PyErr_CheckSignals(void)
15131515
int i;
15141516
PyObject *f;
15151517

1516-
if (!is_tripped)
1518+
if (!_Py_atomic_load(&is_tripped))
15171519
return 0;
15181520

15191521
#ifdef WITH_THREAD
@@ -1535,24 +1537,24 @@ PyErr_CheckSignals(void)
15351537
* we receive a signal i after we zero is_tripped and before we
15361538
* check Handlers[i].tripped.
15371539
*/
1538-
is_tripped = 0;
1540+
_Py_atomic_store(&is_tripped, 0);
15391541

15401542
if (!(f = (PyObject *)PyEval_GetFrame()))
15411543
f = Py_None;
15421544

15431545
for (i = 1; i < NSIG; i++) {
1544-
if (Handlers[i].tripped) {
1546+
if (_Py_atomic_load_relaxed(&Handlers[i].tripped)) {
15451547
PyObject *result = NULL;
15461548
PyObject *arglist = Py_BuildValue("(iO)", i, f);
1547-
Handlers[i].tripped = 0;
1549+
_Py_atomic_store_relaxed(&Handlers[i].tripped, 0);
15481550

15491551
if (arglist) {
15501552
result = PyEval_CallObject(Handlers[i].func,
15511553
arglist);
15521554
Py_DECREF(arglist);
15531555
}
15541556
if (!result) {
1555-
is_tripped = 1;
1557+
_Py_atomic_store(&is_tripped, 1);
15561558
return -1;
15571559
}
15581560

@@ -1591,12 +1593,12 @@ PyOS_FiniInterrupts(void)
15911593
int
15921594
PyOS_InterruptOccurred(void)
15931595
{
1594-
if (Handlers[SIGINT].tripped) {
1596+
if (_Py_atomic_load_relaxed(&Handlers[SIGINT].tripped)) {
15951597
#ifdef WITH_THREAD
15961598
if (PyThread_get_thread_ident() != main_thread)
15971599
return 0;
15981600
#endif
1599-
Handlers[SIGINT].tripped = 0;
1601+
_Py_atomic_store_relaxed(&Handlers[SIGINT].tripped, 0);
16001602
return 1;
16011603
}
16021604
return 0;
@@ -1606,11 +1608,11 @@ static void
16061608
_clear_pending_signals(void)
16071609
{
16081610
int i;
1609-
if (!is_tripped)
1611+
if (!_Py_atomic_load(&is_tripped))
16101612
return;
1611-
is_tripped = 0;
1613+
_Py_atomic_store(&is_tripped, 0);
16121614
for (i = 1; i < NSIG; ++i) {
1613-
Handlers[i].tripped = 0;
1615+
_Py_atomic_store_relaxed(&Handlers[i].tripped, 0);
16141616
}
16151617
}
16161618

0 commit comments

Comments
 (0)