469: Goodbye static mut r=AfoHT a=korken89

Squashed and updated version of @perlindgren branch.

In release there are 0 bytes difference for all examples 🎉 
For debug we see a bloat of ~1-2% worst case, commonly less.

Complete diff of sizes for all examples (first is goodbye static mut, second is master):

```

<   27220	      0	     28	  27248	   6a70	spawn
---
>   27092	      0	     28	  27120	   69f0	spawn

<   16916	      0	     44	  16960	   4240	late
---
>   16836	      0	     44	  16880	   41f0	late

<   15952	      0	     12	  15964	   3e5c	type-usage
---
>   15872	      0	     12	  15884	   3e0c	type-usage

<   22068	      0	     44	  22112	   5660	cfg
---
>   21812	      0	     44	  21856	   5560	cfg

<   34784	      0	     40	  34824	   8808	periodic
---
>   34496	      0	     40	  34536	   86e8	periodic

<   22308	      0	     32	  22340	   5744	task
---
>   21972	      0	     32	  22004	   55f4	task

<   15076	      8	     24	  15108	   3b04	task-local
---
>   14980	      8	     24	  15012	   3aa4	task-local

<   12884	      0	     24	  12908	   326c	destructure
---
>   12820	      0	     24	  12844	   322c	destructure

<   10128	      0	     16	  10144	   27a0	init
---
>   10112	      0	     16	  10128	   2790	init

<   19044	      0	     20	  19064	   4a78	task_named_main
---
>   18916	      0	     20	  18936	   49f8	task_named_main

<   27252	      0	     28	  27280	   6a90	extern_spawn
---
>   27124	      0	     28	  27152	   6a10	extern_spawn

<   10176	      0	     16	  10192	   27d0	idle
---
>   10160	      0	     16	  10176	   27c0	idle

<   13972	      0	     16	  13988	   36a4	resource
---
>   13940	      0	     16	  13956	   3684	resource

<   16228	      0	     24	  16252	   3f7c	multilock
---
>   16116	      0	     24	  16140	   3f0c	multilock

<   14660	      0	     16	  14676	   3954	lock
---
>   14628	      0	     16	  14644	   3934	lock

<   10416	      0	     16	  10432	   28c0	task-local-minimal
---
>   10400	      0	     16	  10416	   28b0	task-local-minimal

<   14164	      0	     24	  14188	   376c	generics
---
>   14148	      0	     24	  14172	   375c	generics

<   30644	      0	     48	  30692	   77e4	message
---
>   30308	      0	     48	  30356	   7694	message

<   28964	      0	     36	  29000	   7148	spawn2
---
>   28724	      0	     36	  28760	   7058	spawn2

<   15952	      0	      8	  15960	   3e58	t-schedule-core-stable
---
>   15872	      0	      8	  15880	   3e08	t-schedule-core-stable

<   17408	      0	     20	  17428	   4414	t-cfg
---
>   17248	      0	     20	  17268	   4374	t-cfg

<   12948	      0	     16	  12964	   32a4	hardware
---
>   12932	      0	     16	  12948	   3294	hardware

<   54640	      0	    104	  54744	   d5d8	t-schedule
---
>   53696	      0	    104	  53800	   d228	t-schedule

<   26132	      0	    548	  26680	   6838	pool
---
>   25876	      0	    548	  26424	   6738	pool

<   22372	      0	     56	  22428	   579c	cfg-whole-task
---
>   22100	      0	     56	  22156	   568c	cfg-whole-task

<   38292	      0	     76	  38368	   95e0	schedule
---
>   37828	      0	     76	  37904	   9410	schedule

<   21216	      0	     32	  21248	   5300	t-spawn
---
>   20880	      0	     32	  20912	   51b0	t-spawn

<   22820	      0	     56	  22876	   595c	capacity
---
>   22580	      0	     56	  22636	   586c	capacity

<   17060	      0	     48	  17108	   42d4	static
---
>   16980	      0	     48	  17028	   4284	static

<   20288	      0	     24	  20312	   4f58	ramfunc
---
>   20096	      0	     24	  20120	   4e98	ramfunc

<   11760	      0	     20	  11780	   2e04	t-resource
---
>   11664	      0	     20	  11684	   2da4	t-resource

<   13028	      0	     16	  13044	   32f4	only-shared-access
---
>   13012	      0	     16	  13028	   32e4	only-shared-access

<   16576	      0	     16	  16592	   40d0	not-sync
---
>   16432	      0	     16	  16448	   4040	not-sync

<   13892	      0	     16	  13908	   3654	resource-user-struct
---
>   13860	      0	     16	  13876	   3634	resource-user-struct

<   37472	      0	     64	  37536	   92a0	double_schedule
---
>   36960	      0	     64	  37024	   90a0	double_schedule

<   17648	      0	      8	  17656	   44f8	t-stask-main
---
>   17520	      0	      8	  17528	   4478	t-stask-main

<    8816	      0	      4	   8820	   2274	t-late-not-send
---
>    8800	      0	      4	   8804	   2264	t-late-not-send

<   23280	      0	     32	  23312	   5b10	types
---
>   23120	      0	     32	  23152	   5a70	types
```

Co-authored-by: Emil Fresk <emil.fresk@gmail.com>
This commit is contained in:
bors[bot] 2021-04-22 16:42:45 +00:00 committed by GitHub
commit aad8f81991
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 156 additions and 59 deletions

View file

@ -141,7 +141,7 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
rtic::export::interrupt::free(|_| {
use rtic::Monotonic as _;
use rtic::time::Clock as _;
if let Some(m) = unsafe{ #app_path::#ident.as_ref() } {
if let Some(m) = unsafe{ #app_path::#ident.get_mut_unchecked() } {
if let Ok(v) = m.try_now() {
v
} else {

View file

@ -26,6 +26,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
})
.collect::<Vec<_>>();
// For future use
// let doc = format!(
// "Software tasks to be dispatched at priority level {}",
// level,
@ -53,13 +54,14 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
)
};
// For future use
// let doc = format!(
// "Queue of tasks ready to be dispatched at priority level {}",
// level
// );
items.push(quote!(
#[doc(hidden)]
static mut #rq: #rq_ty = #rq_expr;
static #rq: rtic::RacyCell<#rq_ty> = rtic::RacyCell::new(#rq_expr);
));
let arms = channel
@ -86,8 +88,12 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
#(#cfgs)*
#t::#name => {
let #tupled =
#inputs.get_unchecked(usize::from(index)).as_ptr().read();
#fq.split().0.enqueue_unchecked(index);
#inputs
.get_unchecked()
.get_unchecked(usize::from(index))
.as_ptr()
.read();
#fq.get_mut_unchecked().split().0.enqueue_unchecked(index);
let priority = &rtic::export::Priority::new(PRIORITY);
#app_path::#name(
#locals_new
@ -100,7 +106,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
.collect::<Vec<_>>();
stmts.push(quote!(
while let Some((task, index)) = #rq.split().1.dequeue() {
while let Some((task, index)) = #rq.get_mut_unchecked().split().1.dequeue() {
match task {
#(#arms)*
}

View file

@ -50,11 +50,11 @@ pub fn codegen(
items.push(quote!(
#(#cfgs)*
#[doc(hidden)]
static mut #name: #ty = #expr
static #name: rtic::RacyCell<#ty> = rtic::RacyCell::new(#expr)
));
values.push(quote!(
#(#cfgs)*
#name: &mut #name
#name: #name.get_mut_unchecked()
));
names.push(name);
pats.push(quote!(
@ -64,7 +64,7 @@ pub fn codegen(
}
if lt.is_some() && has_cfgs {
fields.push(quote!(__marker__: core::marker::PhantomData<&'a mut ()>));
fields.push(quote!(__marker__: core::marker::PhantomData<&'a ()>));
values.push(quote!(__marker__: core::marker::PhantomData));
}

View file

@ -245,14 +245,15 @@ pub fn codegen(
let input = #tupled;
unsafe {
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) {
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.get_mut_unchecked().dequeue()) {
#app_path::#inputs
.get_mut_unchecked()
.get_unchecked_mut(usize::from(index))
.as_mut_ptr()
.write(input);
rtic::export::interrupt::free(|_| {
#app_path::#rq.enqueue_unchecked((#app_path::#t::#name, index));
#app_path::#rq.get_mut_unchecked().enqueue_unchecked((#app_path::#t::#name, index));
});
rtic::pend(#device::#enum_::#interrupt);
@ -304,6 +305,10 @@ pub fn codegen(
let user_imports = &app.user_imports;
let tq_marker = util::mark_internal_ident(&util::timer_queue_marker_ident());
// For future use
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
// items.push(quote!(#[doc = #doc]));
items.push(quote!(
/// Holds methods related to this monotonic
pub mod #m {
@ -325,12 +330,16 @@ pub fn codegen(
impl SpawnHandle {
pub fn cancel(self) -> Result<#ty, ()> {
rtic::export::interrupt::free(|_| unsafe {
let tq = &mut *#app_path::#tq.as_mut_ptr();
let tq = &mut *#app_path::#tq.get_mut_unchecked().as_mut_ptr();
if let Some((_task, index)) = tq.cancel_marker(self.marker) {
// Get the message
let msg = #app_path::#inputs.get_unchecked(usize::from(index)).as_ptr().read();
let msg = #app_path::#inputs
.get_unchecked()
.get_unchecked(usize::from(index))
.as_ptr()
.read();
// Return the index to the free queue
#app_path::#fq.split().0.enqueue_unchecked(index);
#app_path::#fq.get_mut_unchecked().split().0.enqueue_unchecked(index);
Ok(msg)
} else {
@ -350,10 +359,10 @@ pub fn codegen(
pub fn reschedule_at(self, instant: rtic::time::Instant<#app_path::#mono_type>) -> Result<Self, ()>
{
rtic::export::interrupt::free(|_| unsafe {
let marker = #tq_marker;
#tq_marker = #tq_marker.wrapping_add(1);
let marker = *#tq_marker.get_mut_unchecked();
*#tq_marker.get_mut_unchecked() = #tq_marker.get_mut_unchecked().wrapping_add(1);
let tq = &mut *#app_path::#tq.as_mut_ptr();
let tq = &mut *#app_path::#tq.get_mut_unchecked().as_mut_ptr();
tq.update_marker(self.marker, marker, instant, || #pend).map(|_| SpawnHandle { marker })
})
@ -373,7 +382,7 @@ pub fn codegen(
D::T: Into<<#app_path::#mono_type as rtic::time::Clock>::T>,
{
let instant = if rtic::export::interrupt::free(|_| unsafe { #app_path::#m_ident.is_none() }) {
let instant = if rtic::export::interrupt::free(|_| unsafe { #app_path::#m_ident.get_mut_unchecked().is_none() }) {
rtic::time::Instant::new(0)
} else {
#app_path::monotonics::#m::now()
@ -390,19 +399,21 @@ pub fn codegen(
) -> Result<SpawnHandle, #ty> {
unsafe {
let input = #tupled;
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) {
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.get_mut_unchecked().dequeue()) {
#app_path::#inputs
.get_mut_unchecked()
.get_unchecked_mut(usize::from(index))
.as_mut_ptr()
.write(input);
#app_path::#instants
.get_mut_unchecked()
.get_unchecked_mut(usize::from(index))
.as_mut_ptr()
.write(instant);
rtic::export::interrupt::free(|_| {
let marker = #tq_marker;
let marker = *#tq_marker.get_mut_unchecked();
let nr = rtic::export::NotReady {
instant,
index,
@ -410,15 +421,15 @@ pub fn codegen(
marker,
};
#tq_marker = #tq_marker.wrapping_add(1);
*#tq_marker.get_mut_unchecked() = #tq_marker.get_mut_unchecked().wrapping_add(1);
let tq = unsafe { &mut *#app_path::#tq.as_mut_ptr() };
let tq = &mut *#app_path::#tq.get_mut_unchecked().as_mut_ptr();
tq.enqueue_unchecked(
nr,
|| #enable_interrupt,
|| #pend,
#app_path::#m_ident.as_mut());
#app_path::#m_ident.get_mut_unchecked().as_mut());
Ok(SpawnHandle { marker })
})

View file

@ -17,16 +17,24 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
// If it's live
let cfgs = app.late_resources[name].cfgs.clone();
if analysis.locations.get(name).is_some() {
// Need to also include the cfgs
stmts.push(quote!(
// We include the cfgs
#(#cfgs)*
#mangled_name.as_mut_ptr().write(late.#name);
// Late resource is a RacyCell<MaybeUninit<T>>
// - `get_mut_unchecked` to obtain `MaybeUninit<T>`
// - `as_mut_ptr` to obtain a raw pointer to `MaybeUninit<T>`
// - `write` the defined value for the late resource T
#mangled_name.get_mut_unchecked().as_mut_ptr().write(late.#name);
));
}
}
}
for (i, (monotonic, _)) in app.monotonics.iter().enumerate() {
// For future use
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
// stmts.push(quote!(#[doc = #doc]));
let idx = Index {
index: i as u32,
span: Span::call_site(),
@ -36,7 +44,7 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
// Store the monotonic
let name = util::monotonic_ident(&monotonic.to_string());
let name = util::mark_internal_ident(&name);
stmts.push(quote!(#name = Some(monotonics.#idx);));
stmts.push(quote!(*#name.get_mut_unchecked() = Some(monotonics.#idx);));
}
// Enable the interrupts -- this completes the `init`-ialization phase

View file

@ -20,7 +20,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
let fq_ident = util::mark_internal_ident(&fq_ident);
stmts.push(quote!(
(0..#cap).for_each(|i| #fq_ident.enqueue_unchecked(i));
(0..#cap).for_each(|i| #fq_ident.get_mut_unchecked().enqueue_unchecked(i));
));
}
@ -86,7 +86,9 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
let tq = util::mark_internal_ident(&tq);
// Initialize timer queues
stmts.push(quote!(#tq.as_mut_ptr().write(rtic::export::TimerQueue::new());));
stmts.push(
quote!(#tq.get_mut_unchecked().as_mut_ptr().write(rtic::export::TimerQueue::new());),
);
// Compile time assert that this priority is supported by the device
stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));

View file

@ -4,13 +4,20 @@ use rtic_syntax::{analyze::Ownership, ast::App};
use crate::{analyze::Analysis, check::Extra, codegen::util};
/// Generates `static [mut]` variables and resource proxies
/// Generates `static` variables and resource proxies
/// Early resources are stored in `RacyCell<T>`
/// Late resource are stored in `RacyCell<MaybeUninit<T>>`
///
/// Safety:
/// - RacyCell<T> access is `unsafe`.
/// - RacyCell<MaybeUninit> is always written to before user access, thus
// the generated code for user access can safely `assume_init`.
pub fn codegen(
app: &App,
analysis: &Analysis,
extra: &Extra,
) -> (
// mod_app -- the `static [mut]` variables behind the proxies
// mod_app -- the `static` variables behind the proxies
Vec<TokenStream2>,
// mod_resources -- the `resources` module
TokenStream2,
@ -24,35 +31,51 @@ pub fn codegen(
let mangled_name = util::mark_internal_ident(&name);
{
// late resources in `util::link_section_uninit`
let section = if expr.is_none() {
util::link_section_uninit(true)
} else {
None
};
// resource type and assigned value
let (ty, expr) = if let Some(expr) = expr {
(quote!(#ty), quote!(#expr))
} else {
// early resource
(
quote!(core::mem::MaybeUninit<#ty>),
quote!(core::mem::MaybeUninit::uninit()),
quote!(rtic::RacyCell<#ty>),
quote!(rtic::RacyCell::new(#expr)),
)
} else {
// late resource
(
quote!(rtic::RacyCell<core::mem::MaybeUninit<#ty>>),
quote!(rtic::RacyCell::new(core::mem::MaybeUninit::uninit())),
)
};
let attrs = &res.attrs;
// For future use
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
mod_app.push(quote!(
#[allow(non_upper_case_globals)]
// #[doc = #doc]
#[doc(hidden)]
#(#attrs)*
#(#cfgs)*
#section
static mut #mangled_name: #ty = #expr;
static #mangled_name: #ty = #expr;
));
}
let r_prop = &res.properties;
// For future use
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
if !r_prop.task_local && !r_prop.lock_free {
mod_resources.push(quote!(
// #[doc = #doc]
#[doc(hidden)]
#[allow(non_camel_case_types)]
#(#cfgs)*
pub struct #name<'a> {
@ -73,15 +96,23 @@ pub fn codegen(
}
));
let ptr = if expr.is_none() {
let (ptr, _doc) = if expr.is_none() {
// late resource
(
quote!(
#(#cfgs)*
#mangled_name.as_mut_ptr()
#mangled_name.get_mut_unchecked().as_mut_ptr()
),
"late",
)
} else {
// early resource
(
quote!(
#(#cfgs)*
&mut #mangled_name
#mangled_name.get_mut_unchecked()
),
"early",
)
};
@ -92,6 +123,9 @@ pub fn codegen(
None => 0,
};
// For future use
// let doc = format!(" RTIC internal ({} resource): {}:{}", doc, file!(), line!());
mod_app.push(util::impl_mutex(
extra,
cfgs,

View file

@ -79,9 +79,9 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
let is_late = expr.is_none();
if is_late {
let expr = if access.is_exclusive() {
quote!(&mut *#mangled_name.as_mut_ptr())
quote!(&mut *#mangled_name.get_mut_unchecked().as_mut_ptr())
} else {
quote!(&*#mangled_name.as_ptr())
quote!(&*#mangled_name.get_unchecked().as_ptr())
};
values.push(quote!(
@ -91,7 +91,7 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
} else {
values.push(quote!(
#(#cfgs)*
#name: &#mut_ #mangled_name
#name: #mangled_name.get_mut_unchecked()
));
}
}

View file

@ -52,7 +52,7 @@ pub fn codegen(
// /// Queue version of a free-list that keeps track of empty slots in
// /// the following buffers
#[doc(hidden)]
static mut #fq: #fq_ty = #fq_expr;
static #fq: rtic::RacyCell<#fq_ty> = rtic::RacyCell::new(#fq_expr);
));
let elems = &(0..cap)
@ -65,13 +65,16 @@ pub fn codegen(
let mono_type = &monotonic.ty;
let uninit = mk_uninit();
// For future use
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
mod_app.push(quote!(
#uninit
// /// Buffer that holds the instants associated to the inputs of a task
// #[doc = #doc]
#[doc(hidden)]
static mut #instants:
[core::mem::MaybeUninit<rtic::time::Instant<#mono_type>>; #cap_lit] =
[#(#elems,)*];
static #instants:
rtic::RacyCell<[core::mem::MaybeUninit<rtic::time::Instant<#mono_type>>; #cap_lit]> =
rtic::RacyCell::new([#(#elems,)*]);
));
}
@ -82,8 +85,8 @@ pub fn codegen(
#uninit
// /// Buffer that holds the inputs of a task
#[doc(hidden)]
static mut #inputs_ident: [core::mem::MaybeUninit<#input_ty>; #cap_lit] =
[#(#elems,)*];
static #inputs_ident: rtic::RacyCell<[core::mem::MaybeUninit<#input_ty>; #cap_lit]> =
rtic::RacyCell::new([#(#elems,)*]);
));
// `${task}Resources`

View file

@ -15,7 +15,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
// #[doc = #doc]
#[doc(hidden)]
#[allow(non_camel_case_types)]
static mut #tq_marker: u32 = 0;
static #tq_marker: rtic::RacyCell<u32> = rtic::RacyCell::new(0);
));
let t = util::schedule_t_ident();
@ -35,6 +35,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
})
.collect::<Vec<_>>();
// For future use
// let doc = "Tasks that can be scheduled".to_string();
items.push(quote!(
// #[doc = #doc]
@ -61,6 +62,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
// Static variables and resource proxy
{
// For future use
// let doc = &format!("Timer queue for {}", monotonic_name);
let cap = app
.software_tasks
@ -71,18 +73,22 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
let tq_ty =
quote!(core::mem::MaybeUninit<rtic::export::TimerQueue<#mono_type, #t, #n>>);
// For future use
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
items.push(quote!(
#[doc(hidden)]
static mut #tq: #tq_ty = core::mem::MaybeUninit::uninit();
static #tq: rtic::RacyCell<#tq_ty> =
rtic::RacyCell::new(core::mem::MaybeUninit::uninit());
));
let mono = util::monotonic_ident(&monotonic_name);
let mono = util::mark_internal_ident(&mono);
// For future use
// let doc = &format!("Storage for {}", monotonic_name);
items.push(quote!(
#[doc(hidden)]
static mut #mono: Option<#mono_type> = None;
static #mono: rtic::RacyCell<Option<#mono_type>> = rtic::RacyCell::new(None);
));
}
@ -113,7 +119,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
quote!(
#(#cfgs)*
#t::#name => {
rtic::export::interrupt::free(|_| #rq.split().0.enqueue_unchecked((#rqt::#name, index)));
rtic::export::interrupt::free(|_| #rq.get_mut_unchecked().split().0.enqueue_unchecked((#rqt::#name, index)));
#pend
}
@ -132,10 +138,9 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
#[no_mangle]
#[allow(non_snake_case)]
unsafe fn #bound_interrupt() {
while let Some((task, index)) = rtic::export::interrupt::free(|_|
if let Some(mono) = #app_path::#m_ident.as_mut() {
(&mut *#tq.as_mut_ptr()).dequeue(|| #disable_isr, mono)
if let Some(mono) = #app_path::#m_ident.get_mut_unchecked().as_mut() {
(&mut *#tq.get_mut_unchecked().as_mut_ptr()).dequeue(|| #disable_isr, mono)
} else {
// We can only use the timer queue if `init` has returned, and it
// writes the `Some(monotonic)` we are accessing here.
@ -147,7 +152,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
}
}
rtic::export::interrupt::free(|_| if let Some(mono) = #app_path::#m_ident.as_mut() {
rtic::export::interrupt::free(|_| if let Some(mono) = #app_path::#m_ident.get_mut_unchecked().as_mut() {
mono.on_interrupt();
});
}

View file

@ -57,3 +57,31 @@ where
{
NVIC::pend(interrupt)
}
use core::cell::UnsafeCell;
/// Internal replacement for `static mut T`
#[repr(transparent)]
pub struct RacyCell<T>(UnsafeCell<T>);
impl<T> RacyCell<T> {
/// Create a RacyCell
#[inline(always)]
pub const fn new(value: T) -> Self {
RacyCell(UnsafeCell::new(value))
}
/// Get `&mut T`
#[inline(always)]
pub unsafe fn get_mut_unchecked(&self) -> &mut T {
&mut *self.0.get()
}
/// Get `&T`
#[inline(always)]
pub unsafe fn get_unchecked(&self) -> &T {
&*self.0.get()
}
}
unsafe impl<T> Sync for RacyCell<T> {}