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
#![warn(missing_docs)]

//! Isolated tasks of execution

use std::panic;

use crate::binding::Never;
use crate::boxed::prelude::*;
use crate::boxed::type_info::TypeInfo;
use crate::boxed::Heap;

/// Isolated task of execution
///
/// All Arret and RFI code must run inside a task. It provides a dedicated garbage collected
/// [`Heap`] as well as an isolation boundary against panics. A task is inherently single threaded;
/// it's not possible for one task to be executing on multiple threads at the same time.
pub struct Task {
    heap: Heap,
}

impl Task {
    const DEFAULT_CAPACITY: usize = 32;

    /// Creates a new empty task
    pub fn new() -> Task {
        Self::with_type_info(TypeInfo::empty())
    }

    pub(crate) fn with_type_info(type_info: TypeInfo) -> Task {
        Self {
            heap: Heap::new(type_info, Self::DEFAULT_CAPACITY),
        }
    }

    /// Returns this task's dedicated heap
    pub fn heap(&self) -> &Heap {
        &self.heap
    }

    /// Returns a mutable reference to this task's dedicated heap
    pub fn heap_mut(&mut self) -> &mut Heap {
        &mut self.heap
    }

    /// Panics the current task
    ///
    /// This destroys the current task and invokes any cleanup required.
    pub fn panic(&mut self, message: String) -> Never {
        // Using `resume_unwind` accomplishes two things:
        //
        // 1. Avoids printing the panic info to stderr as this is an "intentional" panic
        // 2. Skips incrementing our panic count. This is important for compile time evaluation of
        //    panics. The compiler and stdlib have a different panic count due to being in separate
        //    binaries. With a normal `panic!` the panic count will be increment on the stdlib and
        //    decremented in the compiler. On the second panic the stdlib thinks it's already
        //    panicking and aborts. This is a hacky workaround.
        //
        // TODO: Fix panics uniformly and remove this method. If we panic inside e.g. Rust stdlib
        // we won't follow this path.
        panic::resume_unwind(Box::new(message));
    }
}

impl Default for Task {
    fn default() -> Task {
        Task::new()
    }
}

impl AsHeap for Task {
    fn as_heap(&self) -> &Heap {
        &self.heap
    }

    fn as_heap_mut(&mut self) -> &mut Heap {
        &mut self.heap
    }
}