Skip to content

Commit 1149193

Browse files
committed
Auto merge of #89011 - bjorn3:restructure_rt, r=dtolnay
Restructure std::rt These changes should reduce binary size slightly while at the same slightly improving performance of startup, thread spawning and `std::thread::current()`. I haven't verified if the compiler is able to optimize some of these cases already, but at least for some others the compiler is unable to do these optimizations as they slightly change behavior in cases where program startup would crash anyway by omitting a backtrace and panic location. I can remove 6f6bb16 if preferred.
2 parents 50f9f78 + 37608c7 commit 1149193

File tree

8 files changed

+112
-114
lines changed

8 files changed

+112
-114
lines changed

library/std/src/lib.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -520,20 +520,20 @@ pub mod task {
520520
pub use alloc::task::*;
521521
}
522522

523-
// Platform-abstraction modules
523+
// The runtime entry point and a few unstable public functions used by the
524+
// compiler
524525
#[macro_use]
525-
mod sys_common;
526+
pub mod rt;
527+
528+
// Platform-abstraction modules
526529
mod sys;
530+
mod sys_common;
527531

528532
pub mod alloc;
529533

530534
// Private support modules
531535
mod panicking;
532536

533-
// The runtime entry point and a few unstable public functions used by the
534-
// compiler
535-
pub mod rt;
536-
537537
#[path = "../../backtrace/src/lib.rs"]
538538
#[allow(dead_code, unused_attributes)]
539539
mod backtrace_rs;

library/std/src/process.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1907,7 +1907,7 @@ impl Child {
19071907
/// [platform-specific behavior]: #platform-specific-behavior
19081908
#[stable(feature = "rust1", since = "1.0.0")]
19091909
pub fn exit(code: i32) -> ! {
1910-
crate::sys_common::rt::cleanup();
1910+
crate::rt::cleanup();
19111911
crate::sys::os::exit(code)
19121912
}
19131913

library/std/src/rt.rs

+85-3
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,93 @@
1313
issue = "none"
1414
)]
1515
#![doc(hidden)]
16+
#![deny(unsafe_op_in_unsafe_fn)]
17+
#![allow(unused_macros)]
18+
19+
use crate::ffi::CString;
1620

1721
// Re-export some of our utilities which are expected by other crates.
1822
pub use crate::panicking::{begin_panic, begin_panic_fmt, panic_count};
1923
pub use core::panicking::panic_display;
2024

25+
use crate::sync::Once;
26+
use crate::sys;
27+
use crate::sys_common::thread_info;
28+
use crate::thread::Thread;
29+
30+
// Prints to the "panic output", depending on the platform this may be:
31+
// - the standard error output
32+
// - some dedicated platform specific output
33+
// - nothing (so this macro is a no-op)
34+
macro_rules! rtprintpanic {
35+
($($t:tt)*) => {
36+
if let Some(mut out) = crate::sys::stdio::panic_output() {
37+
let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*));
38+
}
39+
}
40+
}
41+
42+
macro_rules! rtabort {
43+
($($t:tt)*) => {
44+
{
45+
rtprintpanic!("fatal runtime error: {}\n", format_args!($($t)*));
46+
crate::sys::abort_internal();
47+
}
48+
}
49+
}
50+
51+
macro_rules! rtassert {
52+
($e:expr) => {
53+
if !$e {
54+
rtabort!(concat!("assertion failed: ", stringify!($e)));
55+
}
56+
};
57+
}
58+
59+
macro_rules! rtunwrap {
60+
($ok:ident, $e:expr) => {
61+
match $e {
62+
$ok(v) => v,
63+
ref err => {
64+
let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug
65+
rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err)
66+
}
67+
}
68+
};
69+
}
70+
71+
// One-time runtime initialization.
72+
// Runs before `main`.
73+
// SAFETY: must be called only once during runtime initialization.
74+
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
75+
#[cfg_attr(test, allow(dead_code))]
76+
unsafe fn init(argc: isize, argv: *const *const u8) {
77+
unsafe {
78+
sys::init(argc, argv);
79+
80+
let main_guard = sys::thread::guard::init();
81+
// Next, set up the current Thread with the guard information we just
82+
// created. Note that this isn't necessary in general for new threads,
83+
// but we just do this to name the main thread and to give it correct
84+
// info about the stack bounds.
85+
let thread = Thread::new(Some(rtunwrap!(Ok, CString::new("main"))));
86+
thread_info::set(main_guard, thread);
87+
}
88+
}
89+
90+
// One-time runtime cleanup.
91+
// Runs after `main` or at program exit.
92+
// NOTE: this is not guaranteed to run, for example when the program aborts.
93+
pub(crate) fn cleanup() {
94+
static CLEANUP: Once = Once::new();
95+
CLEANUP.call_once(|| unsafe {
96+
// Flush stdout and disable buffering.
97+
crate::io::cleanup();
98+
// SAFETY: Only called once during runtime cleanup.
99+
sys::cleanup();
100+
});
101+
}
102+
21103
// To reduce the generated code of the new `lang_start`, this function is doing
22104
// the real work.
23105
#[cfg(not(test))]
@@ -26,7 +108,7 @@ fn lang_start_internal(
26108
argc: isize,
27109
argv: *const *const u8,
28110
) -> Result<isize, !> {
29-
use crate::{mem, panic, sys, sys_common};
111+
use crate::{mem, panic};
30112
let rt_abort = move |e| {
31113
mem::forget(e);
32114
rtabort!("initialization or cleanup bug");
@@ -42,14 +124,14 @@ fn lang_start_internal(
42124
// prevent libstd from accidentally introducing a panic to these functions. Another is from
43125
// user code from `main` or, more nefariously, as described in e.g. issue #86030.
44126
// SAFETY: Only called once during runtime initialization.
45-
panic::catch_unwind(move || unsafe { sys_common::rt::init(argc, argv) }).map_err(rt_abort)?;
127+
panic::catch_unwind(move || unsafe { init(argc, argv) }).map_err(rt_abort)?;
46128
let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)
47129
.map_err(move |e| {
48130
mem::forget(e);
49131
rtprintpanic!("drop of the panic payload panicked");
50132
sys::abort_internal()
51133
});
52-
panic::catch_unwind(sys_common::rt::cleanup).map_err(rt_abort)?;
134+
panic::catch_unwind(cleanup).map_err(rt_abort)?;
53135
ret_code
54136
}
55137

library/std/src/sys/unix/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
120120

121121
unsafe fn reset_sigpipe() {
122122
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))]
123-
assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
123+
rtassert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
124124
}
125125
}
126126

library/std/src/sys_common/mod.rs

-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ pub mod memchr;
2828
pub mod mutex;
2929
pub mod process;
3030
pub mod remutex;
31-
#[macro_use]
32-
pub mod rt;
3331
pub mod rwlock;
3432
pub mod thread;
3533
pub mod thread_info;

library/std/src/sys_common/rt.rs

-81
This file was deleted.
+14-13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![allow(dead_code)] // stack_guard isn't used right now on all platforms
2+
#![allow(unused_unsafe)] // thread_local with `const {}` triggers this liny
23

34
use crate::cell::RefCell;
45
use crate::sys::thread::guard::Guard;
@@ -9,20 +10,21 @@ struct ThreadInfo {
910
thread: Thread,
1011
}
1112

12-
thread_local! { static THREAD_INFO: RefCell<Option<ThreadInfo>> = RefCell::new(None) }
13+
thread_local! { static THREAD_INFO: RefCell<Option<ThreadInfo>> = const { RefCell::new(None) } }
1314

1415
impl ThreadInfo {
1516
fn with<R, F>(f: F) -> Option<R>
1617
where
1718
F: FnOnce(&mut ThreadInfo) -> R,
1819
{
1920
THREAD_INFO
20-
.try_with(move |c| {
21-
if c.borrow().is_none() {
22-
*c.borrow_mut() =
23-
Some(ThreadInfo { stack_guard: None, thread: Thread::new(None) })
24-
}
25-
f(c.borrow_mut().as_mut().unwrap())
21+
.try_with(move |thread_info| {
22+
let mut thread_info = thread_info.borrow_mut();
23+
let thread_info = thread_info.get_or_insert_with(|| ThreadInfo {
24+
stack_guard: None,
25+
thread: Thread::new(None),
26+
});
27+
f(thread_info)
2628
})
2729
.ok()
2830
}
@@ -37,10 +39,9 @@ pub fn stack_guard() -> Option<Guard> {
3739
}
3840

3941
pub fn set(stack_guard: Option<Guard>, thread: Thread) {
40-
THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
41-
THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo { stack_guard, thread }));
42-
}
43-
44-
pub fn reset_guard(stack_guard: Option<Guard>) {
45-
THREAD_INFO.with(move |c| c.borrow_mut().as_mut().unwrap().stack_guard = stack_guard);
42+
THREAD_INFO.with(move |thread_info| {
43+
let mut thread_info = thread_info.borrow_mut();
44+
rtassert!(thread_info.is_none());
45+
*thread_info = Some(ThreadInfo { stack_guard, thread });
46+
});
4647
}

library/std/src/thread/mod.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,9 @@ impl Builder {
457457

458458
let stack_size = stack_size.unwrap_or_else(thread::min_stack);
459459

460-
let my_thread = Thread::new(name);
460+
let my_thread = Thread::new(name.map(|name| {
461+
CString::new(name).expect("thread name may not contain interior null bytes")
462+
}));
461463
let their_thread = my_thread.clone();
462464

463465
let my_packet: Arc<UnsafeCell<Option<Result<T>>>> = Arc::new(UnsafeCell::new(None));
@@ -1073,12 +1075,8 @@ pub struct Thread {
10731075
impl Thread {
10741076
// Used only internally to construct a thread object without spawning
10751077
// Panics if the name contains nuls.
1076-
pub(crate) fn new(name: Option<String>) -> Thread {
1077-
let cname =
1078-
name.map(|n| CString::new(n).expect("thread name may not contain interior null bytes"));
1079-
Thread {
1080-
inner: Arc::new(Inner { name: cname, id: ThreadId::new(), parker: Parker::new() }),
1081-
}
1078+
pub(crate) fn new(name: Option<CString>) -> Thread {
1079+
Thread { inner: Arc::new(Inner { name, id: ThreadId::new(), parker: Parker::new() }) }
10821080
}
10831081

10841082
/// Atomically makes the handle's token available if it is not already.

0 commit comments

Comments
 (0)