monitor_api/
lib.rs

1//! This crate exists to break a circular dependency between twz-rt and monitor. We use extern
2//! symbols so that we can just call into the monitor without having to have it as an explicit
3//! dependency.
4
5#![feature(naked_functions)]
6#![feature(linkage)]
7#![feature(result_flattening)]
8#![feature(thread_local)]
9#![feature(pointer_is_aligned_to)]
10#![feature(tuple_trait)]
11use std::{
12    alloc::Layout,
13    cell::UnsafeCell,
14    marker::{PhantomData, Tuple},
15    ptr::NonNull,
16    sync::{
17        atomic::{AtomicPtr, AtomicU32, Ordering},
18        OnceLock,
19    },
20};
21
22pub use dynlink::{
23    context::NewCompartmentFlags,
24    tls::{Tcb, TlsRegion},
25};
26use secgate::{
27    util::{Descriptor, Handle},
28    Crossing, DynamicSecGate,
29};
30use twizzler_abi::object::{ObjID, MAX_SIZE, NULLPAGE_SIZE};
31
32#[allow(unused_imports, unused_variables, unexpected_cfgs)]
33mod gates {
34    include! {"../../monitor/secapi/gates.rs"}
35}
36
37pub use gates::*;
38use twizzler_rt_abi::{
39    debug::{DlPhdrInfo, LinkMap, LoadedImageId},
40    error::{ArgumentError, TwzError},
41};
42
43/// Shared data between the monitor and a compartment runtime. Written to by the monitor, and
44/// read-only from the compartment.
45#[repr(C)]
46pub struct SharedCompConfig {
47    /// The security context that this compartment derives from. Read-only, will not be
48    /// overwritten.
49    pub sctx: ObjID,
50    // Pointer to the current TLS template. Read-only by compartment, writable by monitor.
51    tls_template: AtomicPtr<TlsTemplateInfo>,
52    /// The root library ID for this compartment. May be None if no libraries have been loaded.
53    pub root_library_id: Option<LoadedImageId>,
54}
55
56struct CompConfigFinder {
57    config: *const SharedCompConfig,
58}
59
60// Safety: the compartment config address is stable over the life of the compartment and doesn't
61// change after init.
62unsafe impl Sync for CompConfigFinder {}
63unsafe impl Send for CompConfigFinder {}
64
65static COMP_CONFIG: OnceLock<CompConfigFinder> = OnceLock::new();
66
67/// Get a reference to this compartment's [SharedCompConfig].
68pub fn get_comp_config() -> &'static SharedCompConfig {
69    unsafe {
70        COMP_CONFIG
71            .get_or_init(|| CompConfigFinder {
72                config: monitor_rt_get_comp_config().unwrap() as *const _,
73            })
74            .config
75            .as_ref()
76            .unwrap()
77    }
78}
79
80/// Tries to set the comp config pointer. May fail, as this can only be set once.
81/// The comp config pointer is automatically determined if [get_comp_config] is called
82/// without comp config being set, by cross-compartment call into monitor.
83pub fn set_comp_config(cfg: &'static SharedCompConfig) -> Result<(), ()> {
84    COMP_CONFIG
85        .set(CompConfigFinder { config: cfg })
86        .map_err(|_| ())
87}
88
89/// Information about a monitor-generated TLS template.
90#[repr(C)]
91#[derive(Clone, Copy, Debug)]
92pub struct TlsTemplateInfo {
93    pub gen: u64,
94    pub layout: Layout,
95    pub alloc_base: NonNull<u8>,
96    pub tp_offset: usize,
97    pub dtv_offset: usize,
98    pub num_dtv_entries: usize,
99    pub module_top_offset: usize,
100}
101
102// Safety: this type is designed to pass pointers to thread-local memory across boundaries, so we
103// assert this is safe.
104unsafe impl Send for TlsTemplateInfo {}
105unsafe impl Sync for TlsTemplateInfo {}
106
107impl From<TlsRegion> for TlsTemplateInfo {
108    fn from(value: TlsRegion) -> Self {
109        let offset = |ptr: NonNull<u8>| -> usize {
110            unsafe {
111                ptr.as_ptr()
112                    .byte_offset_from(value.alloc_base.as_ptr())
113                    .try_into()
114                    .unwrap()
115            }
116        };
117        Self {
118            gen: value.gen,
119            layout: value.layout,
120            alloc_base: value.alloc_base,
121            num_dtv_entries: value.num_dtv_entries,
122            tp_offset: offset(value.thread_pointer),
123            dtv_offset: offset(value.dtv.cast()),
124            module_top_offset: offset(value.module_top),
125        }
126    }
127}
128
129impl TlsTemplateInfo {
130    /// Initialize a newly allocated memory region with a TLS template and TCB data.
131    ///
132    /// # Safety
133    /// The new pointer must point to a memory region that meets the requirements in self.layout.
134    pub unsafe fn init_new_tls_region<T>(&self, new: *mut u8, tcb_data: T) -> *mut Tcb<T> {
135        assert!(new.is_aligned_to(self.layout.align()));
136        // Step 1: copy the template to the new memory.
137        core::ptr::copy_nonoverlapping(self.alloc_base.as_ptr(), new, self.layout.size());
138
139        let tcb = new.add(self.tp_offset) as *mut Tcb<T>;
140        let dtv_ptr = new.add(self.dtv_offset) as *mut *mut u8;
141        let dtv = core::slice::from_raw_parts_mut(dtv_ptr, self.num_dtv_entries);
142
143        // Step 2a: "relocate" the pointers inside the DTV. First entry is the gen count, so skip
144        // that.
145        for entry in dtv.iter_mut().skip(1) {
146            let offset = (*entry).byte_offset_from(self.alloc_base.as_ptr());
147            *entry = new.byte_offset(offset);
148        }
149
150        // Step 2b: DTV[0] holds the TLS generation ID.
151        let dtv_0 = dtv_ptr as *mut u64;
152        *dtv_0 = self.gen;
153
154        // Step 3: Update the TCB data, including pointer to DTV and self.
155        {
156            let tcb = tcb.as_mut().unwrap();
157            tcb.dtv = dtv_ptr as *const usize;
158            tcb.self_ptr = tcb;
159            tcb.runtime_data = tcb_data;
160        }
161
162        tcb
163    }
164}
165
166impl SharedCompConfig {
167    pub fn new(sctx: ObjID, tls_template: *mut TlsTemplateInfo) -> Self {
168        Self {
169            sctx,
170            tls_template: AtomicPtr::new(tls_template),
171            root_library_id: None,
172        }
173    }
174
175    /// Set the current TLS template for a compartment. Only the monitor can call this.
176    pub fn set_tls_template(&self, ptr: *mut TlsTemplateInfo) {
177        self.tls_template.store(ptr, Ordering::SeqCst);
178    }
179
180    /// Get the current TLS template for the compartment.
181    pub fn get_tls_template(&self) -> *const TlsTemplateInfo {
182        self.tls_template.load(Ordering::SeqCst)
183    }
184}
185
186pub use gates::LibraryInfo as LibraryInfoRaw;
187
188/// Contains information about a library loaded into the address space.
189#[derive(Debug)]
190pub struct LibraryInfo<'a> {
191    /// The library's name
192    pub name: String,
193    /// The compartment of the library
194    pub compartment_id: ObjID,
195    /// The object ID that the library was loaded from
196    pub objid: ObjID,
197    /// The start address of range the library was loaded to
198    pub start: *const u8,
199    /// Length of range library was loaded to
200    pub len: usize,
201    /// The DlPhdrInfo for this library
202    pub dl_info: DlPhdrInfo,
203    /// The link_map structure for this library
204    pub link_map: LinkMap,
205    /// The slot of the library text.
206    pub slot: usize,
207    _pd: PhantomData<&'a ()>,
208    internal_name: Vec<u8>,
209}
210
211impl<'a> LibraryInfo<'a> {
212    fn from_raw(raw: LibraryInfoRaw) -> Self {
213        let name = lazy_sb::read_bytes_from_sb(raw.name_len);
214        let mut this = Self {
215            name: lazy_sb::read_string_from_sb(raw.name_len),
216            compartment_id: raw.compartment_id,
217            objid: raw.objid,
218            start: raw.start,
219            len: raw.len,
220            dl_info: raw.dl_info,
221            slot: raw.slot,
222            _pd: PhantomData,
223            internal_name: name,
224            link_map: raw.link_map,
225        };
226        this.dl_info.name = this.internal_name.as_ptr().cast();
227        this
228    }
229}
230
231/// A handle to a loaded library. On drop, the library may unload.
232#[derive(Debug)]
233pub struct LibraryHandle {
234    desc: Descriptor,
235}
236
237impl LibraryHandle {
238    /// Get the library info.
239    pub fn info(&self) -> LibraryInfo<'_> {
240        LibraryInfo::from_raw(gates::monitor_rt_get_library_info(self.desc).unwrap())
241    }
242
243    /// Get the descriptor for this handle.
244    pub fn desc(&self) -> Descriptor {
245        self.desc
246    }
247}
248
249/// A builder-type for loading libraries.
250pub struct LibraryLoader<'a> {
251    id: ObjID,
252    comp: Option<&'a CompartmentHandle>,
253}
254
255impl<'a> LibraryLoader<'a> {
256    /// Make a new LibraryLoader.
257    pub fn new(id: ObjID) -> Self {
258        Self { id, comp: None }
259    }
260
261    /// Load the library in the given compartment.
262    pub fn in_compartment(&'a mut self, comp: &'a CompartmentHandle) -> &'a mut Self {
263        self.comp = Some(comp);
264        self
265    }
266
267    /// Load the library.
268    pub fn load(&self) -> Result<LibraryHandle, TwzError> {
269        let desc: Descriptor =
270            gates::monitor_rt_load_library(self.comp.map(|comp| comp.desc).flatten(), self.id)?;
271        Ok(LibraryHandle { desc })
272    }
273}
274
275/// A compartment handle. On drop, the compartment may be unloaded.
276pub struct CompartmentHandle {
277    desc: Option<Descriptor>,
278}
279
280impl CompartmentHandle {
281    /// Get the compartment info.
282    pub fn info(&self) -> CompartmentInfo<'_> {
283        CompartmentInfo::from_raw(gates::monitor_rt_get_compartment_info(self.desc).unwrap())
284    }
285
286    /// Get the descriptor for this handle, or None if the handle refers to the current compartment.
287    pub fn desc(&self) -> Option<Descriptor> {
288        self.desc
289    }
290
291    pub unsafe fn dynamic_gate<A: Tuple + Crossing + Copy, R: Crossing + Copy>(
292        &self,
293        name: &str,
294    ) -> Result<DynamicSecGate<'_, A, R>, TwzError> {
295        let name_len = lazy_sb::write_bytes_to_sb(name.as_bytes());
296        let address = gates::monitor_rt_compartment_dynamic_gate(self.desc, name_len)?;
297        Ok(DynamicSecGate::new(address))
298    }
299}
300
301/// A builder-type for loading compartments.
302pub struct CompartmentLoader {
303    name: String,
304    args: Vec<String>,
305    env: Option<Vec<String>>,
306    flags: NewCompartmentFlags,
307}
308
309impl CompartmentLoader {
310    /// Make a new compartment loader.
311    pub fn new(
312        compname: impl ToString,
313        libname: impl ToString,
314        flags: NewCompartmentFlags,
315    ) -> Self {
316        Self {
317            name: format!("{}::{}", compname.to_string(), libname.to_string()),
318            flags,
319            env: None,
320            args: vec![],
321        }
322    }
323
324    /// Append args to this compartment.
325    pub fn args<S: ToString>(&mut self, args: impl IntoIterator<Item = S>) -> &mut Self {
326        for arg in args.into_iter() {
327            self.args.push(arg.to_string())
328        }
329        self
330    }
331
332    /// Set the environment for the compartment
333    pub fn env<S: ToString>(&mut self, env: impl IntoIterator<Item = S>) -> &mut Self {
334        self.env = Some(env.into_iter().map(|s| s.to_string()).collect());
335        self
336    }
337
338    /// Load the compartment.
339    pub fn load(&self) -> Result<CompartmentHandle, TwzError> {
340        fn get_current_env() -> Vec<String> {
341            std::env::vars()
342                .map(|(var, val)| format!("{}={}", var, val))
343                .collect()
344        }
345        let name_len = self.name.as_bytes().len();
346        let args_len = self
347            .args
348            .iter()
349            .fold(0, |acc, arg| acc + arg.as_bytes().len() + 1);
350        let env = self.env.clone().unwrap_or_else(|| get_current_env());
351        let envs_len = env
352            .iter()
353            .fold(0, |acc, arg| acc + arg.as_bytes().len() + 1);
354        let mut bytes = self.name.as_bytes().to_vec();
355        for arg in &self.args {
356            bytes.extend_from_slice(arg.as_bytes());
357            bytes.push(0);
358        }
359        for env in env {
360            bytes.extend_from_slice(env.as_bytes());
361            bytes.push(0);
362        }
363        let len = lazy_sb::write_bytes_to_sb(&bytes);
364        if len < envs_len + args_len + name_len {
365            return Err(ArgumentError::InvalidArgument.into());
366        }
367        let desc = gates::monitor_rt_load_compartment(
368            name_len as u64,
369            args_len as u64,
370            envs_len as u64,
371            self.flags.bits(),
372        )?;
373        Ok(CompartmentHandle { desc: Some(desc) })
374    }
375}
376
377impl Handle for CompartmentHandle {
378    type OpenError = TwzError;
379
380    type OpenInfo = ObjID;
381
382    fn open(info: Self::OpenInfo) -> Result<Self, Self::OpenError>
383    where
384        Self: Sized,
385    {
386        let desc = gates::monitor_rt_get_compartment_handle(info)?;
387        Ok(CompartmentHandle { desc: Some(desc) })
388    }
389
390    fn release(&mut self) {
391        if let Some(desc) = self.desc {
392            let _ = gates::monitor_rt_drop_compartment_handle(desc);
393        }
394    }
395}
396
397impl Drop for CompartmentHandle {
398    fn drop(&mut self) {
399        self.release();
400    }
401}
402
403impl Handle for LibraryHandle {
404    type OpenError = TwzError;
405
406    type OpenInfo = (Option<Descriptor>, usize);
407
408    fn open(info: Self::OpenInfo) -> Result<Self, Self::OpenError>
409    where
410        Self: Sized,
411    {
412        let desc = gates::monitor_rt_get_library_handle(info.0, info.1)?;
413        Ok(LibraryHandle { desc })
414    }
415
416    fn release(&mut self) {
417        let _ = gates::monitor_rt_drop_library_handle(self.desc);
418    }
419}
420
421impl Drop for LibraryHandle {
422    fn drop(&mut self) {
423        self.release()
424    }
425}
426
427/// Information about a compartment.
428#[derive(Clone, Debug)]
429pub struct CompartmentInfo<'a> {
430    /// The name of the compartment.
431    pub name: String,
432    /// The instance ID.
433    pub id: ObjID,
434    /// The security context.
435    pub sctx: ObjID,
436    /// The compartment flags and status.
437    pub flags: CompartmentFlags,
438    /// Number of libraries
439    pub nr_libs: usize,
440    _pd: PhantomData<&'a ()>,
441}
442
443impl<'a> CompartmentInfo<'a> {
444    fn from_raw(raw: gates::CompartmentInfo) -> Self {
445        Self {
446            name: lazy_sb::read_string_from_sb(raw.name_len),
447            id: raw.id,
448            sctx: raw.sctx,
449            flags: CompartmentFlags::from_bits_truncate(raw.flags),
450            nr_libs: raw.nr_libs,
451            _pd: PhantomData,
452        }
453    }
454}
455
456impl CompartmentHandle {
457    /// Get a handle to the current compartment.
458    pub fn current() -> Self {
459        Self { desc: None }
460    }
461
462    /// Lookup a compartment by name.
463    pub fn lookup(name: impl AsRef<str>) -> Result<Self, TwzError> {
464        let name_len = lazy_sb::write_bytes_to_sb(name.as_ref().as_bytes());
465        Ok(Self {
466            desc: Some(gates::monitor_rt_lookup_compartment(name_len)?),
467        })
468    }
469
470    /// Get an iterator over this compartment's dependencies.
471    pub fn deps(&self) -> CompartmentDepsIter {
472        CompartmentDepsIter::new(self)
473    }
474
475    /// Get the root library for this compartment.
476    pub fn root(&self) -> LibraryHandle {
477        self.libs().next().unwrap()
478    }
479
480    /// Get an iterator over the libraries for this compartment.
481    pub fn libs(&self) -> LibraryIter<'_> {
482        LibraryIter::new(self)
483    }
484
485    /// Get an iterator over the libraries for this compartment.
486    pub fn threads(&self) -> CompartmentThreadsIter<'_> {
487        CompartmentThreadsIter::new(self)
488    }
489
490    pub fn wait(&self, flags: CompartmentFlags) -> CompartmentFlags {
491        CompartmentFlags::from_bits_truncate(
492            gates::monitor_rt_compartment_wait(self.desc(), flags.bits()).unwrap(),
493        )
494    }
495}
496
497/// An iterator over libraries in a compartment.
498pub struct LibraryIter<'a> {
499    n: usize,
500    comp: &'a CompartmentHandle,
501}
502
503impl<'a> LibraryIter<'a> {
504    fn new(comp: &'a CompartmentHandle) -> Self {
505        Self { n: 0, comp }
506    }
507}
508
509impl<'a> Iterator for LibraryIter<'a> {
510    type Item = LibraryHandle;
511
512    fn next(&mut self) -> Option<Self::Item> {
513        let handle = LibraryHandle::open((self.comp.desc, self.n)).ok();
514        if handle.is_some() {
515            self.n += 1;
516        }
517        handle
518    }
519}
520
521/// An iterator over a compartment's dependencies.
522pub struct CompartmentDepsIter<'a> {
523    n: usize,
524    comp: &'a CompartmentHandle,
525}
526
527impl<'a> CompartmentDepsIter<'a> {
528    fn new(comp: &'a CompartmentHandle) -> Self {
529        Self { n: 0, comp }
530    }
531}
532
533impl<'a> Iterator for CompartmentDepsIter<'a> {
534    type Item = CompartmentHandle;
535
536    fn next(&mut self) -> Option<Self::Item> {
537        let desc = gates::monitor_rt_get_compartment_deps(self.comp.desc, self.n).ok()?;
538        self.n += 1;
539        Some(CompartmentHandle { desc: Some(desc) })
540    }
541
542    fn nth(&mut self, n: usize) -> Option<Self::Item> {
543        self.n += n;
544        self.next()
545    }
546}
547
548/// An iterator over a compartment's threads.
549pub struct CompartmentThreadsIter<'a> {
550    n: usize,
551    comp: &'a CompartmentHandle,
552}
553
554impl<'a> CompartmentThreadsIter<'a> {
555    fn new(comp: &'a CompartmentHandle) -> Self {
556        Self { n: 0, comp }
557    }
558}
559
560impl<'a> Iterator for CompartmentThreadsIter<'a> {
561    type Item = ThreadInfo;
562
563    fn next(&mut self) -> Option<Self::Item> {
564        let info = gates::monitor_rt_get_compartment_thread(self.comp.desc, self.n).ok()?;
565        self.n += 1;
566        Some(info)
567    }
568
569    fn nth(&mut self, n: usize) -> Option<Self::Item> {
570        self.n += n;
571        self.next()
572    }
573}
574
575bitflags::bitflags! {
576    /// Compartment state flags.
577    #[derive(Clone, Debug, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
578    pub struct CompartmentFlags : u64 {
579        /// Compartment is ready (loaded, reloacated, runtime started and ctors run).
580        const READY = 0x1;
581        /// Compartment is a binary, not a library.
582        const IS_BINARY = 0x2;
583        /// Compartment runtime thread may exit.
584        const THREAD_CAN_EXIT = 0x4;
585        /// Compartment thread has been started once.
586        const STARTED = 0x8;
587        /// Compartment destructors have run.
588        const DESTRUCTED = 0x10;
589        /// Compartment thread has exited.
590        const EXITED = 0x20;
591    }
592}
593
594/// Contains raw mapping addresses, for use when translating to object handles for the runtime.
595#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Debug)]
596pub struct MappedObjectAddrs {
597    pub slot: usize,
598    pub start: usize,
599    pub meta: usize,
600}
601
602impl MappedObjectAddrs {
603    pub fn new(slot: usize) -> Self {
604        Self {
605            start: slot * MAX_SIZE,
606            meta: (slot + 1) * MAX_SIZE - NULLPAGE_SIZE,
607            slot,
608        }
609    }
610}
611
612/// Get stats from the monitor
613pub fn stats() -> Option<gates::MonitorStats> {
614    gates::monitor_rt_stats().ok()
615}
616
617mod lazy_sb {
618    //! A per-thread per-compartment simple buffer used for transferring strings between
619    //! compartments and the monitor. This is necessary because the monitor runs at too low of a
620    //! level for us to use nice shared memory techniques. This is simpler and more secure.
621    use std::cell::{OnceCell, RefCell};
622
623    use secgate::util::SimpleBuffer;
624    use twizzler_rt_abi::object::MapFlags;
625
626    struct LazyThreadSimpleBuffer {
627        sb: OnceCell<SimpleBuffer>,
628    }
629
630    impl LazyThreadSimpleBuffer {
631        const fn new() -> Self {
632            Self {
633                sb: OnceCell::new(),
634            }
635        }
636
637        fn init() -> SimpleBuffer {
638            let id = super::gates::monitor_rt_get_thread_simple_buffer()
639                .expect("failed to get per-thread monitor simple buffer");
640            let oh =
641                twizzler_rt_abi::object::twz_rt_map_object(id, MapFlags::READ | MapFlags::WRITE)
642                    .unwrap();
643            SimpleBuffer::new(oh)
644        }
645
646        fn read(&mut self, buf: &mut [u8]) -> usize {
647            let sb = self.sb.get_or_init(|| Self::init());
648            sb.read(buf)
649        }
650
651        fn write(&mut self, buf: &[u8]) -> usize {
652            if self.sb.get().is_none() {
653                // Unwrap-Ok: we know it's empty.
654                self.sb.set(Self::init()).unwrap();
655            }
656            let sb = self.sb.get_mut().unwrap();
657            sb.write(buf)
658        }
659    }
660
661    #[thread_local]
662    static LAZY_SB: RefCell<LazyThreadSimpleBuffer> = RefCell::new(LazyThreadSimpleBuffer::new());
663
664    pub(super) fn read_string_from_sb(len: usize) -> String {
665        let mut buf = vec![0u8; len];
666        let len = LAZY_SB.borrow_mut().read(&mut buf);
667        String::from_utf8_lossy(&buf[0..len]).to_string()
668    }
669
670    pub(super) fn read_bytes_from_sb(len: usize) -> Vec<u8> {
671        let mut buf = vec![0u8; len];
672        let len = LAZY_SB.borrow_mut().read(&mut buf);
673        buf.truncate(len);
674        buf
675    }
676
677    pub(super) fn write_bytes_to_sb(buf: &[u8]) -> usize {
678        LAZY_SB.borrow_mut().write(buf)
679    }
680}
681
682pub const THREAD_STARTED: u32 = 1;
683pub struct RuntimeThreadControl {
684    pub id: UnsafeCell<u32>,
685    pub did_exit: UnsafeCell<u32>,
686    // Need to keep a lock for the ID, though we don't expect to use it much.
687    pub internal_lock: AtomicU32,
688    pub flags: AtomicU32,
689    pub stack_canary: u64,
690    pub libc_data: [u64; 1000],
691}
692
693impl Default for RuntimeThreadControl {
694    fn default() -> Self {
695        Self::new(0)
696    }
697}
698
699impl RuntimeThreadControl {
700    pub const fn new(id: u32) -> Self {
701        Self {
702            internal_lock: AtomicU32::new(0),
703            flags: AtomicU32::new(0),
704            id: UnsafeCell::new(id),
705            did_exit: UnsafeCell::new(0),
706            stack_canary: 0,
707            libc_data: [0; 1000],
708        }
709    }
710
711    fn write_lock(&self) {
712        loop {
713            let old = self.internal_lock.fetch_or(1, Ordering::Acquire);
714            if old == 0 {
715                break;
716            }
717        }
718    }
719
720    fn write_unlock(&self) {
721        self.internal_lock.fetch_and(!1, Ordering::Release);
722    }
723
724    fn read_lock(&self) {
725        loop {
726            let old = self.internal_lock.fetch_add(2, Ordering::Acquire);
727            // If this happens, something has gone very wrong.
728            if old > i32::MAX as u32 {
729                twizzler_rt_abi::core::twz_rt_abort();
730            }
731            if old & 1 == 0 {
732                break;
733            }
734        }
735    }
736
737    fn read_unlock(&self) {
738        self.internal_lock.fetch_sub(2, Ordering::Release);
739    }
740
741    pub fn set_id(&self, id: u32) {
742        self.write_lock();
743        unsafe {
744            *self.id.get().as_mut().unwrap() = id;
745        }
746        self.write_unlock();
747    }
748
749    pub fn id(&self) -> u32 {
750        self.read_lock();
751        let id = unsafe { *self.id.get().as_ref().unwrap() };
752        self.read_unlock();
753        id
754    }
755}
756
757pub fn set_nameroot(root: ObjID) -> Result<(), TwzError> {
758    gates::monitor_rt_set_nameroot(root)
759}