Skip to content

Lockall #546

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

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- `examples/periodic-at.rs`, an example of a periodic timer without accumulated drift.
- `examples/periodic-at2.rs`, an example of a periodic process with two tasks, with offset timing. Here we depict two alternative usages of the timer type, explicit and trait based.
- book: Update `Monotonic` tips.
- Lockall api added

## [v1.0.0] - 2021-12-25

Expand Down
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ trybuild = "1"
codegen-units = 1
lto = true

[features]
inline-asm = ["cortex-m/inline-asm"]
linker-plugin-lto = ["cortex-m/linker-plugin-lto"]

[workspace]
members = [
"macros",
Expand Down
Empty file added ci/expected/lock_cost.run
Empty file.
3 changes: 3 additions & 0 deletions ci/expected/lockall.run
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
foo: a = 1, b = 2
baz
bar: a = 3
Empty file added ci/expected/lockall_cost.run
Empty file.
3 changes: 3 additions & 0 deletions ci/expected/lockall_destruct.run
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
foo: a = 1, b = 2
baz
bar: a = 3
2 changes: 2 additions & 0 deletions ci/expected/multilock_sequence.run
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Multiple locks, s1: 1, s2: 2, s3: 3
Multiple locks, s1: 2, s2: 4, s3: 6
3 changes: 3 additions & 0 deletions ci/expected/multilock_vs_lockall.run
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Multiple locks, s1: 1, s2: 2, s3: 3
Multiple locks, s1: 2, s2: 4, s3: 6
Multiple locks, s1: 3, s2: 6, s3: 9
67 changes: 67 additions & 0 deletions examples/lock_cost.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//! examples/lock_cost.rs

#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]

use panic_semihosting as _;

#[rtic::app(device = lm3s6965)]
mod app {
#[shared]
struct Shared {
shared: u32,
}

#[local]
struct Local {}

#[init]
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
use cortex_m_semihosting::debug;
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
(Shared { shared: 0 }, Local {}, init::Monotonics())
}

#[task(binds = GPIOA, shared = [shared])]
fn low(mut cx: low::Context) {
cx.shared.shared.lock(|shared| *shared += 1);
}

#[task(binds = GPIOB, priority = 2, shared = [shared])]
fn high(mut cx: high::Context) {
cx.shared.shared.lock(|shared| *shared += 1);
}
}

// cargo objdump --example lock_cost --target thumbv7m-none-eabi --release --features inline-asm -- --disassemble > lock_cost.objdump
//
// Zero-Cost implementations:
// 0000016c <GPIOA>:
// 16c: 80 b5 push {r7, lr}
// 16e: 6f 46 mov r7, sp
// 170: c0 20 movs r0, #192
// 172: 80 f3 11 88 msr basepri, r0
// 176: 40 f2 00 00 movw r0, #0
// 17a: c2 f2 00 00 movt r0, #8192
// 17e: 01 68 ldr r1, [r0]
// 180: 01 31 adds r1, #1
// 182: 01 60 str r1, [r0]
// 184: e0 20 movs r0, #224
// 186: 80 f3 11 88 msr basepri, r0
// 18a: 00 20 movs r0, #0
// 18c: 80 f3 11 88 msr basepri, r0
// 190: 80 bd pop {r7, pc}

// 00000192 <GPIOB>:
// 192: 80 b5 push {r7, lr}
// 194: 6f 46 mov r7, sp
// 196: 40 f2 00 01 movw r1, #0
// 19a: ef f3 11 80 mrs r0, basepri
// 19e: c2 f2 00 01 movt r1, #8192
// 1a2: 0a 68 ldr r2, [r1]
// 1a4: 01 32 adds r2, #1
// 1a6: 0a 60 str r2, [r1]
// 1a8: 80 f3 11 88 msr basepri, r0
// 1ac: 80 bd pop {r7, pc}
58 changes: 58 additions & 0 deletions examples/lockall.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//! examples/lockall.rs

#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]

use panic_semihosting as _;

#[rtic::app(device = lm3s6965, dispatchers = [GPIOA, GPIOB, GPIOC])]
mod app {
use cortex_m_semihosting::{debug, hprintln};

#[shared]
struct Shared {
a: u32,
b: i64,
}

#[local]
struct Local {}

#[init]
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
foo::spawn().unwrap();

(Shared { a: 1, b: 2 }, Local {}, init::Monotonics())
}

// when omitted priority is assumed to be `1`
#[task(shared = [a, b])]
fn foo(mut c: foo::Context) {
c.shared.lock(|s| {
hprintln!("foo: a = {}, b = {}", s.a, s.b).ok();
*s.a += 1;
bar::spawn().unwrap();
baz::spawn().unwrap();
});
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
}

#[task(priority = 2, shared = [a])]
fn bar(mut c: bar::Context) {
// the higher priority task does still need a critical section
let a = c.shared.lock(|s| {
*s.a += 1;
// *s.b += 1; `b` not accessible
*s.a
});

hprintln!("bar: a = {}", a).unwrap();
}

#[task(priority = 3)]
fn baz(_: baz::Context) {
hprintln!("baz").unwrap();
}
}
67 changes: 67 additions & 0 deletions examples/lockall_cost.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//! examples/lockall_cost.rs

#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]

use panic_semihosting as _;

#[rtic::app(device = lm3s6965)]
mod app {
#[shared]
struct Shared {
shared: u32,
}

#[local]
struct Local {}

#[init]
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
use cortex_m_semihosting::debug;
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
(Shared { shared: 0 }, Local {}, init::Monotonics())
}

#[task(binds = GPIOA, shared = [shared])]
fn low(mut cx: low::Context) {
cx.shared.lock(|x| *x.shared += 1);
}

#[task(binds = GPIOB, priority = 2, shared = [shared])]
fn high(mut cx: high::Context) {
cx.shared.lock(|x| *x.shared += 1);
}
}

// cargo objdump --example lockall_cost --target thumbv7m-none-eabi --release --features inline-asm -- --disassemble > lockall_cost.ojbdump
//
// Zero-Cost implementations:
// 0000016c <GPIOA>:
// 16c: 80 b5 push {r7, lr}
// 16e: 6f 46 mov r7, sp
// 170: c0 20 movs r0, #192
// 172: 80 f3 11 88 msr basepri, r0
// 176: 40 f2 00 00 movw r0, #0
// 17a: c2 f2 00 00 movt r0, #8192
// 17e: 01 68 ldr r1, [r0]
// 180: 01 31 adds r1, #1
// 182: 01 60 str r1, [r0]
// 184: e0 20 movs r0, #224
// 186: 80 f3 11 88 msr basepri, r0
// 18a: 00 20 movs r0, #0
// 18c: 80 f3 11 88 msr basepri, r0
// 190: 80 bd pop {r7, pc}

// 00000192 <GPIOB>:
// 192: 80 b5 push {r7, lr}
// 194: 6f 46 mov r7, sp
// 196: 40 f2 00 01 movw r1, #0
// 19a: ef f3 11 80 mrs r0, basepri
// 19e: c2 f2 00 01 movt r1, #8192
// 1a2: 0a 68 ldr r2, [r1]
// 1a4: 01 32 adds r2, #1
// 1a6: 0a 60 str r2, [r1]
// 1a8: 80 f3 11 88 msr basepri, r0
// 1ac: 80 bd pop {r7, pc}
58 changes: 58 additions & 0 deletions examples/lockall_destruct.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//! examples/lockall_destruct.rs

#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]

use panic_semihosting as _;

#[rtic::app(device = lm3s6965, dispatchers = [GPIOA, GPIOB, GPIOC])]
mod app {
use cortex_m_semihosting::{debug, hprintln};

#[shared]
struct Shared {
a: u32,
b: i64,
}

#[local]
struct Local {}

#[init]
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
foo::spawn().unwrap();

(Shared { a: 1, b: 2 }, Local {}, init::Monotonics())
}

// when omitted priority is assumed to be `1`
#[task(shared = [a, b])]
fn foo(mut c: foo::Context) {
c.shared.lock(|foo::Shared { a, b }| {
hprintln!("foo: a = {}, b = {}", a, b).ok();
**a += 1;
bar::spawn().unwrap();
baz::spawn().unwrap();
});
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
}

#[task(priority = 2, shared = [a])]
fn bar(mut c: bar::Context) {
// the higher priority task does still need a critical section
let a = c.shared.lock(|bar::Shared { a }| {
**a += 1;
// *s.b += 1; `b` not accessible
**a
});

hprintln!("bar: a = {}", a).unwrap();
}

#[task(priority = 3)]
fn baz(_: baz::Context) {
hprintln!("baz").unwrap();
}
}
79 changes: 79 additions & 0 deletions examples/multilock_sequence.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//! examples/multilock_vs_lockall.rs

#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]

use panic_semihosting as _;

#[rtic::app(device = lm3s6965, dispatchers = [GPIOA])]
mod app {
use cortex_m_semihosting::{debug, hprintln};

#[shared]
struct Shared {
shared1: u32,
shared2: u32,
shared3: u32,
}

#[local]
struct Local {}

#[init]
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
locks::spawn().unwrap();

(
Shared {
shared1: 0,
shared2: 0,
shared3: 0,
},
Local {},
init::Monotonics(),
)
}

// when omitted priority is assumed to be `1`
#[task(shared = [shared1, shared2, shared3])]
fn locks(c: locks::Context) {
// nested multi-lock
let mut s1 = c.shared.shared1;
let mut s2 = c.shared.shared2;
let mut s3 = c.shared.shared3;

(&mut s1, &mut s2, &mut s3).lock(|s1, s2, s3| {
*s1 += 1;
*s2 += 2;
*s3 += 3;

hprintln!("Multiple locks, s1: {}, s2: {}, s3: {}", s1, s2, s3).ok();
});

// re-construct
let s = locks::SharedResources {
shared1: s1,
shared2: s2,
shared3: s3,
};

// second nested multi-lock destruct
let locks::SharedResources {
shared1,
shared2,
shared3,
} = s;

(shared1, shared2, shared3).lock(|s1, s2, s3| {
*s1 += 1;
*s2 += 2;
*s3 += 3;

hprintln!("Multiple locks, s1: {}, s2: {}, s3: {}", s1, s2, s3).ok();
});

debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
}
}
Loading