Skip to content

Commit cdf4c6f

Browse files
committed
fix finalizing and atexit timing
1 parent 6dd5e36 commit cdf4c6f

File tree

3 files changed

+26
-8
lines changed

3 files changed

+26
-8
lines changed

Lib/test/test_warnings/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -834,8 +834,6 @@ class CWCmdLineTests(WCmdLineTests, unittest.TestCase):
834834
class PyWCmdLineTests(WCmdLineTests, unittest.TestCase):
835835
module = py_warnings
836836

837-
# TODO: RUSTPYTHON
838-
@unittest.expectedFailure
839837
def test_improper_option(self):
840838
# Same as above, but check that the message is printed out when
841839
# the interpreter is executed. This also checks that options are

crates/vm/src/vm/interpreter.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,11 @@ impl Interpreter {
110110

111111
/// Finalize vm and turns an exception to exit code.
112112
///
113-
/// Finalization steps including 5 steps:
113+
/// Finalization steps (matching Py_FinalizeEx):
114114
/// 1. Flush stdout and stderr.
115115
/// 1. Handle exit exception and turn it to exit code.
116-
/// 1. Wait for non-daemon threads (threading._shutdown).
116+
/// 1. Wait for thread shutdown (call threading._shutdown).
117+
/// 1. Mark vm as finalizing.
117118
/// 1. Run atexit exit functions.
118119
/// 1. Mark vm as finalized.
119120
///
@@ -129,13 +130,21 @@ impl Interpreter {
129130
0
130131
};
131132

132-
// Wait for non-daemon threads (wait_for_thread_shutdown)
133-
wait_for_thread_shutdown(vm);
134-
135-
atexit::_run_exitfuncs(vm);
133+
// Wait for thread shutdown - call threading._shutdown() if available.
134+
// This waits for all non-daemon threads to complete.
135+
// threading module may not be imported, so ignore import errors.
136+
if let Ok(threading) = vm.import("threading", 0)
137+
&& let Ok(shutdown) = threading.get_attr("_shutdown", vm)
138+
{
139+
let _ = shutdown.call((), vm);
140+
}
136141

142+
// Mark as finalizing AFTER thread shutdown
137143
vm.state.finalizing.store(true, Ordering::Release);
138144

145+
// Run atexit exit functions
146+
atexit::_run_exitfuncs(vm);
147+
139148
vm.flush_std();
140149

141150
exit_code

crates/vm/src/vm/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,17 @@ impl VirtualMachine {
550550

551551
#[cold]
552552
pub fn run_unraisable(&self, e: PyBaseExceptionRef, msg: Option<String>, object: PyObjectRef) {
553+
// Suppress unraisable exceptions during interpreter finalization.
554+
// when daemon thread exceptions and
555+
// __del__ errors are silently ignored during shutdown.
556+
if self
557+
.state
558+
.finalizing
559+
.load(std::sync::atomic::Ordering::Acquire)
560+
{
561+
return;
562+
}
563+
553564
let sys_module = self.import("sys", 0).unwrap();
554565
let unraisablehook = sys_module.get_attr("unraisablehook", self).unwrap();
555566

0 commit comments

Comments
 (0)