wip tests do pass, MutexStruct based

This commit is contained in:
Per Lindgren 2021-11-03 20:58:21 +01:00
parent 20602bd77c
commit b138cc1631
8 changed files with 76 additions and 40 deletions

View file

@ -143,22 +143,15 @@ pub fn codegen(
); );
let ident_mut = util::shared_resources_ident_mut(ctxt, app); let ident_mut = util::shared_resources_ident_mut(ctxt, app);
let item = quote!( let mut items = vec![];
items.push(quote!(
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[doc = #doc] #[doc = #doc]
pub struct #ident<#lt> { pub struct #ident<#lt> {
#(#fields,)* #(#fields,)*
} }
));
// Used by the lock-all API
#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
#[doc = #doc_mut]
pub struct #ident_mut<#lt> {
#(#fields_mut,)*
}
);
let arg = if ctxt.is_init() { let arg = if ctxt.is_init() {
None None
@ -166,7 +159,16 @@ pub fn codegen(
Some(quote!(priority: &#lt rtic::export::Priority)) Some(quote!(priority: &#lt rtic::export::Priority))
}; };
let (lock_all, get_prio) = if let Some(name) = field_get_prio { let (lock_all, new_struct, get_prio) = if let Some(name) = field_get_prio {
items.push(quote!(
// Used by the lock-all API
#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
#[doc = #doc_mut]
pub struct #ident_mut<#lt> {
#(#fields_mut,)*
}
));
( (
util::impl_mutex_struct( util::impl_mutex_struct(
extra, extra,
@ -177,6 +179,17 @@ pub fn codegen(
quote!(self.priority()), quote!(self.priority()),
quote!(|| { #ident_mut::new() }), quote!(|| { #ident_mut::new() }),
), ),
quote!(
// Used by the lock-all API
impl<#lt> #ident_mut<#lt> {
#[inline(always)]
pub unsafe fn new() -> Self {
#ident_mut {
#(#values_mut,)*
}
}
}
),
quote!( quote!(
// Used by the lock-all API // Used by the lock-all API
#[inline(always)] #[inline(always)]
@ -186,7 +199,14 @@ pub fn codegen(
), ),
) )
} else { } else {
(quote!(), quote!()) items.push(quote!(
// Used by the lock-all API
#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
#[doc = #doc_mut]
pub struct #ident_mut {}
));
(quote!(), quote!(), quote!())
}; };
let implementations = quote!( let implementations = quote!(
@ -201,18 +221,10 @@ pub fn codegen(
#get_prio #get_prio
} }
// Used by the lock-all API #new_struct
impl<#lt> #ident_mut<#lt> {
#[inline(always)]
pub unsafe fn new() -> Self {
#ident_mut {
#(#values_mut,)*
}
}
}
#lock_all #lock_all
); );
(item, implementations) (quote!(#(#items)*), implementations)
} }

View file

@ -71,7 +71,7 @@ pub fn impl_mutex_struct(
type T = #ty; type T = #ty;
#[inline(always)] #[inline(always)]
fn lock<RTIC_INTERNAL_R>(&mut self, f: impl FnOnce(#ty) -> RTIC_INTERNAL_R) -> RTIC_INTERNAL_R { fn lock<RTIC_INTERNAL_R>(&mut self, f: impl FnOnce(&mut #ty) -> RTIC_INTERNAL_R) -> RTIC_INTERNAL_R {
/// Priority ceiling /// Priority ceiling
const CEILING: u8 = #ceiling; const CEILING: u8 = #ceiling;

View file

@ -175,26 +175,27 @@ pub unsafe fn lock_struct<T, R>(
priority: &Priority, priority: &Priority,
ceiling: u8, ceiling: u8,
nvic_prio_bits: u8, nvic_prio_bits: u8,
f: impl FnOnce(T) -> R, f: impl FnOnce(&mut T) -> R,
) -> R { ) -> R {
let current = priority.get(); let current = priority.get();
if current < ceiling { if current < ceiling {
if ceiling == (1 << nvic_prio_bits) { if ceiling == (1 << nvic_prio_bits) {
priority.set(u8::max_value()); priority.set(u8::max_value());
let r = interrupt::free(|_| f(ptr())); let r = interrupt::free(|_| f(&mut ptr()));
priority.set(current); priority.set(current);
r r
} else { } else {
priority.set(ceiling); priority.set(ceiling);
basepri::write(logical2hw(ceiling, nvic_prio_bits)); basepri::write(logical2hw(ceiling, nvic_prio_bits));
let r = f(ptr()); // inside of lock let r = f(&mut ptr()); // inside of lock
cortex_m::asm::nop();
basepri::write(logical2hw(current, nvic_prio_bits)); basepri::write(logical2hw(current, nvic_prio_bits));
priority.set(current); priority.set(current);
r r
} }
} else { } else {
f(ptr()) f(&mut ptr())
} }
} }
@ -226,6 +227,34 @@ pub unsafe fn lock<T, R>(
} }
} }
/// Lock the resource proxy by setting the PRIMASK
/// and running the closure with interrupt::free
///
/// # Safety
///
/// Writing to the PRIMASK
/// Dereferencing a raw pointer
#[cfg(not(armv7m))]
#[inline(always)]
pub unsafe fn lock_struct<T, R>(
ptr: impl Fn() -> T,
priority: &Priority,
ceiling: u8,
_nvic_prio_bits: u8,
f: impl FnOnce(&mut T) -> R,
) -> R {
let current = priority.get();
if current < ceiling {
priority.set(u8::max_value());
let r = interrupt::free(|_| f(&mut ptr()));
priority.set(current);
r
} else {
f(&mut ptr())
}
}
#[inline] #[inline]
pub fn logical2hw(logical: u8, nvic_prio_bits: u8) -> u8 { pub fn logical2hw(logical: u8, nvic_prio_bits: u8) -> u8 {
((1 << nvic_prio_bits) - logical) << (8 - nvic_prio_bits) ((1 << nvic_prio_bits) - logical) << (8 - nvic_prio_bits)

View file

@ -111,5 +111,5 @@ pub trait MutexStruct {
type T; type T;
/// Creates a critical section and grants temporary access to the protected data /// Creates a critical section and grants temporary access to the protected data
fn lock<R>(&mut self, f: impl FnOnce(Self::T) -> R) -> R; fn lock<R>(&mut self, f: impl FnOnce(&mut Self::T) -> R) -> R;
} }

View file

@ -4,5 +4,5 @@ error: lifetime may not live long enough
20 | let _ = c.shared.lock(|s| s); // lifetime 20 | let _ = c.shared.lock(|s| s); // lifetime
| -- ^ returning this value requires that `'1` must outlive `'2` | -- ^ returning this value requires that `'1` must outlive `'2`
| || | ||
| |return type of closure is &'2 mut __rtic_internal_fooShared | |return type of closure is &'2 mut __rtic_internal_fooShared<'_>
| has type `&'1 mut __rtic_internal_fooShared` | has type `&'1 mut __rtic_internal_fooShared<'_>`

View file

@ -1,9 +1,4 @@
//! examples/lockall_soundness.rs
#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main] #![no_main]
#![no_std]
use panic_semihosting as _; use panic_semihosting as _;

View file

@ -1,9 +1,9 @@
error: lifetime may not live long enough error: lifetime may not live long enough
--> ui/lockall_lifetime_destruct_field.rs:28:13 --> ui/lockall_lifetime_destruct_field.rs:23:13
| |
27 | let _ = c.shared.lock(|foo::Shared { a }| { 22 | let _ = c.shared.lock(|foo::Shared { a }| {
| ------------------ return type of closure is &'2 mut &mut u32 | ------------------ return type of closure is &'2 mut &mut u32
| | | |
| has type `&'1 mut __rtic_internal_fooShared` | has type `&'1 mut __rtic_internal_fooShared<'_>`
28 | a // lifetime 23 | a // lifetime
| ^ returning this value requires that `'1` must outlive `'2` | ^ returning this value requires that `'1` must outlive `'2`

View file

@ -5,4 +5,4 @@ error: lifetime may not live long enough
| -- ^^^^^^^^^ returning this value requires that `'1` must outlive `'2` | -- ^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
| || | ||
| |return type of closure is &'2 mut u32 | |return type of closure is &'2 mut u32
| has type `&'1 mut __rtic_internal_fooShared` | has type `&'1 mut __rtic_internal_fooShared<'_>`