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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
//! [ArceOS](https://github.com/arceos-org/arceos) namespaces module.
//!
//! Namespaces are used to control system resource sharing between threads. This
//! module provides a unified interface to access system resources in different
//! scenarios.
//!
//! For a unikernel, there is only one global namespace, so all threads share
//! the same system resources, such as virtual address space, working directory,
//! and file descriptors, etc.
//!
//! For a monolithic kernel, each process corresponds to a namespace, all
//! threads in the same process share the same system resources. Different
//! processes have different namespaces and isolated resources.
//!
//! For further container support, some global system resources can also be
//! grouped into a namespace.
//!
//! See the examples of [`def_resource!`] for more usage.

#![cfg_attr(not(test), no_std)]

extern crate alloc;

use alloc::sync::Arc;
use core::{alloc::Layout, fmt, ops::Deref};

use lazyinit::LazyInit;

extern "C" {
    fn __start_axns_resource();
    fn __stop_axns_resource();
}

/// A namespace that contains all user-defined resources.
///
/// There are two types of namespaces:
///
/// - Global namespace: this namespace is globally unique and all threads share
/// the resources in it. Resources are statically collected into the
/// `axns_resource` section, and the global namespace is constructed by the base
/// address of the section ([`AxNamespace::global`]).
/// - Thread-local namespace: this namespace is per-thread, each thread should
/// call [`AxNamespace::new_thread_local()`] to allocate a memory area as its
/// namespace. Layout of resources in global and thread-local namespaces is
/// consistent. Each namespace has its own resources, which may be unique or
/// shared between threads by the [`Arc`] wrapper.
pub struct AxNamespace {
    base: *mut u8,
    alloc: bool,
}

impl AxNamespace {
    /// Returns the base address of the namespace, which points to the start of
    /// all resources.
    pub const fn base(&self) -> *mut u8 {
        self.base
    }

    /// Returns the size of the namespace (size of all resources).
    pub fn size(&self) -> usize {
        Self::section_size()
    }

    /// Returns the size of the `axns_resource` section.
    fn section_size() -> usize {
        __stop_axns_resource as usize - __start_axns_resource as usize
    }

    /// Returns the global namespace.
    pub fn global() -> Self {
        Self {
            base: __start_axns_resource as *mut u8,
            alloc: false,
        }
    }

    /// Constructs a new thread-local namespace.
    ///
    /// Each thread can have its own namespace instead of the global one, to
    /// isolate resources between threads.
    ///
    /// This function allocates a memory area to store the thread-local resources,
    /// and copies from the global namespace as the initial value.
    #[cfg(feature = "thread-local")]
    pub fn new_thread_local() -> Self {
        let size = Self::section_size();
        let base = if size == 0 {
            core::ptr::null_mut()
        } else {
            let layout = Layout::from_size_align(size, 64).unwrap();
            let dst = unsafe { alloc::alloc::alloc(layout) };
            let src = __start_axns_resource as *const u8;
            unsafe { core::ptr::copy_nonoverlapping(src, dst, size) };
            dst
        };
        Self { base, alloc: true }
    }
}

impl Drop for AxNamespace {
    fn drop(&mut self) {
        if self.alloc {
            let size = Self::section_size();
            if size != 0 && !self.base.is_null() {
                let layout = Layout::from_size_align(size, 64).unwrap();
                unsafe { alloc::alloc::dealloc(self.base, layout) };
            }
        }
    }
}

/// A helper type to easily manage shared resources.
///
/// It provides methods to lazily initialize the resource of the current thread,
/// or to share the resource with other threads.
pub struct AxResource<T>(LazyInit<Arc<T>>);

impl<T> AxResource<T> {
    /// Creates a new uninitialized resource.
    pub const fn new() -> Self {
        Self(LazyInit::new())
    }

    /// Returns a shared reference to the resource.
    pub fn share(&self) -> Arc<T> {
        self.0.deref().clone()
    }

    /// Initializes the resource and does not share with others.
    pub fn init_new(&self, data: T) {
        self.0.init_once(Arc::new(data));
    }

    /// Initializes the resource with the shared data.
    pub fn init_shared(&self, data: Arc<T>) {
        self.0.init_once(data);
    }

    /// Checks whether the value is initialized.
    pub fn is_inited(&self) -> bool {
        self.0.is_inited()
    }
}

impl<T> Deref for AxResource<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        self.0.deref()
    }
}

impl<T: fmt::Debug> fmt::Debug for AxResource<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

/// The interfaces need to be implemented when enable thread-local namespaces.
#[cfg(feature = "thread-local")]
#[crate_interface::def_interface]
pub trait AxNamespaceIf {
    /// Returns the pointer to the current namespace.
    ///
    /// It usually needs to be obtained from the thread local storage.
    fn current_namespace_base() -> *mut u8;
}

/// Returns the pointer to the current namespace.
///
/// When `thread-local` feature is enabled, it returns the thread-local namespace
/// of the current thread. Otherwise, it returns the global namespace.
///
/// # Safety
///
/// This function is unsafe, the returned pointer should not outlive the current
/// thread.
pub unsafe fn current_namespace_base() -> *mut u8 {
    #[cfg(feature = "thread-local")]
    {
        crate_interface::call_interface!(AxNamespaceIf::current_namespace_base)
    }
    #[cfg(not(feature = "thread-local"))]
    {
        AxNamespace::global().base()
    }
}

/// Defines a resource that managed by [`AxNamespace`].
///
/// Each resource will be collected into the `axns_resource` section. When
/// accessed, it is either dereferenced from the global namespace or the
/// thread-local namespace according to the `thread-local` feature.
///
/// # Example
///
/// ```
/// use axns::AxResource;
///
/// axns::def_resource! {
///     static FOO: u32 = 42;
///     static BAR: AxResource<String> = AxResource::new();
/// }
///
/// BAR.init_new("hello world".to_string());
/// assert_eq!(*FOO, 42);
/// assert_eq!(BAR.as_str(), "hello world");
///
/// mod imp {
///     use axns::{AxNamespace, AxNamespaceIf};
///
///     struct AxResourceImpl;
///
///     #[crate_interface::impl_interface]
///     impl AxNamespaceIf for AxResourceImpl {
///         fn current_namespace_base() -> *mut u8 {
///             AxNamespace::global().base()
///         }
///     }
/// }
/// ```
#[macro_export]
macro_rules! def_resource {
    ( $( $(#[$attr:meta])* $vis:vis static $name:ident: $ty:ty = $default:expr; )+ ) => {
        $(
            $(#[$attr])*
            $vis struct $name { __value: () }

            impl $name {
                unsafe fn deref_from_base(&self, ns_base: *mut u8) -> &$ty {
                    extern {
                        fn __start_axns_resource();
                    }

                    #[link_section = "axns_resource"]
                    static RES: $ty = $default;

                    let offset = &RES as *const _ as usize - __start_axns_resource as usize;
                    let ptr = ns_base.add(offset) as *const _;
                    &*ptr
                }

                /// Dereference the resource from the given namespace.
                pub fn deref_from(&self, ns: &$crate::AxNamespace) -> &$ty {
                    unsafe { self.deref_from_base(ns.base()) }
                }

                /// Dereference the resource from the global namespace.
                pub fn deref_global(&self) -> &$ty {
                    self.deref_from(&$crate::AxNamespace::global())
                }

                /// Dereference the resource automatically, according whether the
                /// `thread-local` feature of the `axns` crate is enabled or not.
                ///
                /// When the feature is enabled, it dereferences from the
                /// thread-local namespace of the current thread. Otherwise, it
                /// dereferences from the global namespace.
                pub fn deref_auto(&self) -> &$ty {
                    unsafe { self.deref_from_base($crate::current_namespace_base()) }
                }
            }

            impl core::ops::Deref for $name {
                type Target = $ty;

                #[inline(never)]
                fn deref(&self) -> &Self::Target {
                    self.deref_auto()
                }
            }

            #[used]
            #[doc(hidden)]
            $(#[$attr])*
            $vis static $name: $name = $name { __value: () };
        )+
    };
}