Finalize vm and turns an exception to exit code. Finalization steps (matching Py_FinalizeEx): 1. Flush stdout and stderr. 1. Handle exit exception and turn it to exit code. 1. Call threading._shutdown() to join non-daemon threads. 1. Run atexit exit functions. 1. Set finalizing flag (suppresses unraisable exceptions from __del__). 1. Forced GC collection pass (collect cycles while builtins are av
(self, exc: Option<PyBaseExceptionRef>)
| 404 | /// |
| 405 | /// Note that calling `finalize` is not necessary by purpose though. |
| 406 | pub fn finalize(self, exc: Option<PyBaseExceptionRef>) -> u32 { |
| 407 | self.enter(|vm| { |
| 408 | let mut flush_status = vm.flush_std(); |
| 409 | |
| 410 | // See if any exception leaked out: |
| 411 | let exit_code = if let Some(exc) = exc { |
| 412 | vm.handle_exit_exception(exc) |
| 413 | } else { |
| 414 | 0 |
| 415 | }; |
| 416 | |
| 417 | // Wait for thread shutdown - call threading._shutdown() if available. |
| 418 | // This waits for all non-daemon threads to complete. |
| 419 | // threading module may not be imported, so ignore import errors. |
| 420 | if let Ok(threading) = vm.import("threading", 0) |
| 421 | && let Ok(shutdown) = threading.get_attr("_shutdown", vm) |
| 422 | && let Err(e) = shutdown.call((), vm) |
| 423 | { |
| 424 | vm.run_unraisable( |
| 425 | e, |
| 426 | Some("Exception ignored in threading shutdown".to_owned()), |
| 427 | threading, |
| 428 | ); |
| 429 | } |
| 430 | |
| 431 | // Run atexit handlers before setting finalizing flag. |
| 432 | // This allows unraisable exceptions from atexit handlers to be reported. |
| 433 | atexit::_run_exitfuncs(vm); |
| 434 | |
| 435 | // Now suppress unraisable exceptions from daemon threads and __del__ |
| 436 | // methods during the rest of shutdown. |
| 437 | vm.state.finalizing.store(true, Ordering::Release); |
| 438 | |
| 439 | // GC pass - collect cycles before module cleanup |
| 440 | crate::gc_state::gc_state().collect_force(2); |
| 441 | |
| 442 | // Module finalization: remove modules from sys.modules, GC collect |
| 443 | // (while builtins is still available for __del__), then clear module dicts. |
| 444 | vm.finalize_modules(); |
| 445 | |
| 446 | if vm.flush_std() < 0 && flush_status == 0 { |
| 447 | flush_status = -1; |
| 448 | } |
| 449 | |
| 450 | // Match CPython: if exit_code is 0 and stdout flush failed, exit 120 |
| 451 | if exit_code == 0 && flush_status < 0 { |
| 452 | EXITCODE_FLUSH_FAILURE |
| 453 | } else { |
| 454 | exit_code |
| 455 | } |
| 456 | }) |
| 457 | } |
| 458 | } |
| 459 | |
| 460 | fn core_frozen_inits() -> impl Iterator<Item = (&'static str, FrozenModule)> { |
no test coverage detected