sel4/state/
mod.rs

1//
2// Copyright 2023, Colias Group, LLC
3//
4// SPDX-License-Identifier: MIT
5//
6
7use core::cell::UnsafeCell;
8
9use crate::{InvocationContext, IpcBuffer};
10
11mod token;
12
13#[allow(unused_imports)]
14use token::{Accessor, BorrowError, BorrowMutError, SyncToken, TokenCell, UnsyncToken};
15
16// // //
17
18#[repr(transparent)]
19struct SyncUnsafeCell<T>(UnsafeCell<T>);
20
21unsafe impl<T: Sync> Sync for SyncUnsafeCell<T> {}
22
23#[repr(transparent)]
24struct TokenCellWrapper<A>(TokenCell<TokenImpl, A>);
25
26cfg_if::cfg_if! {
27    if #[cfg(all(any(target_thread_local, feature = "tls"), not(feature = "non-thread-local-state")))] {
28        type TokenImpl = UnsyncToken;
29
30        const STATE_IS_THREAD_LOCAL: bool = true;
31
32        macro_rules! maybe_add_thread_local_attr {
33            { $item:item } => {
34                #[thread_local]
35                $item
36            }
37        }
38    } else if #[cfg(not(feature = "thread-local-state"))] {
39        cfg_if::cfg_if! {
40            if #[cfg(feature = "single-threaded")] {
41                unsafe impl<A> Sync for TokenCellWrapper<A> {}
42
43                type TokenImpl = UnsyncToken;
44            } else {
45                type TokenImpl = SyncToken;
46            }
47        }
48
49        const STATE_IS_THREAD_LOCAL: bool = false;
50
51        macro_rules! maybe_add_thread_local_attr {
52            { $item:item } => {
53                $item
54            }
55        }
56    } else {
57        compile_error!(r#"invalid configuration"#);
58    }
59}
60
61macro_rules! maybe_extern {
62    { $ident:ident: $ty:ty = $init:expr; } => {
63        cfg_if::cfg_if! {
64            if #[cfg(feature = "extern-state")] {
65                extern "C" {
66                    maybe_add_thread_local_attr! {
67                        static $ident: $ty;
68                    }
69                }
70            } else {
71                maybe_add_thread_local_attr! {
72                    #[allow(non_upper_case_globals)]
73                    #[cfg_attr(feature = "exposed-state", no_mangle)]
74                    static $ident: $ty = $init;
75                }
76            }
77        }
78    }
79}
80
81// // //
82
83maybe_extern! {
84    __sel4_ipc_buffer: SyncUnsafeCell<Option<&'static mut IpcBuffer>> =
85        SyncUnsafeCell(UnsafeCell::new(None));
86}
87
88struct IpcBufferAccessor;
89
90impl Accessor<Option<&'static mut IpcBuffer>> for IpcBufferAccessor {
91    #[allow(unused_unsafe)]
92    fn with<F, U>(&self, f: F) -> U
93    where
94        F: FnOnce(&UnsafeCell<Option<&'static mut IpcBuffer>>) -> U,
95    {
96        f(unsafe { &__sel4_ipc_buffer.0 })
97    }
98}
99
100maybe_add_thread_local_attr! {
101    static IPC_BUFFER: TokenCellWrapper<IpcBufferAccessor> = unsafe {
102        TokenCellWrapper(TokenCell::new(IpcBufferAccessor))
103    };
104}
105
106/// Provides low-level access to this thread's IPC buffer.
107///
108/// This function does not modify kernel state. It only affects this crate's thread-local state.
109///
110/// Requires the `"state"` feature to be enabled.
111pub fn try_with_ipc_buffer_slot<F, T>(f: F) -> T
112where
113    F: FnOnce(Result<&Option<&'static mut IpcBuffer>, BorrowError>) -> T,
114{
115    IPC_BUFFER.0.try_with(f)
116}
117
118/// Provides low-level mutable access to this thread's IPC buffer.
119///
120/// This function does not modify kernel state. It only affects this crate's thread-local state.
121///
122/// Requires the `"state"` feature to be enabled.
123pub fn try_with_ipc_buffer_slot_mut<F, T>(f: F) -> T
124where
125    F: FnOnce(Result<&mut Option<&'static mut IpcBuffer>, BorrowMutError>) -> T,
126{
127    IPC_BUFFER.0.try_with_mut(f)
128}
129
130/// Provides access to this thread's IPC buffer.
131///
132/// Requires the `"state"` feature to be enabled.
133pub fn with_ipc_buffer<F, T>(f: F) -> T
134where
135    F: FnOnce(&IpcBuffer) -> T,
136{
137    try_with_ipc_buffer_slot(|buf| f(buf.unwrap().as_ref().unwrap()))
138}
139
140/// Provides mutable access to this thread's IPC buffer.
141///
142/// Requires the `"state"` feature to be enabled.
143pub fn with_ipc_buffer_mut<F, T>(f: F) -> T
144where
145    F: FnOnce(&mut IpcBuffer) -> T,
146{
147    try_with_ipc_buffer_slot_mut(|buf| f(buf.unwrap().as_mut().unwrap()))
148}
149
150/// Sets the IPC buffer that this crate will use for this thread.
151///
152/// This function does not modify kernel state. It only affects this crate's thread-local state.
153///
154/// Requires the `"state"` feature to be enabled.
155pub fn set_ipc_buffer(ipc_buffer: &'static mut IpcBuffer) {
156    try_with_ipc_buffer_slot_mut(|slot| {
157        *slot.unwrap() = Some(ipc_buffer);
158    })
159}
160
161/// Returns whether this crate's IPC buffer slot is thread-local.
162///
163/// Requires the `"state"` feature to be enabled.
164pub const fn ipc_buffer_is_thread_local() -> bool {
165    STATE_IS_THREAD_LOCAL
166}
167
168/// The strategy for discovering the current thread's IPC buffer which uses thread-local state.
169///
170/// This thread-local state can be modified using [`with_ipc_buffer`] and [`set_ipc_buffer`].
171///
172/// Requires the `"state"` feature to be enabled.
173#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Hash)]
174pub struct ImplicitInvocationContext;
175
176impl ImplicitInvocationContext {
177    pub const fn new() -> Self {
178        Self
179    }
180}
181
182impl InvocationContext for ImplicitInvocationContext {
183    fn with_context<T>(&mut self, f: impl FnOnce(&mut IpcBuffer) -> T) -> T {
184        with_ipc_buffer_mut(f)
185    }
186}