@@ -244,6 +244,32 @@ trip_signal(int sig_num) |
|
|
244 |
244 |
|
245 |
245 |
Handlers[sig_num].tripped = 1; |
246 |
246 |
|
|
247 |
+if (!is_tripped) { |
|
248 |
+/* Set is_tripped after setting .tripped, as it gets |
|
249 |
+ cleared in PyErr_CheckSignals() before .tripped. */ |
|
250 |
+is_tripped = 1; |
|
251 |
+Py_AddPendingCall(checksignals_witharg, NULL); |
|
252 |
+ } |
|
253 |
+ |
|
254 |
+/* And then write to the wakeup fd *after* setting all the globals and |
|
255 |
+ doing the Py_AddPendingCall. We used to write to the wakeup fd and then |
|
256 |
+ set the flag, but this allowed the following sequence of events |
|
257 |
+ (especially on windows, where trip_signal runs in a new thread): |
|
258 |
+ |
|
259 |
+ - main thread blocks on select([wakeup_fd], ...) |
|
260 |
+ - signal arrives |
|
261 |
+ - trip_signal writes to the wakeup fd |
|
262 |
+ - the main thread wakes up |
|
263 |
+ - the main thread checks the signal flags, sees that they're unset |
|
264 |
+ - the main thread empties the wakeup fd |
|
265 |
+ - the main thread goes back to sleep |
|
266 |
+ - trip_signal sets the flags to request the Python-level signal handler |
|
267 |
+ be run |
|
268 |
+ - the main thread doesn't notice, because it's asleep |
|
269 |
+ |
|
270 |
+ See bpo-30038 for more details. |
|
271 |
+ */ |
|
272 |
+ |
247 |
273 |
#ifdef MS_WINDOWS |
248 |
274 |
fd = Py_SAFE_DOWNCAST(wakeup.fd, SOCKET_T, int); |
249 |
275 |
#else |
@@ -281,13 +307,6 @@ trip_signal(int sig_num) |
|
|
281 |
307 |
} |
282 |
308 |
} |
283 |
309 |
} |
284 |
|
- |
285 |
|
-if (!is_tripped) { |
286 |
|
-/* Set is_tripped after setting .tripped, as it gets |
287 |
|
- cleared in PyErr_CheckSignals() before .tripped. */ |
288 |
|
-is_tripped = 1; |
289 |
|
-Py_AddPendingCall(checksignals_witharg, NULL); |
290 |
|
- } |
291 |
310 |
} |
292 |
311 |
|
293 |
312 |
static void |