From 07ac4e9db9ac4fb5d8c5b1bc8843113c4419abb1 Mon Sep 17 00:00:00 2001 From: hky1999 <976929993@qq.com> Date: Mon, 14 Oct 2024 20:56:16 +0800 Subject: [PATCH] Add testcases for task wait queue --- .github/workflows/build.yml | 2 + Cargo.toml | 6 +- Makefile | 2 +- rust/task/parallel/src/main.rs | 4 +- rust/task/wait_queue/Cargo.toml | 9 + .../task/wait_queue/expect_info_smp1_fifo.out | 36 ++++ rust/task/wait_queue/expect_info_smp4_cfs.out | 42 ++++ .../task/wait_queue/expect_info_smp4_fifo.out | 42 ++++ rust/task/wait_queue/expect_info_smp4_rr.out | 42 ++++ rust/task/wait_queue/src/main.rs | 186 ++++++++++++++++++ rust/task/wait_queue/test_cmd | 4 + 11 files changed, 370 insertions(+), 5 deletions(-) create mode 100644 rust/task/wait_queue/Cargo.toml create mode 100644 rust/task/wait_queue/expect_info_smp1_fifo.out create mode 100644 rust/task/wait_queue/expect_info_smp4_cfs.out create mode 100644 rust/task/wait_queue/expect_info_smp4_fifo.out create mode 100644 rust/task/wait_queue/expect_info_smp4_rr.out create mode 100644 rust/task/wait_queue/src/main.rs create mode 100644 rust/task/wait_queue/test_cmd diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 730169b..20ac70b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -66,6 +66,8 @@ jobs: run: make ARCH=${{ matrix.arch }} A=rust/task/irq - name: Build rust/task/affinity run: make ARCH=${{ matrix.arch }} A=rust/task/affinity + - name: Build rust/task/wait_queue + run: make ARCH=${{ matrix.arch }} A=rust/task/wait_queue - name: Build rust/fs/shell run: make ARCH=${{ matrix.arch }} A=rust/fs/shell - name: Build rust/net/echoserver diff --git a/Cargo.toml b/Cargo.toml index 93ab387..52dd43c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,9 +18,11 @@ members = [ "rust/task/priority", "rust/task/tls", "rust/task/irq", - "rust/task/affinity", + "rust/task/affinity", + "rust/task/wait_queue", ] exclude = [".arceos"] [workspace.dependencies] -axstd = { git = "https://github.com/arceos-org/arceos.git" } +# axstd = { git = "https://github.com/arceos-org/arceos.git" } +axstd = { path = "../arceos/ulib/axstd" } diff --git a/Makefile b/Makefile index 118312c..66fd017 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ A ?= rust/helloworld -AX_ROOT ?= $(PWD)/.arceos +AX_ROOT ?= ../arceos APP := $(A) ifeq ($(filter /%,$(A)),) diff --git a/rust/task/parallel/src/main.rs b/rust/task/parallel/src/main.rs index 2fe51c4..0ddf283 100644 --- a/rust/task/parallel/src/main.rs +++ b/rust/task/parallel/src/main.rs @@ -22,7 +22,7 @@ fn barrier() { static BARRIER_COUNT: AtomicUsize = AtomicUsize::new(0); BARRIER_COUNT.fetch_add(1, Ordering::Relaxed); - api::ax_wait_queue_wait( + api::ax_wait_queue_wait_cond( &BARRIER_WQ, || BARRIER_COUNT.load(Ordering::Relaxed) == NUM_TASKS, None, @@ -60,7 +60,7 @@ fn main() { #[cfg(feature = "axstd")] { // equals to sleep(500ms) - let timeout = api::ax_wait_queue_wait( + let timeout = api::ax_wait_queue_wait_cond( &AxWaitQueueHandle::new(), || false, Some(std::time::Duration::from_millis(500)), diff --git a/rust/task/wait_queue/Cargo.toml b/rust/task/wait_queue/Cargo.toml new file mode 100644 index 0000000..30760f5 --- /dev/null +++ b/rust/task/wait_queue/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "wait_queue" +version = "0.1.0" +edition = "2021" +authors = ["Keyang Hu "] +description = "A simple demo to test the wait queue for tasks under ArceOS" + +[dependencies] +axstd = { workspace = true, features = ["multitask", "irq"], optional = true } diff --git a/rust/task/wait_queue/expect_info_smp1_fifo.out b/rust/task/wait_queue/expect_info_smp1_fifo.out new file mode 100644 index 0000000..6b98422 --- /dev/null +++ b/rust/task/wait_queue/expect_info_smp1_fifo.out @@ -0,0 +1,36 @@ +smp = 1 +build_mode = release +log_level = info + +Primary CPU 0 started, +Found physcial memory regions: + .text (READ | EXECUTE | RESERVED) + .rodata (READ | RESERVED) + .data .tdata .tbss .percpu (READ | WRITE | RESERVED) + .percpu (READ | WRITE | RESERVED) + boot stack (READ | WRITE | RESERVED) + .bss (READ | WRITE | RESERVED) + free memory (READ | WRITE | FREE) +Initialize global memory allocator... +Initialize platform devices... +Initialize scheduling... + use FIFO scheduler. +Initialize interrupt handlers... +Primary CPU 0 init OK. +Hello, main task +wait_queue: test_wait() +task TaskId(2) is waiting for tasks to start... +task TaskId(2) is waiting for tasks to finish... +wait_queue: test_wait() OK! +wait_timeout_until: tests begin +wait_timeout_until: test tasks woken up by notification, spawn 16 tasks... +wait_timeout_until: sleep for 100ms to let all tasks start +wait_timeout_until: wake up all tasks who are waiting for timeout through notification +wait_timeout_until: tasks woken up by notification test OK! +wait_timeout_until: test tasks woken up by timeout, spawn 16 tasks... +wait_timeout_until: wait for all tasks to finish +wait_timeout_until: tasks woken up by timeout test OK! +wait_timeout_until: test tasks woken up by notification or timeout, spawn 16 tasks... +wait_timeout_until: test tasks woken up by notification or timeout, test OK! +wait_timeout_until: all tests OK! +Shutting down... diff --git a/rust/task/wait_queue/expect_info_smp4_cfs.out b/rust/task/wait_queue/expect_info_smp4_cfs.out new file mode 100644 index 0000000..75a43a4 --- /dev/null +++ b/rust/task/wait_queue/expect_info_smp4_cfs.out @@ -0,0 +1,42 @@ +smp = 4 +build_mode = release +log_level = info + +CPU 0 started +Found physcial memory regions: +.text (READ | EXECUTE | RESERVED) +.rodata (READ | RESERVED) +.data .tdata .tbss .percpu (READ | WRITE | RESERVED) +.percpu (READ | WRITE | RESERVED) +boot stack (READ | WRITE | RESERVED) +.bss (READ | WRITE | RESERVED) +free memory (READ | WRITE | FREE) +Initialize global memory allocator... +Initialize platform devices... +Initialize scheduling... + use Completely Fair scheduler. +Initialize interrupt handlers... +CPU 0 init OK +CPU 1 started +CPU 2 started +CPU 3 started +CPU 1 init OK +CPU 2 init OK +CPU 3 init OK +Hello, main task +wait_queue: test_wait() +task TaskId(2) is waiting for tasks to start... +task TaskId(2) is waiting for tasks to finish... +wait_queue: test_wait() OK! +wait_timeout_until: tests begin +wait_timeout_until: test tasks woken up by notification, spawn 16 tasks... +wait_timeout_until: sleep for 100ms to let all tasks start +wait_timeout_until: wake up all tasks who are waiting for timeout through notification +wait_timeout_until: tasks woken up by notification test OK! +wait_timeout_until: test tasks woken up by timeout, spawn 16 tasks... +wait_timeout_until: wait for all tasks to finish +wait_timeout_until: tasks woken up by timeout test OK! +wait_timeout_until: test tasks woken up by notification or timeout, spawn 16 tasks... +wait_timeout_until: test tasks woken up by notification or timeout, test OK! +wait_timeout_until: all tests OK! +Shutting down... diff --git a/rust/task/wait_queue/expect_info_smp4_fifo.out b/rust/task/wait_queue/expect_info_smp4_fifo.out new file mode 100644 index 0000000..dd0d828 --- /dev/null +++ b/rust/task/wait_queue/expect_info_smp4_fifo.out @@ -0,0 +1,42 @@ +smp = 4 +build_mode = release +log_level = info + +Primary CPU 0 started, +Found physcial memory regions: + .text (READ | EXECUTE | RESERVED) + .rodata (READ | RESERVED) + .data .tdata .tbss .percpu (READ | WRITE | RESERVED) + .percpu (READ | WRITE | RESERVED) + boot stack (READ | WRITE | RESERVED) + .bss (READ | WRITE | RESERVED) + free memory (READ | WRITE | FREE) +Initialize global memory allocator... +Initialize platform devices... +Initialize scheduling... + use FIFO scheduler. +Initialize interrupt handlers... +CPU 0 init OK +CPU 1 started +CPU 2 started +CPU 3 started +CPU 1 init OK +CPU 2 init OK +CPU 3 init OK +Hello, main task +wait_queue: test_wait() +task TaskId(2) is waiting for tasks to start... +task TaskId(2) is waiting for tasks to finish... +wait_queue: test_wait() OK! +wait_timeout_until: tests begin +wait_timeout_until: test tasks woken up by notification, spawn 16 tasks... +wait_timeout_until: sleep for 100ms to let all tasks start +wait_timeout_until: wake up all tasks who are waiting for timeout through notification +wait_timeout_until: tasks woken up by notification test OK! +wait_timeout_until: test tasks woken up by timeout, spawn 16 tasks... +wait_timeout_until: wait for all tasks to finish +wait_timeout_until: tasks woken up by timeout test OK! +wait_timeout_until: test tasks woken up by notification or timeout, spawn 16 tasks... +wait_timeout_until: test tasks woken up by notification or timeout, test OK! +wait_timeout_until: all tests OK! +Shutting down... diff --git a/rust/task/wait_queue/expect_info_smp4_rr.out b/rust/task/wait_queue/expect_info_smp4_rr.out new file mode 100644 index 0000000..449a68c --- /dev/null +++ b/rust/task/wait_queue/expect_info_smp4_rr.out @@ -0,0 +1,42 @@ +smp = 4 +build_mode = release +log_level = info + +Primary CPU 0 started, +Found physcial memory regions: + .text (READ | EXECUTE | RESERVED) + .rodata (READ | RESERVED) + .data .tdata .tbss .percpu (READ | WRITE | RESERVED) + .percpu (READ | WRITE | RESERVED) + boot stack (READ | WRITE | RESERVED) + .bss (READ | WRITE | RESERVED) + free memory (READ | WRITE | FREE) +Initialize global memory allocator... +Initialize platform devices... +Initialize scheduling... + use Round-robin scheduler. +Initialize interrupt handlers... +CPU 0 init OK +CPU 1 started +CPU 2 started +CPU 3 started +CPU 1 init OK +CPU 2 init OK +CPU 3 init OK +Hello, main task +wait_queue: test_wait() +task TaskId(2) is waiting for tasks to start... +task TaskId(2) is waiting for tasks to finish... +wait_queue: test_wait() OK! +wait_timeout_until: tests begin +wait_timeout_until: test tasks woken up by notification, spawn 16 tasks... +wait_timeout_until: sleep for 100ms to let all tasks start +wait_timeout_until: wake up all tasks who are waiting for timeout through notification +wait_timeout_until: tasks woken up by notification test OK! +wait_timeout_until: test tasks woken up by timeout, spawn 16 tasks... +wait_timeout_until: wait for all tasks to finish +wait_timeout_until: tasks woken up by timeout test OK! +wait_timeout_until: test tasks woken up by notification or timeout, spawn 16 tasks... +wait_timeout_until: test tasks woken up by notification or timeout, test OK! +wait_timeout_until: all tests OK! +Shutting down... diff --git a/rust/task/wait_queue/src/main.rs b/rust/task/wait_queue/src/main.rs new file mode 100644 index 0000000..1f98cad --- /dev/null +++ b/rust/task/wait_queue/src/main.rs @@ -0,0 +1,186 @@ +#![cfg_attr(feature = "axstd", no_std)] +#![cfg_attr(feature = "axstd", no_main)] + +#[macro_use] +#[cfg(feature = "axstd")] +extern crate axstd as std; + +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use std::thread; +use std::time::Duration; + +#[cfg(feature = "axstd")] +use std::os::arceos::api::task::{self as api, AxWaitQueueHandle}; +#[cfg(feature = "axstd")] +use std::os::arceos::modules::axtask; + +const NUM_TASKS: usize = 16; + +#[cfg(feature = "axstd")] +fn test_wait() { + static WQ1: AxWaitQueueHandle = AxWaitQueueHandle::new(); + static WQ2: AxWaitQueueHandle = AxWaitQueueHandle::new(); + static COUNTER: AtomicUsize = AtomicUsize::new(0); + println!("wait_queue: test_wait()"); + + for _ in 0..NUM_TASKS { + thread::spawn(move || { + COUNTER.fetch_add(1, Ordering::Relaxed); + api::ax_wait_queue_wake(&WQ1, 1); // WQ1.wait_until() + api::ax_wait_queue_wait(&WQ2); + + COUNTER.fetch_sub(1, Ordering::Relaxed); + api::ax_wait_queue_wake(&WQ1, 1); // WQ1.wait_until() + }); + } + + println!( + "task {:?} is waiting for tasks to start...", + axtask::current().id() + ); + api::ax_wait_queue_wait_cond(&WQ1, || COUNTER.load(Ordering::Relaxed) == NUM_TASKS, None); + assert_eq!(COUNTER.load(Ordering::Relaxed), NUM_TASKS); + + api::ax_wait_queue_wake(&WQ2, u32::MAX); // WQ2.wait() + + println!( + "task {:?} is waiting for tasks to finish...", + axtask::current().id() + ); + api::ax_wait_queue_wait_cond(&WQ1, || COUNTER.load(Ordering::Relaxed) == 0, None); + assert_eq!(COUNTER.load(Ordering::Relaxed), 0); + + println!("wait_queue: test_wait() OK!"); +} + +#[cfg(feature = "axstd")] +fn test_wait_timeout_until() { + static WQ3: AxWaitQueueHandle = AxWaitQueueHandle::new(); + static WQ4: AxWaitQueueHandle = AxWaitQueueHandle::new(); + static COUNTER2: AtomicUsize = AtomicUsize::new(0); + println!("wait_timeout_until: tests begin"); + + // First, test the case that the task is woken up by notification. + println!( + "wait_timeout_until: test tasks woken up by notification, spawn {} tasks...", + NUM_TASKS, + ); + + for _ in 0..NUM_TASKS { + // Sleep more than 60s, which exceeds the timeout limited by test script. + let time_to_wait_in_seconds = 100; + thread::spawn(move || { + let timeout = api::ax_wait_queue_wait_cond( + &WQ3, + // It is strange, but it is just for testing. + // We have to use `true` here to allow the task to be woken up by notification. + || true, + // equals to sleep(100s) + Some(Duration::from_secs(time_to_wait_in_seconds)), + ); + assert!(!timeout, "It should not be woken up by timeout"); + COUNTER2.fetch_add(1, Ordering::Relaxed); + // Notify the main task who waits on WQ4 that this task is finished. + api::ax_wait_queue_wake(&WQ4, 1); + }); + } + + // Sleep for a while to let all tasks start and wait for timeout. + println!("wait_timeout_until: sleep for 100ms to let all tasks start"); + thread::sleep(Duration::from_millis(100)); + println!( + "wait_timeout_until: wake up all tasks who are waiting for timeout through notification" + ); + // Wake up all tasks who are waiting for timeout. + api::ax_wait_queue_wake(&WQ3, u32::MAX); + // Wait for all tasks to finish (woken up by notification). + api::ax_wait_queue_wait_cond(&WQ4, || COUNTER2.load(Ordering::Relaxed) == NUM_TASKS, None); + assert_eq!(COUNTER2.load(Ordering::Relaxed), NUM_TASKS); + + println!("wait_timeout_until: tasks woken up by notification test OK!"); + + // Second, test the case that the task is woken up by timeout. + println!( + "wait_timeout_until: test tasks woken up by timeout, spawn {} tasks...", + NUM_TASKS, + ); + + // Sleep just 100ms. + let time_to_wait_in_millis = 100; + + for _ in 0..NUM_TASKS { + thread::spawn(move || { + let timeout = api::ax_wait_queue_wait_cond( + &WQ3, + || false, + // equals to sleep(0.1s) + Some(Duration::from_millis(time_to_wait_in_millis)), + ); + assert!(timeout, "It should be woken up by timeout"); + COUNTER2.fetch_sub(1, Ordering::Relaxed); + + // Notify the main task who waits on WQ4 that this task is finished. + api::ax_wait_queue_wake(&WQ4, 1); + }); + } + + println!("wait_timeout_until: wait for all tasks to finish"); + // Wait for all tasks to finish (woken up by timeout). + api::ax_wait_queue_wait_cond(&WQ4, || COUNTER2.load(Ordering::Relaxed) == 0, None); + assert_eq!(COUNTER2.load(Ordering::Relaxed), 0); + + println!("wait_timeout_until: tasks woken up by timeout test OK!"); + + // Finally, test the case that the task maybe woken up by notification or timeout. + println!( + "wait_timeout_until: test tasks woken up by notification or timeout, spawn {} tasks...", + NUM_TASKS, + ); + + static CONDITION: AtomicBool = AtomicBool::new(false); + + for _ in 0..NUM_TASKS { + // Sleep just 100ms. + thread::spawn(move || { + let timeout = api::ax_wait_queue_wait_cond( + &WQ3, + || CONDITION.load(Ordering::Relaxed), + // equals to sleep(0.1s) + Some(Duration::from_millis(time_to_wait_in_millis)), + ); + println!( + "wait_timeout_until: task {:?} woken up by {}", + axtask::current().id(), + if timeout { "timeout" } else { "notification" } + ); + COUNTER2.fetch_add(1, Ordering::Relaxed); + + // Notify the main task who waits on WQ4 that this task is finished. + api::ax_wait_queue_wake(&WQ4, 1); + }); + } + + // Sleep for 100ms to let all tasks start and wait for timeout. + thread::sleep(Duration::from_millis(time_to_wait_in_millis - 10)); + // Set condition to true to wake up all tasks who call `ax_wait_queue_wait_cond`. + CONDITION.store(true, Ordering::Relaxed); + // Wake up all tasks who are waiting for timeout. + api::ax_wait_queue_wake(&WQ3, u32::MAX); + + // Wait for all tasks to finish (woken up by timeout). + api::ax_wait_queue_wait_cond(&WQ4, || COUNTER2.load(Ordering::Relaxed) == NUM_TASKS, None); + assert_eq!(COUNTER2.load(Ordering::Relaxed), NUM_TASKS); + + println!("wait_timeout_until: test tasks woken up by notification or timeout, test OK!"); + + println!("wait_timeout_until: all tests OK!"); +} + +#[cfg_attr(feature = "axstd", no_mangle)] +fn main() { + println!("Hello, main task"); + #[cfg(feature = "axstd")] + test_wait(); + #[cfg(feature = "axstd")] + test_wait_timeout_until(); +} diff --git a/rust/task/wait_queue/test_cmd b/rust/task/wait_queue/test_cmd new file mode 100644 index 0000000..c341ea6 --- /dev/null +++ b/rust/task/wait_queue/test_cmd @@ -0,0 +1,4 @@ +test_one "LOG=info" "expect_info_smp1_fifo.out" +test_one "SMP=4 LOG=info" "expect_info_smp4_fifo.out" +test_one "SMP=4 LOG=info FEATURES=sched_rr" "expect_info_smp4_rr.out" +test_one "SMP=4 LOG=info FEATURES=sched_cfs" "expect_info_smp4_cfs.out"