From 5b30662741afdb59865ecefe3026fcaf1f853c7d Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sun, 11 Apr 2021 07:05:39 +0200 Subject: [PATCH 1/6] Rework `at_exit` to `cleanup` --- library/std/src/io/mod.rs | 4 ++ library/std/src/io/stdio.rs | 41 ++++++------- library/std/src/process.rs | 2 +- library/std/src/rt.rs | 28 ++------- library/std/src/sys/hermit/mod.rs | 7 ++- library/std/src/sys/sgx/mod.rs | 7 ++- library/std/src/sys/unix/mod.rs | 15 +++-- library/std/src/sys/unsupported/common.rs | 7 ++- library/std/src/sys/windows/mod.rs | 9 ++- library/std/src/sys/windows/net.rs | 12 ++-- library/std/src/sys_common/at_exit_imp.rs | 74 ----------------------- library/std/src/sys_common/mod.rs | 55 +---------------- library/std/src/sys_common/rt.rs | 69 +++++++++++++++++++++ 13 files changed, 134 insertions(+), 196 deletions(-) delete mode 100644 library/std/src/sys_common/at_exit_imp.rs create mode 100644 library/std/src/sys_common/rt.rs diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 9625984195b..94c70c4f267 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -293,6 +293,10 @@ mod util; const DEFAULT_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; +pub(crate) fn cleanup() { + stdio::cleanup() +} + struct Guard<'a> { buf: &'a mut Vec, len: usize, diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index c2e0b24ba83..2b0d2b7e0be 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -13,7 +13,6 @@ use crate::pin::Pin; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{Arc, Mutex, MutexGuard}; use crate::sys::stdio; -use crate::sys_common; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; type LocalStream = Arc>>; @@ -508,6 +507,8 @@ pub struct StdoutLock<'a> { inner: ReentrantMutexGuard<'a, RefCell>>, } +static STDOUT: SyncOnceCell>>> = SyncOnceCell::new(); + /// Constructs a new handle to the standard output of the current process. /// /// Each handle returned is a reference to a shared global buffer whose access @@ -549,34 +550,28 @@ pub struct StdoutLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { - static INSTANCE: SyncOnceCell>>> = - SyncOnceCell::new(); - - fn cleanup() { - if let Some(instance) = INSTANCE.get() { - // Flush the data and disable buffering during shutdown - // by replacing the line writer by one with zero - // buffering capacity. - // We use try_lock() instead of lock(), because someone - // might have leaked a StdoutLock, which would - // otherwise cause a deadlock here. - if let Some(lock) = Pin::static_ref(instance).try_lock() { - *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); - } - } - } - Stdout { - inner: Pin::static_ref(&INSTANCE).get_or_init_pin( - || unsafe { - let _ = sys_common::at_exit(cleanup); - ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))) - }, + inner: Pin::static_ref(&STDOUT).get_or_init_pin( + || unsafe { ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))) }, |mutex| unsafe { mutex.init() }, ), } } +pub fn cleanup() { + if let Some(instance) = STDOUT.get() { + // Flush the data and disable buffering during shutdown + // by replacing the line writer by one with zero + // buffering capacity. + // We use try_lock() instead of lock(), because someone + // might have leaked a StdoutLock, which would + // otherwise cause a deadlock here. + if let Some(lock) = Pin::static_ref(instance).try_lock() { + *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); + } + } +} + impl Stdout { /// Locks this handle to the standard output stream, returning a writable /// guard. diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 931b3b600a3..b45c620fd0b 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1749,7 +1749,7 @@ impl Child { /// [platform-specific behavior]: #platform-specific-behavior #[stable(feature = "rust1", since = "1.0.0")] pub fn exit(code: i32) -> ! { - crate::sys_common::cleanup(); + crate::sys_common::rt::cleanup(); crate::sys::os::exit(code) } diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 45af9f68a0f..ce6e318c9de 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -26,33 +26,13 @@ fn lang_start_internal( argv: *const *const u8, ) -> isize { use crate::panic; - use crate::sys; use crate::sys_common; - use crate::sys_common::thread_info; - use crate::thread::Thread; - sys::init(); + sys_common::rt::init(argc, argv); + let exit_code = panic::catch_unwind(main); + sys_common::rt::cleanup(); - unsafe { - let main_guard = sys::thread::guard::init(); - sys::stack_overflow::init(); - - // Next, set up the current Thread with the guard information we just - // created. Note that this isn't necessary in general for new threads, - // but we just do this to name the main thread and to give it correct - // info about the stack bounds. - let thread = Thread::new(Some("main".to_owned())); - thread_info::set(main_guard, thread); - - // Store our args if necessary in a squirreled away location - sys::args::init(argc, argv); - - // Let's run some code! - let exit_code = panic::catch_unwind(main); - - sys_common::cleanup(); - exit_code.unwrap_or(101) as isize - } + exit_code.unwrap_or(101) as isize } #[cfg(not(test))] diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs index 56497162c03..ebfc39bdef3 100644 --- a/library/std/src/sys/hermit/mod.rs +++ b/library/std/src/sys/hermit/mod.rs @@ -96,11 +96,14 @@ pub extern "C" fn __rust_abort() { abort_internal(); } -#[cfg(not(test))] -pub fn init() { +// SAFETY: must be called only once during runtime initialization. +pub unsafe fn init() { let _ = net::init(); } +// SAFETY: must be called only once during runtime cleanup. +pub unsafe fn cleanup() {} + #[cfg(not(test))] #[no_mangle] pub unsafe extern "C" fn runtime_entry( diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs index d6a56830733..9681336631f 100644 --- a/library/std/src/sys/sgx/mod.rs +++ b/library/std/src/sys/sgx/mod.rs @@ -40,8 +40,11 @@ pub mod time; pub use crate::sys_common::os_str_bytes as os_str; -#[cfg(not(test))] -pub fn init() {} +// SAFETY: must be called only once during runtime initialization. +pub unsafe fn init() {} + +// SAFETY: must be called only once during runtime cleanup. +pub unsafe fn cleanup() {} /// This function is used to implement functionality that simply doesn't exist. /// Programs relying on this functionality will need to deal with the error. diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 1316835a89d..3b86d373796 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -44,14 +44,12 @@ pub mod time; pub use crate::sys_common::os_str_bytes as os_str; -#[cfg(not(test))] -pub fn init() { +// SAFETY: must be called only once during runtime initialization. +pub unsafe fn init() { // The standard streams might be closed on application startup. To prevent // std::io::{stdin, stdout,stderr} objects from using other unrelated file // resources opened later, we reopen standards streams when they are closed. - unsafe { - sanitize_standard_fds(); - } + sanitize_standard_fds(); // By default, some platforms will send a *signal* when an EPIPE error // would otherwise be delivered. This runtime doesn't install a SIGPIPE @@ -60,9 +58,7 @@ pub fn init() { // // Hence, we set SIGPIPE to ignore when the program starts up in order // to prevent this problem. - unsafe { - reset_sigpipe(); - } + reset_sigpipe(); cfg_if::cfg_if! { if #[cfg(miri)] { @@ -129,6 +125,9 @@ pub fn init() { unsafe fn reset_sigpipe() {} } +// SAFETY: must be called only once during runtime cleanup. +pub unsafe fn cleanup() {} + #[cfg(target_os = "android")] pub use crate::sys::android::signal; #[cfg(not(target_os = "android"))] diff --git a/library/std/src/sys/unsupported/common.rs b/library/std/src/sys/unsupported/common.rs index 0ef84c84ee8..5ab22bd3ff4 100644 --- a/library/std/src/sys/unsupported/common.rs +++ b/library/std/src/sys/unsupported/common.rs @@ -10,8 +10,11 @@ pub use crate::sys_common::os_str_bytes as os_str; // spec definition? use crate::os::raw::c_char; -#[cfg(not(test))] -pub fn init() {} +// SAFETY: must be called only once during runtime initialization. +pub unsafe fn init() {} + +// SAFETY: must be called only once during runtime cleanup. +pub unsafe fn cleanup() {} pub fn unsupported() -> std_io::Result { Err(unsupported_err()) diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index 973301af2d9..4563bca93b3 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -49,8 +49,13 @@ cfg_if::cfg_if! { } } -#[cfg(not(test))] -pub fn init() {} +// SAFETY: must be called only once during runtime initialization. +pub unsafe fn init() {} + +// SAFETY: must be called only once during runtime cleanup. +pub unsafe fn cleanup() { + net::cleanup(); +} pub fn decode_error_kind(errno: i32) -> ErrorKind { match errno as c::DWORD { diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index ad04afc0b6d..f577169e0e0 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -9,7 +9,7 @@ use crate::sync::Once; use crate::sys; use crate::sys::c; use crate::sys_common::net; -use crate::sys_common::{self, AsInner, FromInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; use libc::{c_int, c_long, c_ulong, c_void}; @@ -38,13 +38,15 @@ pub fn init() { &mut data, ); assert_eq!(ret, 0); - - let _ = sys_common::at_exit(|| { - c::WSACleanup(); - }); }); } +pub fn cleanup() { + unsafe { + c::WSACleanup(); + } +} + /// Returns the last error from the Windows socket interface. fn last_error() -> io::Error { io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() }) diff --git a/library/std/src/sys_common/at_exit_imp.rs b/library/std/src/sys_common/at_exit_imp.rs deleted file mode 100644 index 90d5d3a7898..00000000000 --- a/library/std/src/sys_common/at_exit_imp.rs +++ /dev/null @@ -1,74 +0,0 @@ -//! Implementation of running at_exit routines -//! -//! Documentation can be found on the `rt::at_exit` function. - -use crate::mem; -use crate::ptr; -use crate::sys_common::mutex::StaticMutex; - -type Queue = Vec>; - -// NB these are specifically not types from `std::sync` as they currently rely -// on poisoning and this module needs to operate at a lower level than requiring -// the thread infrastructure to be in place (useful on the borders of -// initialization/destruction). -// It is UB to attempt to acquire this mutex reentrantly! -static LOCK: StaticMutex = StaticMutex::new(); -static mut QUEUE: *mut Queue = ptr::null_mut(); - -const DONE: *mut Queue = 1_usize as *mut _; - -// The maximum number of times the cleanup routines will be run. While running -// the at_exit closures new ones may be registered, and this count is the number -// of times the new closures will be allowed to register successfully. After -// this number of iterations all new registrations will return `false`. -const ITERS: usize = 10; - -unsafe fn init() -> bool { - if QUEUE.is_null() { - let state: Box = box Vec::new(); - QUEUE = Box::into_raw(state); - } else if QUEUE == DONE { - // can't re-init after a cleanup - return false; - } - - true -} - -pub fn cleanup() { - for i in 1..=ITERS { - unsafe { - let queue = { - let _guard = LOCK.lock(); - mem::replace(&mut QUEUE, if i == ITERS { DONE } else { ptr::null_mut() }) - }; - - // make sure we're not recursively cleaning up - assert!(queue != DONE); - - // If we never called init, not need to cleanup! - if !queue.is_null() { - let queue: Box = Box::from_raw(queue); - for to_run in *queue { - // We are not holding any lock, so reentrancy is fine. - to_run(); - } - } - } - } -} - -pub fn push(f: Box) -> bool { - unsafe { - let _guard = LOCK.lock(); - if init() { - // We are just moving `f` around, not calling it. - // There is no possibility of reentrancy here. - (*QUEUE).push(f); - true - } else { - false - } - } -} diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 23a3a0e907d..449ce509d25 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -20,35 +20,6 @@ #[cfg(test)] mod tests; -use crate::sync::Once; -use crate::sys; - -macro_rules! rtabort { - ($($t:tt)*) => (crate::sys_common::util::abort(format_args!($($t)*))) -} - -macro_rules! rtassert { - ($e:expr) => { - if !$e { - rtabort!(concat!("assertion failed: ", stringify!($e))); - } - }; -} - -#[allow(unused_macros)] // not used on all platforms -macro_rules! rtunwrap { - ($ok:ident, $e:expr) => { - match $e { - $ok(v) => v, - ref err => { - let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug - rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err) - } - } - }; -} - -pub mod at_exit_imp; pub mod backtrace; pub mod bytestring; pub mod condvar; @@ -62,6 +33,8 @@ pub mod os_str_bytes; pub mod poison; pub mod process; pub mod remutex; +#[macro_use] +pub mod rt; pub mod rwlock; pub mod thread; pub mod thread_info; @@ -109,30 +82,6 @@ pub trait FromInner { fn from_inner(inner: Inner) -> Self; } -/// Enqueues a procedure to run when the main thread exits. -/// -/// Currently these closures are only run once the main *Rust* thread exits. -/// Once the `at_exit` handlers begin running, more may be enqueued, but not -/// infinitely so. Eventually a handler registration will be forced to fail. -/// -/// Returns `Ok` if the handler was successfully registered, meaning that the -/// closure will be run once the main thread exits. Returns `Err` to indicate -/// that the closure could not be registered, meaning that it is not scheduled -/// to be run. -pub fn at_exit(f: F) -> Result<(), ()> { - if at_exit_imp::push(Box::new(f)) { Ok(()) } else { Err(()) } -} - -/// One-time runtime cleanup. -pub fn cleanup() { - static CLEANUP: Once = Once::new(); - CLEANUP.call_once(|| unsafe { - sys::args::cleanup(); - sys::stack_overflow::cleanup(); - at_exit_imp::cleanup(); - }); -} - // Computes (value*numer)/denom without overflow, as long as both // (numer*denom) and the overall result fit into i64 (which is the case // for our time conversions). diff --git a/library/std/src/sys_common/rt.rs b/library/std/src/sys_common/rt.rs new file mode 100644 index 00000000000..2635aea68c9 --- /dev/null +++ b/library/std/src/sys_common/rt.rs @@ -0,0 +1,69 @@ +use crate::sync::Once; +use crate::sys; +use crate::sys_common::thread_info; +use crate::thread::Thread; + +// One-time runtime initialization. +// Runs before `main`. +#[cfg_attr(test, allow(dead_code))] +pub fn init(argc: isize, argv: *const *const u8) { + static INIT: Once = Once::new(); + INIT.call_once(|| unsafe { + // SAFETY: Only called once during runtime initialization. + sys::init(); + + let main_guard = sys::thread::guard::init(); + sys::stack_overflow::init(); + + // Next, set up the current Thread with the guard information we just + // created. Note that this isn't necessary in general for new threads, + // but we just do this to name the main thread and to give it correct + // info about the stack bounds. + let thread = Thread::new(Some("main".to_owned())); + thread_info::set(main_guard, thread); + + // Store our args if necessary in a squirreled away location + sys::args::init(argc, argv); + }); +} + +// One-time runtime cleanup. +// Runs after `main` or at program exit. Note however that this is not guaranteed to run, +// for example when the program aborts. +#[cfg_attr(test, allow(dead_code))] +pub fn cleanup() { + static CLEANUP: Once = Once::new(); + CLEANUP.call_once(|| unsafe { + // SAFETY: Only called once during runtime cleanup. + sys::cleanup(); + sys::args::cleanup(); + sys::stack_overflow::cleanup(); + // Flush stdout and disable buffering. + crate::io::cleanup(); + }); +} + +macro_rules! rtabort { + ($($t:tt)*) => (crate::sys_common::util::abort(format_args!($($t)*))) +} + +macro_rules! rtassert { + ($e:expr) => { + if !$e { + rtabort!(concat!("assertion failed: ", stringify!($e))); + } + }; +} + +#[allow(unused_macros)] // not used on all platforms +macro_rules! rtunwrap { + ($ok:ident, $e:expr) => { + match $e { + $ok(v) => v, + ref err => { + let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug + rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err) + } + } + }; +} From cf470197addb37146eb2e0d16f14dd14293d91f0 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sun, 11 Apr 2021 23:20:01 +0200 Subject: [PATCH 2/6] Move all cleanup to `sys::cleanup` --- library/std/src/sys/hermit/mod.rs | 4 +++- library/std/src/sys/hermit/stack_overflow.rs | 3 --- library/std/src/sys/sgx/args.rs | 2 -- library/std/src/sys/sgx/stack_overflow.rs | 2 -- library/std/src/sys/unix/mod.rs | 5 ++++- library/std/src/sys/unsupported/args.rs | 1 - library/std/src/sys/unsupported/stack_overflow.rs | 2 -- library/std/src/sys/wasi/args.rs | 2 -- library/std/src/sys/wasm/args.rs | 2 -- library/std/src/sys/windows/args.rs | 2 -- library/std/src/sys/windows/stack_overflow.rs | 2 -- library/std/src/sys/windows/stack_overflow_uwp.rs | 2 -- library/std/src/sys_common/rt.rs | 2 -- 13 files changed, 7 insertions(+), 24 deletions(-) diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs index ebfc39bdef3..3da865021f3 100644 --- a/library/std/src/sys/hermit/mod.rs +++ b/library/std/src/sys/hermit/mod.rs @@ -102,7 +102,9 @@ pub unsafe fn init() { } // SAFETY: must be called only once during runtime cleanup. -pub unsafe fn cleanup() {} +pub unsafe fn cleanup() { + args::cleanup(); +} #[cfg(not(test))] #[no_mangle] diff --git a/library/std/src/sys/hermit/stack_overflow.rs b/library/std/src/sys/hermit/stack_overflow.rs index 121fe42011d..f276799661e 100644 --- a/library/std/src/sys/hermit/stack_overflow.rs +++ b/library/std/src/sys/hermit/stack_overflow.rs @@ -1,5 +1,2 @@ #[inline] pub unsafe fn init() {} - -#[inline] -pub unsafe fn cleanup() {} diff --git a/library/std/src/sys/sgx/args.rs b/library/std/src/sys/sgx/args.rs index 2d2e692ec7d..7f484b6d136 100644 --- a/library/std/src/sys/sgx/args.rs +++ b/library/std/src/sys/sgx/args.rs @@ -22,8 +22,6 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { } } -pub unsafe fn cleanup() {} - pub fn args() -> Args { let args = unsafe { (ARGS.load(Ordering::Relaxed) as *const ArgsStore).as_ref() }; if let Some(args) = args { Args(args.iter()) } else { Args([].iter()) } diff --git a/library/std/src/sys/sgx/stack_overflow.rs b/library/std/src/sys/sgx/stack_overflow.rs index b96652a8330..1ca5810e61b 100644 --- a/library/std/src/sys/sgx/stack_overflow.rs +++ b/library/std/src/sys/sgx/stack_overflow.rs @@ -1,4 +1,2 @@ #[cfg_attr(test, allow(dead_code))] pub unsafe fn init() {} - -pub unsafe fn cleanup() {} diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 3b86d373796..fd74c10ecd7 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -126,7 +126,10 @@ pub unsafe fn init() { } // SAFETY: must be called only once during runtime cleanup. -pub unsafe fn cleanup() {} +pub unsafe fn cleanup() { + args::cleanup(); + stack_overflow::cleanup(); +} #[cfg(target_os = "android")] pub use crate::sys::android::signal; diff --git a/library/std/src/sys/unsupported/args.rs b/library/std/src/sys/unsupported/args.rs index 71d0c5fa13e..f9d41c6cda6 100644 --- a/library/std/src/sys/unsupported/args.rs +++ b/library/std/src/sys/unsupported/args.rs @@ -1,7 +1,6 @@ use crate::ffi::OsString; pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} -pub unsafe fn cleanup() {} pub struct Args {} diff --git a/library/std/src/sys/unsupported/stack_overflow.rs b/library/std/src/sys/unsupported/stack_overflow.rs index 32555394cd5..2461fc2dad7 100644 --- a/library/std/src/sys/unsupported/stack_overflow.rs +++ b/library/std/src/sys/unsupported/stack_overflow.rs @@ -1,3 +1 @@ pub unsafe fn init() {} - -pub unsafe fn cleanup() {} diff --git a/library/std/src/sys/wasi/args.rs b/library/std/src/sys/wasi/args.rs index 9a27218e1fb..7f7f989e2ae 100644 --- a/library/std/src/sys/wasi/args.rs +++ b/library/std/src/sys/wasi/args.rs @@ -7,8 +7,6 @@ use crate::vec; pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} -pub unsafe fn cleanup() {} - pub struct Args { iter: vec::IntoIter, _dont_send_or_sync_me: PhantomData<*mut ()>, diff --git a/library/std/src/sys/wasm/args.rs b/library/std/src/sys/wasm/args.rs index 3b6557ae325..987585af2d5 100644 --- a/library/std/src/sys/wasm/args.rs +++ b/library/std/src/sys/wasm/args.rs @@ -6,8 +6,6 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8) { // On wasm these should always be null, so there's nothing for us to do here } -pub unsafe fn cleanup() {} - pub fn args() -> Args { Args { iter: Vec::new().into_iter(), _dont_send_or_sync_me: PhantomData } } diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs index bcc2ea9ae00..7ec3c592ada 100644 --- a/library/std/src/sys/windows/args.rs +++ b/library/std/src/sys/windows/args.rs @@ -16,8 +16,6 @@ use core::iter; pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} -pub unsafe fn cleanup() {} - pub fn args() -> Args { unsafe { let lp_cmd_line = c::GetCommandLineW(); diff --git a/library/std/src/sys/windows/stack_overflow.rs b/library/std/src/sys/windows/stack_overflow.rs index 187ad4e66c3..39efb778207 100644 --- a/library/std/src/sys/windows/stack_overflow.rs +++ b/library/std/src/sys/windows/stack_overflow.rs @@ -37,5 +37,3 @@ pub unsafe fn init() { // Set the thread stack guarantee for the main thread. let _h = Handler::new(); } - -pub unsafe fn cleanup() {} diff --git a/library/std/src/sys/windows/stack_overflow_uwp.rs b/library/std/src/sys/windows/stack_overflow_uwp.rs index e7236cf359c..afdf7f566ae 100644 --- a/library/std/src/sys/windows/stack_overflow_uwp.rs +++ b/library/std/src/sys/windows/stack_overflow_uwp.rs @@ -9,5 +9,3 @@ impl Handler { } pub unsafe fn init() {} - -pub unsafe fn cleanup() {} diff --git a/library/std/src/sys_common/rt.rs b/library/std/src/sys_common/rt.rs index 2635aea68c9..515e754b416 100644 --- a/library/std/src/sys_common/rt.rs +++ b/library/std/src/sys_common/rt.rs @@ -36,8 +36,6 @@ pub fn cleanup() { CLEANUP.call_once(|| unsafe { // SAFETY: Only called once during runtime cleanup. sys::cleanup(); - sys::args::cleanup(); - sys::stack_overflow::cleanup(); // Flush stdout and disable buffering. crate::io::cleanup(); }); From 11445c10ab630a6ad8526f3fc5bcea1badad2964 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sun, 11 Apr 2021 23:48:10 +0200 Subject: [PATCH 3/6] Move most init to `sys::init` --- library/std/src/sys/hermit/mod.rs | 4 +- library/std/src/sys/hermit/stack_overflow.rs | 2 - library/std/src/sys/sgx/mod.rs | 7 ++- library/std/src/sys/sgx/stack_overflow.rs | 2 - library/std/src/sys/unix/mod.rs | 44 ++++++++----------- library/std/src/sys/unsupported/args.rs | 2 - library/std/src/sys/unsupported/common.rs | 2 +- library/std/src/sys/unsupported/mod.rs | 1 - .../std/src/sys/unsupported/stack_overflow.rs | 1 - library/std/src/sys/wasi/args.rs | 2 - library/std/src/sys/wasi/mod.rs | 2 - library/std/src/sys/wasm/args.rs | 4 -- library/std/src/sys/wasm/mod.rs | 2 - library/std/src/sys/windows/args.rs | 2 - library/std/src/sys/windows/mod.rs | 4 +- library/std/src/sys_common/rt.rs | 7 +-- 16 files changed, 31 insertions(+), 57 deletions(-) delete mode 100644 library/std/src/sys/hermit/stack_overflow.rs delete mode 100644 library/std/src/sys/sgx/stack_overflow.rs delete mode 100644 library/std/src/sys/unsupported/stack_overflow.rs diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs index 3da865021f3..77c068e1a97 100644 --- a/library/std/src/sys/hermit/mod.rs +++ b/library/std/src/sys/hermit/mod.rs @@ -37,7 +37,6 @@ pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; pub mod rwlock; -pub mod stack_overflow; pub mod stdio; pub mod thread; pub mod thread_local_dtor; @@ -97,8 +96,9 @@ pub extern "C" fn __rust_abort() { } // SAFETY: must be called only once during runtime initialization. -pub unsafe fn init() { +pub unsafe fn init(argc: isize, argv: *const *const u8) { let _ = net::init(); + args::init(argc, argv); } // SAFETY: must be called only once during runtime cleanup. diff --git a/library/std/src/sys/hermit/stack_overflow.rs b/library/std/src/sys/hermit/stack_overflow.rs deleted file mode 100644 index f276799661e..00000000000 --- a/library/std/src/sys/hermit/stack_overflow.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[inline] -pub unsafe fn init() {} diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs index 9681336631f..25250d060d0 100644 --- a/library/std/src/sys/sgx/mod.rs +++ b/library/std/src/sys/sgx/mod.rs @@ -32,7 +32,6 @@ pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; pub mod rwlock; -pub mod stack_overflow; pub mod stdio; pub mod thread; pub mod thread_local_key; @@ -41,7 +40,11 @@ pub mod time; pub use crate::sys_common::os_str_bytes as os_str; // SAFETY: must be called only once during runtime initialization. -pub unsafe fn init() {} +pub unsafe fn init(argc: isize, argv: *const *const u8) { + unsafe { + args::init(argc, argv); + } +} // SAFETY: must be called only once during runtime cleanup. pub unsafe fn cleanup() {} diff --git a/library/std/src/sys/sgx/stack_overflow.rs b/library/std/src/sys/sgx/stack_overflow.rs deleted file mode 100644 index 1ca5810e61b..00000000000 --- a/library/std/src/sys/sgx/stack_overflow.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg_attr(test, allow(dead_code))] -pub unsafe fn init() {} diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index fd74c10ecd7..bd9ac32b0d2 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -45,7 +45,7 @@ pub mod time; pub use crate::sys_common::os_str_bytes as os_str; // SAFETY: must be called only once during runtime initialization. -pub unsafe fn init() { +pub unsafe fn init(argc: isize, argv: *const *const u8) { // The standard streams might be closed on application startup. To prevent // std::io::{stdin, stdout,stderr} objects from using other unrelated file // resources opened later, we reopen standards streams when they are closed. @@ -60,22 +60,22 @@ pub unsafe fn init() { // to prevent this problem. reset_sigpipe(); - cfg_if::cfg_if! { - if #[cfg(miri)] { - // The standard fds are always available in Miri. - unsafe fn sanitize_standard_fds() {} - } else if #[cfg(not(any( - target_os = "emscripten", - target_os = "fuchsia", - target_os = "vxworks", - // The poll on Darwin doesn't set POLLNVAL for closed fds. - target_os = "macos", - target_os = "ios", - target_os = "redox", - )))] { - // In the case when all file descriptors are open, the poll has been - // observed to perform better than fcntl (on GNU/Linux). - unsafe fn sanitize_standard_fds() { + stack_overflow::init(); + args::init(argc, argv); + + unsafe fn sanitize_standard_fds() { + cfg_if::cfg_if! { + if #[cfg(not(any( + // The standard fds are always available in Miri. + miri, + target_os = "emscripten", + target_os = "fuchsia", + target_os = "vxworks", + // The poll on Darwin doesn't set POLLNVAL for closed fds. + target_os = "macos", + target_os = "ios", + target_os = "redox", + )))] { use crate::sys::os::errno; let pfds: &mut [_] = &mut [ libc::pollfd { fd: 0, events: 0, revents: 0 }, @@ -100,9 +100,7 @@ pub unsafe fn init() { libc::abort(); } } - } - } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "redox"))] { - unsafe fn sanitize_standard_fds() { + } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "redox"))] { use crate::sys::os::errno; for fd in 0..3 { if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF { @@ -112,17 +110,13 @@ pub unsafe fn init() { } } } - } else { - unsafe fn sanitize_standard_fds() {} } } - #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))] unsafe fn reset_sigpipe() { + #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))] assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); } - #[cfg(any(target_os = "emscripten", target_os = "fuchsia"))] - unsafe fn reset_sigpipe() {} } // SAFETY: must be called only once during runtime cleanup. diff --git a/library/std/src/sys/unsupported/args.rs b/library/std/src/sys/unsupported/args.rs index f9d41c6cda6..cdb474b5b15 100644 --- a/library/std/src/sys/unsupported/args.rs +++ b/library/std/src/sys/unsupported/args.rs @@ -1,7 +1,5 @@ use crate::ffi::OsString; -pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} - pub struct Args {} pub fn args() -> Args { diff --git a/library/std/src/sys/unsupported/common.rs b/library/std/src/sys/unsupported/common.rs index 5ab22bd3ff4..c60c2a9b8e8 100644 --- a/library/std/src/sys/unsupported/common.rs +++ b/library/std/src/sys/unsupported/common.rs @@ -11,7 +11,7 @@ pub use crate::sys_common::os_str_bytes as os_str; use crate::os::raw::c_char; // SAFETY: must be called only once during runtime initialization. -pub unsafe fn init() {} +pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} // SAFETY: must be called only once during runtime cleanup. pub unsafe fn cleanup() {} diff --git a/library/std/src/sys/unsupported/mod.rs b/library/std/src/sys/unsupported/mod.rs index d9efdec33d9..32ca68ef15b 100644 --- a/library/std/src/sys/unsupported/mod.rs +++ b/library/std/src/sys/unsupported/mod.rs @@ -15,7 +15,6 @@ pub mod path; pub mod pipe; pub mod process; pub mod rwlock; -pub mod stack_overflow; pub mod stdio; pub mod thread; #[cfg(target_thread_local)] diff --git a/library/std/src/sys/unsupported/stack_overflow.rs b/library/std/src/sys/unsupported/stack_overflow.rs deleted file mode 100644 index 2461fc2dad7..00000000000 --- a/library/std/src/sys/unsupported/stack_overflow.rs +++ /dev/null @@ -1 +0,0 @@ -pub unsafe fn init() {} diff --git a/library/std/src/sys/wasi/args.rs b/library/std/src/sys/wasi/args.rs index 7f7f989e2ae..004d47960f7 100644 --- a/library/std/src/sys/wasi/args.rs +++ b/library/std/src/sys/wasi/args.rs @@ -5,8 +5,6 @@ use crate::marker::PhantomData; use crate::os::wasi::ffi::OsStrExt; use crate::vec; -pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} - pub struct Args { iter: vec::IntoIter, _dont_send_or_sync_me: PhantomData<*mut ()>, diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs index b7b640b174f..2584d35b6ef 100644 --- a/library/std/src/sys/wasi/mod.rs +++ b/library/std/src/sys/wasi/mod.rs @@ -42,8 +42,6 @@ pub mod pipe; pub mod process; #[path = "../unsupported/rwlock.rs"] pub mod rwlock; -#[path = "../unsupported/stack_overflow.rs"] -pub mod stack_overflow; pub mod stdio; pub mod thread; #[path = "../unsupported/thread_local_dtor.rs"] diff --git a/library/std/src/sys/wasm/args.rs b/library/std/src/sys/wasm/args.rs index 987585af2d5..3672227bf66 100644 --- a/library/std/src/sys/wasm/args.rs +++ b/library/std/src/sys/wasm/args.rs @@ -2,10 +2,6 @@ use crate::ffi::OsString; use crate::marker::PhantomData; use crate::vec; -pub unsafe fn init(_argc: isize, _argv: *const *const u8) { - // On wasm these should always be null, so there's nothing for us to do here -} - pub fn args() -> Args { Args { iter: Vec::new().into_iter(), _dont_send_or_sync_me: PhantomData } } diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs index 82683c0f624..8705910c73a 100644 --- a/library/std/src/sys/wasm/mod.rs +++ b/library/std/src/sys/wasm/mod.rs @@ -35,8 +35,6 @@ pub mod path; pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -#[path = "../unsupported/stack_overflow.rs"] -pub mod stack_overflow; #[path = "../unsupported/stdio.rs"] pub mod stdio; pub mod thread; diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs index 7ec3c592ada..feddb1ea78e 100644 --- a/library/std/src/sys/windows/args.rs +++ b/library/std/src/sys/windows/args.rs @@ -14,8 +14,6 @@ use crate::vec; use core::iter; -pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} - pub fn args() -> Args { unsafe { let lp_cmd_line = c::GetCommandLineW(); diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index 4563bca93b3..21fec2aa01b 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -50,7 +50,9 @@ cfg_if::cfg_if! { } // SAFETY: must be called only once during runtime initialization. -pub unsafe fn init() {} +pub unsafe fn init(_argc: isize, _argv: *const *const u8) { + stack_overflow::init(); +} // SAFETY: must be called only once during runtime cleanup. pub unsafe fn cleanup() { diff --git a/library/std/src/sys_common/rt.rs b/library/std/src/sys_common/rt.rs index 515e754b416..dc20cf0e14a 100644 --- a/library/std/src/sys_common/rt.rs +++ b/library/std/src/sys_common/rt.rs @@ -10,20 +10,15 @@ pub fn init(argc: isize, argv: *const *const u8) { static INIT: Once = Once::new(); INIT.call_once(|| unsafe { // SAFETY: Only called once during runtime initialization. - sys::init(); + sys::init(argc, argv); let main_guard = sys::thread::guard::init(); - sys::stack_overflow::init(); - // Next, set up the current Thread with the guard information we just // created. Note that this isn't necessary in general for new threads, // but we just do this to name the main thread and to give it correct // info about the stack bounds. let thread = Thread::new(Some("main".to_owned())); thread_info::set(main_guard, thread); - - // Store our args if necessary in a squirreled away location - sys::args::init(argc, argv); }); } From 8aeea227daf4a78761c41bb32321e8b2e505d27e Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sun, 18 Apr 2021 05:13:53 +0200 Subject: [PATCH 4/6] Apply suggestions from review --- library/std/src/sys/unix/mod.rs | 4 ++-- library/std/src/sys/windows/net.rs | 13 ++++++++----- library/std/src/sys_common/rt.rs | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index bd9ac32b0d2..8ae0c1120ff 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -64,10 +64,10 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { args::init(argc, argv); unsafe fn sanitize_standard_fds() { + #[cfg(not(miri))] + // The standard fds are always available in Miri. cfg_if::cfg_if! { if #[cfg(not(any( - // The standard fds are always available in Miri. - miri, target_os = "emscripten", target_os = "fuchsia", target_os = "vxworks", diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index f577169e0e0..1ad13254c08 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -26,12 +26,12 @@ pub mod netc { pub struct Socket(c::SOCKET); +static INIT: Once = Once::new(); + /// Checks whether the Windows socket interface has been started already, and /// if not, starts it. pub fn init() { - static START: Once = Once::new(); - - START.call_once(|| unsafe { + INIT.call_once(|| unsafe { let mut data: c::WSADATA = mem::zeroed(); let ret = c::WSAStartup( 0x202, // version 2.2 @@ -42,8 +42,11 @@ pub fn init() { } pub fn cleanup() { - unsafe { - c::WSACleanup(); + if INIT.is_completed() { + // only close the socket interface if it has actually been started + unsafe { + c::WSACleanup(); + } } } diff --git a/library/std/src/sys_common/rt.rs b/library/std/src/sys_common/rt.rs index dc20cf0e14a..5906b4e3e0e 100644 --- a/library/std/src/sys_common/rt.rs +++ b/library/std/src/sys_common/rt.rs @@ -29,10 +29,10 @@ pub fn init(argc: isize, argv: *const *const u8) { pub fn cleanup() { static CLEANUP: Once = Once::new(); CLEANUP.call_once(|| unsafe { - // SAFETY: Only called once during runtime cleanup. - sys::cleanup(); // Flush stdout and disable buffering. crate::io::cleanup(); + // SAFETY: Only called once during runtime cleanup. + sys::cleanup(); }); } From e1b1081d2ff80f49129da2002ce3f5efa6186825 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sun, 18 Apr 2021 07:19:39 +0200 Subject: [PATCH 5/6] Document that `init` and `cleanup` are not guaranteed to run --- library/std/src/sys/hermit/mod.rs | 2 ++ library/std/src/sys/sgx/mod.rs | 2 ++ library/std/src/sys/unix/mod.rs | 2 ++ library/std/src/sys/unsupported/common.rs | 2 ++ library/std/src/sys/windows/mod.rs | 2 ++ library/std/src/sys_common/rt.rs | 5 +++-- 6 files changed, 13 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs index 77c068e1a97..a70d1db7ca6 100644 --- a/library/std/src/sys/hermit/mod.rs +++ b/library/std/src/sys/hermit/mod.rs @@ -96,12 +96,14 @@ pub extern "C" fn __rust_abort() { } // SAFETY: must be called only once during runtime initialization. +// NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(argc: isize, argv: *const *const u8) { let _ = net::init(); args::init(argc, argv); } // SAFETY: must be called only once during runtime cleanup. +// NOTE: this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() { args::cleanup(); } diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs index 25250d060d0..059d6cb5ba1 100644 --- a/library/std/src/sys/sgx/mod.rs +++ b/library/std/src/sys/sgx/mod.rs @@ -40,6 +40,7 @@ pub mod time; pub use crate::sys_common::os_str_bytes as os_str; // SAFETY: must be called only once during runtime initialization. +// NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(argc: isize, argv: *const *const u8) { unsafe { args::init(argc, argv); @@ -47,6 +48,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { } // SAFETY: must be called only once during runtime cleanup. +// NOTE: this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() {} /// This function is used to implement functionality that simply doesn't exist. diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 8ae0c1120ff..a0ee69c2f72 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -45,6 +45,7 @@ pub mod time; pub use crate::sys_common::os_str_bytes as os_str; // SAFETY: must be called only once during runtime initialization. +// NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(argc: isize, argv: *const *const u8) { // The standard streams might be closed on application startup. To prevent // std::io::{stdin, stdout,stderr} objects from using other unrelated file @@ -120,6 +121,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { } // SAFETY: must be called only once during runtime cleanup. +// NOTE: this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() { args::cleanup(); stack_overflow::cleanup(); diff --git a/library/std/src/sys/unsupported/common.rs b/library/std/src/sys/unsupported/common.rs index c60c2a9b8e8..6e72a7c632e 100644 --- a/library/std/src/sys/unsupported/common.rs +++ b/library/std/src/sys/unsupported/common.rs @@ -11,9 +11,11 @@ pub use crate::sys_common::os_str_bytes as os_str; use crate::os::raw::c_char; // SAFETY: must be called only once during runtime initialization. +// NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} // SAFETY: must be called only once during runtime cleanup. +// NOTE: this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() {} pub fn unsupported() -> std_io::Result { diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index 21fec2aa01b..ddb6ac5f55c 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -50,11 +50,13 @@ cfg_if::cfg_if! { } // SAFETY: must be called only once during runtime initialization. +// NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(_argc: isize, _argv: *const *const u8) { stack_overflow::init(); } // SAFETY: must be called only once during runtime cleanup. +// NOTE: this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() { net::cleanup(); } diff --git a/library/std/src/sys_common/rt.rs b/library/std/src/sys_common/rt.rs index 5906b4e3e0e..c0c4a63cde9 100644 --- a/library/std/src/sys_common/rt.rs +++ b/library/std/src/sys_common/rt.rs @@ -5,6 +5,7 @@ use crate::thread::Thread; // One-time runtime initialization. // Runs before `main`. +// NOTE: this is not guaranteed to run, for example when Rust code is called externally. #[cfg_attr(test, allow(dead_code))] pub fn init(argc: isize, argv: *const *const u8) { static INIT: Once = Once::new(); @@ -23,8 +24,8 @@ pub fn init(argc: isize, argv: *const *const u8) { } // One-time runtime cleanup. -// Runs after `main` or at program exit. Note however that this is not guaranteed to run, -// for example when the program aborts. +// Runs after `main` or at program exit. +// NOTE: this is not guaranteed to run, for example when the program aborts. #[cfg_attr(test, allow(dead_code))] pub fn cleanup() { static CLEANUP: Once = Once::new(); From 7171fec13f3a3091f702a8e55f495ad1563dc4cd Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Wed, 21 Apr 2021 16:21:10 +0200 Subject: [PATCH 6/6] Remove `Once` from `init` --- library/std/src/rt.rs | 5 ++++- library/std/src/sys_common/rt.rs | 11 ++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index ce6e318c9de..1e19aff51f8 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -28,8 +28,11 @@ fn lang_start_internal( use crate::panic; use crate::sys_common; - sys_common::rt::init(argc, argv); + // SAFETY: Only called once during runtime initialization. + unsafe { sys_common::rt::init(argc, argv) }; + let exit_code = panic::catch_unwind(main); + sys_common::rt::cleanup(); exit_code.unwrap_or(101) as isize diff --git a/library/std/src/sys_common/rt.rs b/library/std/src/sys_common/rt.rs index c0c4a63cde9..c70f2ecc04e 100644 --- a/library/std/src/sys_common/rt.rs +++ b/library/std/src/sys_common/rt.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use crate::sync::Once; use crate::sys; use crate::sys_common::thread_info; @@ -5,12 +7,11 @@ use crate::thread::Thread; // One-time runtime initialization. // Runs before `main`. +// SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. #[cfg_attr(test, allow(dead_code))] -pub fn init(argc: isize, argv: *const *const u8) { - static INIT: Once = Once::new(); - INIT.call_once(|| unsafe { - // SAFETY: Only called once during runtime initialization. +pub unsafe fn init(argc: isize, argv: *const *const u8) { + unsafe { sys::init(argc, argv); let main_guard = sys::thread::guard::init(); @@ -20,7 +21,7 @@ pub fn init(argc: isize, argv: *const *const u8) { // info about the stack bounds. let thread = Thread::new(Some("main".to_owned())); thread_info::set(main_guard, thread); - }); + } } // One-time runtime cleanup.