Skip to content

Commit

Permalink
feat(tests): add threading-mutex test
Browse files Browse the repository at this point in the history
This demonstrates how multiple threads can wait for the same mutex,
get unblocked by priority, and the owning thread inherits the priority
of the highest waiting thread.
  • Loading branch information
elenaf9 committed Oct 2, 2024
1 parent d252376 commit 7e29254
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 0 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ members = [
"tests/i2c-controller",
"tests/threading-dynamic-prios",
"tests/threading-lock",
"tests/threading-mutex",
]

exclude = ["src/lib"]
Expand Down
1 change: 1 addition & 0 deletions tests/laze.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ subdirs:
- i2c-controller
- threading-dynamic-prios
- threading-lock
- threading-mutex
13 changes: 13 additions & 0 deletions tests/threading-mutex/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "threading-mutex"
version = "0.1.0"
authors = ["Elena Frank <[email protected]>"]
edition.workspace = true
license.workspace = true
publish = false

[dependencies]
embassy-executor = { workspace = true }
riot-rs = { path = "../../src/riot-rs", features = ["threading"] }
riot-rs-boards = { path = "../../src/riot-rs-boards" }
portable-atomic = "1.6.0"
5 changes: 5 additions & 0 deletions tests/threading-mutex/laze.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
apps:
- name: threading-mutex
selects:
- ?release
- sw/threading
106 changes: 106 additions & 0 deletions tests/threading-mutex/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#![no_main]
#![no_std]
#![feature(type_alias_impl_trait)]
#![feature(used_with_arg)]

use portable_atomic::{AtomicUsize, Ordering};
use riot_rs::thread::{sync::Mutex, thread_flags, RunqueueId, ThreadId};

static MUTEX: Mutex<usize> = Mutex::new(0);
static RUN_ORDER: AtomicUsize = AtomicUsize::new(0);

#[riot_rs::thread(autostart, priority = 1)]
fn thread0() {
let pid = riot_rs::thread::current_pid().unwrap();
assert_eq!(riot_rs::thread::get_priority(pid), Some(RunqueueId::new(1)));

assert_eq!(RUN_ORDER.fetch_add(1, Ordering::AcqRel), 0);

let mut counter = MUTEX.lock();

// Unblock other threads in the order of their IDs.
//
// Because all other threads have higher priorities, setting
// a flag will each time cause a context switch and give each
// thread the chance to run and try acquire the lock.
thread_flags::set(ThreadId::new(1), 0b1);
// Inherit prio of higher prio waiting thread.
assert_eq!(
riot_rs::thread::get_priority(pid),
riot_rs::thread::get_priority(ThreadId::new(1)),
);
thread_flags::set(ThreadId::new(2), 0b1);
// Inherit prio of highest waiting thread.
assert_eq!(
riot_rs::thread::get_priority(pid),
riot_rs::thread::get_priority(ThreadId::new(2)),
);
thread_flags::set(ThreadId::new(3), 0b1);
// Still has priority of highest waiting thread.
assert_eq!(
riot_rs::thread::get_priority(pid),
riot_rs::thread::get_priority(ThreadId::new(2)),
);

assert_eq!(*counter, 0);
*counter += 1;

drop(counter);

// Return to old prio.
assert_eq!(riot_rs::thread::get_priority(pid), Some(RunqueueId::new(1)));

// Wait for other threads to complete.
thread_flags::wait_all(0b111);

assert_eq!(*MUTEX.lock(), 4);
riot_rs::debug::log::info!("Test passed!");
}

#[riot_rs::thread(autostart, priority = 2)]
fn thread1() {
let pid = riot_rs::thread::current_pid().unwrap();
assert_eq!(riot_rs::thread::get_priority(pid), Some(RunqueueId::new(2)));

thread_flags::wait_one(0b1);
assert_eq!(RUN_ORDER.fetch_add(1, Ordering::AcqRel), 1);

let mut counter = MUTEX.lock();
assert_eq!(*counter, 2);
*counter += 1;

thread_flags::set(ThreadId::new(0), 0b1);
}

#[riot_rs::thread(autostart, priority = 3)]
fn thread2() {
let pid = riot_rs::thread::current_pid().unwrap();
assert_eq!(riot_rs::thread::get_priority(pid), Some(RunqueueId::new(3)));

thread_flags::wait_one(0b1);
assert_eq!(RUN_ORDER.fetch_add(1, Ordering::AcqRel), 2);

let mut counter = MUTEX.lock();
assert_eq!(*counter, 1);
// Priority didn't change because this thread has higher prio
// than all waiting threads.
assert_eq!(riot_rs::thread::get_priority(pid), Some(RunqueueId::new(3)),);
*counter += 1;

thread_flags::set(ThreadId::new(0), 0b10);
}

#[riot_rs::thread(autostart, priority = 2)]
fn thread3() {
let pid = riot_rs::thread::current_pid().unwrap();
assert_eq!(riot_rs::thread::get_priority(pid), Some(RunqueueId::new(2)));

thread_flags::wait_one(0b1);
assert_eq!(RUN_ORDER.fetch_add(1, Ordering::AcqRel), 3);

let mut counter = MUTEX.lock();
assert_eq!(*counter, 3);
*counter += 1;

thread_flags::set(ThreadId::new(0), 0b100);
}

0 comments on commit 7e29254

Please sign in to comment.