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
//! 运行时服务
//!
//! `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 代码时。
#[cfg_attr(test, allow(dead_code))]
unsafe fn init(argc: isize, argv: *const *const u8) {
    unsafe {
        sys::init(argc, argv);

        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,
) -> Result<isize, !> {
    use crate::{mem, panic};
    let rt_abort = move |e| {
        mem::forget(e);
        rtabort!("initialization or cleanup bug");
    };
    // 在 Rust 控制的代码之外,要防范这个函数从展开中调用的代码,也就是 UB。
    // 这是由 `#[lang="start"]` 属性的实现方式以及 panicking 机制本身的实现所强加的要求。
    //
    //
    // 有几种情况可以开始展开。首先是 libstd 控制的 `rt::init`、`rt::cleanup` 等类似函数的内部。
    // 在这些情况下,panic 是 libstd 实现错误。
    // 也很有可能,因为没有任何方法可以防止 libstd 意外地将 panic 引入这些函数。
    // 另一个来自 `main` 的用户代码,或者更邪恶的是,如
    // issue #86030.
    // SAFETY: 在运行时初始化期间只调用一次。
    //
    panic::catch_unwind(move || unsafe { init(argc, argv) }).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,
) -> isize {
    let Ok(v) = lang_start_internal(
        &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report(),
        argc,
        argv,
    );
    v
}