-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add test for panic upon erroneous blocking.
- Loading branch information
Showing
13 changed files
with
379 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
117
examples/tests/task/unwind/block_while_sched_suspend.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
Oops, something went wrong.