1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
//! 运行时服务
//!
//! `rt` 模块提供了一组 narrow 的运行时服务,包括全局堆 (在 `heap` 中导出) 以及展开和回溯支持。
//!
//! 该模块中的 API 高度不稳定,因此暂时应将其视为私有实现细节。
//!
//!
#![unstable(
feature = "rt",
reason = "this public module should not exist and is highly likely \
to disappear",
issue = "none"
)]
#![doc(hidden)]
#![deny(unsafe_op_in_unsafe_fn)]
#![allow(unused_macros)]
use crate::ffi::CString;
// 重导出其他 crates 期望的一些实用工具。
pub use crate::panicking::{begin_panic, panic_count};
pub use core::panicking::{panic_display, panic_fmt};
use crate::sync::Once;
use crate::sys;
use crate::sys_common::thread_info;
use crate::thread::Thread;
// 打印到 "panic output",取决于平台,这可能是:
// - 标准错误输出
// - 一些专用平台特定的输出
// - 什么都没有 (所以这个宏是一个空操作)
macro_rules! rtprintpanic {
($($t:tt)*) => {
if let Some(mut out) = crate::sys::stdio::panic_output() {
let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*));
}
}
}
macro_rules! rtabort {
($($t:tt)*) => {
{
rtprintpanic!("fatal runtime error: {}\n", format_args!($($t)*));
crate::sys::abort_internal();
}
}
}
macro_rules! rtassert {
($e:expr) => {
if !$e {
rtabort!(concat!("assertion failed: ", stringify!($e)));
}
};
}
macro_rules! rtunwrap {
($ok:ident, $e:expr) => {
match $e {
$ok(v) => v,
ref err => {
let err = err.as_ref().map(drop); // 映射 Ok/Some,可能不是 Debug
rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err)
}
}
};
}
// 一次性运行时初始化。
// 在 `main` 之前运行。
// SAFETY: 在运行时初始化期间只能调用一次。
// NOTE: 这不能保证运行,例如在外部调用 Rust 代码时。
//
// # `sigpipe` 参数
//
// 自 2014 年以来,Unix 上的 Rust 运行时已将 `SIGPIPE` 处理程序设置为 `SIG_IGN`。
// 不过,应用程序有充分的理由需要不同的行为,因此 `fn main()` 上有一个 `#[unix_sigpipe = "..."]` 属性,可用于选择在调用 `fn main()` 之前如何设置 `SIGPIPE` (如果完全更改)。
//
// 有关详细信息,请参见 <https://github.com/rust-lang/rust/issues/97889>。
//
// 该函数的 `sigpipe` 参数通过 rustc 为调用 `fn lang_start()` 生成的代码获取其值。
// 我们为所有平台而不仅仅是 Unix 都有 `sigpipe` 的原因是因为 std 不允许将 `cfg` 指令作为这个高级别的。
// 有关更多信息,请参见 `src/tools/tidy/src/pal.rs` 中的模块文档。
// 在所有其他平台上,`sigpipe` 都有一个值,但它的值被忽略。
//
// 即使它是 `u8`,它也只有 4 个值。这些记录在 `compiler/rustc_session/src/config/sigpipe.rs` 中。
//
//
//
//
//
#[cfg_attr(test, allow(dead_code))]
unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
unsafe {
sys::init(argc, argv, sigpipe);
let main_guard = sys::thread::guard::init();
// 接下来,使用我们刚刚创建的保护信息设置当前线程。
// 请注意,通常对于新线程来说这不是必需的,但是我们只是这样做以命名主线程并为它提供有关栈边界的正确信息。
//
//
let thread = Thread::new(Some(rtunwrap!(Ok, CString::new("main"))));
thread_info::set(main_guard, thread);
}
}
// 一次性运行时清理。
// 在 `main` 之后或在程序退出时运行。
// NOTE: 这不能保证运行,例如当程序中止时。
pub(crate) fn cleanup() {
static CLEANUP: Once = Once::new();
CLEANUP.call_once(|| unsafe {
// 刷新 stdout 并禁用缓冲。
crate::io::cleanup();
// SAFETY: 仅在运行时清理期间调用一次。
sys::cleanup();
});
}
// 为了减少新 `lang_start` 的生成代码,此函数正在做实际工作。
//
#[cfg(not(test))]
fn lang_start_internal(
main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe),
argc: isize,
argv: *const *const u8,
sigpipe: u8,
) -> Result<isize, !> {
use crate::{mem, panic};
let rt_abort = move |e| {
mem::forget(e);
rtabort!("initialization or cleanup bug");
};
// 在 Rust 控制的代码之外,要防范这个函数从展开中调用的代码,也就是 UB。
// 这是由 `#[lang="start"]` 属性的实现方式以及 panicking 机制本身的实现所强加的要求。
//
//
// 有几种情况可以开始展开。首先是由 bstd 控制的 `rt::init`、`rt::cleanup` 和类似函数的内部。
// 在这些情况下,panic 是 std 实现错误。
// 也很有可能,因为没有任何方法可以防止 std 意外地向这些函数引入 panic。
// 另一个来自 `main` 的用户代码,或者更邪恶的是,如
// issue #86030.
// SAFETY: 在运行时初始化期间只调用一次。
//
panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?;
let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)
.map_err(move |e| {
mem::forget(e);
rtabort!("drop of the panic payload panicked");
});
panic::catch_unwind(cleanup).map_err(rt_abort)?;
ret_code
}
#[cfg(not(test))]
#[lang = "start"]
fn lang_start<T: crate::process::Termination + 'static>(
main: fn() -> T,
argc: isize,
argv: *const *const u8,
sigpipe: u8,
) -> isize {
let Ok(v) = lang_start_internal(
&move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report().to_i32(),
argc,
argv,
sigpipe,
);
v
}