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 item = quote!(
let mut items = vec![];
items.push(quote!(
#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
#[doc = #doc]
pub struct #ident<#lt> {
#(#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() {
None
@ -166,7 +159,16 @@ pub fn codegen(
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(
extra,
@ -177,6 +179,17 @@ pub fn codegen(
quote!(self.priority()),
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!(
// Used by the lock-all API
#[inline(always)]
@ -186,7 +199,14 @@ pub fn codegen(
),
)
} 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!(
@ -201,18 +221,10 @@ pub fn codegen(
#get_prio
}
// Used by the lock-all API
impl<#lt> #ident_mut<#lt> {
#[inline(always)]
pub unsafe fn new() -> Self {
#ident_mut {
#(#values_mut,)*
}
}
}
#new_struct
#lock_all
);
(item, implementations)
(quote!(#(#items)*), implementations)
}

View file

@ -71,7 +71,7 @@ pub fn impl_mutex_struct(
type T = #ty;
#[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
const CEILING: u8 = #ceiling;

View file

@ -175,26 +175,27 @@ pub unsafe fn lock_struct<T, R>(
priority: &Priority,
ceiling: u8,
nvic_prio_bits: u8,
f: impl FnOnce(T) -> R,
f: impl FnOnce(&mut T) -> R,
) -> R {
let current = priority.get();
if current < ceiling {
if ceiling == (1 << nvic_prio_bits) {
priority.set(u8::max_value());
let r = interrupt::free(|_| f(ptr()));
let r = interrupt::free(|_| f(&mut ptr()));
priority.set(current);
r
} else {
priority.set(ceiling);
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));
priority.set(current);
r
}
} 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]
pub fn logical2hw(logical: u8, nvic_prio_bits: u8) -> u8 {
((1 << nvic_prio_bits) - logical) << (8 - nvic_prio_bits)

View file

@ -111,5 +111,5 @@ pub trait MutexStruct {
type T;
/// 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
| -- ^ returning this value requires that `'1` must outlive `'2`
| ||
| |return type of closure is &'2 mut __rtic_internal_fooShared
| has type `&'1 mut __rtic_internal_fooShared`
| |return type of closure is &'2 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_std]
use panic_semihosting as _;

View file

@ -1,9 +1,9 @@
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
| |
| has type `&'1 mut __rtic_internal_fooShared`
28 | a // lifetime
| has type `&'1 mut __rtic_internal_fooShared<'_>`
23 | a // lifetime
| ^ 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`
| ||
| |return type of closure is &'2 mut u32
| has type `&'1 mut __rtic_internal_fooShared`
| has type `&'1 mut __rtic_internal_fooShared<'_>`