sel4/state/
mod.rs
1use 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#[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
81maybe_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
106pub 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
118pub 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
130pub 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
140pub 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
150pub 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
161pub const fn ipc_buffer_is_thread_local() -> bool {
165 STATE_IS_THREAD_LOCAL
166}
167
168#[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}