mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-12-25 19:39:32 +01:00
Merge #548
548: Fixed aliasing issue due to RacyCell implementation r=perlindgren a=korken89 Co-authored-by: Emil Fresk <emil.fresk@gmail.com> Co-authored-by: Per Lindgren <per.lindgren@ltu.se>
This commit is contained in:
commit
7155b55ac8
11 changed files with 68 additions and 51 deletions
|
@ -15,7 +15,6 @@ mod app {
|
||||||
|
|
||||||
#[shared]
|
#[shared]
|
||||||
struct Shared {
|
struct Shared {
|
||||||
#[cfg(debug_assertions)] // <- `true` when using the `dev` profile
|
|
||||||
count: u32,
|
count: u32,
|
||||||
#[cfg(never)]
|
#[cfg(never)]
|
||||||
unused: u32,
|
unused: u32,
|
||||||
|
@ -31,7 +30,6 @@ mod app {
|
||||||
|
|
||||||
(
|
(
|
||||||
Shared {
|
Shared {
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
count: 0,
|
count: 0,
|
||||||
#[cfg(never)]
|
#[cfg(never)]
|
||||||
unused: 1,
|
unused: 1,
|
||||||
|
|
|
@ -135,7 +135,7 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
|
||||||
rtic::export::interrupt::free(|_| {
|
rtic::export::interrupt::free(|_| {
|
||||||
use rtic::Monotonic as _;
|
use rtic::Monotonic as _;
|
||||||
use rtic::time::Clock as _;
|
use rtic::time::Clock as _;
|
||||||
if let Some(m) = unsafe{ super::super::#ident.get_mut_unchecked() } {
|
if let Some(m) = unsafe{ &mut *super::super::#ident.get_mut() } {
|
||||||
if let Ok(v) = m.try_now() {
|
if let Ok(v) = m.try_now() {
|
||||||
v
|
v
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -78,12 +78,12 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
#t::#name => {
|
#t::#name => {
|
||||||
let #tupled =
|
let #tupled =
|
||||||
#inputs
|
(&*#inputs
|
||||||
.get_unchecked()
|
.get())
|
||||||
.get_unchecked(usize::from(index))
|
.get_unchecked(usize::from(index))
|
||||||
.as_ptr()
|
.as_ptr()
|
||||||
.read();
|
.read();
|
||||||
#fq.get_mut_unchecked().split().0.enqueue_unchecked(index);
|
(&mut *#fq.get_mut()).split().0.enqueue_unchecked(index);
|
||||||
let priority = &rtic::export::Priority::new(PRIORITY);
|
let priority = &rtic::export::Priority::new(PRIORITY);
|
||||||
#name(
|
#name(
|
||||||
#name::Context::new(priority)
|
#name::Context::new(priority)
|
||||||
|
@ -95,7 +95,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
stmts.push(quote!(
|
stmts.push(quote!(
|
||||||
while let Some((task, index)) = #rq.get_mut_unchecked().split().1.dequeue() {
|
while let Some((task, index)) = (&mut *#rq.get_mut()).split().1.dequeue() {
|
||||||
match task {
|
match task {
|
||||||
#(#arms)*
|
#(#arms)*
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,9 +57,9 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
|
||||||
let expr = if is_declared {
|
let expr = if is_declared {
|
||||||
// If the local resources is already initialized, we only need to access its value and
|
// If the local resources is already initialized, we only need to access its value and
|
||||||
// not go through an `MaybeUninit`
|
// not go through an `MaybeUninit`
|
||||||
quote!(#mangled_name.get_mut_unchecked())
|
quote!(&mut *#mangled_name.get_mut())
|
||||||
} else {
|
} else {
|
||||||
quote!(&mut *#mangled_name.get_mut_unchecked().as_mut_ptr())
|
quote!(&mut *(&mut *#mangled_name.get_mut()).as_mut_ptr())
|
||||||
};
|
};
|
||||||
|
|
||||||
values.push(quote!(
|
values.push(quote!(
|
||||||
|
|
|
@ -232,15 +232,15 @@ pub fn codegen(
|
||||||
let input = #tupled;
|
let input = #tupled;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Some(index) = rtic::export::interrupt::free(|_| #fq.get_mut_unchecked().dequeue()) {
|
if let Some(index) = rtic::export::interrupt::free(|_| (&mut *#fq.get_mut()).dequeue()) {
|
||||||
#inputs
|
(&mut *#inputs
|
||||||
.get_mut_unchecked()
|
.get_mut())
|
||||||
.get_unchecked_mut(usize::from(index))
|
.get_unchecked_mut(usize::from(index))
|
||||||
.as_mut_ptr()
|
.as_mut_ptr()
|
||||||
.write(input);
|
.write(input);
|
||||||
|
|
||||||
rtic::export::interrupt::free(|_| {
|
rtic::export::interrupt::free(|_| {
|
||||||
#rq.get_mut_unchecked().enqueue_unchecked((#t::#name, index));
|
(&mut *#rq.get_mut()).enqueue_unchecked((#t::#name, index));
|
||||||
});
|
});
|
||||||
|
|
||||||
rtic::pend(#device::#enum_::#interrupt);
|
rtic::pend(#device::#enum_::#interrupt);
|
||||||
|
@ -330,16 +330,16 @@ pub fn codegen(
|
||||||
impl #internal_spawn_handle_ident {
|
impl #internal_spawn_handle_ident {
|
||||||
pub fn cancel(self) -> Result<#ty, ()> {
|
pub fn cancel(self) -> Result<#ty, ()> {
|
||||||
rtic::export::interrupt::free(|_| unsafe {
|
rtic::export::interrupt::free(|_| unsafe {
|
||||||
let tq = #tq.get_mut_unchecked();
|
let tq = &mut *#tq.get_mut();
|
||||||
if let Some((_task, index)) = tq.cancel_marker(self.marker) {
|
if let Some((_task, index)) = tq.cancel_marker(self.marker) {
|
||||||
// Get the message
|
// Get the message
|
||||||
let msg = #inputs
|
let msg = (&*#inputs
|
||||||
.get_unchecked()
|
.get())
|
||||||
.get_unchecked(usize::from(index))
|
.get_unchecked(usize::from(index))
|
||||||
.as_ptr()
|
.as_ptr()
|
||||||
.read();
|
.read();
|
||||||
// Return the index to the free queue
|
// Return the index to the free queue
|
||||||
#fq.get_mut_unchecked().split().0.enqueue_unchecked(index);
|
(&mut *#fq.get_mut()).split().0.enqueue_unchecked(index);
|
||||||
|
|
||||||
Ok(msg)
|
Ok(msg)
|
||||||
} else {
|
} else {
|
||||||
|
@ -359,10 +359,10 @@ pub fn codegen(
|
||||||
pub fn reschedule_at(self, instant: rtic::time::Instant<#mono_type>) -> Result<Self, ()>
|
pub fn reschedule_at(self, instant: rtic::time::Instant<#mono_type>) -> Result<Self, ()>
|
||||||
{
|
{
|
||||||
rtic::export::interrupt::free(|_| unsafe {
|
rtic::export::interrupt::free(|_| unsafe {
|
||||||
let marker = *#tq_marker.get_mut_unchecked();
|
let marker = #tq_marker.get().read();
|
||||||
*#tq_marker.get_mut_unchecked() = #tq_marker.get_mut_unchecked().wrapping_add(1);
|
#tq_marker.get_mut().write(marker.wrapping_add(1));
|
||||||
|
|
||||||
let tq = #tq.get_mut_unchecked();
|
let tq = (&mut *#tq.get_mut());
|
||||||
|
|
||||||
tq.update_marker(self.marker, marker, instant, || #pend).map(|_| #name::#m::SpawnHandle { marker })
|
tq.update_marker(self.marker, marker, instant, || #pend).map(|_| #name::#m::SpawnHandle { marker })
|
||||||
})
|
})
|
||||||
|
@ -383,7 +383,7 @@ pub fn codegen(
|
||||||
D::T: Into<<#mono_type as rtic::time::Clock>::T>,
|
D::T: Into<<#mono_type as rtic::time::Clock>::T>,
|
||||||
{
|
{
|
||||||
|
|
||||||
let instant = if rtic::export::interrupt::free(|_| unsafe { #m_ident.get_mut_unchecked().is_none() }) {
|
let instant = if rtic::export::interrupt::free(|_| unsafe { (&*#m_ident.get()).is_none() }) {
|
||||||
rtic::time::Instant::new(0)
|
rtic::time::Instant::new(0)
|
||||||
} else {
|
} else {
|
||||||
monotonics::#m::now()
|
monotonics::#m::now()
|
||||||
|
@ -401,21 +401,21 @@ pub fn codegen(
|
||||||
) -> Result<#name::#m::SpawnHandle, #ty> {
|
) -> Result<#name::#m::SpawnHandle, #ty> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let input = #tupled;
|
let input = #tupled;
|
||||||
if let Some(index) = rtic::export::interrupt::free(|_| #fq.get_mut_unchecked().dequeue()) {
|
if let Some(index) = rtic::export::interrupt::free(|_| (&mut *#fq.get_mut()).dequeue()) {
|
||||||
#inputs
|
(&mut *#inputs
|
||||||
.get_mut_unchecked()
|
.get_mut())
|
||||||
.get_unchecked_mut(usize::from(index))
|
.get_unchecked_mut(usize::from(index))
|
||||||
.as_mut_ptr()
|
.as_mut_ptr()
|
||||||
.write(input);
|
.write(input);
|
||||||
|
|
||||||
#instants
|
(&mut *#instants
|
||||||
.get_mut_unchecked()
|
.get_mut())
|
||||||
.get_unchecked_mut(usize::from(index))
|
.get_unchecked_mut(usize::from(index))
|
||||||
.as_mut_ptr()
|
.as_mut_ptr()
|
||||||
.write(instant);
|
.write(instant);
|
||||||
|
|
||||||
rtic::export::interrupt::free(|_| {
|
rtic::export::interrupt::free(|_| {
|
||||||
let marker = *#tq_marker.get_mut_unchecked();
|
let marker = #tq_marker.get().read();
|
||||||
let nr = rtic::export::NotReady {
|
let nr = rtic::export::NotReady {
|
||||||
instant,
|
instant,
|
||||||
index,
|
index,
|
||||||
|
@ -423,15 +423,15 @@ pub fn codegen(
|
||||||
marker,
|
marker,
|
||||||
};
|
};
|
||||||
|
|
||||||
*#tq_marker.get_mut_unchecked() = #tq_marker.get_mut_unchecked().wrapping_add(1);
|
#tq_marker.get_mut().write(#tq_marker.get().read().wrapping_add(1));
|
||||||
|
|
||||||
let tq = #tq.get_mut_unchecked();
|
let tq = &mut *#tq.get_mut();
|
||||||
|
|
||||||
tq.enqueue_unchecked(
|
tq.enqueue_unchecked(
|
||||||
nr,
|
nr,
|
||||||
|| #enable_interrupt,
|
|| #enable_interrupt,
|
||||||
|| #pend,
|
|| #pend,
|
||||||
#m_ident.get_mut_unchecked().as_mut());
|
(&mut *#m_ident.get_mut()).as_mut());
|
||||||
|
|
||||||
Ok(#name::#m::SpawnHandle { marker })
|
Ok(#name::#m::SpawnHandle { marker })
|
||||||
})
|
})
|
||||||
|
|
|
@ -19,10 +19,9 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
|
||||||
// We include the cfgs
|
// We include the cfgs
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
// Resource is a RacyCell<MaybeUninit<T>>
|
// Resource is a RacyCell<MaybeUninit<T>>
|
||||||
// - `get_mut_unchecked` to obtain `MaybeUninit<T>`
|
// - `get_mut` to obtain a raw pointer to `MaybeUninit<T>`
|
||||||
// - `as_mut_ptr` to obtain a raw pointer to `MaybeUninit<T>`
|
|
||||||
// - `write` the defined value for the late resource T
|
// - `write` the defined value for the late resource T
|
||||||
#mangled_name.get_mut_unchecked().as_mut_ptr().write(shared_resources.#name);
|
#mangled_name.get_mut().write(core::mem::MaybeUninit::new(shared_resources.#name));
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,10 +36,9 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
|
||||||
// We include the cfgs
|
// We include the cfgs
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
// Resource is a RacyCell<MaybeUninit<T>>
|
// Resource is a RacyCell<MaybeUninit<T>>
|
||||||
// - `get_mut_unchecked` to obtain `MaybeUninit<T>`
|
// - `get_mut` to obtain a raw pointer to `MaybeUninit<T>`
|
||||||
// - `as_mut_ptr` to obtain a raw pointer to `MaybeUninit<T>`
|
|
||||||
// - `write` the defined value for the late resource T
|
// - `write` the defined value for the late resource T
|
||||||
#mangled_name.get_mut_unchecked().as_mut_ptr().write(local_resources.#name);
|
#mangled_name.get_mut().write(core::mem::MaybeUninit::new(local_resources.#name));
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +56,7 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
|
||||||
|
|
||||||
// Store the monotonic
|
// Store the monotonic
|
||||||
let name = util::monotonic_ident(&monotonic.to_string());
|
let name = util::monotonic_ident(&monotonic.to_string());
|
||||||
stmts.push(quote!(*#name.get_mut_unchecked() = Some(monotonics.#idx);));
|
stmts.push(quote!(#name.get_mut().write(Some(monotonics.#idx));));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable the interrupts -- this completes the `init`-ialization phase
|
// Enable the interrupts -- this completes the `init`-ialization phase
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
|
||||||
let fq_ident = util::fq_ident(name);
|
let fq_ident = util::fq_ident(name);
|
||||||
|
|
||||||
stmts.push(quote!(
|
stmts.push(quote!(
|
||||||
(0..#cap).for_each(|i| #fq_ident.get_mut_unchecked().enqueue_unchecked(i));
|
(0..#cap).for_each(|i| (&mut *#fq_ident.get_mut()).enqueue_unchecked(i));
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ pub fn codegen(
|
||||||
|
|
||||||
let ptr = quote!(
|
let ptr = quote!(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
#mangled_name.get_mut_unchecked().as_mut_ptr()
|
#mangled_name.get_mut() as *mut _
|
||||||
);
|
);
|
||||||
|
|
||||||
let ceiling = match analysis.ownerships.get(name) {
|
let ceiling = match analysis.ownerships.get(name) {
|
||||||
|
|
|
@ -75,9 +75,9 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
|
||||||
}
|
}
|
||||||
|
|
||||||
let expr = if access.is_exclusive() {
|
let expr = if access.is_exclusive() {
|
||||||
quote!(&mut *#mangled_name.get_mut_unchecked().as_mut_ptr())
|
quote!(&mut *(&mut *#mangled_name.get_mut()).as_mut_ptr())
|
||||||
} else {
|
} else {
|
||||||
quote!(&*#mangled_name.get_unchecked().as_ptr())
|
quote!(&*(&*#mangled_name.get()).as_ptr())
|
||||||
};
|
};
|
||||||
|
|
||||||
values.push(quote!(
|
values.push(quote!(
|
||||||
|
|
|
@ -117,7 +117,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
|
||||||
quote!(
|
quote!(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
#t::#name => {
|
#t::#name => {
|
||||||
rtic::export::interrupt::free(|_| #rq.get_mut_unchecked().split().0.enqueue_unchecked((#rqt::#name, index)));
|
rtic::export::interrupt::free(|_| (&mut *#rq.get_mut()).split().0.enqueue_unchecked((#rqt::#name, index)));
|
||||||
|
|
||||||
#pend
|
#pend
|
||||||
}
|
}
|
||||||
|
@ -137,8 +137,8 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
unsafe fn #bound_interrupt() {
|
unsafe fn #bound_interrupt() {
|
||||||
while let Some((task, index)) = rtic::export::interrupt::free(|_|
|
while let Some((task, index)) = rtic::export::interrupt::free(|_|
|
||||||
if let Some(mono) = #m_ident.get_mut_unchecked().as_mut() {
|
if let Some(mono) = (&mut *#m_ident.get_mut()).as_mut() {
|
||||||
#tq.get_mut_unchecked().dequeue(|| #disable_isr, mono)
|
(&mut *#tq.get_mut()).dequeue(|| #disable_isr, mono)
|
||||||
} else {
|
} else {
|
||||||
// We can only use the timer queue if `init` has returned, and it
|
// We can only use the timer queue if `init` has returned, and it
|
||||||
// writes the `Some(monotonic)` we are accessing here.
|
// writes the `Some(monotonic)` we are accessing here.
|
||||||
|
@ -150,7 +150,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rtic::export::interrupt::free(|_| if let Some(mono) = #m_ident.get_mut_unchecked().as_mut() {
|
rtic::export::interrupt::free(|_| if let Some(mono) = (&mut *#m_ident.get_mut()).as_mut() {
|
||||||
mono.on_interrupt();
|
mono.on_interrupt();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
33
src/lib.rs
33
src/lib.rs
|
@ -59,6 +59,27 @@ where
|
||||||
use core::cell::UnsafeCell;
|
use core::cell::UnsafeCell;
|
||||||
|
|
||||||
/// Internal replacement for `static mut T`
|
/// Internal replacement for `static mut T`
|
||||||
|
///
|
||||||
|
/// Used to represent RTIC Resources
|
||||||
|
///
|
||||||
|
/// Soundness:
|
||||||
|
/// 1) Unsafe API for internal use only
|
||||||
|
/// 2) get_mut(&self) -> *mut T
|
||||||
|
/// returns a raw mutable pointer to the inner T
|
||||||
|
/// casting to &mut T is under control of RTIC
|
||||||
|
/// RTIC ensures &mut T to be unique under Rust aliasing rules.
|
||||||
|
///
|
||||||
|
/// Implementation uses the underlying UnsafeCell<T>
|
||||||
|
/// self.0.get() -> *mut T
|
||||||
|
///
|
||||||
|
/// 3) get(&self) -> *const T
|
||||||
|
/// returns a raw immutable (const) pointer to the inner T
|
||||||
|
/// casting to &T is under control of RTIC
|
||||||
|
/// RTIC ensures &T to be shared under Rust aliasing rules.
|
||||||
|
///
|
||||||
|
/// Implementation uses the underlying UnsafeCell<T>
|
||||||
|
/// self.0.get() -> *mut T, demoted to *const T
|
||||||
|
///
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct RacyCell<T>(UnsafeCell<T>);
|
pub struct RacyCell<T>(UnsafeCell<T>);
|
||||||
|
|
||||||
|
@ -69,16 +90,16 @@ impl<T> RacyCell<T> {
|
||||||
RacyCell(UnsafeCell::new(value))
|
RacyCell(UnsafeCell::new(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get `&mut T`
|
/// Get `*mut T`
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn get_mut_unchecked(&self) -> &mut T {
|
pub unsafe fn get_mut(&self) -> *mut T {
|
||||||
&mut *self.0.get()
|
self.0.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get `&T`
|
/// Get `*const T`
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn get_unchecked(&self) -> &T {
|
pub unsafe fn get(&self) -> *const T {
|
||||||
&*self.0.get()
|
self.0.get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue