Skip to content

Commit

Permalink
Add test for panic upon erroneous blocking.
Browse files Browse the repository at this point in the history
  • Loading branch information
zyma98 committed Oct 10, 2024
1 parent b3af165 commit 924a7bd
Show file tree
Hide file tree
Showing 13 changed files with 379 additions and 10 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/actions/build/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,13 @@ runs:
sub-category: unwind
test-name: concurrent_restart

- name: Build test test-task-unwind-block_while_sched_suspend
uses: ./.github/workflows/actions/build-test
with:
category: task
sub-category: unwind
test-name: block_while_sched_suspend

# *** Tests for task - segmented stack ***

- name: Build test test-task-segmented_stack-function_arguments
Expand Down Expand Up @@ -337,6 +344,13 @@ runs:
sub-category: unwind
test-name: simple

- name: Build test test-interrupt-unwind-panic_upon_blocking
uses: ./.github/workflows/actions/build-test
with:
category: interrupt
sub-category: unwind
test-name: panic_upon_blocking

# *** Tests for debug - cpu load ***

- name: Build test test-debug-cpu_load-load_40_percent
Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/interrupt-unwind.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,17 @@ jobs:
sub-category: unwind
test-name: simple
timeout: 15s

panic_upon_blocking:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Run test panic_upon_blocking
uses: ./.github/workflows/actions/run-test
with:
category: interrupt
sub-category: unwind
test-name: panic_upon_blocking
timeout: 15s
13 changes: 13 additions & 0 deletions .github/workflows/task-unwind.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,16 @@ jobs:
category: task
sub-category: unwind
test-name: concurrent_restart

block_while_sched_suspend:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Run test block_while_sched_suspend
uses: ./.github/workflows/actions/run-test
with:
category: task
sub-category: unwind
test-name: block_while_sched_suspend
8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,10 @@ path = "examples/tests/task/unwind/concurrent_restart.rs"
name = "test-task-unwind-failed_concurrent_restart"
path = "examples/tests/task/unwind/failed_concurrent_restart.rs"

[[example]]
name = "test-task-unwind-block_while_sched_suspend"
path = "examples/tests/task/unwind/block_while_sched_suspend.rs"

# *** Tests for task - segmented stack ***

[[example]]
Expand All @@ -284,6 +288,10 @@ path = "examples/tests/task/context_switch/fp_registers.rs"
name = "test-interrupt-unwind-simple"
path = "examples/tests/interrupt/unwind/simple.rs"

[[example]]
name = "test-interrupt-unwind-panic_upon_blocking"
path = "examples/tests/interrupt/unwind/panic_upon_blocking.rs"

# *** Tests for debug - cpu load ***

[[example]]
Expand Down
179 changes: 179 additions & 0 deletions examples/tests/interrupt/unwind/panic_upon_blocking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
//! Tests that panics can be caught in an interrupt handler.
#![no_main]
#![no_std]
#![feature(naked_functions)]
#![feature(asm_const)]

extern crate alloc;

use core::sync::atomic::{AtomicUsize, Ordering};
use hopter::{
debug::semihosting::{self, dbg_println},
interrupt::declare::{handler, irq},
sync::{self, CondVar, Consumer, Mailbox, Mutex, Semaphore, SpinIrqSafe},
task::main,
time,
};
use stm32f4xx_hal::{
pac::{Interrupt, Peripherals, TIM2},
prelude::*,
timer::{CounterUs, Event},
};

irq!(Tim2Irq, Interrupt::TIM2);
static TIMER: SpinIrqSafe<Option<CounterUs<TIM2>>, Tim2Irq> = SpinIrqSafe::new(None);

static CONS: SpinIrqSafe<Option<Consumer<(), 4>>, Tim2Irq> = SpinIrqSafe::new(None);

#[main]
fn main(_cp: cortex_m::Peripherals) {
let (prod, cons) = sync::create_channel::<(), 4>();
{
CONS.lock().replace(cons);
}

// Prevent the channel from being dropped during test.
core::mem::forget(prod);

let dp = unsafe { Peripherals::steal() };

// For unknown reason QEMU accepts only the following clock frequency.
let rcc = dp.RCC.constrain();

#[cfg(feature = "qemu")]
let clocks = rcc.cfgr.sysclk(16.MHz()).pclk1(8.MHz()).freeze();
#[cfg(feature = "stm32f411")]
let clocks = rcc
.cfgr
.use_hse(8.MHz())
.sysclk(100.MHz())
.pclk1(25.MHz())
.pclk2(50.MHz())
.freeze();
#[cfg(feature = "stm32f407")]
let clocks = rcc
.cfgr
.use_hse(8.MHz())
.sysclk(168.MHz())
.pclk1(42.MHz())
.pclk2(84.MHz())
.freeze();

let mut timer = dp.TIM2.counter(&clocks);

// Generate an interrupt when the timer expires.
timer.listen(Event::Update);

// Enable TIM2 interrupt.
unsafe {
cortex_m::peripheral::NVIC::unmask(Interrupt::TIM2);
}

// Set the timer to expire every 1 second.
// Empirically when set to 62 seconds the interval is actually
// approximately 1 second. Weird QEMU.
#[cfg(feature = "qemu")]
timer.start(62.secs()).unwrap();
#[cfg(not(feature = "qemu"))]
timer.start(1.secs()).unwrap();

// Move the timer into the global storage to prevent it from being dropped.
*TIMER.lock() = Some(timer);
}

/// Get invoked approximately every 1 second.
#[handler(TIM2)]
fn tim2_handler() {
TIMER.lock().as_mut().unwrap().wait().unwrap();

static IRQ_CNT: AtomicUsize = AtomicUsize::new(0);
let prev_cnt = IRQ_CNT.fetch_add(1, Ordering::SeqCst);

match prev_cnt {
0 => panic_with_semaphore(),
1 => panic_with_mutex(),
2 => panic_with_channel(),
3 => panic_with_condvar(),
4 => panic_with_mailbox(),
5 => panic_with_sleep(),
_ => {}
}

if prev_cnt >= 6 {
#[cfg(feature = "qemu")]
semihosting::terminate(true);
#[cfg(not(feature = "qemu"))]
{
dbg_println!("test complete!");
loop {}
}
}
}

fn panic_with_semaphore() {
static SEM: Semaphore = Semaphore::new(1, 0);

let pod = PrintOnDrop("Panicked with semaphore.");
SEM.down();

// Don't print if not panic.
core::mem::forget(pod);
}

fn panic_with_mutex() {
static MTX: Mutex<()> = Mutex::new(());

let pod = PrintOnDrop("Panicked with mutex.");

let _mtx_gurad = MTX.lock();
MTX.lock();

// Don't print if not panic.
core::mem::forget(pod);
}

fn panic_with_channel() {
let cons = { CONS.lock().take().unwrap() };
let pod = PrintOnDrop("Panicked with channel.");
cons.consume();

// Don't print if not panic.
core::mem::forget(pod);
}

fn panic_with_condvar() {
static CV: CondVar = CondVar::new();

let pod = PrintOnDrop("Panicked with condvar.");
CV.wait_without_lock_until(|| false);

// Don't print if not panic.
core::mem::forget(pod);
}

fn panic_with_mailbox() {
static MAILBOX: Mailbox = Mailbox::new();

let pod = PrintOnDrop("Panicked with mailbox.");
MAILBOX.wait();

// Don't print if not panic.
core::mem::forget(pod);
}

fn panic_with_sleep() {
let pod = PrintOnDrop("Panicked with sleep.");
time::sleep_ms(1000).unwrap();

// Don't print if not panic.
core::mem::forget(pod);
}

struct PrintOnDrop(&'static str);

impl Drop for PrintOnDrop {
fn drop(&mut self) {
dbg_println!("{}", self.0);
}
}
6 changes: 6 additions & 0 deletions examples/tests/interrupt/unwind/panic_upon_blocking.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Panicked with semaphore.
Panicked with mutex.
Panicked with channel.
Panicked with condvar.
Panicked with mailbox.
Panicked with sleep.
117 changes: 117 additions & 0 deletions examples/tests/task/unwind/block_while_sched_suspend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
//! A forced unwinding should occur when a task without dynamic stack extension
//! is going to overflow its stack.
#![no_std]
#![no_main]

extern crate alloc;
use hopter::{
debug::semihosting::{self, dbg_println},
interrupt::mask::{AllIrqExceptSvc, MaskableIrq},
sync::{self, CondVar, Mailbox, Mutex, Semaphore},
task::{self, main},
time,
};
use hopter_conf_params::DEFAULT_TASK_PRIORITY;

#[main]
fn main(_: cortex_m::Peripherals) {
task::change_current_priority(DEFAULT_TASK_PRIORITY + 1).unwrap();

task::build()
.set_entry(panic_with_semaphore)
.spawn()
.unwrap();
task::build().set_entry(panic_with_mutex).spawn().unwrap();
task::build().set_entry(panic_with_channel).spawn().unwrap();
task::build().set_entry(panic_with_condvar).spawn().unwrap();
task::build().set_entry(panic_with_mailbox).spawn().unwrap();
task::build().set_entry(panic_with_sleep).spawn().unwrap();

#[cfg(feature = "qemu")]
semihosting::terminate(true);
#[cfg(not(feature = "qemu"))]
{
dbg_println!("test complete!");
loop {}
}
}

fn panic_with_semaphore() {
static SEM: Semaphore = Semaphore::new(1, 0);

let pod = PrintOnDrop("Panicked with semaphore.");
let _guard = AllIrqExceptSvc::mask();

SEM.down();

// Don't print if not panic.
core::mem::forget(pod);
}

fn panic_with_mutex() {
static MTX: Mutex<()> = Mutex::new(());

let pod = PrintOnDrop("Panicked with mutex.");
let _guard = AllIrqExceptSvc::mask();

let _mtx_gurad = MTX.lock();
MTX.lock();

// Don't print if not panic.
core::mem::forget(pod);
}

fn panic_with_channel() {
let (_, cons) = sync::create_channel::<(), 4>();

let pod = PrintOnDrop("Panicked with channel.");
let _guard = AllIrqExceptSvc::mask();

cons.consume();

// Don't print if not panic.
core::mem::forget(pod);
}

fn panic_with_condvar() {
static CV: CondVar = CondVar::new();

let pod = PrintOnDrop("Panicked with condvar.");
let _guard = AllIrqExceptSvc::mask();

CV.wait_without_lock_until(|| false);

// Don't print if not panic.
core::mem::forget(pod);
}

fn panic_with_mailbox() {
static MAILBOX: Mailbox = Mailbox::new();

let pod = PrintOnDrop("Panicked with mailbox.");
let _guard = AllIrqExceptSvc::mask();

MAILBOX.wait();

// Don't print if not panic.
core::mem::forget(pod);
}

fn panic_with_sleep() {
let pod = PrintOnDrop("Panicked with sleep.");
let _guard = AllIrqExceptSvc::mask();

time::sleep_ms(1000).unwrap();

// Don't print if not panic.
core::mem::forget(pod);
}

struct PrintOnDrop(&'static str);

impl Drop for PrintOnDrop {
fn drop(&mut self) {
dbg_println!("{}", self.0);
}
}
6 changes: 6 additions & 0 deletions examples/tests/task/unwind/block_while_sched_suspend.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Panicked with semaphore.
Panicked with mutex.
Panicked with channel.
Panicked with condvar.
Panicked with mailbox.
Panicked with sleep.
Loading

0 comments on commit 924a7bd

Please sign in to comment.