Handlers[sig_num].tripped = 1;
+ if (!is_tripped) {
+ /* Set is_tripped after setting .tripped, as it gets
+ cleared in PyErr_CheckSignals() before .tripped. */
+ is_tripped = 1;
+ Py_AddPendingCall(checksignals_witharg, NULL);
+ }
+
+ /* And then write to the wakeup fd *after* setting all the globals and
+ doing the Py_AddPendingCall. We used to write to the wakeup fd and then
+ set the flag, but this allowed the following sequence of events
+ (especially on windows, where trip_signal runs in a new thread):
+
+ - main thread blocks on select([wakeup_fd], ...)
+ - signal arrives
+ - trip_signal writes to the wakeup fd
+ - the main thread wakes up
+ - the main thread checks the signal flags, sees that they're unset
+ - the main thread empties the wakeup fd
+ - the main thread goes back to sleep
+ - trip_signal sets the flags to request the Python-level signal handler
+ be run
+ - the main thread doesn't notice, because it's asleep
+
+ See bpo-30038 for more details.
+ */
+
#ifdef MS_WINDOWS
fd = Py_SAFE_DOWNCAST(wakeup.fd, SOCKET_T, int);
#else
}
}
}
-
- if (!is_tripped) {
- /* Set is_tripped after setting .tripped, as it gets
- cleared in PyErr_CheckSignals() before .tripped. */
- is_tripped = 1;
- Py_AddPendingCall(checksignals_witharg, NULL);
- }
}
static void