You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently RTFM has the notion of asymmetric access to shared resources. Tasks with highest priority accessing shared:T gets a &mut T API, while other tasks (if any) gets a resource proxy, with a lock API (former claim). The examples/lock.rs from the current upstream.
#[rtfm::app(device = lm3s6965)]constAPP:() = {structResources{#[init(0)]shared:u32,}#[init]fninit(_: init::Context){
rtfm::pend(Interrupt::GPIOA);}// when omitted priority is assumed to be `1`#[task(binds = GPIOA, resources = [shared])]fngpioa(mutc: gpioa::Context){hprintln!("A").unwrap();// the lower priority task requires a critical section to access the data
c.resources.shared.lock(|shared| {// data can only be modified within this critical section (closure)*shared += 1;// GPIOB will *not* run right now due to the critical section
rtfm::pend(Interrupt::GPIOB);hprintln!("B - shared = {}",*shared).unwrap();// GPIOC does not contend for `shared` so it's allowed to run now
rtfm::pend(Interrupt::GPIOC);});// critical section is over: GPIOB can now starthprintln!("E").unwrap();
debug::exit(debug::EXIT_SUCCESS);}#[task(binds = GPIOB, priority = 2, resources = [shared])]fngpiob(c: gpiob::Context){// the higher priority task does *not* need a critical section*c.resources.shared += 1;hprintln!("D - shared = {}",*c.resources.shared).unwrap();}#[task(binds = GPIOC, priority = 3)]fngpioc(_: gpioc::Context){hprintln!("C").unwrap();}};
This is unfortunate, as
Introducing another task in the application may break code. gpiob would need to be changed API if allowing gpioc access to shared.
If we want gpioa to pass the resource access to another (external) function (like a HAL), we would need to wrap shared by Exclusive (which gives a lock API to inner).
Context cannot have 'static lifetime if allowed to have &mut T in resources. This will prevent from captures in static stored generators (which requires 'static lifetime). Generators can be useful as is (initial experiments confirm the possibility), and are used under the hood for async/await, so if we want to keep this door open, we will eventually run into this problem.
Proposal.
Offer only a single API (always resource proxy) for all shared resources.
Pros:
Symmetrical API with no risk of breakage.
Mitigates the need for Exclusive.
Potentially reducing the complexity of codegen internally in RTFM. (Right now there a bunch of edge cases in the codegen).
Cons:
More verbose user code, the price we pay for ensuring composition property. With the new multi-lock Mutex (korken), we can reduce rightward drift.
Performance:
Locks will be optimized out by the compiler in case your task has exclusive access.
[resource] vs [mut resource] (or [&resource] vs [resource])
In a related RFC, Jorge proposed to distinguish between mutable and immutable access. With the above proposal, this will amount in a slight syntax extension. (Following Rust I would think that [mut resource] would be appropriate, but the &syntax would be backwards compatible, so I don't have a strong opinion).
Pros:
Improved schedulability (less blocking from lower priority tasks)
Improved performance (unnecessary locks are optimized out at compile time)
Cons:
None.
Under the "Goodby Exclusive" proposal, the optimization can be done fully transparent to the API. lock will lend out &T/&mut T, for immutable/mutable access respectively and the compiler will block misuse.
I might have missed something, looking forward to input.
Best regards
Per
The text was updated successfully, but these errors were encountered:
The non symetrical API also introduces issues when using the resource proxy concrete types because the higher prio task doesn't get a resource proxy, instead it gets the resource directly. Example:
Currently RTFM has the notion of asymmetric access to shared resources. Tasks with highest priority accessing
shared:T
gets a&mut T
API, while other tasks (if any) gets a resource proxy, with alock
API (formerclaim
). Theexamples/lock.rs
from the current upstream.This is unfortunate, as
gpiob
would need to be changed API if allowinggpioc
access toshared
.gpioa
to pass the resource access to another (external) function (like a HAL), we would need to wrapshared
byExclusive
(which gives alock
API to inner).Context
cannot have'static
lifetime if allowed to have&mut T
inresources
. This will prevent from captures in static stored generators (which requires'static
lifetime). Generators can be useful as is (initial experiments confirm the possibility), and are used under the hood forasync/await
, so if we want to keep this door open, we will eventually run into this problem.Proposal.
Offer only a single API (always resource proxy) for all shared resources.
Pros:
Exclusive
.codegen
internally in RTFM. (Right now there a bunch of edge cases in thecodegen
).Cons:
Performance:
[resource] vs [mut resource] (or [&resource] vs [resource])
In a related RFC, Jorge proposed to distinguish between mutable and immutable access. With the above proposal, this will amount in a slight syntax extension. (Following Rust I would think that [mut resource] would be appropriate, but the &syntax would be backwards compatible, so I don't have a strong opinion).
Pros:
Cons:
Under the "Goodby Exclusive" proposal, the optimization can be done fully transparent to the API.
lock
will lend out&T
/&mut T
, for immutable/mutable access respectively and the compiler will block misuse.I might have missed something, looking forward to input.
Best regards
Per
The text was updated successfully, but these errors were encountered: