Skip to content

Commit

Permalink
Auto merge of #84115 - CDirkx:rt, r=m-ou-se
Browse files Browse the repository at this point in the history
Rework `init` and `cleanup`

This PR reworks the code in `std` that runs before and after `main` and centralizes this code respectively in the functions `init` and `cleanup` in both `sys_common` and `sys`. This makes is easy to see what code is executed during initialization and cleanup on each platform just by looking at e.g. `sys::windows::init`.

Full list of changes:
- new module `rt` in `sys_common` to contain `init` and `cleanup` and the runtime macros.
- `at_exit` and the mechanism to register exit handlers has been completely removed. In practice this was only used for closing sockets on windows and flushing stdout, which have been moved to `cleanup`.
- <s>On windows `alloc` and `net` initialization is now done in `init`, this saves a runtime check in every allocation and network use.</s>
  • Loading branch information
bors committed Apr 25, 2021
2 parents f7c468f + 7171fec commit 5da10c0
Show file tree
Hide file tree
Showing 26 changed files with 175 additions and 262 deletions.
4 changes: 4 additions & 0 deletions library/std/src/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8>,
len: usize,
Expand Down
41 changes: 18 additions & 23 deletions library/std/src/io/stdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Mutex<Vec<u8>>>;
Expand Down Expand Up @@ -508,6 +507,8 @@ pub struct StdoutLock<'a> {
inner: ReentrantMutexGuard<'a, RefCell<LineWriter<StdoutRaw>>>,
}

static STDOUT: SyncOnceCell<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = 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
Expand Down Expand Up @@ -549,34 +550,28 @@ pub struct StdoutLock<'a> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdout() -> Stdout {
static INSTANCE: SyncOnceCell<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> =
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.
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down
27 changes: 5 additions & 22 deletions library/std/src/rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,33 +26,16 @@ 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();
// SAFETY: Only called once during runtime initialization.
unsafe { sys_common::rt::init(argc, argv) };

unsafe {
let main_guard = sys::thread::guard::init();
sys::stack_overflow::init();
let exit_code = panic::catch_unwind(main);

// 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);
sys_common::rt::cleanup();

// 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))]
Expand Down
13 changes: 10 additions & 3 deletions library/std/src/sys/hermit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -96,9 +95,17 @@ pub extern "C" fn __rust_abort() {
abort_internal();
}

#[cfg(not(test))]
pub fn init() {
// 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();
}

#[cfg(not(test))]
Expand Down
5 changes: 0 additions & 5 deletions library/std/src/sys/hermit/stack_overflow.rs

This file was deleted.

2 changes: 0 additions & 2 deletions library/std/src/sys/sgx/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,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()) }
Expand Down
14 changes: 11 additions & 3 deletions library/std/src/sys/sgx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,24 @@ 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;
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.
// 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);
}
}

// 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.
/// Programs relying on this functionality will need to deal with the error.
Expand Down
4 changes: 0 additions & 4 deletions library/std/src/sys/sgx/stack_overflow.rs

This file was deleted.

62 changes: 30 additions & 32 deletions library/std/src/sys/unix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,13 @@ 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.
// 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
// 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
Expand All @@ -60,26 +59,24 @@ 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();

stack_overflow::init();
args::init(argc, argv);

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() {
unsafe fn sanitize_standard_fds() {
#[cfg(not(miri))]
// The standard fds are always available in Miri.
cfg_if::cfg_if! {
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",
)))] {
use crate::sys::os::errno;
let pfds: &mut [_] = &mut [
libc::pollfd { fd: 0, events: 0, revents: 0 },
Expand All @@ -104,9 +101,7 @@ pub 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 {
Expand All @@ -116,17 +111,20 @@ pub 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.
// NOTE: this is not guaranteed to run, for example when the program aborts.
pub unsafe fn cleanup() {
args::cleanup();
stack_overflow::cleanup();
}

#[cfg(target_os = "android")]
Expand Down
3 changes: 0 additions & 3 deletions library/std/src/sys/unsupported/args.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use crate::ffi::OsString;

pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
pub unsafe fn cleanup() {}

pub struct Args {}

pub fn args() -> Args {
Expand Down
9 changes: 7 additions & 2 deletions library/std/src/sys/unsupported/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ 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.
// 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<T>() -> std_io::Result<T> {
Err(unsupported_err())
Expand Down
1 change: 0 additions & 1 deletion library/std/src/sys/unsupported/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
3 changes: 0 additions & 3 deletions library/std/src/sys/unsupported/stack_overflow.rs

This file was deleted.

4 changes: 0 additions & 4 deletions library/std/src/sys/wasi/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ use crate::fmt;
use crate::os::wasi::ffi::OsStrExt;
use crate::vec;

pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}

pub unsafe fn cleanup() {}

pub struct Args {
iter: vec::IntoIter<OsString>,
}
Expand Down
2 changes: 0 additions & 2 deletions library/std/src/sys/wasi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
6 changes: 0 additions & 6 deletions library/std/src/sys/wasm/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@ use crate::ffi::OsString;
use crate::fmt;
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 unsafe fn cleanup() {}

pub fn args() -> Args {
Args { iter: Vec::new().into_iter() }
}
Expand Down
2 changes: 0 additions & 2 deletions library/std/src/sys/wasm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 0 additions & 4 deletions library/std/src/sys/windows/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ use crate::vec;

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();
Expand Down
Loading

0 comments on commit 5da10c0

Please sign in to comment.