-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Resource proxy mutabability, mutex Trait and closure captures (async fn) #36
Comments
Looking closer at the implementation. The "resource_proxy" could be created for each task invocation, meaning that the OH of an extra field would be only a stack allocation, never stored on the (static heap), so its not really an issue (at least not as much as a static allocation). |
Another positive implication is that this approach can be seen as a limited soundness run-time verification. I.e., if the borrow checker somehow would be broken, at least the we would catch this by a panic. This is not a very strong guarantee though, since it only checks the case of nested re-locking, not other soundness issues that would be caused by a broken borrow checker. However, if we store the Notably, the big difference in between FreeRTOS and SafeRTOS, is that the latter is certified to standards, automotive etc., by run-time checking/verification (and crippling API functionality/surface). In our case the OH would be very small and predictable (and we do not need to cripple API functionality/surface), since the API is sound by design. The only potentially unsound operations in RTIC reside in the small and well defined blocks of unsafe code. |
There is now a testing branch for the aforementioned approach. The Mutex trait no longer takes an &mut self, but the more relaxed &self. In any case, the Boolean impl<'a> rtic::Mutex for resources::shared<'a> {
type T = u32;
#[inline(always)]
fn lock<R>(&self, f: impl FnOnce(&mut u32) -> R) -> R {
#[doc = r" Priority ceiling"]
const CEILING: u8 = 2u8;
if unsafe { self.get_locked() } {
::core::panicking::panic("Resource locked in sequential context");
};
unsafe {
self.set_locked(true);
}
let r = unsafe {
rtic::export::lock(
&mut shared,
self.priority(),
CEILING,
lm3s6965::NVIC_PRIO_BITS,
f,
)
};
unsafe {
self.set_locked(false);
}
r
}
}
The The A
B - shared = 1
panicked at 'Resource locked in sequential context', examples/lock4.rs:12:1 Source: 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
rtic::pend(Interrupt::GPIOB);
hprintln!("B - shared = {}", *shared).unwrap();
c.resources.shared.lock(|_shared| {}); // here we try to re-lock I tested this both in dev and release mode. It will be interesting to see how well LLVM copes with the added complexity regarding optimization, and if not what a realistic overhead would be. The
This code includes pending a task and exiting the simulator. A more realistic example would be Here we get: 000000f0 GPIOA:
f0: push {r7, lr}
f2: mov r7, sp
f4: movs r0, #192
f6: bl #324
fa: movw r0, #0
fe: movt r0, #8192
102: ldr r1, [r0]
104: adds r1, #1
106: str r1, [r0]
108: movs r0, #224
10a: bl #304
10e: movs r0, #0
110: pop.w {r7, lr}
114: b.w #294 <__basepri_w> As a comparison. The same example under vanilla RTIC, gives: 000000f0 GPIOA:
f0: push {r7, lr}
f2: mov r7, sp
f4: movs r0, #192
f6: bl #324
fa: movw r0, #0
fe: movt r0, #8192
102: ldr r1, [r0]
104: adds r1, #1
106: str r1, [r0]
108: movs r0, #224
10a: bl #304
10e: movs r0, #0
110: pop.w {r7, lr}
114: b.w #294 <__basepri_w> At least for simple examples, there is Zero OH inferred by the immutable_resource_proxies, LLVM was able to remove all reference counting, setting, clearing the As its passed 2AM, I will rest at this. Feel free to experiment with the relaxed resource proxies, I look forward to further discussions, evaluations etc. I hope it will play nicely with other developments, like goodby exclusive, lock-optimisation, etc. |
Closed by mistake ... |
By the way, the bl, is calling the read/write of BASEPRI, the cargo obdump lost the named symbols to external code somehow in the dissasembly. (Should have run with the inline asm instead on nightly, then you see exactly what's going on.) We should have a closer look at the fences, not entirely sure they are correct/sufficient. |
Update. The Currently, RTIC hands out &mut T, for resources exclusively owned. These can now be wrapped into an In this way, we can support a symmetric API. In the future we might choose to hand out The examples, lock5..lock9 demonstrates various safety features. No OH measurements have been done, but as being less complex than general Mutex resource proxies, LLVM will have an easier task to optimize away the underlying Cell and its counterparts. The panics could be be implemented as a linked library (non present) thus any such calls could be spotted at compile time. A re-locking, would cause an linking error. ❯ cargo run --example lock8 --target thumbv7m-none-eabi --release
Compiling rtic-core v0.3.0 (/home/pln/rust/grepit/rtic-core)
Compiling cortex-m-rtic v0.5.3 (/home/pln/rust/grepit/cortex-m-rtic)
error: linking with `rust-lld` failed: exit code: 1
|
= ...88J/libcortex_m-19f1dd21ecd80693.rlib" "--end-group" "/home/pln/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/thumbv7m-none-eabi/lib/libcompiler_builtins-fa0816b847f38cf8.rlib" "-Tlink.x" "-Bdynamic"
= note: rust-lld: error: undefined symbol: re_lock
>>> referenced by lock8.cmw4tywi-cgu.0
>>> Notice, this is a poor man's solution, but gives a static guarantee that the program will never reference the external |
Update. As a proof of concept, there is now a feature link_fail. Compiling cortex-m-rtic v0.5.3 (/home/pln/rust/grepit/cortex-m-rtic)
error: linking with `rust-lld` failed: exit code: 1
|
= note: "rust-lld" "-flavor" "gnu" "-L" "/home/pln/.rustup/toolchains...fa0816b847f38cf8.rlib" "-Tlink.x" "-Bdynamic"
= note: rust-lld: error: undefined symbol: re_lock
>>> referenced by lock8.9vno1x9n-cgu.0
>>> /home/pln/rust/grepit/cortex-m-rtic/target/thumbv7m-none-eabi/release/examples/lock8-6bf696e4b09f1abf.lock8.9vno1x9n-cgu.0.rcgu.o:(GPIOC) While cargo run --example lock8 --target thumbv7m-none-eabi --release
Finished release [optimized] target(s) in 0.02s
Running `qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel target/thumbv7m-none-eabi/release/examples/lock8`
A
B - shared = 1
panicked at 'Re-lock of Exclusive resource', /home/pln/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/macros/mod.rs:34:9 I have not implemented link_fail for the Mutex panics, but it could be done in a similar fashion. Not sure the name |
Resource proxy mutability
Mutable references to resource proxies
Currently in RTIC/RTFM we need a mutable reference to the resource proxies:
Rust requires that no two references in scope points to the same location. We use the borrow checker to ensure that at compile time.
Pros
Cons
Alternative approach
Currently lock optimizations is done by the llvm backend using "meta data" holding the current priority. This is done by passing an additional parameter (
priority
), that is optimized out.We could think of a similar approach, but applied to the resource proxies. In this case it would be reference counter (in fact a
locked: bool
would do). All resource proxies in the context could be initialised tofalse
, and when locked set totrue
and when unlocked reset tofalse
. When locking we couldpanic
in case the (locked == true
), indicating*ERROR*
in the code above.Pros
&resource_proxy
, instead of&mut resource_proxy
), allowing the Mutex trait to be relaxed consequently.Cons
locked
field will still be allocated (but never touched).Soundness
As we panic if a "double lock" occurs it should be safe.
Complexity of implementation
Fairly low.
Breaking change?
The change will likely not break current code, since mutable references will be downgraded to immutable references.
The text was updated successfully, but these errors were encountered: