Repository navigation
Align signal wakeup errors and delivery with Python 3.15 #9199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
86e4368
5da772c
00fba93
b46dcae
1bb5aa8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -134,48 +134,68 @@ fn trigger_signals(vm: &VirtualMachine) -> PyResult<()> { | |
| } | ||
| let _guard = SignalHandlerGuard; | ||
|
|
||
| #[cfg(all(feature = "host_env", windows))] | ||
| if vm.is_main_thread() && vm.state.is_main_interpreter() { | ||
| // Report before a Python signal handler can raise out of the current | ||
| // error-reporting scope. | ||
| crate::stdlib::_signal::_signal::report_wakeup_send_errors(vm); | ||
| } else if crate::stdlib::_signal::_signal::wakeup_send_errors_pending() { | ||
| // A different interpreter/thread must leave the report for the main one. | ||
| set_triggered(); | ||
| } | ||
|
|
||
| let signal_handlers = vm | ||
| .signal_handlers | ||
| .get() | ||
| .expect("should never fail since we check above"); | ||
| let can_handle_signals = vm.is_main_thread() && vm.state.is_main_interpreter(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Useful? React with 👍 / 👎. |
||
| if can_handle_signals { | ||
| let signal_handlers = vm | ||
| .signal_handlers | ||
| .get() | ||
| .expect("should never fail since we check above"); | ||
|
|
||
| for (signum, trigger) in TRIGGERS.iter().enumerate().skip(1) { | ||
| let triggered = trigger.swap(false, Ordering::Relaxed); | ||
| if !triggered { | ||
| continue; | ||
| } | ||
|
|
||
| for (signum, trigger) in TRIGGERS.iter().enumerate().skip(1) { | ||
| let triggered = trigger.swap(false, Ordering::Relaxed); | ||
| if !triggered { | ||
| continue; | ||
| // SAFETY: TRIGGERS has the same length as the signal_handlers | ||
| let signum = unsafe { SignalNum::new_unchecked(signum as i32) }; | ||
|
|
||
| // Read the handler out and drop the borrow before running it. A | ||
| // handler is free to call signal.signal(), which takes the same cell | ||
| // mutably, and a live read borrow turns that into a panic. | ||
| let handler = signal_handlers.borrow()[signum].clone(); | ||
|
|
||
| if let Some(handler) = handler | ||
| && let Some(callable) = handler.to_callable() | ||
| && let Err(exc) = callable.invoke((signum.as_i32(), vm.ctx.none()), vm) | ||
| { | ||
| // On error, re-schedule a call to trigger_signals() for the | ||
| // remaining signals and the pending wakeup errors. | ||
| set_triggered(); | ||
| return Err(exc); | ||
| } | ||
| } | ||
|
|
||
| // SAFETY: TRIGGERS has the same length as the signal_handlers | ||
| let signum = unsafe { SignalNum::new_unchecked(signum as i32) }; | ||
|
|
||
| // Read the handler out and drop the borrow before running it. A | ||
| // handler is free to call signal.signal(), which takes the same cell | ||
| // mutably, and a live read borrow turns that into a panic. | ||
| let handler = signal_handlers.borrow()[signum].clone(); | ||
|
|
||
| if let Some(handler) = handler | ||
| && let Some(callable) = handler.to_callable() | ||
| { | ||
| callable.invoke((signum.as_i32(), vm.ctx.none()), vm)?; | ||
| } else { | ||
| let os_signals_pending = TRIGGERS | ||
| .iter() | ||
| .skip(1) | ||
| .any(|trigger| trigger.load(Ordering::Relaxed)); | ||
| #[cfg(all(feature = "host_env", any(unix, windows)))] | ||
| let os_signals_pending = | ||
| os_signals_pending || crate::stdlib::_signal::_signal::wakeup_errors_pending(); | ||
| if os_signals_pending { | ||
| // Leave OS signals for the main interpreter's main thread. Re-arm | ||
| // before running VM-local callbacks, which may raise. | ||
| set_triggered(); | ||
| } | ||
| } | ||
|
|
||
| if let Some(signal_rx) = &vm.signal_rx { | ||
| for f in signal_rx.rx.try_iter() { | ||
| f(vm)?; | ||
| if let Err(exc) = f(vm) { | ||
| set_triggered(); | ||
| return Err(exc); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Wakeup fd errors are pending calls that only the main interpreter's | ||
| // main thread runs. | ||
| #[cfg(all(feature = "host_env", any(unix, windows)))] | ||
| if can_handle_signals { | ||
| crate::stdlib::_signal::_signal::report_wakeup_errors(vm); | ||
| } | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding
@force_not_colorizedand its import changes test execution metadata, but this repository explicitly limits test-file edits to adding or removingexpectedFailuremarkers. Revert this synchronization and validate the runtime behavior without modifying the CPython test in this way.AGENTS.md reference: AGENTS.md:L280-L282
Useful? React with 👍 / 👎.