Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ members = [
"rust/task/irq",
"rust/task/affinity",
"rust/task/wait_queue",
"rust/task/sync",
]
exclude = [".arceos"]

Expand Down
3 changes: 1 addition & 2 deletions rust/task/affinity/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ use std::os::arceos::api::task::{ax_set_current_affinity, AxCpuMask};
#[cfg(feature = "axstd")]
use std::os::arceos::modules::axhal::cpu::this_cpu_id;

const KERNEL_STACK_SIZE: usize = 0x40000; // 256 KiB

const NUM_TASKS: usize = 10;
const NUM_TIMES: usize = 100;
static FINISHED_TASKS: AtomicUsize = AtomicUsize::new(0);
Expand All @@ -26,6 +24,7 @@ static FINISHED_TASKS: AtomicUsize = AtomicUsize::new(0);
fn main() {
println!("Hello, main task!");
for i in 0..NUM_TASKS {
#[cfg(feature = "axstd")]
let cpu_id = i % SMP;
thread::spawn(move || {
// Initialize cpu affinity here.
Expand Down
6 changes: 5 additions & 1 deletion rust/task/sleep/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fn main() {
println!("main task sleep for {:?}", elapsed);

// backgroud ticks, 0.5s x 30 = 15s
thread::spawn(|| {
let background_thread = thread::spawn(|| {
for i in 0..30 {
println!(" tick {}", i);
thread::sleep(Duration::from_millis(500));
Expand All @@ -47,5 +47,9 @@ fn main() {
while FINISHED_TASKS.load(Ordering::Relaxed) < NUM_TASKS {
thread::sleep(Duration::from_millis(10));
}

// Wait for background ticks to finish.
background_thread.join().unwrap();

println!("Sleep tests run OK!");
}
15 changes: 15 additions & 0 deletions rust/task/sync/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "arceos-sync"
version = "0.1.0"
edition = "2021"
authors = ["Keyang Hu <[email protected]>"]
description = "A simple demo to test the task synchronization mechanisms provided by ArceOS"

[features]
sched_rr = ["axstd?/sched_rr"]
sched_cfs = ["axstd?/sched_cfs"]

[dependencies]
axstd = { workspace = true, features = ["alloc", "multitask", "irq"], optional = true }

rand = { version = "0.8", default-features = false, features = ["small_rng"] }
32 changes: 32 additions & 0 deletions rust/task/sync/expect_info_smp1_fifo.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
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, synchronization mechanisms test for ArceOS!
Mutex test...
Mutex test ok
Condvar test...
Condvar test ok
Barrier test...
Barrier test OK
RwLock test...
RwLock test ok
Semaphore test...
Semaphore test ok
All synchronization mechanisms provided by ArceOS seem to work fine, enjoy!
Shutting down...
38 changes: 38 additions & 0 deletions rust/task/sync/expect_info_smp4_cfs.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
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, synchronization mechanisms test for ArceOS!
Mutex test...
Mutex test ok
Condvar test...
Condvar test ok
Barrier test...
Barrier test OK
RwLock test...
RwLock test ok
Semaphore test...
Semaphore test ok
All synchronization mechanisms provided by ArceOS seem to work fine, enjoy!
Shutting down...
38 changes: 38 additions & 0 deletions rust/task/sync/expect_info_smp4_fifo.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
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 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, synchronization mechanisms test for ArceOS!
Mutex test...
Mutex test ok
Condvar test...
Condvar test ok
Barrier test...
Barrier test OK
RwLock test...
RwLock test ok
Semaphore test...
Semaphore test ok
All synchronization mechanisms provided by ArceOS seem to work fine, enjoy!
Shutting down...
38 changes: 38 additions & 0 deletions rust/task/sync/expect_info_smp4_rr.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
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 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, synchronization mechanisms test for ArceOS!
Mutex test...
Mutex test ok
Condvar test...
Condvar test ok
Barrier test...
Barrier test OK
RwLock test...
RwLock test ok
Semaphore test...
Semaphore test ok
All synchronization mechanisms provided by ArceOS seem to work fine, enjoy!
Shutting down...
79 changes: 79 additions & 0 deletions rust/task/sync/src/barrier.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::{Arc, Barrier};
use std::thread;
use std::vec::Vec;

const NUM_TASKS: u32 = 10;
const NUM_ITERS: u32 = 100;

fn test_barrier_rendezvous() {
static BARRIER: Barrier = Barrier::new(NUM_TASKS as usize);
static FINISHED_TASKS: AtomicUsize = AtomicUsize::new(0);

fn rendezvous() {
for _ in 0..NUM_ITERS {
BARRIER.wait();
}
FINISHED_TASKS.fetch_add(1, Ordering::SeqCst);
}

for _ in 0..NUM_TASKS {
thread::spawn(rendezvous);
}

// Wait for all threads to finish.
while FINISHED_TASKS.load(Ordering::SeqCst) < NUM_TASKS as usize {
// Note: on FIFO scheduler, "preempt" is not enabled,
// yield manually to avoid deadlock.
#[cfg(all(not(feature = "sched_rr"), not(feature = "sched_cfs")))]
thread::yield_now();
}
}

fn test_wait_result() {
static LEADER_FOUND: AtomicBool = AtomicBool::new(false);
static FINISHED_TASKS: AtomicUsize = AtomicUsize::new(0);

let barrier = Arc::new(Barrier::new(NUM_TASKS as _));

let mut join_handlers = Vec::new();

for _ in 0..NUM_TASKS - 1 {
let c = barrier.clone();
join_handlers.push(thread::spawn(move || {
let is_leader = c.wait().is_leader();
if is_leader {
LEADER_FOUND.store(true, Ordering::SeqCst);
}
FINISHED_TASKS.fetch_add(1, Ordering::SeqCst);
}));
}

// At this point, all spawned threads should be blocked,
// so we shouldn't get a true value from `LEADER_FOUND`.
assert!(!LEADER_FOUND.load(Ordering::Acquire));

let leader_found = barrier.wait().is_leader();
if leader_found {
LEADER_FOUND.store(true, Ordering::SeqCst);
}

// Wait for all threads to finish.
for join_handler in join_handlers {
join_handler.join().unwrap();
}

assert_eq!(
FINISHED_TASKS.load(Ordering::Relaxed),
NUM_TASKS as usize - 1
);
// Now, the barrier is cleared and we should get true from `LEADER_FOUND`.
assert!(LEADER_FOUND.load(Ordering::Relaxed));
}

pub fn test_barrier() {
println!("Barrier test...");
thread::spawn(|| test_barrier_rendezvous()).join().unwrap();
thread::spawn(|| test_wait_result()).join().unwrap();
println!("Barrier test OK");
}
Loading
Loading