diff --git a/.github/workflows/actions/build/action.yaml b/.github/workflows/actions/build/action.yaml index 84f6e48..2952b7c 100644 --- a/.github/workflows/actions/build/action.yaml +++ b/.github/workflows/actions/build/action.yaml @@ -217,6 +217,13 @@ runs: sub-category: unwind test-name: deferred_nested_drop + - name: Build test test-task-unwind-concurrent_restart + uses: ./.github/workflows/actions/build-test + with: + category: task + sub-category: unwind + test-name: concurrent_restart + # *** Tests for task - segmented stack *** - name: Build test test-task-segmented_stack-function_arguments diff --git a/.github/workflows/task-unwind.yaml b/.github/workflows/task-unwind.yaml index 809fb4d..2f95de4 100644 --- a/.github/workflows/task-unwind.yaml +++ b/.github/workflows/task-unwind.yaml @@ -65,3 +65,17 @@ jobs: category: task sub-category: unwind test-name: deferred_nested_drop + + concurrent_restart: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Run test concurrent_restart + uses: ./.github/workflows/actions/run-test + with: + cookie: ${{ secrets.cookie }} + category: task + sub-category: unwind + test-name: concurrent_restart diff --git a/Cargo.toml b/Cargo.toml index 4dca5d9..28bd249 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -201,6 +201,10 @@ path = "examples/tests/task/unwind/deferred_indirect_drop.rs" name = "test-task-unwind-deferred_nested_drop" path = "examples/tests/task/unwind/deferred_nested_drop.rs" +[[example]] +name = "test-task-unwind-concurrent_restart" +path = "examples/tests/task/unwind/concurrent_restart.rs" + # *** Tests for task - segmented stack *** [[example]] diff --git a/examples/tests/task/unwind/concurrent_restart.rs b/examples/tests/task/unwind/concurrent_restart.rs new file mode 100644 index 0000000..1ebc956 --- /dev/null +++ b/examples/tests/task/unwind/concurrent_restart.rs @@ -0,0 +1,46 @@ +//! Tests that a panicked task will be restarted by a new instance running in +//! concurrent with the unwinding process of the panicked instance. The old +//! panicked instance should be reduced to a low priority (`UNWIND_PRIORITY`) +//! and thus the restarted instance should finish before the unwinding completes. + +#![no_std] +#![no_main] + +extern crate alloc; +use core::sync::atomic::{AtomicBool, Ordering}; +use hopter::{boot::main, config, debug::semihosting, hprintln, task}; + +#[main] +fn main(_: cortex_m::Peripherals) { + task::build() + .set_entry(will_panic) + .spawn_restartable() + .unwrap(); + + // Let the test task and its unwinding complete first. + task::change_current_priority(config::UNWIND_PRIORITY + 1).unwrap(); + + semihosting::terminate(true); +} + +fn will_panic() { + static FIRST_TIME: AtomicBool = AtomicBool::new(true); + let first_time = FIRST_TIME.fetch_and(false, Ordering::SeqCst); + + // Deliberate panic when the task is executed for the first time. + // Unwinding should happen after the second run is completed. + if first_time { + let _print_on_drop = PrintOnDrop("First run dropped on panic"); + panic!() + } + + hprintln!("Second run completed"); +} + +struct PrintOnDrop(&'static str); + +impl Drop for PrintOnDrop { + fn drop(&mut self) { + hprintln!("{}", self.0) + } +} diff --git a/examples/tests/task/unwind/concurrent_restart.txt b/examples/tests/task/unwind/concurrent_restart.txt new file mode 100644 index 0000000..6e82710 --- /dev/null +++ b/examples/tests/task/unwind/concurrent_restart.txt @@ -0,0 +1,2 @@ +Second run completed +First run dropped on panic