summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
Diffstat (limited to 'Modules')
-rw-r--r--Modules/signalmodule.c33
1 files changed, 26 insertions, 7 deletions
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index 7982139..108832b 100644
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -244,6 +244,32 @@ trip_signal(int sig_num)
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
@@ -281,13 +307,6 @@ trip_signal(int sig_num)
}
}
}
-
- 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