Skip to content

Commit

Permalink
feat(tests): add threading-lock test
Browse files Browse the repository at this point in the history
This demonstrates how multiple threads can wait for the same lock and
get unblocked by priority, and within a prio by FIFO order.
  • Loading branch information
elenaf9 committed Sep 9, 2024
1 parent 8ae6b02 commit 67a8e9c
Show file tree
Hide file tree
Showing 6 changed files with 102 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 @@ -18,6 +18,7 @@ members = [
"tests/gpio",
"tests/gpio-interrupt-nrf",
"tests/gpio-interrupt-stm32",
"tests/threading-lock",
]

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 @@ -3,3 +3,4 @@ subdirs:
- gpio
- gpio-interrupt-nrf
- gpio-interrupt-stm32
- threading-lock
12 changes: 12 additions & 0 deletions tests/threading-lock/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "threading-lock"
version = "0.1.0"
authors = ["Elena Frank <[email protected]>"]
edition.workspace = true
publish = false

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

use portable_atomic::{AtomicUsize, Ordering};
use riot_rs::thread::{lock::Lock, thread_flags, ThreadId};

static LOCK: Lock = Lock::new();
static RUN_ORDER: AtomicUsize = AtomicUsize::new(0);
static LOCK_ORDER: AtomicUsize = AtomicUsize::new(0);

#[riot_rs::thread(autostart, priority = 1)]
fn thread0() {
assert_eq!(RUN_ORDER.fetch_add(1, Ordering::AcqRel), 0);

LOCK.acquire();

// 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);
thread_flags::set(ThreadId::new(2), 0b1);
thread_flags::set(ThreadId::new(3), 0b1);

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

LOCK.release();

// Wait for other threads to complete.
thread_flags::wait_all(0b111);
riot_rs::debug::log::info!("Test passed!");
}

#[riot_rs::thread(autostart, priority = 2)]
fn thread1() {
thread_flags::wait_one(0b1);
assert_eq!(RUN_ORDER.fetch_add(1, Ordering::AcqRel), 1);

LOCK.acquire();
assert_eq!(LOCK_ORDER.fetch_add(1, Ordering::AcqRel), 2);
LOCK.release();

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

#[riot_rs::thread(autostart, priority = 3)]
fn thread2() {
thread_flags::wait_one(0b1);
assert_eq!(RUN_ORDER.fetch_add(1, Ordering::AcqRel), 2);

LOCK.acquire();
// Expect to be the second thread that acquires the lock.
assert_eq!(LOCK_ORDER.fetch_add(1, Ordering::AcqRel), 1);
LOCK.release();

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

#[riot_rs::thread(autostart, priority = 2)]
fn thread3() {
thread_flags::wait_one(0b1);
assert_eq!(RUN_ORDER.fetch_add(1, Ordering::AcqRel), 3);

LOCK.acquire();
assert_eq!(LOCK_ORDER.fetch_add(1, Ordering::AcqRel), 3);
LOCK.release();

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

0 comments on commit 67a8e9c

Please sign in to comment.