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
//! Top level runtime module, managing the basic presentation of the runtime.

use std::sync::{
    atomic::{AtomicU32, Ordering},
    Mutex,
};

mod alloc;
mod core;
mod debug;
mod file;
mod object;
mod process;
mod slot;
mod stdio;
mod thread;
mod time;
pub(crate) mod upcall;

pub use core::CompartmentInitInfo;

pub use thread::RuntimeThreadControl;
pub use upcall::set_upcall_handler;

use self::object::ObjectHandleManager;

/// The runtime trait implementer itself.
pub struct ReferenceRuntime {
    pub(crate) state: AtomicU32,
    pub(crate) object_manager: Mutex<ObjectHandleManager>,
}

impl std::fmt::Debug for ReferenceRuntime {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "RefRun({})",
            if self.state().contains(RuntimeState::READY) {
                "ready"
            } else {
                "not-ready"
            }
        )
    }
}

bitflags::bitflags! {
    /// Various state flags for the runtime.
    pub struct RuntimeState : u32 {
        const READY = 1;
        const IS_MONITOR = 2;
    }
}

impl ReferenceRuntime {
    /// Returns the runtime state flags.
    pub fn state(&self) -> RuntimeState {
        RuntimeState::from_bits_truncate(self.state.load(Ordering::SeqCst))
    }

    /// Set the runtime ready state. If the runtime has not been initialized, the result is
    /// undefined.
    pub unsafe fn set_runtime_ready(&self) {
        self.state
            .fetch_or(RuntimeState::READY.bits(), Ordering::SeqCst);
    }

    fn set_is_monitor(&self) {
        self.state
            .fetch_or(RuntimeState::IS_MONITOR.bits(), Ordering::SeqCst);
    }
}

pub static OUR_RUNTIME: ReferenceRuntime = ReferenceRuntime {
    state: AtomicU32::new(0),
    object_manager: Mutex::new(ObjectHandleManager::new()),
};

#[cfg(feature = "runtime")]
pub(crate) mod do_impl {
    use twizzler_runtime_api::Runtime;

    use super::ReferenceRuntime;
    use crate::preinit_println;

    impl Runtime for ReferenceRuntime {}

    #[inline]
    #[no_mangle]
    // Returns a reference to the currently-linked Runtime implementation.
    pub fn __twz_get_runtime() -> &'static (dyn Runtime + Sync) {
        &super::OUR_RUNTIME
    }

    // Ensure the compiler doesn't optimize us away.
    #[used]
    static USE_MARKER: fn() -> &'static (dyn Runtime + Sync) = __twz_get_runtime;
}

// These are exported by libunwind, but not re-exported by the standard library that pulls that in.
// Or, at least, that's what it seems like. In any case, they're no-ops in libunwind and musl, so
// this is fine for now.
#[no_mangle]
pub fn __register_frame_info() {}
#[no_mangle]
pub fn __deregister_frame_info() {}
#[no_mangle]
pub fn __cxa_finalize() {}