From c199ac5e467d2b7c97896971922b77708cd29ed6 Mon Sep 17 00:00:00 2001 From: lvyuemeng Date: Sun, 4 May 2025 10:40:26 +0800 Subject: [PATCH 01/11] feat(async, embassy): add embassy test with async --- .gitignore | 1 + Cargo.lock | 239 +++++++++++++++++++++++++++++- Cargo.toml | 2 +- api/arceos_api/src/imp/task.rs | 14 ++ api/arceos_api/src/lib.rs | 5 + examples/embassy/.axconfig.toml | 81 ++++++++++ examples/embassy/Cargo.toml | 11 ++ examples/embassy/src/executor.rs | 66 +++++++++ examples/embassy/src/main.rs | 45 ++++++ modules/axsync/Cargo.toml | 5 +- modules/axsync/src/condvar.rs | 67 +++++++++ modules/axsync/src/lib.rs | 2 + modules/axsync/src/mutex.rs | 8 + modules/axtask/src/api.rs | 2 + modules/axtask/src/lib.rs | 1 + modules/axtask/src/wait_queues.rs | 65 ++++++++ ulib/axstd/src/sync/condvar.rs | 69 +++++++++ ulib/axstd/src/sync/mod.rs | 5 + ulib/axstd/src/sync/mutex.rs | 8 + 19 files changed, 690 insertions(+), 6 deletions(-) create mode 100644 examples/embassy/.axconfig.toml create mode 100644 examples/embassy/Cargo.toml create mode 100644 examples/embassy/src/executor.rs create mode 100644 examples/embassy/src/main.rs create mode 100644 modules/axsync/src/condvar.rs create mode 100644 modules/axtask/src/wait_queues.rs create mode 100644 ulib/axstd/src/sync/condvar.rs diff --git a/.gitignore b/.gitignore index 2a2c5a3dd2..7838e7f45e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /target +examples/*/target /.vscode .DS_Store *.asm diff --git a/Cargo.lock b/Cargo.lock index d1f04281f6..d9423f4834 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -889,6 +889,41 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.98", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.98", +] + [[package]] name = "defmt" version = "0.3.10" @@ -921,6 +956,15 @@ dependencies = [ "thiserror", ] +[[package]] +name = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", +] + [[package]] name = "dw_apb_uart" version = "0.1.0" @@ -936,12 +980,107 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d" +[[package]] +name = "embassy" +version = "0.0.0" +dependencies = [ + "axhal", + "axstd", + "embassy-executor", + "embassy-futures", + "embassy-time", +] + +[[package]] +name = "embassy-executor" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90327bcc66333a507f89ecc4e2d911b265c45f5c9bc241f98eee076752d35ac6" +dependencies = [ + "critical-section", + "document-features", + "embassy-executor-macros", +] + +[[package]] +name = "embassy-executor-macros" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3577b1e9446f61381179a330fc5324b01d511624c55f25e3c66c9e3c626dbecf" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "embassy-futures" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067" + +[[package]] +name = "embassy-time" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f820157f198ada183ad62e0a66f554c610cdcd1a9f27d4b316358103ced7a1f8" +dependencies = [ + "cfg-if", + "critical-section", + "document-features", + "embassy-time-driver", + "embassy-time-queue-utils", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "futures-util", +] + +[[package]] +name = "embassy-time-driver" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d45f5d833b6d98bd2aab0c2de70b18bfaa10faf661a1578fd8e5dfb15eb7eba" +dependencies = [ + "document-features", +] + +[[package]] +name = "embassy-time-queue-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc55c748d16908a65b166d09ce976575fb8852cf60ccd06174092b41064d8f83" +dependencies = [ + "embassy-executor", + "heapless 0.8.0", +] + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + [[package]] name = "embedded-hal" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -976,6 +1115,36 @@ dependencies = [ "bitmaps", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + [[package]] name = "fxmac_rs" version = "0.2.0" @@ -1018,6 +1187,15 @@ dependencies = [ "byteorder", ] +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.15.2" @@ -1031,12 +1209,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" dependencies = [ "atomic-polyfill", - "hash32", + "hash32 0.2.1", "rustc_version", "spin", "stable_deref_trait", ] +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32 0.3.1", + "stable_deref_trait", +] + [[package]] name = "heck" version = "0.5.0" @@ -1075,6 +1263,12 @@ dependencies = [ "cc", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "indexmap" version = "2.7.1" @@ -1216,6 +1410,12 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + [[package]] name = "lock_api" version = "0.4.12" @@ -1275,6 +1475,21 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + [[package]] name = "nom" version = "7.1.3" @@ -1361,6 +1576,18 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -1504,7 +1731,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ea8ff73d3720bdd0a97925f0bf79ad2744b6da8ff36be3840c48ac81191d7a7" dependencies = [ "critical-section", - "embedded-hal", + "embedded-hal 1.0.0", "paste", "riscv-macros", "riscv-pac", @@ -1637,7 +1864,7 @@ dependencies = [ "byteorder", "cfg-if", "defmt", - "heapless", + "heapless 0.7.17", "log", "managed", ] @@ -1788,6 +2015,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + [[package]] name = "volatile" version = "0.2.7" diff --git a/Cargo.toml b/Cargo.toml index dfc0a37bda..7df14252bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ members = [ "examples/httpclient", "examples/httpserver", "examples/httpserver", - "examples/shell", + "examples/shell", "examples/embassy", ] [workspace.package] diff --git a/api/arceos_api/src/imp/task.rs b/api/arceos_api/src/imp/task.rs index 9764bb1c00..0cb1e6d60a 100644 --- a/api/arceos_api/src/imp/task.rs +++ b/api/arceos_api/src/imp/task.rs @@ -26,6 +26,20 @@ pub fn ax_exit(_exit_code: i32) -> ! { cfg_task! { use core::time::Duration; + pub type AxFutex = axtask::Futex; + + pub fn ax_futex_wake(futex: &AxFutex) { + axtask::futex_wake(futex); + } + + pub fn ax_futex_wake_all(futex: &AxFutex) { + axtask::futex_wake_all(futex); + } + + pub fn ax_futex_wait(futex: &AxFutex, expected: u32, timeout: Option) -> bool { + axtask::futex_wait(futex, expected, timeout) + } + /// A handle to a task. pub struct AxTaskHandle { inner: axtask::AxTaskRef, diff --git a/api/arceos_api/src/lib.rs b/api/arceos_api/src/lib.rs index 3e6d291870..1232b393c5 100644 --- a/api/arceos_api/src/lib.rs +++ b/api/arceos_api/src/lib.rs @@ -122,6 +122,7 @@ pub mod task { pub type AxTaskHandle; pub type AxWaitQueueHandle; pub type AxCpuMask; + pub type AxFutex; } define_api! { @@ -175,6 +176,10 @@ pub mod task { /// The maximum number of tasks to wake up is specified by `count`. If /// `count` is `u32::MAX`, it will wake up all tasks in the wait queue. pub fn ax_wait_queue_wake(wq: &AxWaitQueueHandle, count: u32); + + pub fn ax_futex_wake(futex: &AxFutex); + pub fn ax_futex_wake_all(futex: &AxFutex); + pub fn ax_futex_wait(futex: &AxFutex, expected: u32, timeout: Option) -> bool; } } diff --git a/examples/embassy/.axconfig.toml b/examples/embassy/.axconfig.toml new file mode 100644 index 0000000000..42465c83b4 --- /dev/null +++ b/examples/embassy/.axconfig.toml @@ -0,0 +1,81 @@ +# Architecture identifier. +arch = "riscv64" # str +# Platform identifier. +platform = "riscv64-qemu-virt" # str +# Number of CPUs +smp = 1 # uint +# Stack size of each task. +task-stack-size = 0x40000 # uint +# Number of timer ticks per second (Hz). A timer tick may contain several timer +# interrupts. +ticks-per-sec = 100 # uint + +# +# Device specifications +# +[devices] +# MMIO regions with format (`base_paddr`, `size`). +mmio-regions = [ + [0x0010_1000, 0x1000], + [0x0c00_0000, 0x21_0000], + [0x1000_0000, 0x1000], + [0x1000_1000, 0x8000], + [0x3000_0000, 0x1000_0000], + [0x4000_0000, 0x4000_0000] +] # [(uint, uint)] +# End PCI bus number (`bus-range` property in device tree). +pci-bus-end = 0xff # uint +# Base physical address of the PCIe ECAM space. +pci-ecam-base = 0x3000_0000 # uint +# PCI device memory ranges (`ranges` property in device tree). +pci-ranges = [ + [0x0300_0000, 0x1_0000], + [0x4000_0000, 0x4000_0000], + [0x4_0000_0000, 0x4_0000_0000] +] # [(uint, uint)] +# rtc@101000 { +# interrupts = <0x0b>; +# interrupt-parent = <0x03>; +# reg = <0x00 0x101000 0x00 0x1000>; +# compatible = "google,goldfish-rtc"; +# }; +# RTC (goldfish) Address +rtc-paddr = 0x10_1000 # uint +# Timer interrupt frequency in Hz. +timer-frequency = 10_000_000 # uint +# VirtIO MMIO regions with format (`base_paddr`, `size`). +virtio-mmio-regions = [ + [0x1000_1000, 0x1000], + [0x1000_2000, 0x1000], + [0x1000_3000, 0x1000], + [0x1000_4000, 0x1000], + [0x1000_5000, 0x1000], + [0x1000_6000, 0x1000], + [0x1000_7000, 0x1000], + [0x1000_8000, 0x1000] +] # [(uint, uint)] + +# +# Platform configs +# +[plat] +# Platform family. +family = "riscv64-qemu-virt" # str +# Kernel address space base. +kernel-aspace-base = "0xffff_ffc0_0000_0000" # uint +# Kernel address space size. +kernel-aspace-size = "0x0000_003f_ffff_f000" # uint +# Base physical address of the kernel image. +kernel-base-paddr = 0x8020_0000 # uint +# Base virtual address of the kernel image. +kernel-base-vaddr = "0xffff_ffc0_8020_0000" # uint +# Offset of bus address and phys address. some boards, the bus address is +# different from the physical address. +phys-bus-offset = 0 # uint +# Base address of the whole physical memory. +phys-memory-base = 0x8000_0000 # uint +# Size of the whole physical memory. (128M) +phys-memory-size = 0x800_0000 # uint +# Linear mapping offset, for quick conversions between physical and virtual +# addresses. +phys-virt-offset = "0xffff_ffc0_0000_0000" # uint diff --git a/examples/embassy/Cargo.toml b/examples/embassy/Cargo.toml new file mode 100644 index 0000000000..05cb52828d --- /dev/null +++ b/examples/embassy/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "embassy" +authors = ["nostalgia "] +edition.workspace = true + +[dependencies] +axhal = { workspace=true, features = ["irq"] } +axstd = { workspace = true, features = ["alloc","multitask"], optional = true } +embassy-futures = "0.1.1" +embassy-executor = { version = "0.7.0", features = ["nightly","executor-thread"] } +embassy-time = {version = "0.4.0", features = ["mock-driver"]} diff --git a/examples/embassy/src/executor.rs b/examples/embassy/src/executor.rs new file mode 100644 index 0000000000..85f6af7dc6 --- /dev/null +++ b/examples/embassy/src/executor.rs @@ -0,0 +1,66 @@ +use core::marker::PhantomData; +use embassy_executor::raw; +use std::sync::{Condvar, Mutex}; +use std::boxed::Box; + + +#[unsafe(export_name = "__pender")] +fn __pender(context: *mut ()) { + let signaler: &'static Signaler = unsafe { std::mem::transmute(context) }; + signaler.signal() +} + +pub struct Executor { + inner: raw::Executor, + not_send: PhantomData<*mut ()>, + signaler: &'static Signaler, +} + +impl Executor { + pub fn new() -> Self { + let signaler = Box::leak(Box::new(Signaler::new())); + Self { + inner: raw::Executor::new(signaler as *mut Signaler as *mut ()), + not_send: PhantomData, + signaler, + } + } + + pub fn run(&'static mut self, init: impl FnOnce(embassy_executor::Spawner)) -> ! { + init(self.inner.spawner()); + + loop { + unsafe { self.inner.poll() }; + self.signaler.wait() + } + } +} + +struct Signaler { + mutex: Mutex, + condvar: Condvar, +} + +impl Signaler { + fn new() -> Self { + Self { + mutex: Mutex::new(false), + condvar: Condvar::new(), + } + } + + fn signal(&self) { + let mut guard= self.mutex.lock(); + *guard = true; + self.condvar.notify_one(); + } + + fn wait(&self) { + let mut guard = self.mutex.lock(); + while !*guard { + guard = self.condvar.wait(guard); + } + *guard = false; + } +} + diff --git a/examples/embassy/src/main.rs b/examples/embassy/src/main.rs new file mode 100644 index 0000000000..cb335c7a86 --- /dev/null +++ b/examples/embassy/src/main.rs @@ -0,0 +1,45 @@ +#![feature(impl_trait_in_assoc_type)] +#![cfg_attr(feature = "axstd", no_std)] +#![cfg_attr(feature = "axstd", no_main)] + +#[macro_use] +#[cfg(feature = "axstd")] +extern crate axstd as std; + +use embassy_futures::yield_now; +use embassy_time::{Duration, MockDriver}; +use std::boxed::Box; + +mod executor; +mod timer; + +fn tick(sec: u64, f: fn()) -> embassy_executor::SpawnToken { + let task = Box::leak(Box::new(embassy_executor::raw::TaskStorage::new())); + task.spawn(move || async move { + for _ in 0..10 { + f(); + yield_now().await; + } + }) +} + +// used as a tick timer to delay +fn idle() -> embassy_executor::SpawnToken { + let task = Box::leak(Box::new(embassy_executor::raw::TaskStorage::new())); + task.spawn(move || async move { + for _ in 0..10 { + yield_now().await; + } + }) +} + +#[cfg_attr(feature = "axstd", unsafe(no_mangle))] +fn main() { + println!("Embassy Test"); + let exec = Box::leak(Box::new(executor::Executor::new())); + exec.run(|s| { + s.spawn(idle()).unwrap(); + s.spawn(tick(1, || {println!("tick for 1 sec")})).unwrap(); + s.spawn(tick(2, || {println!("tick for 2 sec")})).unwrap(); + }); +} diff --git a/modules/axsync/Cargo.toml b/modules/axsync/Cargo.toml index db7ef1206e..f791ed65b6 100644 --- a/modules/axsync/Cargo.toml +++ b/modules/axsync/Cargo.toml @@ -10,12 +10,13 @@ repository = "https://github.com/arceos-org/arceos/tree/main/modules/axsync" documentation = "https://arceos-org.github.io/arceos/axsync/index.html" [features] -multitask = ["axtask/multitask"] default = [] +multitask = ["axtask/multitask"] + [dependencies] kspin = "0.1" -axtask = { workspace = true } +axtask = { workspace = true, features = ["irq", "multitask"] } [dev-dependencies] rand = "0.8" diff --git a/modules/axsync/src/condvar.rs b/modules/axsync/src/condvar.rs new file mode 100644 index 0000000000..5f5eaaf183 --- /dev/null +++ b/modules/axsync/src/condvar.rs @@ -0,0 +1,67 @@ +extern crate alloc; + +use crate::MutexGuard; +use axtask::{Futex, futex_wait, futex_wake, futex_wake_all}; + +use core::{sync::atomic::AtomicU32, time::Duration}; + +pub struct Condvar { + // The value of this atomic is simply incremented on every notification. + // This is used by `.wait()` to not miss any notifications after + // unlocking the mutex and before waiting for notifications. + futex: Futex, +} + +impl Condvar { + #[inline] + pub const fn new() -> Self { + Self { + futex: AtomicU32::new(0), + } + } + + pub fn notify_one(&self) { + self.futex + .fetch_add(1, core::sync::atomic::Ordering::Relaxed); + futex_wake(&self.futex); + } + + pub fn notify_all(&self) { + self.futex + .fetch_add(1, core::sync::atomic::Ordering::Relaxed); + futex_wake_all(&self.futex); + } + + pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> { + // wait with no timeout should always return the guard + self.wait_optional_timeout(guard, None) + .expect("Condvar::wait with no timeout should not return None on timeout") + } + + pub fn wait_timeout<'a, T>( + &self, + guard: MutexGuard<'a, T>, + timeout: Duration, + ) -> Option> { + self.wait_optional_timeout(guard, Some(timeout)) + } + + fn wait_optional_timeout<'a, T>( + &self, + guard: MutexGuard<'a, T>, + timeout: Option, + ) -> Option> { + let expected = self.futex.load(core::sync::atomic::Ordering::Relaxed); + let mutex = guard.mutex(); + + let suc = futex_wait(&self.futex, expected, timeout); + + let new_guard = mutex.lock(); + + if !suc && timeout.is_some() { + None + } else { + Some(new_guard) + } + } +} diff --git a/modules/axsync/src/lib.rs b/modules/axsync/src/lib.rs index cc71a12833..690ec5b26d 100644 --- a/modules/axsync/src/lib.rs +++ b/modules/axsync/src/lib.rs @@ -18,10 +18,12 @@ pub use kspin as spin; #[cfg(feature = "multitask")] mod mutex; +mod condvar; #[cfg(feature = "multitask")] #[doc(cfg(feature = "multitask"))] pub use self::mutex::{Mutex, MutexGuard}; +pub use self::condvar::Condvar; #[cfg(not(feature = "multitask"))] #[doc(cfg(not(feature = "multitask")))] diff --git a/modules/axsync/src/mutex.rs b/modules/axsync/src/mutex.rs index fdc6d614f5..a9ee36c344 100644 --- a/modules/axsync/src/mutex.rs +++ b/modules/axsync/src/mutex.rs @@ -167,6 +167,14 @@ impl fmt::Debug for Mutex { } } +impl<'a, T: ?Sized> MutexGuard<'a, T> { + #[inline(always)] + pub fn mutex(&self) -> &'a Mutex { + let m = self.lock; + &*m + } +} + impl Deref for MutexGuard<'_, T> { type Target = T; #[inline(always)] diff --git a/modules/axtask/src/api.rs b/modules/axtask/src/api.rs index 7cf96a043c..77380dcbdd 100644 --- a/modules/axtask/src/api.rs +++ b/modules/axtask/src/api.rs @@ -12,6 +12,8 @@ pub use crate::task::{CurrentTask, TaskId, TaskInner}; pub use crate::task_ext::{TaskExtMut, TaskExtRef}; #[doc(cfg(feature = "multitask"))] pub use crate::wait_queue::WaitQueue; +#[doc(cfg(feature = "multitask"))] +pub use crate::wait_queues::{Futex,futex_wait,futex_wake,futex_wake_all}; /// The reference type of a task. pub type AxTaskRef = Arc; diff --git a/modules/axtask/src/lib.rs b/modules/axtask/src/lib.rs index acfdb6717a..67814f049d 100644 --- a/modules/axtask/src/lib.rs +++ b/modules/axtask/src/lib.rs @@ -45,6 +45,7 @@ cfg_if::cfg_if! { mod task_ext; mod api; mod wait_queue; + mod wait_queues; #[cfg(feature = "irq")] mod timers; diff --git a/modules/axtask/src/wait_queues.rs b/modules/axtask/src/wait_queues.rs new file mode 100644 index 0000000000..c6dd44460b --- /dev/null +++ b/modules/axtask/src/wait_queues.rs @@ -0,0 +1,65 @@ +use core::{sync::atomic::AtomicU32, time::Duration}; + +use alloc::collections::BTreeMap; + +use kspin::SpinNoIrq; + +use crate::WaitQueue; + +pub type Futex = AtomicU32; + +static FUTEX_WAIT_QUEUES: SpinNoIrq> = SpinNoIrq::new(BTreeMap::new()); + +pub fn futex_wake(futex: &Futex) { + let futex_addr = futex as *const _ as usize; + let mut wait_queues = FUTEX_WAIT_QUEUES.lock(); + if let Some(queue) = wait_queues.get_mut(&futex_addr) { + // Wake up one task waiting on this queue. + // `notify_one(true)` means it will potentially yield the CPU + // if the woken task has higher priority. + queue.notify_one(true); + } + // The lock is automatically released when wait_queues goes out of scope +} + +pub fn futex_wake_all(futex: &Futex) { + let futex_addr = futex as *const _ as usize; + let mut wait_queues = FUTEX_WAIT_QUEUES.lock(); + if let Some(queue) = wait_queues.get_mut(&futex_addr) { + // Wake up all tasks waiting on this queue. + queue.notify_all(true); + } + // The lock is automatically released when wait_queues goes out of scope +} + +pub fn futex_wait(futex: &Futex, expected: u32, timeout: Option) -> bool { + let futex_addr = futex as *const _ as usize; + + let current_val = futex.load(core::sync::atomic::Ordering::Relaxed); + if current_val != expected { + return false; + } + + let mut wait_queues = FUTEX_WAIT_QUEUES.lock(); + let queue = wait_queues + .entry(futex_addr) + .or_insert_with(|| WaitQueue::new()); + + let waited = match timeout { + Some(dur) => { + #[cfg(feature = "irq")] + { + !queue.wait_timeout(dur) + } + #[cfg(not(feature = "irq"))] + { + panic!("wait_timeout is not supported in this configuration"); + } + } + None => { + queue.wait(); + true + } + }; + waited +} \ No newline at end of file diff --git a/ulib/axstd/src/sync/condvar.rs b/ulib/axstd/src/sync/condvar.rs new file mode 100644 index 0000000000..b38e4e3f36 --- /dev/null +++ b/ulib/axstd/src/sync/condvar.rs @@ -0,0 +1,69 @@ + +extern crate alloc; + +use arceos_api::task::{AxFutex,ax_futex_wait, ax_futex_wake, ax_futex_wake_all}; +use core::time::Duration; + +use crate::sync::MutexGuard; + +pub struct Condvar { + // The value of this atomic is simply incremented on every notification. + // This is used by `.wait()` to not miss any notifications after + // unlocking the mutex and before waiting for notifications. + futex: AxFutex, +} + +impl Condvar { + #[inline] + pub const fn new() -> Self { + Self { + futex: AxFutex::new(0), + } + } + + pub fn notify_one(&self) { + self.futex + .fetch_add(1, core::sync::atomic::Ordering::Relaxed); + ax_futex_wake(&self.futex); + } + + pub fn notify_all(&self) { + self.futex + .fetch_add(1, core::sync::atomic::Ordering::Relaxed); + ax_futex_wake_all(&self.futex); + } + + pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> { + // wait with no timeout should always return the guard + self.wait_optional_timeout(guard, None).expect("Condvar::wait with no timeout should not return None on timeout") + } + + pub fn wait_timeout<'a, T>( + &self, + guard: MutexGuard<'a, T>, + timeout: Duration, + ) -> Option> { + self.wait_optional_timeout(guard, Some(timeout)) + } + + + fn wait_optional_timeout<'a, T>( + &self, + guard: MutexGuard<'a, T>, + timeout: Option, + ) -> Option> { + let expected = self.futex.load(core::sync::atomic::Ordering::Relaxed); + let mutex = guard.mutex(); + + let suc = ax_futex_wait(&self.futex, expected, timeout); + + let new_guard = mutex.lock(); + + if !suc && timeout.is_some() { + None + } else { + Some(new_guard) + } + } +} + diff --git a/ulib/axstd/src/sync/mod.rs b/ulib/axstd/src/sync/mod.rs index 45546e77c7..d06e9c4067 100644 --- a/ulib/axstd/src/sync/mod.rs +++ b/ulib/axstd/src/sync/mod.rs @@ -9,10 +9,15 @@ pub use alloc::sync::{Arc, Weak}; #[cfg(feature = "multitask")] mod mutex; +#[cfg(feature = "multitask")] +mod condvar; #[cfg(feature = "multitask")] #[doc(cfg(feature = "multitask"))] pub use self::mutex::{Mutex, MutexGuard}; +#[cfg(feature = "multitask")] +#[doc(cfg(feature = "multitask"))] +pub use self::condvar::Condvar; #[cfg(not(feature = "multitask"))] #[doc(cfg(not(feature = "multitask")))] diff --git a/ulib/axstd/src/sync/mutex.rs b/ulib/axstd/src/sync/mutex.rs index d3ed49c907..8c77850321 100644 --- a/ulib/axstd/src/sync/mutex.rs +++ b/ulib/axstd/src/sync/mutex.rs @@ -167,6 +167,14 @@ impl fmt::Debug for Mutex { } } +impl<'a, T: ?Sized> MutexGuard<'a, T> { + #[inline(always)] + pub fn mutex(&self) -> &'a Mutex { + let m = self.lock; + &*m + } +} + impl Deref for MutexGuard<'_, T> { type Target = T; #[inline(always)] From 9b4d00dd57563efac0b3be0d1d90781441487fa3 Mon Sep 17 00:00:00 2001 From: lvyuemeng Date: Sun, 4 May 2025 20:38:32 +0800 Subject: [PATCH 02/11] [feat] add axembassy prototype and register in axfeat --- Cargo.lock | 16 +++++ Cargo.toml | 5 +- api/axfeat/Cargo.toml | 33 +++++++-- examples/embassy/src/main.rs | 2 - modules/axembassy/Cargo.toml | 35 +++++++++ modules/axembassy/src/executor.rs | 40 +++++++++++ modules/axembassy/src/lib.rs | 6 ++ modules/axembassy/src/time_driver.rs | 88 +++++++++++++++++++++++ modules/axruntime/Cargo.toml | 3 + modules/axruntime/src/lib.rs | 103 ++++++++++++++++++++++----- ulib/axstd/Cargo.toml | 3 + 11 files changed, 309 insertions(+), 25 deletions(-) create mode 100644 modules/axembassy/Cargo.toml create mode 100644 modules/axembassy/src/executor.rs create mode 100644 modules/axembassy/src/lib.rs create mode 100644 modules/axembassy/src/time_driver.rs diff --git a/Cargo.lock b/Cargo.lock index d9423f4834..b3dd1b1d9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -367,6 +367,20 @@ dependencies = [ "virtio-drivers", ] +[[package]] +name = "axembassy" +version = "0.1.0" +dependencies = [ + "axconfig", + "axhal", + "embassy-executor", + "embassy-futures", + "embassy-time-driver", + "embassy-time-queue-utils", + "kspin", + "percpu", +] + [[package]] name = "axerrno" version = "0.1.0" @@ -383,6 +397,7 @@ dependencies = [ "axalloc", "axdisplay", "axdriver", + "axembassy", "axfs", "axhal", "axlog", @@ -569,6 +584,7 @@ dependencies = [ "axconfig", "axdisplay", "axdriver", + "axembassy", "axfs", "axhal", "axlog", diff --git a/Cargo.toml b/Cargo.toml index 7df14252bc..e80aed959c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "modules/axconfig", "modules/axdisplay", "modules/axdriver", + "modules/axembassy", "modules/axfs", "modules/axhal", "modules/axlog", @@ -28,7 +29,8 @@ members = [ "examples/httpclient", "examples/httpserver", "examples/httpserver", - "examples/shell", "examples/embassy", + "examples/shell", + "examples/embassy", ] [workspace.package] @@ -54,6 +56,7 @@ axalloc = { path = "modules/axalloc" } axconfig = { path = "modules/axconfig" } axdisplay = { path = "modules/axdisplay" } axdriver = { path = "modules/axdriver" } +axembassy = { path = "modules/axembassy" } axfs = { path = "modules/axfs" } axhal = { path = "modules/axhal" } axlog = { path = "modules/axlog" } diff --git a/api/axfeat/Cargo.toml b/api/axfeat/Cargo.toml index c53aef7a25..4dbbced4a2 100644 --- a/api/axfeat/Cargo.toml +++ b/api/axfeat/Cargo.toml @@ -26,27 +26,47 @@ alloc = ["axalloc", "axruntime/alloc"] alloc-tlsf = ["axalloc/tlsf"] alloc-slab = ["axalloc/slab"] alloc-buddy = ["axalloc/buddy"] -page-alloc-64g = ["axalloc/page-alloc-64g"] # up to 64G memory capacity -page-alloc-4g = ["axalloc/page-alloc-4g"] # up to 4G memory capacity +page-alloc-64g = ["axalloc/page-alloc-64g"] # up to 64G memory capacity +page-alloc-4g = ["axalloc/page-alloc-4g"] # up to 4G memory capacity paging = ["alloc", "axhal/paging", "axruntime/paging"] tls = ["alloc", "axhal/tls", "axruntime/tls", "axtask?/tls"] dma = ["alloc", "paging"] # Multi-threading and scheduler -multitask = ["alloc", "axtask/multitask", "axsync/multitask", "axruntime/multitask"] +multitask = [ + "alloc", + "axtask/multitask", + "axsync/multitask", + "axruntime/multitask", +] sched_fifo = ["axtask/sched_fifo"] sched_rr = ["axtask/sched_rr", "irq"] sched_cfs = ["axtask/sched_cfs", "irq"] +# Embassy Timer +embassy-timer = ["axembassy/driver", "axruntime/embassy-timer"] + # File system -fs = ["alloc", "paging", "axdriver/virtio-blk", "dep:axfs", "axruntime/fs"] # TODO: try to remove "paging" +fs = [ + "alloc", + "paging", + "axdriver/virtio-blk", + "dep:axfs", + "axruntime/fs", +] # TODO: try to remove "paging" myfs = ["axfs?/myfs"] # Networking net = ["alloc", "paging", "axdriver/virtio-net", "dep:axnet", "axruntime/net"] # Display -display = ["alloc", "paging", "axdriver/virtio-gpu", "dep:axdisplay", "axruntime/display"] +display = [ + "alloc", + "paging", + "axdriver/virtio-gpu", + "dep:axdisplay", + "axruntime/display", +] # Real Time Clock (RTC) Driver. rtc = ["axhal/rtc", "axruntime/rtc"] @@ -56,7 +76,7 @@ bus-mmio = ["axdriver?/bus-mmio"] bus-pci = ["axdriver?/bus-pci"] driver-ramdisk = ["axdriver?/ramdisk", "axfs?/use-ramdisk"] driver-ixgbe = ["axdriver?/ixgbe"] -driver-fxmac = ["axdriver?/fxmac"] # fxmac ethernet driver for PhytiumPi +driver-fxmac = ["axdriver?/fxmac"] # fxmac ethernet driver for PhytiumPi driver-bcm2835-sdhci = ["axdriver?/bcm2835-sdhci"] # Logging @@ -78,4 +98,5 @@ axnet = { workspace = true, optional = true } axdisplay = { workspace = true, optional = true } axsync = { workspace = true, optional = true } axtask = { workspace = true, optional = true } +axembassy = { workspace = true, optional = true } kspin = { version = "0.1", optional = true } diff --git a/examples/embassy/src/main.rs b/examples/embassy/src/main.rs index cb335c7a86..01ab5e6dec 100644 --- a/examples/embassy/src/main.rs +++ b/examples/embassy/src/main.rs @@ -7,11 +7,9 @@ extern crate axstd as std; use embassy_futures::yield_now; -use embassy_time::{Duration, MockDriver}; use std::boxed::Box; mod executor; -mod timer; fn tick(sec: u64, f: fn()) -> embassy_executor::SpawnToken { let task = Box::leak(Box::new(embassy_executor::raw::TaskStorage::new())); diff --git a/modules/axembassy/Cargo.toml b/modules/axembassy/Cargo.toml new file mode 100644 index 0000000000..84cc65c9b2 --- /dev/null +++ b/modules/axembassy/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "axembassy" +version.workspace = true +edition.workspace = true +authors = ["nostalgia "] +license.workspace = true +homepage.workspace = true + +[features] +driver = [ + "dep:embassy-time-driver", + "dep:embassy-time-queue-utils", + "dep:kspin", + "dep:percpu", + "axhal/irq", +] +executor = ["dep:embassy-executor"] +futures = ["dep:embassy-futures"] + +default = ["driver", "executor", "futures"] + +[dependencies] +axconfig = { workspace = true } +axhal = { workspace = true, features = ["irq"] } + +embassy-time-driver = { version = "0.2.0", optional = true } +embassy-time-queue-utils = { version = "0.1.0", optional = true } +embassy-executor = { version = "0.7.0", features = [ + "nightly", + "executor-thread", +], optional = true } +embassy-futures = { version = "0.1.1", optional = true } + +kspin = { version = "0.1", optional = true } +percpu = { version = "0.2", optional = true } diff --git a/modules/axembassy/src/executor.rs b/modules/axembassy/src/executor.rs new file mode 100644 index 0000000000..13ac340d57 --- /dev/null +++ b/modules/axembassy/src/executor.rs @@ -0,0 +1,40 @@ +use axhal::arch; +use core::marker::PhantomData; +use core::sync::atomic::{AtomicBool, Ordering}; +use embassy_executor::raw; + +static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); + +#[unsafe(export_name = "__pender")] +fn __pender(_context: *mut ()) { + SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); +} + +pub struct Executor { + inner: raw::Executor, + not_send: PhantomData<*mut ()>, +} + +impl Executor { + pub fn new() -> Self { + Self { + inner: raw::Executor::new(core::ptr::null_mut()), + not_send: PhantomData, + } + } + + pub fn run(&'static mut self, init: impl FnOnce(embassy_executor::Spawner)) -> ! { + init(self.inner.spawner()); + + loop { + unsafe { + self.inner.poll(); + if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) { + SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst); + } else { + arch::wait_for_irqs(); + } + }; + } + } +} diff --git a/modules/axembassy/src/lib.rs b/modules/axembassy/src/lib.rs new file mode 100644 index 0000000000..e0fdc89ebe --- /dev/null +++ b/modules/axembassy/src/lib.rs @@ -0,0 +1,6 @@ +#![no_std] +mod executor; +mod time_driver; + +pub use crate::executor::Executor; +pub use crate::time_driver::{AxDriver, nanos_to_ticks, ticks_to_nanos}; diff --git a/modules/axembassy/src/time_driver.rs b/modules/axembassy/src/time_driver.rs new file mode 100644 index 0000000000..25dd4d7027 --- /dev/null +++ b/modules/axembassy/src/time_driver.rs @@ -0,0 +1,88 @@ +use core::cell::RefCell; +use core::task; + +use axhal::irq; +use axhal::time::{self, NANOS_PER_SEC, TIMER_IRQ_NUM}; +use kspin::SpinNoIrq; + +use embassy_time_driver::Driver; +use embassy_time_driver::TICK_HZ; +use embassy_time_queue_utils::Queue; + +pub fn ticks_to_nanos(ticks: u64) -> u64 { + (ticks as u128 * NANOS_PER_SEC as u128 / TICK_HZ as u128) as u64 +} + +pub fn nanos_to_ticks(nanos: u64) -> u64 { + (nanos as u128 * TICK_HZ as u128 / NANOS_PER_SEC as u128) as u64 +} + +pub struct AxDriver { + queue: SpinNoIrq>, + periodic_interval_nanos: SpinNoIrq, +} + +impl AxDriver { + pub const fn new() -> Self { + AxDriver { + queue: SpinNoIrq::new(RefCell::new(Queue::new())), + periodic_interval_nanos: SpinNoIrq::new(0), + } + } + + pub fn runtime_init(&self, periodic_interval_nanos: u64, sched_lock: &SpinNoIrq) { + let mut _queue_guard = self.queue.lock(); + let mut sched_lock = sched_lock.lock(); + let mut interval_lock = self.periodic_interval_nanos.lock(); + + let now_nanos = axhal::time::monotonic_time_nanos(); + + *interval_lock = periodic_interval_nanos; + *sched_lock = now_nanos + periodic_interval_nanos; + } + + /// Set the alarm to wake up at the given time in **nanosecond**. + fn set_alarm_at(&self, at: u64) -> bool { + if at == u64::MAX { + // TODO: Disable the hardware timer interrupt here, as there's nothing to wait for. + // Assuming time::disable_timer_interrupt() exists or similar via axhal/platform. + irq::set_enable(TIMER_IRQ_NUM, false); + return true; + } + + let nanos_now = time::monotonic_time_nanos(); + if at <= nanos_now { + return false; + } + + time::set_oneshot_timer(at); + true + } +} + +impl Driver for AxDriver { + // Returns the current time in **embassy ticks**. + fn now(&self) -> u64 { + let nanos_now = time::monotonic_time_nanos(); + + nanos_to_ticks(nanos_now) + } + + // Driver::schedule_wake() will add to the queue, then call set_alarm_nanos_locked + // for the earliest of the next embassy timer or next scheduler tick. + fn schedule_wake(&self, at: u64, waker: &task::Waker) { + let queue_guard = self.queue.lock(); + let mut queue = queue_guard.borrow_mut(); + + if queue.schedule_wake(at, waker) { + let mut next_at = queue.next_expiration(self.now()); + // repeatly set until it succeeds + while next_at != u64::MAX { + if self.set_alarm_at(next_at) { + break; + } + next_at = queue.next_expiration(self.now()) + } + } + } +} \ No newline at end of file diff --git a/modules/axruntime/Cargo.toml b/modules/axruntime/Cargo.toml index 8209722d1d..bfbbc61185 100644 --- a/modules/axruntime/Cargo.toml +++ b/modules/axruntime/Cargo.toml @@ -24,6 +24,8 @@ net = ["axdriver", "axnet"] display = ["axdriver", "axdisplay"] rtc = [] +embassy-timer = ["axembassy/driver"] + [dependencies] axhal = { workspace = true } axlog = { workspace = true } @@ -35,6 +37,7 @@ axfs = { workspace = true, optional = true } axnet = { workspace = true, optional = true } axdisplay = { workspace = true, optional = true } axtask = { workspace = true, optional = true } +axembassy = { workspace = true, optional = true } crate_interface = "0.1" percpu = { version = "0.2", optional = true } diff --git a/modules/axruntime/src/lib.rs b/modules/axruntime/src/lib.rs index 1261f95116..75d39f245a 100644 --- a/modules/axruntime/src/lib.rs +++ b/modules/axruntime/src/lib.rs @@ -240,25 +240,96 @@ fn init_interrupt() { const PERIODIC_INTERVAL_NANOS: u64 = axhal::time::NANOS_PER_SEC / axconfig::TICKS_PER_SEC as u64; - #[percpu::def_percpu] - static NEXT_DEADLINE: u64 = 0; - - fn update_timer() { - let now_ns = axhal::time::monotonic_time_nanos(); - // Safety: we have disabled preemption in IRQ handler. - let mut deadline = unsafe { NEXT_DEADLINE.read_current_raw() }; - if now_ns >= deadline { - deadline = now_ns + PERIODIC_INTERVAL_NANOS; + #[cfg(not(feature = "embassy-timer"))] + { + #[percpu::def_percpu] + static NEXT_DEADLINE: u64 = 0; + + fn update_timer() { + let now_ns = axhal::time::monotonic_time_nanos(); + // Safety: we have disabled preemption in IRQ handler. + let mut deadline = unsafe { NEXT_DEADLINE.read_current_raw() }; + if now_ns >= deadline { + deadline = now_ns + PERIODIC_INTERVAL_NANOS; + } + unsafe { NEXT_DEADLINE.write_current_raw(deadline + PERIODIC_INTERVAL_NANOS) }; + axhal::time::set_oneshot_timer(deadline); } - unsafe { NEXT_DEADLINE.write_current_raw(deadline + PERIODIC_INTERVAL_NANOS) }; - axhal::time::set_oneshot_timer(deadline); + + axhal::irq::register_handler(TIMER_IRQ_NUM, || { + update_timer(); + #[cfg(feature = "multitask")] + axtask::on_timer_tick(); + }); } - axhal::irq::register_handler(TIMER_IRQ_NUM, || { - update_timer(); - #[cfg(feature = "multitask")] - axtask::on_timer_tick(); - }); + #[cfg(feature = "embassy-timer")] + { + use axembassy::time_driver::{AxDriver, ticks_to_nanos}; + + static AX_DRIVER: AxDriver = AxDriver::new(); + + #[percpu::def_percpu] + static NANOS_NEXT_SCHED: SpinNoIrq = SpinNoIrq::new(0); + AX_DERIVER.runtime_init(PERIODIC_INTERVAL_NANOS, &NANOS_NEXT_SCHED); + + /// Timer interrupt handler merged with embassy + /// + /// Integrate both embassy and task scheduler: + /// - Record schedule time to call `axtask::on_timer_tick()` + /// - Set the next timer alarm by comparing the next embassy timer and the next scheduler tick repeatedly until works. + pub fn embassy_update_timer() { + let queue_guard = AX_DRIVER.queue.lock(); + let _queue = queue_guard.borrow_mut(); + + let ticks_now = AX_DRIVER.now(); + let nanos_now = time::monotonic_time_nanos(); + + let ticks_next_at = queue_guard.borrow_mut().next_expiration(ticks_now); + + let mut sched_lock = unsafe { NANOS_NEXT_SCHED.current_ref_mut_raw().lock() }; + let periodic_lock = AX_DRIVER.periodic_interval_nanos.lock(); + + let mut nanos_next_sched = *sched_lock; + if nanos_now >= nanos_next_sched { + #[cfg(feature = "multitask")] + axtask::on_timer_tick(); + + let periodic = *periodic_lock; + while nanos_next_sched <= nanos_now { + nanos_next_sched += periodic; + } + *sched_lock = nanos_next_sched; + } + + let nanos_next_at = if ticks_next_at == u64::MAX { + u64::MAX + } else { + ticks_to_nanos(ticks_next_at) + }; + + let nanos_earlier = core::cmp::min(nanos_next_sched, nanos_next_at); + let mut nanos_try = nanos_earlier; + while nanos_try != u64::MAX { + if AX_DRIVER.set_alarm_at(nanos_try) { + break; + } + + // Setting failed + let ticks_next_failure = queue_guard.borrow_mut().next_expiration(AX_DRIVER.now()); + let nanos_next_failure = if ticks_next_failure == u64::MAX { + u64::MAX + } else { + ticks_to_nanos(ticks_next_failure) + }; + + let sched_failure_lock = unsafe { NANOS_NEXT_SCHED.current_ref_raw().lock() }; + let nanos_sched_failure = *sched_failure_lock; + nanos_try = core::cmp::min(nanos_next_failure, nanos_sched_failure); + } + } + axhal::irq::register_handler(TIMER_IRQ_NUM, embassy_update_timer); + } // Enable IRQs before starting app axhal::arch::enable_irqs(); diff --git a/ulib/axstd/Cargo.toml b/ulib/axstd/Cargo.toml index 3323281909..aea7fb6d2d 100644 --- a/ulib/axstd/Cargo.toml +++ b/ulib/axstd/Cargo.toml @@ -45,6 +45,9 @@ sched_fifo = ["axfeat/sched_fifo"] sched_rr = ["axfeat/sched_rr"] sched_cfs = ["axfeat/sched_cfs"] +# Embassy Timer +embassy-timer = ["axfeat/embassy-timer"] + # File system fs = ["arceos_api/fs", "axfeat/fs"] myfs = ["arceos_api/myfs", "axfeat/myfs"] From 5d40fbc9adc71dba5a6691a971aee3ec36591cac Mon Sep 17 00:00:00 2001 From: lvyuemeng Date: Sun, 11 May 2025 20:12:51 +0800 Subject: [PATCH 03/11] [feat] add axembassy waker and small init as attempt --- Cargo.lock | 59 ++++++++---- Cargo.toml | 2 +- .../{embassy => embassy-local}/Cargo.toml | 6 +- examples/embassy-local/src/main.rs | 12 +++ .../{embassy => embassy-user}/.axconfig.toml | 0 examples/embassy-user/Cargo.toml | 14 +++ .../{embassy => embassy-user}/src/executor.rs | 0 .../{embassy => embassy-user}/src/main.rs | 18 ++-- examples/helloworld/.axconfig.toml | 81 ++++++++++++++++ examples/httpclient/.axconfig.toml | 81 ++++++++++++++++ examples/httpserver/.axconfig.toml | 81 ++++++++++++++++ modules/axembassy/.axconfig.toml | 81 ++++++++++++++++ modules/axembassy/.vscode/settings.json | 3 + modules/axembassy/Cargo.toml | 10 +- modules/axembassy/src/executor.rs | 10 +- modules/axembassy/src/lib.rs | 29 +++++- modules/axembassy/src/runtime.rs | 73 +++++++++++++++ modules/axembassy/src/time_driver.rs | 86 ++++++++++++++++- modules/axembassy/src/waker/mod.rs | 92 +++++++++++++++++++ modules/axruntime/Cargo.toml | 2 +- modules/axruntime/src/lib.rs | 73 ++------------- modules/axtask/src/api.rs | 4 + modules/axtask/src/lib.rs | 1 + modules/axtask/src/run_queue.rs | 19 ++++ modules/axtask/src/task_registry.rs | 40 ++++++++ 25 files changed, 773 insertions(+), 104 deletions(-) rename examples/{embassy => embassy-local}/Cargo.toml (69%) create mode 100644 examples/embassy-local/src/main.rs rename examples/{embassy => embassy-user}/.axconfig.toml (100%) create mode 100644 examples/embassy-user/Cargo.toml rename examples/{embassy => embassy-user}/src/executor.rs (100%) rename examples/{embassy => embassy-user}/src/main.rs (68%) create mode 100644 examples/helloworld/.axconfig.toml create mode 100644 examples/httpclient/.axconfig.toml create mode 100644 examples/httpserver/.axconfig.toml create mode 100644 modules/axembassy/.axconfig.toml create mode 100644 modules/axembassy/.vscode/settings.json create mode 100644 modules/axembassy/src/runtime.rs create mode 100644 modules/axembassy/src/waker/mod.rs create mode 100644 modules/axtask/src/task_registry.rs diff --git a/Cargo.lock b/Cargo.lock index b3dd1b1d9a..aaf9f8dd29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -373,12 +373,15 @@ version = "0.1.0" dependencies = [ "axconfig", "axhal", + "axtask", "embassy-executor", "embassy-futures", "embassy-time-driver", "embassy-time-queue-utils", "kspin", + "log", "percpu", + "static_cell", ] [[package]] @@ -996,17 +999,6 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d" -[[package]] -name = "embassy" -version = "0.0.0" -dependencies = [ - "axhal", - "axstd", - "embassy-executor", - "embassy-futures", - "embassy-time", -] - [[package]] name = "embassy-executor" version = "0.7.0" @@ -1046,7 +1038,6 @@ dependencies = [ "critical-section", "document-features", "embassy-time-driver", - "embassy-time-queue-utils", "embedded-hal 0.2.7", "embedded-hal 1.0.0", "embedded-hal-async", @@ -1072,6 +1063,16 @@ dependencies = [ "heapless 0.8.0", ] +[[package]] +name = "embassy-user" +version = "0.0.0" +dependencies = [ + "axstd", + "embassy-executor", + "embassy-futures", + "embassy-time", +] + [[package]] name = "embedded-hal" version = "0.2.7" @@ -1604,6 +1605,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "portable-atomic" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -1906,6 +1913,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "static_cell" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89b0684884a883431282db1e4343f34afc2ff6996fe1f4a1664519b66e14c1e" +dependencies = [ + "portable-atomic", +] + [[package]] name = "strsim" version = "0.11.1" @@ -1987,21 +2003,28 @@ checksum = "2b9e2fdb3a1e862c0661768b7ed25390811df1947a8acbfbefe09b47078d93c4" [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ "indexmap", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + [[package]] name = "unicode-ident" version = "1.0.17" @@ -2221,9 +2244,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.3" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index e80aed959c..e671240343 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ members = [ "examples/httpserver", "examples/httpserver", "examples/shell", - "examples/embassy", + "examples/embassy-user", ] [workspace.package] diff --git a/examples/embassy/Cargo.toml b/examples/embassy-local/Cargo.toml similarity index 69% rename from examples/embassy/Cargo.toml rename to examples/embassy-local/Cargo.toml index 05cb52828d..04f45d5b2e 100644 --- a/examples/embassy/Cargo.toml +++ b/examples/embassy-local/Cargo.toml @@ -1,11 +1,11 @@ [package] -name = "embassy" +name = "embassy-user" authors = ["nostalgia "] edition.workspace = true [dependencies] -axhal = { workspace=true, features = ["irq"] } axstd = { workspace = true, features = ["alloc","multitask"], optional = true } + embassy-futures = "0.1.1" embassy-executor = { version = "0.7.0", features = ["nightly","executor-thread"] } -embassy-time = {version = "0.4.0", features = ["mock-driver"]} +embassy-time = {version = "0.4.0", features = ["mock-driver"]} \ No newline at end of file diff --git a/examples/embassy-local/src/main.rs b/examples/embassy-local/src/main.rs new file mode 100644 index 0000000000..221cf5cd45 --- /dev/null +++ b/examples/embassy-local/src/main.rs @@ -0,0 +1,12 @@ +#![feature(impl_trait_in_assoc_type)] +#![cfg_attr(feature = "axstd", no_std)] +#![cfg_attr(feature = "axstd", no_main)] + +#[macro_use] +#[cfg(feature = "axstd")] +extern crate axstd as std; + +#[cfg_attr(feature = "axstd", unsafe(no_mangle))] +fn main() { + +} \ No newline at end of file diff --git a/examples/embassy/.axconfig.toml b/examples/embassy-user/.axconfig.toml similarity index 100% rename from examples/embassy/.axconfig.toml rename to examples/embassy-user/.axconfig.toml diff --git a/examples/embassy-user/Cargo.toml b/examples/embassy-user/Cargo.toml new file mode 100644 index 0000000000..5016d1ccfc --- /dev/null +++ b/examples/embassy-user/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "embassy-user" +authors = ["nostalgia "] +edition.workspace = true + +[dependencies] +axstd = { workspace = true, features = ["alloc", "multitask"], optional = true } + +embassy-futures = "0.1.1" +embassy-executor = { version = "0.7.0", features = [ + "nightly", + "executor-thread", +] } +embassy-time = { version = "0.4.0" } diff --git a/examples/embassy/src/executor.rs b/examples/embassy-user/src/executor.rs similarity index 100% rename from examples/embassy/src/executor.rs rename to examples/embassy-user/src/executor.rs diff --git a/examples/embassy/src/main.rs b/examples/embassy-user/src/main.rs similarity index 68% rename from examples/embassy/src/main.rs rename to examples/embassy-user/src/main.rs index 01ab5e6dec..d35dfb2cc4 100644 --- a/examples/embassy/src/main.rs +++ b/examples/embassy-user/src/main.rs @@ -11,21 +11,21 @@ use std::boxed::Box; mod executor; -fn tick(sec: u64, f: fn()) -> embassy_executor::SpawnToken { +fn tick(_sec: u64, f: fn()) -> embassy_executor::SpawnToken { let task = Box::leak(Box::new(embassy_executor::raw::TaskStorage::new())); task.spawn(move || async move { - for _ in 0..10 { + for _ in 0..4 { f(); - yield_now().await; + embassy_time::Timer::after_secs(_sec).await; } + panic!("tick finished"); }) } -// used as a tick timer to delay fn idle() -> embassy_executor::SpawnToken { let task = Box::leak(Box::new(embassy_executor::raw::TaskStorage::new())); task.spawn(move || async move { - for _ in 0..10 { + loop { yield_now().await; } }) @@ -36,8 +36,8 @@ fn main() { println!("Embassy Test"); let exec = Box::leak(Box::new(executor::Executor::new())); exec.run(|s| { - s.spawn(idle()).unwrap(); - s.spawn(tick(1, || {println!("tick for 1 sec")})).unwrap(); - s.spawn(tick(2, || {println!("tick for 2 sec")})).unwrap(); + // s.spawn(idle()).unwrap(); + s.spawn(tick(1, || println!("tick for 1 sec"))).unwrap(); + s.spawn(tick(2, || println!("tick for 2 sec"))).unwrap(); }); -} +} \ No newline at end of file diff --git a/examples/helloworld/.axconfig.toml b/examples/helloworld/.axconfig.toml new file mode 100644 index 0000000000..42465c83b4 --- /dev/null +++ b/examples/helloworld/.axconfig.toml @@ -0,0 +1,81 @@ +# Architecture identifier. +arch = "riscv64" # str +# Platform identifier. +platform = "riscv64-qemu-virt" # str +# Number of CPUs +smp = 1 # uint +# Stack size of each task. +task-stack-size = 0x40000 # uint +# Number of timer ticks per second (Hz). A timer tick may contain several timer +# interrupts. +ticks-per-sec = 100 # uint + +# +# Device specifications +# +[devices] +# MMIO regions with format (`base_paddr`, `size`). +mmio-regions = [ + [0x0010_1000, 0x1000], + [0x0c00_0000, 0x21_0000], + [0x1000_0000, 0x1000], + [0x1000_1000, 0x8000], + [0x3000_0000, 0x1000_0000], + [0x4000_0000, 0x4000_0000] +] # [(uint, uint)] +# End PCI bus number (`bus-range` property in device tree). +pci-bus-end = 0xff # uint +# Base physical address of the PCIe ECAM space. +pci-ecam-base = 0x3000_0000 # uint +# PCI device memory ranges (`ranges` property in device tree). +pci-ranges = [ + [0x0300_0000, 0x1_0000], + [0x4000_0000, 0x4000_0000], + [0x4_0000_0000, 0x4_0000_0000] +] # [(uint, uint)] +# rtc@101000 { +# interrupts = <0x0b>; +# interrupt-parent = <0x03>; +# reg = <0x00 0x101000 0x00 0x1000>; +# compatible = "google,goldfish-rtc"; +# }; +# RTC (goldfish) Address +rtc-paddr = 0x10_1000 # uint +# Timer interrupt frequency in Hz. +timer-frequency = 10_000_000 # uint +# VirtIO MMIO regions with format (`base_paddr`, `size`). +virtio-mmio-regions = [ + [0x1000_1000, 0x1000], + [0x1000_2000, 0x1000], + [0x1000_3000, 0x1000], + [0x1000_4000, 0x1000], + [0x1000_5000, 0x1000], + [0x1000_6000, 0x1000], + [0x1000_7000, 0x1000], + [0x1000_8000, 0x1000] +] # [(uint, uint)] + +# +# Platform configs +# +[plat] +# Platform family. +family = "riscv64-qemu-virt" # str +# Kernel address space base. +kernel-aspace-base = "0xffff_ffc0_0000_0000" # uint +# Kernel address space size. +kernel-aspace-size = "0x0000_003f_ffff_f000" # uint +# Base physical address of the kernel image. +kernel-base-paddr = 0x8020_0000 # uint +# Base virtual address of the kernel image. +kernel-base-vaddr = "0xffff_ffc0_8020_0000" # uint +# Offset of bus address and phys address. some boards, the bus address is +# different from the physical address. +phys-bus-offset = 0 # uint +# Base address of the whole physical memory. +phys-memory-base = 0x8000_0000 # uint +# Size of the whole physical memory. (128M) +phys-memory-size = 0x800_0000 # uint +# Linear mapping offset, for quick conversions between physical and virtual +# addresses. +phys-virt-offset = "0xffff_ffc0_0000_0000" # uint diff --git a/examples/httpclient/.axconfig.toml b/examples/httpclient/.axconfig.toml new file mode 100644 index 0000000000..42465c83b4 --- /dev/null +++ b/examples/httpclient/.axconfig.toml @@ -0,0 +1,81 @@ +# Architecture identifier. +arch = "riscv64" # str +# Platform identifier. +platform = "riscv64-qemu-virt" # str +# Number of CPUs +smp = 1 # uint +# Stack size of each task. +task-stack-size = 0x40000 # uint +# Number of timer ticks per second (Hz). A timer tick may contain several timer +# interrupts. +ticks-per-sec = 100 # uint + +# +# Device specifications +# +[devices] +# MMIO regions with format (`base_paddr`, `size`). +mmio-regions = [ + [0x0010_1000, 0x1000], + [0x0c00_0000, 0x21_0000], + [0x1000_0000, 0x1000], + [0x1000_1000, 0x8000], + [0x3000_0000, 0x1000_0000], + [0x4000_0000, 0x4000_0000] +] # [(uint, uint)] +# End PCI bus number (`bus-range` property in device tree). +pci-bus-end = 0xff # uint +# Base physical address of the PCIe ECAM space. +pci-ecam-base = 0x3000_0000 # uint +# PCI device memory ranges (`ranges` property in device tree). +pci-ranges = [ + [0x0300_0000, 0x1_0000], + [0x4000_0000, 0x4000_0000], + [0x4_0000_0000, 0x4_0000_0000] +] # [(uint, uint)] +# rtc@101000 { +# interrupts = <0x0b>; +# interrupt-parent = <0x03>; +# reg = <0x00 0x101000 0x00 0x1000>; +# compatible = "google,goldfish-rtc"; +# }; +# RTC (goldfish) Address +rtc-paddr = 0x10_1000 # uint +# Timer interrupt frequency in Hz. +timer-frequency = 10_000_000 # uint +# VirtIO MMIO regions with format (`base_paddr`, `size`). +virtio-mmio-regions = [ + [0x1000_1000, 0x1000], + [0x1000_2000, 0x1000], + [0x1000_3000, 0x1000], + [0x1000_4000, 0x1000], + [0x1000_5000, 0x1000], + [0x1000_6000, 0x1000], + [0x1000_7000, 0x1000], + [0x1000_8000, 0x1000] +] # [(uint, uint)] + +# +# Platform configs +# +[plat] +# Platform family. +family = "riscv64-qemu-virt" # str +# Kernel address space base. +kernel-aspace-base = "0xffff_ffc0_0000_0000" # uint +# Kernel address space size. +kernel-aspace-size = "0x0000_003f_ffff_f000" # uint +# Base physical address of the kernel image. +kernel-base-paddr = 0x8020_0000 # uint +# Base virtual address of the kernel image. +kernel-base-vaddr = "0xffff_ffc0_8020_0000" # uint +# Offset of bus address and phys address. some boards, the bus address is +# different from the physical address. +phys-bus-offset = 0 # uint +# Base address of the whole physical memory. +phys-memory-base = 0x8000_0000 # uint +# Size of the whole physical memory. (128M) +phys-memory-size = 0x800_0000 # uint +# Linear mapping offset, for quick conversions between physical and virtual +# addresses. +phys-virt-offset = "0xffff_ffc0_0000_0000" # uint diff --git a/examples/httpserver/.axconfig.toml b/examples/httpserver/.axconfig.toml new file mode 100644 index 0000000000..42465c83b4 --- /dev/null +++ b/examples/httpserver/.axconfig.toml @@ -0,0 +1,81 @@ +# Architecture identifier. +arch = "riscv64" # str +# Platform identifier. +platform = "riscv64-qemu-virt" # str +# Number of CPUs +smp = 1 # uint +# Stack size of each task. +task-stack-size = 0x40000 # uint +# Number of timer ticks per second (Hz). A timer tick may contain several timer +# interrupts. +ticks-per-sec = 100 # uint + +# +# Device specifications +# +[devices] +# MMIO regions with format (`base_paddr`, `size`). +mmio-regions = [ + [0x0010_1000, 0x1000], + [0x0c00_0000, 0x21_0000], + [0x1000_0000, 0x1000], + [0x1000_1000, 0x8000], + [0x3000_0000, 0x1000_0000], + [0x4000_0000, 0x4000_0000] +] # [(uint, uint)] +# End PCI bus number (`bus-range` property in device tree). +pci-bus-end = 0xff # uint +# Base physical address of the PCIe ECAM space. +pci-ecam-base = 0x3000_0000 # uint +# PCI device memory ranges (`ranges` property in device tree). +pci-ranges = [ + [0x0300_0000, 0x1_0000], + [0x4000_0000, 0x4000_0000], + [0x4_0000_0000, 0x4_0000_0000] +] # [(uint, uint)] +# rtc@101000 { +# interrupts = <0x0b>; +# interrupt-parent = <0x03>; +# reg = <0x00 0x101000 0x00 0x1000>; +# compatible = "google,goldfish-rtc"; +# }; +# RTC (goldfish) Address +rtc-paddr = 0x10_1000 # uint +# Timer interrupt frequency in Hz. +timer-frequency = 10_000_000 # uint +# VirtIO MMIO regions with format (`base_paddr`, `size`). +virtio-mmio-regions = [ + [0x1000_1000, 0x1000], + [0x1000_2000, 0x1000], + [0x1000_3000, 0x1000], + [0x1000_4000, 0x1000], + [0x1000_5000, 0x1000], + [0x1000_6000, 0x1000], + [0x1000_7000, 0x1000], + [0x1000_8000, 0x1000] +] # [(uint, uint)] + +# +# Platform configs +# +[plat] +# Platform family. +family = "riscv64-qemu-virt" # str +# Kernel address space base. +kernel-aspace-base = "0xffff_ffc0_0000_0000" # uint +# Kernel address space size. +kernel-aspace-size = "0x0000_003f_ffff_f000" # uint +# Base physical address of the kernel image. +kernel-base-paddr = 0x8020_0000 # uint +# Base virtual address of the kernel image. +kernel-base-vaddr = "0xffff_ffc0_8020_0000" # uint +# Offset of bus address and phys address. some boards, the bus address is +# different from the physical address. +phys-bus-offset = 0 # uint +# Base address of the whole physical memory. +phys-memory-base = 0x8000_0000 # uint +# Size of the whole physical memory. (128M) +phys-memory-size = 0x800_0000 # uint +# Linear mapping offset, for quick conversions between physical and virtual +# addresses. +phys-virt-offset = "0xffff_ffc0_0000_0000" # uint diff --git a/modules/axembassy/.axconfig.toml b/modules/axembassy/.axconfig.toml new file mode 100644 index 0000000000..42465c83b4 --- /dev/null +++ b/modules/axembassy/.axconfig.toml @@ -0,0 +1,81 @@ +# Architecture identifier. +arch = "riscv64" # str +# Platform identifier. +platform = "riscv64-qemu-virt" # str +# Number of CPUs +smp = 1 # uint +# Stack size of each task. +task-stack-size = 0x40000 # uint +# Number of timer ticks per second (Hz). A timer tick may contain several timer +# interrupts. +ticks-per-sec = 100 # uint + +# +# Device specifications +# +[devices] +# MMIO regions with format (`base_paddr`, `size`). +mmio-regions = [ + [0x0010_1000, 0x1000], + [0x0c00_0000, 0x21_0000], + [0x1000_0000, 0x1000], + [0x1000_1000, 0x8000], + [0x3000_0000, 0x1000_0000], + [0x4000_0000, 0x4000_0000] +] # [(uint, uint)] +# End PCI bus number (`bus-range` property in device tree). +pci-bus-end = 0xff # uint +# Base physical address of the PCIe ECAM space. +pci-ecam-base = 0x3000_0000 # uint +# PCI device memory ranges (`ranges` property in device tree). +pci-ranges = [ + [0x0300_0000, 0x1_0000], + [0x4000_0000, 0x4000_0000], + [0x4_0000_0000, 0x4_0000_0000] +] # [(uint, uint)] +# rtc@101000 { +# interrupts = <0x0b>; +# interrupt-parent = <0x03>; +# reg = <0x00 0x101000 0x00 0x1000>; +# compatible = "google,goldfish-rtc"; +# }; +# RTC (goldfish) Address +rtc-paddr = 0x10_1000 # uint +# Timer interrupt frequency in Hz. +timer-frequency = 10_000_000 # uint +# VirtIO MMIO regions with format (`base_paddr`, `size`). +virtio-mmio-regions = [ + [0x1000_1000, 0x1000], + [0x1000_2000, 0x1000], + [0x1000_3000, 0x1000], + [0x1000_4000, 0x1000], + [0x1000_5000, 0x1000], + [0x1000_6000, 0x1000], + [0x1000_7000, 0x1000], + [0x1000_8000, 0x1000] +] # [(uint, uint)] + +# +# Platform configs +# +[plat] +# Platform family. +family = "riscv64-qemu-virt" # str +# Kernel address space base. +kernel-aspace-base = "0xffff_ffc0_0000_0000" # uint +# Kernel address space size. +kernel-aspace-size = "0x0000_003f_ffff_f000" # uint +# Base physical address of the kernel image. +kernel-base-paddr = 0x8020_0000 # uint +# Base virtual address of the kernel image. +kernel-base-vaddr = "0xffff_ffc0_8020_0000" # uint +# Offset of bus address and phys address. some boards, the bus address is +# different from the physical address. +phys-bus-offset = 0 # uint +# Base address of the whole physical memory. +phys-memory-base = 0x8000_0000 # uint +# Size of the whole physical memory. (128M) +phys-memory-size = 0x800_0000 # uint +# Linear mapping offset, for quick conversions between physical and virtual +# addresses. +phys-virt-offset = "0xffff_ffc0_0000_0000" # uint diff --git a/modules/axembassy/.vscode/settings.json b/modules/axembassy/.vscode/settings.json new file mode 100644 index 0000000000..82b9969af8 --- /dev/null +++ b/modules/axembassy/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.cargo.features": ["executor"] +} \ No newline at end of file diff --git a/modules/axembassy/Cargo.toml b/modules/axembassy/Cargo.toml index 84cc65c9b2..bcad41d517 100644 --- a/modules/axembassy/Cargo.toml +++ b/modules/axembassy/Cargo.toml @@ -16,14 +16,18 @@ driver = [ ] executor = ["dep:embassy-executor"] futures = ["dep:embassy-futures"] +multitask = ["axtask/multitask"] -default = ["driver", "executor", "futures"] +default = ["driver","executor", "futures"] [dependencies] axconfig = { workspace = true } axhal = { workspace = true, features = ["irq"] } +axtask = { workspace = true, features = ["multitask"] } -embassy-time-driver = { version = "0.2.0", optional = true } +embassy-time-driver = { version = "0.2.0", optional = true, features = [ + "tick-hz-100", +] } embassy-time-queue-utils = { version = "0.1.0", optional = true } embassy-executor = { version = "0.7.0", features = [ "nightly", @@ -31,5 +35,7 @@ embassy-executor = { version = "0.7.0", features = [ ], optional = true } embassy-futures = { version = "0.1.1", optional = true } +log = "=0.4.21" kspin = { version = "0.1", optional = true } percpu = { version = "0.2", optional = true } +static_cell = "2.1.0" diff --git a/modules/axembassy/src/executor.rs b/modules/axembassy/src/executor.rs index 13ac340d57..1ee41eb276 100644 --- a/modules/axembassy/src/executor.rs +++ b/modules/axembassy/src/executor.rs @@ -1,7 +1,7 @@ use axhal::arch; use core::marker::PhantomData; use core::sync::atomic::{AtomicBool, Ordering}; -use embassy_executor::raw; +use embassy_executor::{Spawner, raw}; static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); @@ -10,6 +10,10 @@ fn __pender(_context: *mut ()) { SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); } +pub fn signal_executor() { + __pender(core::ptr::null_mut()); +} + pub struct Executor { inner: raw::Executor, not_send: PhantomData<*mut ()>, @@ -37,4 +41,8 @@ impl Executor { }; } } + + pub fn spawner(&'static mut self) -> Spawner { + self.inner.spawner() + } } diff --git a/modules/axembassy/src/lib.rs b/modules/axembassy/src/lib.rs index e0fdc89ebe..9b111d2550 100644 --- a/modules/axembassy/src/lib.rs +++ b/modules/axembassy/src/lib.rs @@ -1,6 +1,31 @@ -#![no_std] +#![feature(impl_trait_in_assoc_type)] +#![cfg_attr(not(test), no_std)] +#![feature(doc_cfg)] + +extern crate alloc; +#[cfg(feature = "executor")] +extern crate embassy_executor; +#[cfg(feature = "futures")] +extern crate embassy_futures; +extern crate log; + +#[cfg(feature = "executor")] mod executor; +#[cfg(feature = "executor")] +mod runtime; +#[cfg(feature = "driver")] mod time_driver; +mod waker; +#[cfg(feature = "executor")] pub use crate::executor::Executor; -pub use crate::time_driver::{AxDriver, nanos_to_ticks, ticks_to_nanos}; +#[cfg(feature = "executor")] +pub use crate::runtime::init; +#[cfg(feature = "driver")] +pub use crate::time_driver::{AxDriverAPI, embassy_update_timer}; +#[cfg(feature = "executor")] +#[doc(no_inline)] +pub use embassy_executor::*; +#[cfg(feature = "futures")] +#[doc(no_inline)] +pub use embassy_futures::*; diff --git a/modules/axembassy/src/runtime.rs b/modules/axembassy/src/runtime.rs new file mode 100644 index 0000000000..8d8b66ce33 --- /dev/null +++ b/modules/axembassy/src/runtime.rs @@ -0,0 +1,73 @@ +use core::{sync::atomic::AtomicU64, task::Waker}; + +use alloc::collections::BTreeMap; +use embassy_executor::Spawner; +use embassy_futures::yield_now; +use kspin::SpinNoIrq; +use log::info; +use static_cell::StaticCell; + +use crate::executor::{self, signal_executor}; + +static EXECUTOR: StaticCell = StaticCell::new(); + +pub fn runtime(initial: F) -> ! +where + F: FnOnce(Spawner) + Send + 'static, +{ + let exec = EXECUTOR.init(executor::Executor::new()); + exec.run(initial) +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct EventId(u64); + +static EVENT_ID: AtomicU64 = AtomicU64::new(0); + +impl EventId { + pub fn new() -> Self { + EventId(EVENT_ID.fetch_add(1, core::sync::atomic::Ordering::Relaxed)) + } +} + +static PENDING_WAKERS: SpinNoIrq> = SpinNoIrq::new(BTreeMap::new()); + +fn register_waker(id: EventId, waker: Waker) { + PENDING_WAKERS.lock().insert(id, waker); +} + +fn unregister_waker(id: EventId) { + PENDING_WAKERS.lock().remove(&id); +} + +pub fn signal_event(id: EventId) { + let mut pending_wakers = PENDING_WAKERS.lock(); + if let Some(waker) = pending_wakers.remove(&id) { + waker.wake_by_ref(); + signal_executor(); + } +} + +#[embassy_executor::task] +async fn tick(_sec: u64) { + for _ in 0..4 { + info!("tick for {} sec", _sec); + yield_now().await; + } +} + +#[embassy_executor::task] +async fn tick_2(_sec: u64) { + for _ in 0..4 { + info!("tick for {} sec", _sec); + yield_now().await; + } +} + +pub fn init() { + let exec = EXECUTOR.init(executor::Executor::new()); + exec.run(|s| { + s.spawn(tick(1)).unwrap(); + s.spawn(tick_2(2)).unwrap(); + }) +} diff --git a/modules/axembassy/src/time_driver.rs b/modules/axembassy/src/time_driver.rs index 25dd4d7027..2e21802723 100644 --- a/modules/axembassy/src/time_driver.rs +++ b/modules/axembassy/src/time_driver.rs @@ -5,23 +5,35 @@ use axhal::irq; use axhal::time::{self, NANOS_PER_SEC, TIMER_IRQ_NUM}; use kspin::SpinNoIrq; -use embassy_time_driver::Driver; use embassy_time_driver::TICK_HZ; +use embassy_time_driver::{Driver, time_driver_impl}; use embassy_time_queue_utils::Queue; -pub fn ticks_to_nanos(ticks: u64) -> u64 { +use crate::executor::signal_executor; + +pub struct AxDriverAPI; + +impl AxDriverAPI { + pub fn runtime_init(periodic_interval_nanos: u64) { + AX_DRIVER.runtime_init(periodic_interval_nanos, unsafe { NANOS_NEXT_SCHED.current_ref_raw() }); + } +} + +fn ticks_to_nanos(ticks: u64) -> u64 { (ticks as u128 * NANOS_PER_SEC as u128 / TICK_HZ as u128) as u64 } -pub fn nanos_to_ticks(nanos: u64) -> u64 { +fn nanos_to_ticks(nanos: u64) -> u64 { (nanos as u128 * TICK_HZ as u128 / NANOS_PER_SEC as u128) as u64 } -pub struct AxDriver { +struct AxDriver { queue: SpinNoIrq>, periodic_interval_nanos: SpinNoIrq, } +time_driver_impl!(static AX_DRIVER: AxDriver = AxDriver::new()); + impl AxDriver { pub const fn new() -> Self { AxDriver { @@ -85,4 +97,70 @@ impl Driver for AxDriver { } } } +} + +#[percpu::def_percpu] +static NANOS_NEXT_SCHED: SpinNoIrq = SpinNoIrq::new(0); + +/// Timer interrupt handler merged with embassy +/// +/// Integrate both embassy and task scheduler: +/// - Record schedule time to call `axtask::on_timer_tick()` +/// - Set the next timer alarm by comparing the next embassy timer and the next scheduler tick repeatedly until works. +pub fn embassy_update_timer() { + let queue_guard = AX_DRIVER.queue.lock(); + let mut queue = queue_guard.borrow_mut(); + + let ticks_now = AX_DRIVER.now(); + let nanos_now = time::monotonic_time_nanos(); + + let ticks_next_at = queue.next_expiration(ticks_now); + + let mut sched_lock = unsafe { NANOS_NEXT_SCHED.current_ref_mut_raw().lock() }; + let periodic_lock = AX_DRIVER.periodic_interval_nanos.lock(); + + let mut nanos_next_sched = *sched_lock; + let schedule_tick = if nanos_now >= nanos_next_sched { + #[cfg(feature = "multitask")] + axtask::on_timer_tick(); + + let periodic = *periodic_lock; + while nanos_next_sched <= nanos_now { + nanos_next_sched += periodic; + } + *sched_lock = nanos_next_sched; + true + } else { + false + }; + + let (timer_tick, nanos_next_at) = if ticks_next_at == u64::MAX { + (false, u64::MAX) + } else { + (true, ticks_to_nanos(ticks_next_at)) + }; + + let nanos_earlier = core::cmp::min(nanos_next_sched, nanos_next_at); + let mut nanos_try = nanos_earlier; + while nanos_try != u64::MAX { + if AX_DRIVER.set_alarm_at(nanos_try) { + break; + } + + // Setting failed + let ticks_next_failure = queue_guard.borrow_mut().next_expiration(AX_DRIVER.now()); + let nanos_next_failure = if ticks_next_failure == u64::MAX { + u64::MAX + } else { + ticks_to_nanos(ticks_next_failure) + }; + + let sched_failure_lock = unsafe { NANOS_NEXT_SCHED.current_ref_raw().lock() }; + let nanos_sched_failure = *sched_failure_lock; + nanos_try = core::cmp::min(nanos_next_failure, nanos_sched_failure); + }; + + if timer_tick || schedule_tick { + signal_executor(); + } } \ No newline at end of file diff --git a/modules/axembassy/src/waker/mod.rs b/modules/axembassy/src/waker/mod.rs new file mode 100644 index 0000000000..328d30fb65 --- /dev/null +++ b/modules/axembassy/src/waker/mod.rs @@ -0,0 +1,92 @@ +use core::{pin::Pin, task::{Context, Poll, RawWaker, RawWakerVTable, Waker}}; +use alloc::sync::Arc; + +// use core::task::RawWaker; + +use axtask::{current, park_current_task, unpark_task, AxTaskRef}; +// +use crate::executor::__pender; + +static AX_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new( + clone, + wake, + wake_by_ref, + drop, +); + +// unsafe fn clone(_data:*const ()) -> RawWaker { +// unsafe { Arc::increment_strong_count(_data as *const AxTaskRef) }; +// RawWaker::new(_data, &AX_WAKER_VTABLE) +// } + +// unsafe fn wake(_data:*const ()) { +// let task_ref = unsafe { Arc::from_raw(_data as *const AxTaskRef) }; +// let id = task_ref.id().as_u64(); + +// unpark_task(id); +// } + +// unsafe fn wake_by_ref(_data:*const ()) { +// let task_ref = unsafe { (_data as *const AxTaskRef).as_ref().unwrap() }; +// let id = task_ref.id().as_u64(); + +// unpark_task(id); +// } + +// unsafe fn drop(_data:*const ()) { +// unsafe { Arc::decrement_strong_count(_data as *const AxTaskRef) }; +// } +// +unsafe fn clone(_data:*const ()) -> RawWaker { + // trivial clone + RawWaker::new(_data, &AX_WAKER_VTABLE) +} + +unsafe fn wake(_data: *const ()) { + // Call Executor pender function + __pender(core::ptr::null_mut()); +} + +unsafe fn wake_by_ref(_data: *const ()) { + // Call Executor pender function + __pender(core::ptr::null_mut()); +} + +unsafe fn drop(_data: *const ()) { + // No resource to drop +} + +fn axtask_waker(task:&AxTaskRef) -> Waker { + let data = Arc::into_raw(task.clone()) as *const (); + let raw_waker = RawWaker::new(data, &AX_WAKER_VTABLE); + unsafe { Waker::from_raw(raw_waker) } +} + +fn executor_waker() -> Waker { + // No resource management + let data = core::ptr::null() as *const (); + let raw_waker = RawWaker::new(data, &AX_WAKER_VTABLE); + unsafe { Waker::from_raw(raw_waker) } +} + +/// Minimal Design +pub fn async_task_run(future:impl Future) { + let curr_task = current().as_task_ref().clone(); + let waker = axtask_waker(&curr_task); + let mut cx = Context::from_waker(&waker); + let mut pinned = core::pin::pin!(future); + + loop { + match pinned.as_mut().poll(&mut cx) { + Poll::Ready(()) => { + break; + } + Poll::Pending => { + // Yield the current task to allow other tasks to run + park_current_task(); + // Switch to the current task again + // Repeat the loop to poll + } + } + } +} \ No newline at end of file diff --git a/modules/axruntime/Cargo.toml b/modules/axruntime/Cargo.toml index bfbbc61185..8b90c2ca38 100644 --- a/modules/axruntime/Cargo.toml +++ b/modules/axruntime/Cargo.toml @@ -37,7 +37,7 @@ axfs = { workspace = true, optional = true } axnet = { workspace = true, optional = true } axdisplay = { workspace = true, optional = true } axtask = { workspace = true, optional = true } -axembassy = { workspace = true, optional = true } +axembassy = { workspace = true, optional = true, features = ["default","multitask"] } crate_interface = "0.1" percpu = { version = "0.2", optional = true } diff --git a/modules/axruntime/src/lib.rs b/modules/axruntime/src/lib.rs index 75d39f245a..79704eb304 100644 --- a/modules/axruntime/src/lib.rs +++ b/modules/axruntime/src/lib.rs @@ -192,6 +192,12 @@ pub extern "C" fn rust_main(cpu_id: usize, dtb: usize) -> ! { core::hint::spin_loop(); } + // #[cfg(feature = "embassy-timer")] + // { + // use axembassy::init; + // init(); + // } + unsafe { main() }; #[cfg(feature = "multitask")] @@ -265,70 +271,11 @@ fn init_interrupt() { #[cfg(feature = "embassy-timer")] { - use axembassy::time_driver::{AxDriver, ticks_to_nanos}; - - static AX_DRIVER: AxDriver = AxDriver::new(); - - #[percpu::def_percpu] - static NANOS_NEXT_SCHED: SpinNoIrq = SpinNoIrq::new(0); - AX_DERIVER.runtime_init(PERIODIC_INTERVAL_NANOS, &NANOS_NEXT_SCHED); - - /// Timer interrupt handler merged with embassy - /// - /// Integrate both embassy and task scheduler: - /// - Record schedule time to call `axtask::on_timer_tick()` - /// - Set the next timer alarm by comparing the next embassy timer and the next scheduler tick repeatedly until works. - pub fn embassy_update_timer() { - let queue_guard = AX_DRIVER.queue.lock(); - let _queue = queue_guard.borrow_mut(); - - let ticks_now = AX_DRIVER.now(); - let nanos_now = time::monotonic_time_nanos(); - - let ticks_next_at = queue_guard.borrow_mut().next_expiration(ticks_now); - - let mut sched_lock = unsafe { NANOS_NEXT_SCHED.current_ref_mut_raw().lock() }; - let periodic_lock = AX_DRIVER.periodic_interval_nanos.lock(); - - let mut nanos_next_sched = *sched_lock; - if nanos_now >= nanos_next_sched { - #[cfg(feature = "multitask")] - axtask::on_timer_tick(); - - let periodic = *periodic_lock; - while nanos_next_sched <= nanos_now { - nanos_next_sched += periodic; - } - *sched_lock = nanos_next_sched; - } - - let nanos_next_at = if ticks_next_at == u64::MAX { - u64::MAX - } else { - ticks_to_nanos(ticks_next_at) - }; - - let nanos_earlier = core::cmp::min(nanos_next_sched, nanos_next_at); - let mut nanos_try = nanos_earlier; - while nanos_try != u64::MAX { - if AX_DRIVER.set_alarm_at(nanos_try) { - break; - } - - // Setting failed - let ticks_next_failure = queue_guard.borrow_mut().next_expiration(AX_DRIVER.now()); - let nanos_next_failure = if ticks_next_failure == u64::MAX { - u64::MAX - } else { - ticks_to_nanos(ticks_next_failure) - }; - - let sched_failure_lock = unsafe { NANOS_NEXT_SCHED.current_ref_raw().lock() }; - let nanos_sched_failure = *sched_failure_lock; - nanos_try = core::cmp::min(nanos_next_failure, nanos_sched_failure); - } - } + use axembassy::{AxDriverAPI,embassy_update_timer,init}; + + AxDriverAPI::runtime_init(PERIODIC_INTERVAL_NANOS); axhal::irq::register_handler(TIMER_IRQ_NUM, embassy_update_timer); + info!("Embassy timer driver initialized."); } // Enable IRQs before starting app diff --git a/modules/axtask/src/api.rs b/modules/axtask/src/api.rs index 77380dcbdd..059c8e33d6 100644 --- a/modules/axtask/src/api.rs +++ b/modules/axtask/src/api.rs @@ -10,10 +10,13 @@ pub(crate) use crate::run_queue::{current_run_queue, select_run_queue}; pub use crate::task::{CurrentTask, TaskId, TaskInner}; #[doc(cfg(feature = "multitask"))] pub use crate::task_ext::{TaskExtMut, TaskExtRef}; +use crate::task_registry::{register_task, unregister_task}; #[doc(cfg(feature = "multitask"))] pub use crate::wait_queue::WaitQueue; #[doc(cfg(feature = "multitask"))] pub use crate::wait_queues::{Futex,futex_wait,futex_wake,futex_wake_all}; +#[doc(cfg(feature = "multitask"))] +pub use crate::task_registry::{find_task_by_id, unpark_task, park_current_task}; /// The reference type of a task. pub type AxTaskRef = Arc; @@ -105,6 +108,7 @@ pub fn on_timer_tick() { pub fn spawn_task(task: TaskInner) -> AxTaskRef { let task_ref = task.into_arc(); select_run_queue::(&task_ref).add_task(task_ref.clone()); + register_task(task_ref.clone()); task_ref } diff --git a/modules/axtask/src/lib.rs b/modules/axtask/src/lib.rs index 67814f049d..6222cac77b 100644 --- a/modules/axtask/src/lib.rs +++ b/modules/axtask/src/lib.rs @@ -43,6 +43,7 @@ cfg_if::cfg_if! { mod run_queue; mod task; mod task_ext; + mod task_registry; mod api; mod wait_queue; mod wait_queues; diff --git a/modules/axtask/src/run_queue.rs b/modules/axtask/src/run_queue.rs index 2e68bc1559..38df1d1945 100644 --- a/modules/axtask/src/run_queue.rs +++ b/modules/axtask/src/run_queue.rs @@ -13,6 +13,7 @@ use scheduler::BaseScheduler; use axhal::cpu::this_cpu_id; use crate::task::{CurrentTask, TaskState}; +use crate::task_registry::unregister_task; use crate::wait_queue::WaitQueueGuard; use crate::{AxCpuMask, AxTaskRef, Scheduler, TaskInner, WaitQueue}; @@ -357,6 +358,11 @@ impl CurrentRunQueueRef<'_, G> { debug!("task exit: {}, exit_code={}", curr.id_name(), exit_code); assert!(curr.is_running(), "task is not running: {:?}", curr.state()); assert!(!curr.is_idle()); + + let task_id = curr.id().as_u64(); + unregister_task(task_id); + debug!("task {} unregistered", task_id); + if curr.is_init() { // Safety: it is called from `current_run_queue::().exit_current(exit_code)`, // which disabled IRQs and preemption. @@ -418,6 +424,19 @@ impl CurrentRunQueueRef<'_, G> { debug!("task block: {}", curr.id_name()); self.inner.resched(); } + + pub fn park_current_task(&mut self) { + let curr = &self.current_task; + assert!(curr.is_running()); + assert!(!curr.is_idle()); + + // Ensure preemption is disabled + #[cfg(feature = "preempt")] + assert!(curr.can_preempt(1)); + + curr.set_state(TaskState::Blocked); + self.inner.resched(); + } #[cfg(feature = "irq")] pub fn sleep_until(&mut self, deadline: axhal::time::TimeValue) { diff --git a/modules/axtask/src/task_registry.rs b/modules/axtask/src/task_registry.rs new file mode 100644 index 0000000000..2e8a7f808e --- /dev/null +++ b/modules/axtask/src/task_registry.rs @@ -0,0 +1,40 @@ +use alloc::collections::BTreeMap; + +use kernel_guard::{BaseGuard, NoPreemptIrqSave}; +use kspin::SpinNoIrq; + +use crate::{current, current_run_queue, run_queue, select_run_queue, AxTaskRef}; + +static TASK_REGISTRY: SpinNoIrq> = SpinNoIrq::new(BTreeMap::new()); + +pub fn register_task(task: AxTaskRef) { + let mut tasks = TASK_REGISTRY.lock(); + let id = task.id().as_u64(); + tasks.insert(id, task); + debug!("Task {} registered", id); +} + +pub fn unregister_task(id:u64) { + let mut tasks = TASK_REGISTRY.lock(); + tasks.remove(&id); + debug!("Task {} registered", id); +} + +pub fn find_task_by_id(id: u64) -> Option { + let tasks = TASK_REGISTRY.lock(); + tasks.get(&id).cloned() +} + +pub fn unpark_task(id:u64) { + if let Some(task) = find_task_by_id(id) { + select_run_queue::(&task).unblock_task(task, true); + } else { + debug!("Task {} not found", id); + } +} + +pub fn park_current_task() { + let mut cur_rq = current_run_queue::(); + cur_rq.park_current_task(); +} + From 0a42a92a37abc7624b2ba45565afdee0f393b2a0 Mon Sep 17 00:00:00 2001 From: lvyuemeng Date: Thu, 15 May 2025 22:49:19 +0800 Subject: [PATCH 04/11] [feat] add embassy executor park and local test --- Cargo.lock | 11 +++ Cargo.toml | 1 + api/arceos_api/Cargo.toml | 1 + api/arceos_api/src/lib.rs | 1 + examples/embassy-local/.axconfig.toml | 81 ++++++++++++++++ examples/embassy-local/Cargo.toml | 11 ++- examples/embassy-local/src/main.rs | 51 +++++++++- examples/embassy-user/src/main.rs | 10 +- modules/axembassy/Cargo.toml | 4 +- modules/axembassy/src/executor.rs | 34 +++++-- modules/axembassy/src/runtime.rs | 33 +------ modules/axembassy/src/time_driver.rs | 9 +- modules/axembassy/src/waker/mod.rs | 135 ++++++++++++++++---------- modules/axruntime/src/lib.rs | 2 +- modules/axtask/src/run_queue.rs | 35 ++++++- modules/axtask/src/task.rs | 2 + modules/axtask/src/task_registry.rs | 43 ++++---- ulib/axstd/src/lib.rs | 2 + 18 files changed, 341 insertions(+), 125 deletions(-) create mode 100644 examples/embassy-local/.axconfig.toml diff --git a/Cargo.lock b/Cargo.lock index aaf9f8dd29..a44668e3e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -146,6 +146,7 @@ dependencies = [ "axdisplay", "axdma", "axdriver", + "axembassy", "axerrno", "axfeat", "axfs", @@ -1028,6 +1029,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067" +[[package]] +name = "embassy-local" +version = "0.0.0" +dependencies = [ + "axstd", + "embassy-executor", + "embassy-futures", + "embassy-time", +] + [[package]] name = "embassy-time" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index e671240343..62887459f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ members = [ "examples/httpserver", "examples/shell", "examples/embassy-user", + "examples/embassy-local", ] [workspace.package] diff --git a/api/arceos_api/Cargo.toml b/api/arceos_api/Cargo.toml index 9f679d830f..36cd0bced3 100644 --- a/api/arceos_api/Cargo.toml +++ b/api/arceos_api/Cargo.toml @@ -43,3 +43,4 @@ axdriver = { workspace = true, optional = true } axfs = { workspace = true, optional = true } axnet = { workspace = true, optional = true } axdisplay = { workspace = true, optional = true } +axembassy = { workspace = true} diff --git a/api/arceos_api/src/lib.rs b/api/arceos_api/src/lib.rs index 1232b393c5..0f4f9422c0 100644 --- a/api/arceos_api/src/lib.rs +++ b/api/arceos_api/src/lib.rs @@ -396,6 +396,7 @@ pub mod modules { pub use axlog; pub use axruntime; pub use axsync; + pub use axembassy; #[cfg(feature = "alloc")] pub use axalloc; diff --git a/examples/embassy-local/.axconfig.toml b/examples/embassy-local/.axconfig.toml new file mode 100644 index 0000000000..42465c83b4 --- /dev/null +++ b/examples/embassy-local/.axconfig.toml @@ -0,0 +1,81 @@ +# Architecture identifier. +arch = "riscv64" # str +# Platform identifier. +platform = "riscv64-qemu-virt" # str +# Number of CPUs +smp = 1 # uint +# Stack size of each task. +task-stack-size = 0x40000 # uint +# Number of timer ticks per second (Hz). A timer tick may contain several timer +# interrupts. +ticks-per-sec = 100 # uint + +# +# Device specifications +# +[devices] +# MMIO regions with format (`base_paddr`, `size`). +mmio-regions = [ + [0x0010_1000, 0x1000], + [0x0c00_0000, 0x21_0000], + [0x1000_0000, 0x1000], + [0x1000_1000, 0x8000], + [0x3000_0000, 0x1000_0000], + [0x4000_0000, 0x4000_0000] +] # [(uint, uint)] +# End PCI bus number (`bus-range` property in device tree). +pci-bus-end = 0xff # uint +# Base physical address of the PCIe ECAM space. +pci-ecam-base = 0x3000_0000 # uint +# PCI device memory ranges (`ranges` property in device tree). +pci-ranges = [ + [0x0300_0000, 0x1_0000], + [0x4000_0000, 0x4000_0000], + [0x4_0000_0000, 0x4_0000_0000] +] # [(uint, uint)] +# rtc@101000 { +# interrupts = <0x0b>; +# interrupt-parent = <0x03>; +# reg = <0x00 0x101000 0x00 0x1000>; +# compatible = "google,goldfish-rtc"; +# }; +# RTC (goldfish) Address +rtc-paddr = 0x10_1000 # uint +# Timer interrupt frequency in Hz. +timer-frequency = 10_000_000 # uint +# VirtIO MMIO regions with format (`base_paddr`, `size`). +virtio-mmio-regions = [ + [0x1000_1000, 0x1000], + [0x1000_2000, 0x1000], + [0x1000_3000, 0x1000], + [0x1000_4000, 0x1000], + [0x1000_5000, 0x1000], + [0x1000_6000, 0x1000], + [0x1000_7000, 0x1000], + [0x1000_8000, 0x1000] +] # [(uint, uint)] + +# +# Platform configs +# +[plat] +# Platform family. +family = "riscv64-qemu-virt" # str +# Kernel address space base. +kernel-aspace-base = "0xffff_ffc0_0000_0000" # uint +# Kernel address space size. +kernel-aspace-size = "0x0000_003f_ffff_f000" # uint +# Base physical address of the kernel image. +kernel-base-paddr = 0x8020_0000 # uint +# Base virtual address of the kernel image. +kernel-base-vaddr = "0xffff_ffc0_8020_0000" # uint +# Offset of bus address and phys address. some boards, the bus address is +# different from the physical address. +phys-bus-offset = 0 # uint +# Base address of the whole physical memory. +phys-memory-base = 0x8000_0000 # uint +# Size of the whole physical memory. (128M) +phys-memory-size = 0x800_0000 # uint +# Linear mapping offset, for quick conversions between physical and virtual +# addresses. +phys-virt-offset = "0xffff_ffc0_0000_0000" # uint diff --git a/examples/embassy-local/Cargo.toml b/examples/embassy-local/Cargo.toml index 04f45d5b2e..d9cdca1ac8 100644 --- a/examples/embassy-local/Cargo.toml +++ b/examples/embassy-local/Cargo.toml @@ -1,11 +1,14 @@ [package] -name = "embassy-user" +name = "embassy-local" authors = ["nostalgia "] edition.workspace = true [dependencies] -axstd = { workspace = true, features = ["alloc","multitask"], optional = true } +axstd = { workspace = true, features = ["alloc", "multitask"], optional = true } embassy-futures = "0.1.1" -embassy-executor = { version = "0.7.0", features = ["nightly","executor-thread"] } -embassy-time = {version = "0.4.0", features = ["mock-driver"]} \ No newline at end of file +embassy-executor = { version = "0.7.0", features = [ + "nightly", + "executor-thread", +] } +embassy-time = { version = "0.4.0" } diff --git a/examples/embassy-local/src/main.rs b/examples/embassy-local/src/main.rs index 221cf5cd45..992f09e2cc 100644 --- a/examples/embassy-local/src/main.rs +++ b/examples/embassy-local/src/main.rs @@ -6,7 +6,54 @@ #[cfg(feature = "axstd")] extern crate axstd as std; +use embassy_futures::yield_now; +use std::Executor; +use std::time::Duration; +use std::{ + boxed::Box, + thread::{self, sleep}, +}; + +fn tick(_sec: u64, busy_nano: u64) -> embassy_executor::SpawnToken { + let task = Box::leak(Box::new(embassy_executor::raw::TaskStorage::new())); + task.spawn(move || async move { + for i in 0..10 { + println!("embassy tick {}/s :{}", _sec, i); + for _ in 0..busy_nano { + // Simulate some busy work + let _ = (0..1000).fold(0, |acc, x| acc + x); + } + embassy_time::Timer::after_secs(_sec).await; + } + panic!("tick finished"); + }) +} + +fn idle() -> embassy_executor::SpawnToken { + let task = Box::leak(Box::new(embassy_executor::raw::TaskStorage::new())); + task.spawn(move || async move { + loop { + yield_now().await; + } + }) +} + #[cfg_attr(feature = "axstd", unsafe(no_mangle))] fn main() { - -} \ No newline at end of file + println!("Embassy Test"); + for i in 1..4 { + println!("spawned thread {}", i); + thread::spawn(move || { + for j in 0..10 { + println!("spawn tick {}: {}", i, j); + sleep(Duration::from_millis(500 * i as u64)); + } + println!("spawned thread {} finished", i); + }); + } + let exec = Box::leak(Box::new(Executor::new())); + exec.run(|s| { + // s.spawn(idle()).unwrap(); + s.spawn(tick(1, 0)).unwrap(); + }); +} diff --git a/examples/embassy-user/src/main.rs b/examples/embassy-user/src/main.rs index d35dfb2cc4..fc002b44b1 100644 --- a/examples/embassy-user/src/main.rs +++ b/examples/embassy-user/src/main.rs @@ -7,14 +7,14 @@ extern crate axstd as std; use embassy_futures::yield_now; -use std::boxed::Box; +use std::{boxed::Box, thread::{self, Thread}}; mod executor; fn tick(_sec: u64, f: fn()) -> embassy_executor::SpawnToken { let task = Box::leak(Box::new(embassy_executor::raw::TaskStorage::new())); task.spawn(move || async move { - for _ in 0..4 { + for _ in 0..10 { f(); embassy_time::Timer::after_secs(_sec).await; } @@ -34,10 +34,14 @@ fn idle() -> embassy_executor::SpawnToken { #[cfg_attr(feature = "axstd", unsafe(no_mangle))] fn main() { println!("Embassy Test"); + thread::spawn(|| { + for _ in 0..10 { + println!("spawn tick") + } + }); let exec = Box::leak(Box::new(executor::Executor::new())); exec.run(|s| { // s.spawn(idle()).unwrap(); s.spawn(tick(1, || println!("tick for 1 sec"))).unwrap(); - s.spawn(tick(2, || println!("tick for 2 sec"))).unwrap(); }); } \ No newline at end of file diff --git a/modules/axembassy/Cargo.toml b/modules/axembassy/Cargo.toml index bcad41d517..174f84bb60 100644 --- a/modules/axembassy/Cargo.toml +++ b/modules/axembassy/Cargo.toml @@ -18,7 +18,7 @@ executor = ["dep:embassy-executor"] futures = ["dep:embassy-futures"] multitask = ["axtask/multitask"] -default = ["driver","executor", "futures"] +default = ["driver", "futures","executor"] [dependencies] axconfig = { workspace = true } @@ -26,7 +26,7 @@ axhal = { workspace = true, features = ["irq"] } axtask = { workspace = true, features = ["multitask"] } embassy-time-driver = { version = "0.2.0", optional = true, features = [ - "tick-hz-100", + "tick-hz-100" ] } embassy-time-queue-utils = { version = "0.1.0", optional = true } embassy-executor = { version = "0.7.0", features = [ diff --git a/modules/axembassy/src/executor.rs b/modules/axembassy/src/executor.rs index 1ee41eb276..db7e78eda5 100644 --- a/modules/axembassy/src/executor.rs +++ b/modules/axembassy/src/executor.rs @@ -1,13 +1,24 @@ -use axhal::arch; +use axtask::{park_current_task, unpark_task}; +use log::debug; use core::marker::PhantomData; -use core::sync::atomic::{AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use core::u64; use embassy_executor::{Spawner, raw}; +#[percpu::def_percpu] static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); +#[percpu::def_percpu] +static EXECUTOR_TASK_ID:AtomicU64 = AtomicU64::new(u64::MAX); #[unsafe(export_name = "__pender")] fn __pender(_context: *mut ()) { - SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); + SIGNAL_WORK_THREAD_MODE.with_current(|m| { + m.store(true, Ordering::SeqCst); + }); + let task_id = EXECUTOR_TASK_ID.with_current(|m| { + m.load(Ordering::Acquire) + }); + unpark_task(task_id, true); } pub fn signal_executor() { @@ -28,15 +39,26 @@ impl Executor { } pub fn run(&'static mut self, init: impl FnOnce(embassy_executor::Spawner)) -> ! { + let cur_id = axtask::current().id().as_u64(); + EXECUTOR_TASK_ID.with_current(|m| { + m.store(cur_id, Ordering::SeqCst); + }); + debug!("Executor::run: {}", cur_id); init(self.inner.spawner()); loop { unsafe { + park_current_task(); self.inner.poll(); - if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) { - SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst); + let to_poll = SIGNAL_WORK_THREAD_MODE.with_current(|m| { + m.load(Ordering::Acquire) + }); + if to_poll { + SIGNAL_WORK_THREAD_MODE.with_current(|m| { + m.store(false, Ordering::SeqCst); + }); } else { - arch::wait_for_irqs(); + debug!("park current task"); } }; } diff --git a/modules/axembassy/src/runtime.rs b/modules/axembassy/src/runtime.rs index 8d8b66ce33..c293957a25 100644 --- a/modules/axembassy/src/runtime.rs +++ b/modules/axembassy/src/runtime.rs @@ -1,3 +1,5 @@ +use axtask::{unpark_task, TaskId}; + use core::{sync::atomic::AtomicU64, task::Waker}; use alloc::collections::BTreeMap; @@ -7,7 +9,7 @@ use kspin::SpinNoIrq; use log::info; use static_cell::StaticCell; -use crate::executor::{self, signal_executor}; +use crate::executor::{self}; static EXECUTOR: StaticCell = StaticCell::new(); @@ -19,34 +21,6 @@ where exec.run(initial) } -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct EventId(u64); - -static EVENT_ID: AtomicU64 = AtomicU64::new(0); - -impl EventId { - pub fn new() -> Self { - EventId(EVENT_ID.fetch_add(1, core::sync::atomic::Ordering::Relaxed)) - } -} - -static PENDING_WAKERS: SpinNoIrq> = SpinNoIrq::new(BTreeMap::new()); - -fn register_waker(id: EventId, waker: Waker) { - PENDING_WAKERS.lock().insert(id, waker); -} - -fn unregister_waker(id: EventId) { - PENDING_WAKERS.lock().remove(&id); -} - -pub fn signal_event(id: EventId) { - let mut pending_wakers = PENDING_WAKERS.lock(); - if let Some(waker) = pending_wakers.remove(&id) { - waker.wake_by_ref(); - signal_executor(); - } -} #[embassy_executor::task] async fn tick(_sec: u64) { @@ -66,6 +40,7 @@ async fn tick_2(_sec: u64) { pub fn init() { let exec = EXECUTOR.init(executor::Executor::new()); + exec.run(|s| { s.spawn(tick(1)).unwrap(); s.spawn(tick_2(2)).unwrap(); diff --git a/modules/axembassy/src/time_driver.rs b/modules/axembassy/src/time_driver.rs index 2e21802723..506cce5b76 100644 --- a/modules/axembassy/src/time_driver.rs +++ b/modules/axembassy/src/time_driver.rs @@ -9,8 +9,6 @@ use embassy_time_driver::TICK_HZ; use embassy_time_driver::{Driver, time_driver_impl}; use embassy_time_queue_utils::Queue; -use crate::executor::signal_executor; - pub struct AxDriverAPI; impl AxDriverAPI { @@ -115,6 +113,7 @@ pub fn embassy_update_timer() { let nanos_now = time::monotonic_time_nanos(); let ticks_next_at = queue.next_expiration(ticks_now); + drop(queue); let mut sched_lock = unsafe { NANOS_NEXT_SCHED.current_ref_mut_raw().lock() }; let periodic_lock = AX_DRIVER.periodic_interval_nanos.lock(); @@ -161,6 +160,10 @@ pub fn embassy_update_timer() { }; if timer_tick || schedule_tick { - signal_executor(); + #[cfg(feature="executor")] + { + use crate::executor::signal_executor; + signal_executor(); + } } } \ No newline at end of file diff --git a/modules/axembassy/src/waker/mod.rs b/modules/axembassy/src/waker/mod.rs index 328d30fb65..8582a99052 100644 --- a/modules/axembassy/src/waker/mod.rs +++ b/modules/axembassy/src/waker/mod.rs @@ -1,18 +1,16 @@ -use core::{pin::Pin, task::{Context, Poll, RawWaker, RawWakerVTable, Waker}}; +use alloc::collections::BTreeMap; use alloc::sync::Arc; +use core::{ + pin::Pin, + sync::atomic::AtomicU64, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, +}; -// use core::task::RawWaker; +use crate::executor::signal_executor; +use axtask::{AxTaskRef, TaskId, current, park_current_task, unpark_task}; +use kspin::SpinNoIrq; -use axtask::{current, park_current_task, unpark_task, AxTaskRef}; -// -use crate::executor::__pender; - -static AX_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new( - clone, - wake, - wake_by_ref, - drop, -); +static AX_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop); // unsafe fn clone(_data:*const ()) -> RawWaker { // unsafe { Arc::increment_strong_count(_data as *const AxTaskRef) }; @@ -22,71 +20,108 @@ static AX_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new( // unsafe fn wake(_data:*const ()) { // let task_ref = unsafe { Arc::from_raw(_data as *const AxTaskRef) }; // let id = task_ref.id().as_u64(); - + // unpark_task(id); // } // unsafe fn wake_by_ref(_data:*const ()) { // let task_ref = unsafe { (_data as *const AxTaskRef).as_ref().unwrap() }; // let id = task_ref.id().as_u64(); - + // unpark_task(id); // } // unsafe fn drop(_data:*const ()) { // unsafe { Arc::decrement_strong_count(_data as *const AxTaskRef) }; // } -// -unsafe fn clone(_data:*const ()) -> RawWaker { - // trivial clone - RawWaker::new(_data, &AX_WAKER_VTABLE) +// +unsafe fn clone(_data: *const ()) -> RawWaker { + // trivial clone + RawWaker::new(_data, &AX_WAKER_VTABLE) } unsafe fn wake(_data: *const ()) { - // Call Executor pender function - __pender(core::ptr::null_mut()); + // Call Executor pender function + signal_executor(); } unsafe fn wake_by_ref(_data: *const ()) { - // Call Executor pender function - __pender(core::ptr::null_mut()); + // Call Executor pender function + signal_executor(); } unsafe fn drop(_data: *const ()) { - // No resource to drop + // No resource to drop } -fn axtask_waker(task:&AxTaskRef) -> Waker { - let data = Arc::into_raw(task.clone()) as *const (); - let raw_waker = RawWaker::new(data, &AX_WAKER_VTABLE); - unsafe { Waker::from_raw(raw_waker) } +fn axtask_waker(task: &AxTaskRef) -> Waker { + let data = Arc::into_raw(task.clone()) as *const (); + let raw_waker = RawWaker::new(data, &AX_WAKER_VTABLE); + unsafe { Waker::from_raw(raw_waker) } } fn executor_waker() -> Waker { - // No resource management - let data = core::ptr::null() as *const (); - let raw_waker = RawWaker::new(data, &AX_WAKER_VTABLE); - unsafe { Waker::from_raw(raw_waker) } + // No resource management + let data = core::ptr::null() as *const (); + let raw_waker = RawWaker::new(data, &AX_WAKER_VTABLE); + unsafe { Waker::from_raw(raw_waker) } } /// Minimal Design -pub fn async_task_run(future:impl Future) { - let curr_task = current().as_task_ref().clone(); - let waker = axtask_waker(&curr_task); - let mut cx = Context::from_waker(&waker); - let mut pinned = core::pin::pin!(future); - - loop { - match pinned.as_mut().poll(&mut cx) { - Poll::Ready(()) => { - break; - } - Poll::Pending => { - // Yield the current task to allow other tasks to run - park_current_task(); - // Switch to the current task again - // Repeat the loop to poll - } - } +pub fn async_task_run(future: impl Future) { + let curr_task = current().as_task_ref().clone(); + let waker = axtask_waker(&curr_task); + let mut cx = Context::from_waker(&waker); + let mut pinned = core::pin::pin!(future); + + loop { + match pinned.as_mut().poll(&mut cx) { + Poll::Ready(()) => { + break; + } + Poll::Pending => { + // Yield the current task to allow other tasks to run + park_current_task(); + // Switch to the current task again + // Repeat the loop to poll + } + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct EventId(u64); + +static EVENT_ID: AtomicU64 = AtomicU64::new(0); + +impl EventId { + pub fn new() -> Self { + EventId(EVENT_ID.fetch_add(1, core::sync::atomic::Ordering::Relaxed)) + } +} + +impl From for EventId { + fn from(value: u64) -> Self { + EventId(value) } -} \ No newline at end of file +} + +type TaskWaker = (Waker, u64); +static PENDING_WAKERS: SpinNoIrq> = SpinNoIrq::new(BTreeMap::new()); + +fn register_waker(waker: Waker, task_id: u64) { + let id = EventId::new(); + PENDING_WAKERS.lock().insert(id, (waker, task_id)); +} + +fn unregister_waker(id: EventId) { + PENDING_WAKERS.lock().remove(&id); +} + +pub fn signal_event(id: EventId) { + let mut pending_wakers = PENDING_WAKERS.lock(); + if let Some((waker, task_id)) = pending_wakers.remove(&id) { + waker.wake_by_ref(); + unpark_task(task_id, true); + } +} diff --git a/modules/axruntime/src/lib.rs b/modules/axruntime/src/lib.rs index 79704eb304..3e526afbce 100644 --- a/modules/axruntime/src/lib.rs +++ b/modules/axruntime/src/lib.rs @@ -271,7 +271,7 @@ fn init_interrupt() { #[cfg(feature = "embassy-timer")] { - use axembassy::{AxDriverAPI,embassy_update_timer,init}; + use axembassy::{AxDriverAPI,embassy_update_timer}; AxDriverAPI::runtime_init(PERIODIC_INTERVAL_NANOS); axhal::irq::register_handler(TIMER_IRQ_NUM, embassy_update_timer); diff --git a/modules/axtask/src/run_queue.rs b/modules/axtask/src/run_queue.rs index 38df1d1945..501629c211 100644 --- a/modules/axtask/src/run_queue.rs +++ b/modules/axtask/src/run_queue.rs @@ -13,7 +13,7 @@ use scheduler::BaseScheduler; use axhal::cpu::this_cpu_id; use crate::task::{CurrentTask, TaskState}; -use crate::task_registry::unregister_task; +use crate::task_registry::{register_task, unregister_task}; use crate::wait_queue::WaitQueueGuard; use crate::{AxCpuMask, AxTaskRef, Scheduler, TaskInner, WaitQueue}; @@ -260,7 +260,34 @@ impl AxRunQueueRef<'_, G> { let cpu_id = self.inner.cpu_id; debug!("task unblock: {} on run_queue {}", task_id_name, cpu_id); // Note: when the task is unblocked on another CPU's run queue, - // we just ingiore the `resched` flag. + // we just ingore the `resched` flag. + if resched && cpu_id == this_cpu_id() { + #[cfg(feature = "preempt")] + crate::current().set_preempt_pending(true); + } + } + } + + /// Unpark one task by inserting it into the run queue. + /// + /// This function does nothing if the task is not in [`TaskState::Parked`], + /// which means the task is already unparked by other cores. + pub fn unpark_task(&mut self, task: AxTaskRef, resched: bool) { + let task_id_name = task.id_name(); + // Try to change the state of the task from `Parked` to `Ready`, + // if successful, the task will be put into this run queue, + // otherwise, the task is already unblocked by other cores. + // Note: + // target task can not be insert into the run queue until it finishes its scheduling process. + if self + .inner + .put_task_with_state(task, TaskState::Parked, resched) + { + // Since now, the task to be unblocked is in the `Ready` state. + let cpu_id = self.inner.cpu_id; + debug!("task unpark: {} on run_queue {}", task_id_name, cpu_id); + // Note: when the task is unblocked on another CPU's run queue, + // we just ignore the `resched` flag. if resched && cpu_id == this_cpu_id() { #[cfg(feature = "preempt")] crate::current().set_preempt_pending(true); @@ -434,7 +461,7 @@ impl CurrentRunQueueRef<'_, G> { #[cfg(feature = "preempt")] assert!(curr.can_preempt(1)); - curr.set_state(TaskState::Blocked); + curr.set_state(TaskState::Parked); self.inner.resched(); } @@ -655,6 +682,8 @@ pub(crate) fn init() { // Put the subsequent execution into the `main` task. let main_task = TaskInner::new_init("main".into()).into_arc(); main_task.set_state(TaskState::Running); + debug!("main task registered: {}, id {}", main_task.id_name(), main_task.id().as_u64()); + register_task(main_task.clone()); unsafe { CurrentTask::init_current(main_task) } RUN_QUEUE.with_current(|rq| { diff --git a/modules/axtask/src/task.rs b/modules/axtask/src/task.rs index dfb2a844c0..be12b1edb0 100644 --- a/modules/axtask/src/task.rs +++ b/modules/axtask/src/task.rs @@ -33,6 +33,8 @@ pub(crate) enum TaskState { Blocked = 3, /// Task is exited and waiting for being dropped. Exited = 4, + /// Task is an asynchronous task, waiting for even completion to be unparked. + Parked = 5, } /// The inner task structure. diff --git a/modules/axtask/src/task_registry.rs b/modules/axtask/src/task_registry.rs index 2e8a7f808e..48efb2a3d1 100644 --- a/modules/axtask/src/task_registry.rs +++ b/modules/axtask/src/task_registry.rs @@ -1,40 +1,39 @@ use alloc::collections::BTreeMap; -use kernel_guard::{BaseGuard, NoPreemptIrqSave}; +use kernel_guard::NoPreemptIrqSave; use kspin::SpinNoIrq; -use crate::{current, current_run_queue, run_queue, select_run_queue, AxTaskRef}; +use crate::{AxTaskRef, current_run_queue, select_run_queue}; -static TASK_REGISTRY: SpinNoIrq> = SpinNoIrq::new(BTreeMap::new()); +static TASK_REGISTRY: SpinNoIrq> = SpinNoIrq::new(BTreeMap::new()); pub fn register_task(task: AxTaskRef) { - let mut tasks = TASK_REGISTRY.lock(); - let id = task.id().as_u64(); - tasks.insert(id, task); - debug!("Task {} registered", id); + let mut tasks = TASK_REGISTRY.lock(); + let id = task.id().as_u64(); + tasks.insert(id, task); + debug!("Task {} registered", id); } -pub fn unregister_task(id:u64) { - let mut tasks = TASK_REGISTRY.lock(); - tasks.remove(&id); - debug!("Task {} registered", id); +pub fn unregister_task(id: u64) { + let mut tasks = TASK_REGISTRY.lock(); + tasks.remove(&id); + debug!("Task {} registered", id); } pub fn find_task_by_id(id: u64) -> Option { - let tasks = TASK_REGISTRY.lock(); - tasks.get(&id).cloned() + let tasks = TASK_REGISTRY.lock(); + tasks.get(&id).cloned() } -pub fn unpark_task(id:u64) { - if let Some(task) = find_task_by_id(id) { - select_run_queue::(&task).unblock_task(task, true); - } else { - debug!("Task {} not found", id); - } +pub fn unpark_task(id: u64, resched: bool) { + if let Some(task) = find_task_by_id(id) { + select_run_queue::(&task).unpark_task(task, resched); + } else { + debug!("Attempt to unpark non-existent task {}", id); + } } pub fn park_current_task() { - let mut cur_rq = current_run_queue::(); - cur_rq.park_current_task(); + let mut cur_rq = current_run_queue::(); + cur_rq.park_current_task(); } - diff --git a/ulib/axstd/src/lib.rs b/ulib/axstd/src/lib.rs index 5ab051702a..772b33c668 100644 --- a/ulib/axstd/src/lib.rs +++ b/ulib/axstd/src/lib.rs @@ -75,3 +75,5 @@ pub mod time; pub mod fs; #[cfg(feature = "net")] pub mod net; + +pub use arceos_api::modules::axembassy::Executor; From d18e3f1d3b6005255f1452a2bc0bccb31e831850 Mon Sep 17 00:00:00 2001 From: lvyuemeng Date: Sat, 31 May 2025 13:51:33 +0800 Subject: [PATCH 05/11] [feat] add global spawner and block_on in embassy api --- Cargo.lock | 339 +++++++++++++++++++--------- modules/axembassy/Cargo.toml | 1 + modules/axembassy/src/asynch.rs | 61 +++++ modules/axembassy/src/executor.rs | 35 +-- modules/axembassy/src/lib.rs | 33 ++- modules/axembassy/src/runtime.rs | 0 modules/axembassy/src/waker/mod.rs | 5 +- modules/axruntime/Cargo.toml | 2 +- modules/axruntime/src/lib.rs | 5 +- modules/axtask/src/run_queue.rs | 24 +- modules/axtask/src/task.rs | 7 +- modules/axtask/src/task_registry.rs | 16 +- 12 files changed, 382 insertions(+), 146 deletions(-) create mode 100644 modules/axembassy/src/asynch.rs delete mode 100644 modules/axembassy/src/runtime.rs diff --git a/Cargo.lock b/Cargo.lock index 4da5f95849..16ef985532 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -97,12 +97,12 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa" dependencies = [ "anstyle", - "once_cell", + "once_cell_polyfill", "windows-sys", ] @@ -265,7 +265,7 @@ dependencies = [ "axconfig-gen", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -678,7 +678,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -749,9 +749,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.16" +version = "1.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" dependencies = [ "shlex", ] @@ -798,9 +798,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.31" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" +checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" dependencies = [ "clap_builder", "clap_derive", @@ -808,9 +808,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.31" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" +checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" dependencies = [ "anstream", "anstyle", @@ -820,14 +820,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.28" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -877,7 +877,7 @@ checksum = "70272a03a2cef15589bac05d3d15c023752f5f8f2da8be977d983a9d9e6250fb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -903,7 +903,7 @@ checksum = "9a49d5cd78b1c748184d41407b14a58af8403c13328ff2b9f49b0a418c24e3ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -927,7 +927,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -938,14 +938,23 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.98", + "syn 2.0.101", +] + +[[package]] +name = "defmt" +version = "0.3.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad" +dependencies = [ + "defmt 1.0.1", ] [[package]] name = "defmt" -version = "0.3.10" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f6162c53f659f65d00619fe31f14556a6e9f8752ccc4a41bd177ffcf3d6130" +checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" dependencies = [ "bitflags 1.3.2", "defmt-macros", @@ -953,22 +962,22 @@ dependencies = [ [[package]] name = "defmt-macros" -version = "0.4.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d135dd939bad62d7490b0002602d35b358dce5fd9233a709d3c1ef467d4bde6" +checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" dependencies = [ "defmt-parser", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] name = "defmt-parser" -version = "0.4.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3983b127f13995e68c1e29071e5d115cd96f215ccb5e6812e3728cd6f92653b3" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" dependencies = [ "thiserror", ] @@ -993,9 +1002,9 @@ dependencies = [ [[package]] name = "either" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "embassy-executor" @@ -1017,7 +1026,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -1214,9 +1223,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" [[package]] name = "heapless" @@ -1249,14 +1258,15 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -1278,9 +1288,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indexmap" -version = "2.7.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown", @@ -1300,9 +1310,9 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] @@ -1366,18 +1376,18 @@ checksum = "3861aac8febbb038673bf945ee47ac67940ca741b94d1bb3ff6066af2a181338" [[package]] name = "libc" -version = "0.2.170" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets", + "windows-targets 0.53.0", ] [[package]] @@ -1402,16 +1412,9 @@ checksum = "04d55ca5d5a14363da83bf3c33874b8feaa34653e760d5216d7ef9829c88001a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] -[[package]] -<<<<<<< HEAD -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - [[package]] name = "litrs" version = "0.4.1" @@ -1419,12 +1422,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] -======= ->>>>>>> f4428b49970c9b4d871d4dd37cf3e0f1cc200bb1 name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -1521,9 +1522,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.3" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "page_table_entry" @@ -1577,7 +1584,7 @@ checksum = "8a9f4cc54a2e471ff72f1499461ba381ad4eae9cbd60d29c258545b995e406e0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -1600,21 +1607,21 @@ checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy", + "zerocopy 0.8.25", ] [[package]] name = "prettyplease" -version = "0.2.29" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" +checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d" dependencies = [ "proc-macro2", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -1636,23 +1643,23 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -1758,7 +1765,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afa3cdbeccae4359f6839a00e8b77e5736caa200ba216caf38d24e4c16e2b586" dependencies = [ "critical-section", - "embedded-hal", + "embedded-hal 1.0.0", "paste", "riscv-macros", "riscv-pac", @@ -1772,7 +1779,7 @@ checksum = "e8c4aa1ea1af6dcc83a61be12e8189f9b293c3ba5a487778a4cd89fb060fdbbc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -1816,9 +1823,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.19" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "sbi-rt" @@ -1851,9 +1858,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "shlex" @@ -1877,7 +1884,7 @@ dependencies = [ "bitflags 1.3.2", "byteorder", "cfg-if", - "defmt", + "defmt 0.3.100", "heapless 0.7.17", "log", "managed", @@ -1945,9 +1952,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.98" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -1956,22 +1963,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -2018,9 +2025,9 @@ checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" [[package]] name = "unicode-ident" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-width" @@ -2042,7 +2049,7 @@ checksum = "aa40e09453618c7a927c08c5a990497a2954da7c2aaa6c65e0d4f0fc975f6114" dependencies = [ "bitflags 2.9.1", "log", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -2100,7 +2107,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", "wasm-bindgen-shared", ] @@ -2122,7 +2129,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2138,18 +2145,62 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.52.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-targets", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", ] [[package]] name = "windows-link" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] [[package]] name = "windows-sys" @@ -2157,7 +2208,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -2166,14 +2217,30 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] @@ -2182,48 +2249,96 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.7.10" @@ -2307,7 +2422,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive 0.8.25", ] [[package]] @@ -2318,5 +2442,16 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", ] diff --git a/modules/axembassy/Cargo.toml b/modules/axembassy/Cargo.toml index 6d4810ba29..efff7a775f 100644 --- a/modules/axembassy/Cargo.toml +++ b/modules/axembassy/Cargo.toml @@ -22,6 +22,7 @@ default = ["driver", "futures", "executor"] [dependencies] axconfig = { workspace = true } axhal = { workspace = true, features = ["irq"] } +axtask = { workspace = true } embassy-time-driver = { version = "0.2.0", optional = true, features = [ # annotate explicitly diff --git a/modules/axembassy/src/asynch.rs b/modules/axembassy/src/asynch.rs new file mode 100644 index 0000000000..e8404bf456 --- /dev/null +++ b/modules/axembassy/src/asynch.rs @@ -0,0 +1,61 @@ +#![deny(missing_docs)] + +use core::{ + cell::OnceCell, + pin::Pin, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, +}; + +use axtask::{park_current_task, unpark_task}; +use kspin::SpinNoIrq; + +pub use embassy_executor::{SendSpawner, Spawner}; + +pub(crate) static SPAWNER: SpinNoIrq> = SpinNoIrq::new(OnceCell::new()); + +/// Get a spawner for the system executor. +/// +/// # Panics +/// +/// Panics if the system executor is not initialized. +pub fn spawner() -> SendSpawner { + let sp = SPAWNER.lock(); + *sp.get().unwrap() +} + +/// Set the spawner for the system executor. +/// +/// May only be called once. +pub(crate) fn set_spawner(spawner: SendSpawner) { + let sp = SPAWNER.lock(); + let _ = sp.set(spawner); +} + +fn wake(ctx: *const ()) { + let id = ctx as u64; + unpark_task(id, true); +} + +static VTABLE: RawWakerVTable = + RawWakerVTable::new(|ctx| RawWaker::new(ctx, &VTABLE), wake, wake, wake); + +/// Blocks the current task until the given future is ready. +/// +/// # Panics +/// +/// Panics if not called in a thread task +pub fn block_on(mut fut: F) -> F::Output { + let mut fut = unsafe { Pin::new_unchecked(&mut fut) }; + + let id = axtask::current().id().as_u64(); + let raw_waker = RawWaker::new(id as *const (), &VTABLE); + let waker = unsafe { Waker::from_raw(raw_waker) }; + let mut ctx = Context::from_waker(&waker); + + loop { + if let Poll::Ready(res) = fut.as_mut().poll(&mut ctx) { + return res; + } + park_current_task(); + } +} diff --git a/modules/axembassy/src/executor.rs b/modules/axembassy/src/executor.rs index e4b17e3869..471f49ca7b 100644 --- a/modules/axembassy/src/executor.rs +++ b/modules/axembassy/src/executor.rs @@ -7,26 +7,14 @@ use log::{debug, info}; #[percpu::def_percpu] static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); -#[percpu::def_percpu] -static EXECUTOR_TASK_ID: AtomicU64 = AtomicU64::new(u64::MAX); #[unsafe(export_name = "__pender")] fn __pender(_context: *mut ()) { SIGNAL_WORK_THREAD_MODE.with_current(|m| { m.store(true, Ordering::SeqCst); }); -} - -/// Unpark executor if there is a pending signal -pub fn signal_executor() { - if unsafe { - SIGNAL_WORK_THREAD_MODE - .current_ref_raw() - .load(Ordering::Acquire) - } { - let task_id = EXECUTOR_TASK_ID.with_current(|m| m.load(Ordering::Acquire)); - unpark_task(task_id, true); - } + let task_id = _context as u64; + unpark_task(task_id, true); } pub struct Executor { @@ -35,18 +23,22 @@ pub struct Executor { } impl Executor { + /// Create a new executor and initialize context with current task id pub fn new() -> Self { + let cur_id = axtask::current().id().as_u64(); Self { - inner: raw::Executor::new(core::ptr::null_mut()), + inner: raw::Executor::new(cur_id as *mut ()), not_send: PhantomData, } } + /// Runs the executor. + /// + /// The `init` closure is called with a [`Spawner`] that spawns tasks on + /// this executor. Use it to spawn the initial task(s). After `init` returns, + /// the executor starts running the tasks. + /// pub fn run(&'static mut self, init: impl FnOnce(embassy_executor::Spawner)) -> ! { - let cur_id = axtask::current().id().as_u64(); - EXECUTOR_TASK_ID.with_current(|m| { - m.store(cur_id, Ordering::SeqCst); - }); init(self.inner.spawner()); loop { @@ -59,13 +51,8 @@ impl Executor { }); } else { park_current_task(); - debug!("park current task"); } }; } } - - pub fn spawner(&'static mut self) -> Spawner { - self.inner.spawner() - } } diff --git a/modules/axembassy/src/lib.rs b/modules/axembassy/src/lib.rs index f431371ec01..e1707e17ec 100644 --- a/modules/axembassy/src/lib.rs +++ b/modules/axembassy/src/lib.rs @@ -7,14 +7,16 @@ extern crate log; #[cfg(feature = "executor")] mod executor; -#[cfg(feature = "executor")] -mod runtime; #[cfg(feature = "driver")] mod time_driver; -mod waker; +// mod waker; +mod asynch; #[cfg(feature = "executor")] -pub use crate::executor::{Executor, signal_executor}; +pub use crate::asynch::{block_on, spawner}; +#[cfg(feature = "executor")] +pub use crate::executor::Executor; +use axtask::spawn_raw; #[cfg(feature = "executor")] #[doc(no_inline)] pub use embassy_executor::*; @@ -24,3 +26,26 @@ pub use embassy_futures::*; #[cfg(feature = "driver")] pub use crate::time_driver::AxDriverAPI; + +pub fn spawn_init() { + spawn_raw(init, "async".into(), 4096); +} + +fn init() { + use static_cell::StaticCell; + + static EXECUTOR: StaticCell = StaticCell::new(); + EXECUTOR + .init_with(Executor::new) + .run(|sp| sp.must_spawn(init_task())); +} + +#[embassy_executor::task] +async fn init_task() { + use log::debug; + + let spawner = asynch::Spawner::for_current_executor().await; + asynch::set_spawner(spawner.make_send()); + + debug!("axembassy::init_task()"); +} diff --git a/modules/axembassy/src/runtime.rs b/modules/axembassy/src/runtime.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/modules/axembassy/src/waker/mod.rs b/modules/axembassy/src/waker/mod.rs index 8582a99052..dc7d2dce2c 100644 --- a/modules/axembassy/src/waker/mod.rs +++ b/modules/axembassy/src/waker/mod.rs @@ -6,7 +6,6 @@ use core::{ task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, }; -use crate::executor::signal_executor; use axtask::{AxTaskRef, TaskId, current, park_current_task, unpark_task}; use kspin::SpinNoIrq; @@ -42,12 +41,12 @@ unsafe fn clone(_data: *const ()) -> RawWaker { unsafe fn wake(_data: *const ()) { // Call Executor pender function - signal_executor(); + // signal_executor(); } unsafe fn wake_by_ref(_data: *const ()) { // Call Executor pender function - signal_executor(); + // signal_executor(); } unsafe fn drop(_data: *const ()) { diff --git a/modules/axruntime/Cargo.toml b/modules/axruntime/Cargo.toml index 8b90c2ca38..bfbbc61185 100644 --- a/modules/axruntime/Cargo.toml +++ b/modules/axruntime/Cargo.toml @@ -37,7 +37,7 @@ axfs = { workspace = true, optional = true } axnet = { workspace = true, optional = true } axdisplay = { workspace = true, optional = true } axtask = { workspace = true, optional = true } -axembassy = { workspace = true, optional = true, features = ["default","multitask"] } +axembassy = { workspace = true, optional = true } crate_interface = "0.1" percpu = { version = "0.2", optional = true } diff --git a/modules/axruntime/src/lib.rs b/modules/axruntime/src/lib.rs index 2cababcaf2..13a81ccb8c 100644 --- a/modules/axruntime/src/lib.rs +++ b/modules/axruntime/src/lib.rs @@ -153,6 +153,9 @@ pub extern "C" fn rust_main(cpu_id: usize, dtb: usize) -> ! { #[cfg(feature = "multitask")] axtask::init_scheduler(); + #[cfg(feature = "embassy-timer")] + axembassy::spawn_init(); + #[cfg(any(feature = "fs", feature = "net", feature = "display"))] { #[allow(unused_variables)] @@ -272,8 +275,6 @@ fn init_interrupt() { update_timer(); #[cfg(feature = "multitask")] axtask::on_timer_tick(); - #[cfg(feature = "embassy-timer")] - axembassy::signal_executor(); }); // Enable IRQs before starting app diff --git a/modules/axtask/src/run_queue.rs b/modules/axtask/src/run_queue.rs index 501629c211..0843d4abed 100644 --- a/modules/axtask/src/run_queue.rs +++ b/modules/axtask/src/run_queue.rs @@ -451,7 +451,8 @@ impl CurrentRunQueueRef<'_, G> { debug!("task block: {}", curr.id_name()); self.inner.resched(); } - + + /// Park the current task, and reschedule. pub fn park_current_task(&mut self) { let curr = &self.current_task; assert!(curr.is_running()); @@ -460,7 +461,7 @@ impl CurrentRunQueueRef<'_, G> { // Ensure preemption is disabled #[cfg(feature = "preempt")] assert!(curr.can_preempt(1)); - + curr.set_state(TaskState::Parked); self.inner.resched(); } @@ -682,12 +683,29 @@ pub(crate) fn init() { // Put the subsequent execution into the `main` task. let main_task = TaskInner::new_init("main".into()).into_arc(); main_task.set_state(TaskState::Running); - debug!("main task registered: {}, id {}", main_task.id_name(), main_task.id().as_u64()); register_task(main_task.clone()); + debug!( + "main task registered: {}, id {}", + main_task.id_name(), + main_task.id().as_u64() + ); unsafe { CurrentTask::init_current(main_task) } + // // Pub the embassy executor into the `async` task. + // let async_task = + // TaskInner::new(axembassy::init, "async".into(), IDLE_TASK_STACK_SIZE).into_arc(); + // async_task.set_state(TaskState::Running); + // register_task(async_task.clone()); + // debug!( + // "embassy async task registered: {}, id {}", + // async_task.id_name(), + // async_task.id().as_u64() + // ); + RUN_QUEUE.with_current(|rq| { rq.init_once(AxRunQueue::new(cpu_id)); + // let rq_ = rq.get().unwrap(); + // rq_.scheduler.lock().add_task(async_task); }); unsafe { RUN_QUEUES[cpu_id].write(RUN_QUEUE.current_ref_mut_raw()); diff --git a/modules/axtask/src/task.rs b/modules/axtask/src/task.rs index be12b1edb0..775897a3e6 100644 --- a/modules/axtask/src/task.rs +++ b/modules/axtask/src/task.rs @@ -31,10 +31,11 @@ pub(crate) enum TaskState { /// Task is blocked (in the wait queue or timer list), /// and it has finished its scheduling process, it can be wake up by `notify()` on any run queue safely. Blocked = 3, + /// Task is Suspended, + /// Not in wait queue. + Parked = 4, /// Task is exited and waiting for being dropped. - Exited = 4, - /// Task is an asynchronous task, waiting for even completion to be unparked. - Parked = 5, + Exited = 5, } /// The inner task structure. diff --git a/modules/axtask/src/task_registry.rs b/modules/axtask/src/task_registry.rs index 3ee317ac86..fb973cf81b 100644 --- a/modules/axtask/src/task_registry.rs +++ b/modules/axtask/src/task_registry.rs @@ -5,8 +5,12 @@ use kspin::SpinNoIrq; use crate::{AxTaskRef, current_run_queue, select_run_queue}; +/// Task registry by task id static TASK_REGISTRY: SpinNoIrq> = SpinNoIrq::new(BTreeMap::new()); +/// Register a task to the task registry. +/// +/// Should be called in the process of task spawn. pub fn register_task(task: AxTaskRef) { let mut tasks = TASK_REGISTRY.lock(); let id = task.id().as_u64(); @@ -14,25 +18,29 @@ pub fn register_task(task: AxTaskRef) { debug!("Task {} registered", id); } +/// Unregister a task from the task registry. +/// +/// Should be called in the process of task exit. pub fn unregister_task(id: u64) { let mut tasks = TASK_REGISTRY.lock(); tasks.remove(&id); - debug!("Task {} registered", id); + debug!("Task {} unregistered", id); } +/// Find a task by its ID. pub fn find_task_by_id(id: u64) -> Option { let tasks = TASK_REGISTRY.lock(); tasks.get(&id).cloned() } +/// Unpark a task by its id. pub fn unpark_task(id: u64, resched: bool) { if let Some(task) = find_task_by_id(id) { select_run_queue::(&task).unpark_task(task, resched); - } else { -/* debug!("Attempt to unpark non-existent task {}", id); */ - } + } } +/// Park the current task. pub fn park_current_task() { let mut cur_rq = current_run_queue::(); cur_rq.park_current_task(); From f38133d3fa33459b394cca1256c9705233453e0f Mon Sep 17 00:00:00 2001 From: lvyuemeng Date: Sun, 1 Jun 2025 23:07:26 +0800 Subject: [PATCH 06/11] [feat]: add arceos_api for axembassy --- Cargo.lock | 97 +++++++--- Cargo.toml | 3 +- api/arceos_api/Cargo.toml | 5 +- api/arceos_api/src/imp/embassy_async.rs | 16 ++ api/arceos_api/src/imp/mod.rs | 2 + api/arceos_api/src/lib.rs | 37 +++- api/arceos_api/src/macros.rs | 24 ++- api/axfeat/Cargo.toml | 14 +- api/axfeat/src/lib.rs | 4 +- examples/embassy-local/Cargo.toml | 9 +- examples/embassy-local/src/main.rs | 51 ++--- examples/embassy-user/.axconfig.toml | 81 -------- examples/embassy-user/Cargo.toml | 14 -- examples/embassy-user/src/executor.rs | 66 ------- examples/embassy-user/src/main.rs | 47 ----- modules/axembassy/Cargo.toml | 36 ++-- modules/axembassy/src/asynch.rs | 6 - modules/axembassy/src/delegate.rs | 236 +++++++++++++++++++++++ modules/axembassy/src/executor.rs | 27 +-- modules/axembassy/src/executor_thread.rs | 57 ++++++ modules/axembassy/src/lib.rs | 92 +++++---- modules/axembassy/src/waker/mod.rs | 126 ------------ modules/axruntime/src/lib.rs | 23 +-- modules/axtask/src/api.rs | 10 +- modules/axtask/src/events.rs | 86 +++++++++ modules/axtask/src/lib.rs | 1 + modules/axtask/src/run_queue.rs | 16 +- modules/axtask/src/task.rs | 4 +- modules/axtask/src/wait_queue.rs | 12 ++ ulib/axasync/Cargo.toml | 26 +++ ulib/axasync/src/lib.rs | 11 ++ ulib/axstd/Cargo.toml | 3 - ulib/axstd/src/lib.rs | 4 +- 33 files changed, 737 insertions(+), 509 deletions(-) create mode 100644 api/arceos_api/src/imp/embassy_async.rs delete mode 100644 examples/embassy-user/.axconfig.toml delete mode 100644 examples/embassy-user/Cargo.toml delete mode 100644 examples/embassy-user/src/executor.rs delete mode 100644 examples/embassy-user/src/main.rs create mode 100644 modules/axembassy/src/delegate.rs create mode 100644 modules/axembassy/src/executor_thread.rs delete mode 100644 modules/axembassy/src/waker/mod.rs create mode 100644 modules/axtask/src/events.rs create mode 100644 ulib/axasync/Cargo.toml create mode 100644 ulib/axasync/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 16ef985532..84c5d40208 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -239,6 +239,19 @@ dependencies = [ "memory_addr", ] +[[package]] +name = "axasync" +version = "0.1.0" +dependencies = [ + "arceos_api", + "axfeat", + "cfg-if", + "embassy-executor", + "embassy-futures 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "embassy-sync 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "static_cell", +] + [[package]] name = "axconfig" version = "0.1.0" @@ -375,8 +388,10 @@ dependencies = [ "axconfig", "axhal", "axtask", + "cfg-if", "embassy-executor", - "embassy-futures", + "embassy-futures 0.1.1 (git+https://github.com/embassy-rs/embassy?branch=main)", + "embassy-sync 0.7.0 (git+https://github.com/embassy-rs/embassy?branch=main)", "embassy-time-driver", "embassy-time-queue-utils", "kspin", @@ -1009,8 +1024,7 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "embassy-executor" version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90327bcc66333a507f89ecc4e2d911b265c45f5c9bc241f98eee076752d35ac6" +source = "git+https://github.com/embassy-rs/embassy?branch=main#d23d5d6a4ce44056d6340b37f6145a061f2f2889" dependencies = [ "critical-section", "document-features", @@ -1020,8 +1034,7 @@ dependencies = [ [[package]] name = "embassy-executor-macros" version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3577b1e9446f61381179a330fc5324b01d511624c55f25e3c66c9e3c626dbecf" +source = "git+https://github.com/embassy-rs/embassy?branch=main#d23d5d6a4ce44056d6340b37f6145a061f2f2889" dependencies = [ "darling", "proc-macro2", @@ -1035,21 +1048,52 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067" +[[package]] +name = "embassy-futures" +version = "0.1.1" +source = "git+https://github.com/embassy-rs/embassy?branch=main#c637ee7d79552d9b9bfa0c0f4199372975acc343" + [[package]] name = "embassy-local" version = "0.0.0" dependencies = [ + "axasync", "axstd", "embassy-executor", - "embassy-futures", "embassy-time", ] +[[package]] +name = "embassy-sync" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cef1a8a1ea892f9b656de0295532ac5d8067e9830d49ec75076291fd6066b136" +dependencies = [ + "cfg-if", + "critical-section", + "embedded-io-async", + "futures-sink", + "futures-util", + "heapless 0.8.0", +] + +[[package]] +name = "embassy-sync" +version = "0.7.0" +source = "git+https://github.com/embassy-rs/embassy?branch=main#c637ee7d79552d9b9bfa0c0f4199372975acc343" +dependencies = [ + "cfg-if", + "critical-section", + "embedded-io-async", + "futures-sink", + "futures-util", + "heapless 0.8.0", +] + [[package]] name = "embassy-time" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f820157f198ada183ad62e0a66f554c610cdcd1a9f27d4b316358103ced7a1f8" +source = "git+https://github.com/embassy-rs/embassy?branch=main#d23d5d6a4ce44056d6340b37f6145a061f2f2889" dependencies = [ "cfg-if", "critical-section", @@ -1064,8 +1108,7 @@ dependencies = [ [[package]] name = "embassy-time-driver" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d45f5d833b6d98bd2aab0c2de70b18bfaa10faf661a1578fd8e5dfb15eb7eba" +source = "git+https://github.com/embassy-rs/embassy?branch=main#d23d5d6a4ce44056d6340b37f6145a061f2f2889" dependencies = [ "document-features", ] @@ -1073,23 +1116,12 @@ dependencies = [ [[package]] name = "embassy-time-queue-utils" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc55c748d16908a65b166d09ce976575fb8852cf60ccd06174092b41064d8f83" +source = "git+https://github.com/embassy-rs/embassy?branch=main#d23d5d6a4ce44056d6340b37f6145a061f2f2889" dependencies = [ "embassy-executor", "heapless 0.8.0", ] -[[package]] -name = "embassy-user" -version = "0.0.0" -dependencies = [ - "axstd", - "embassy-executor", - "embassy-futures", - "embassy-time", -] - [[package]] name = "embedded-hal" version = "0.2.7" @@ -1115,6 +1147,21 @@ dependencies = [ "embedded-hal 1.0.0", ] +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "embedded-io-async" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" +dependencies = [ + "embedded-io", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -1151,6 +1198,12 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + [[package]] name = "futures-task" version = "0.3.31" diff --git a/Cargo.toml b/Cargo.toml index 62887459f4..0420d3482f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ members = [ "api/arceos_api", "api/arceos_posix_api", + "ulib/axasync", "ulib/axstd", "ulib/axlibc", @@ -30,7 +31,6 @@ members = [ "examples/httpserver", "examples/httpserver", "examples/shell", - "examples/embassy-user", "examples/embassy-local", ] @@ -46,6 +46,7 @@ keywords = ["arceos", "kernel"] categories = ["os", "no-std"] [workspace.dependencies] +axasync = { path = "ulib/axasync" } axstd = { path = "ulib/axstd" } axlibc = { path = "ulib/axlibc" } diff --git a/api/arceos_api/Cargo.toml b/api/arceos_api/Cargo.toml index 36cd0bced3..2b9e0965aa 100644 --- a/api/arceos_api/Cargo.toml +++ b/api/arceos_api/Cargo.toml @@ -23,6 +23,9 @@ display = ["dep:axdisplay", "dep:axdriver", "axfeat/display"] myfs = ["axfeat/myfs"] +async-thread = ["dep:axembassy", "axfeat/async-thread"] +async-single = ["dep:axembassy", "axfeat/async-single"] + # Use dummy functions if the feature is not enabled dummy-if-not-enabled = [] @@ -43,4 +46,4 @@ axdriver = { workspace = true, optional = true } axfs = { workspace = true, optional = true } axnet = { workspace = true, optional = true } axdisplay = { workspace = true, optional = true } -axembassy = { workspace = true} +axembassy = { workspace = true, optional = true } diff --git a/api/arceos_api/src/imp/embassy_async.rs b/api/arceos_api/src/imp/embassy_async.rs new file mode 100644 index 0000000000..62c459d517 --- /dev/null +++ b/api/arceos_api/src/imp/embassy_async.rs @@ -0,0 +1,16 @@ +cfg_async! { + pub use axembassy::Executor as AxExecutor; + pub use axembassy::Spawner as AxSpawner; +} + +cfg_async_thread! { + pub use axembassy::SendSpawner as AxSendSpawner; + + pub fn ax_spawner() -> AxSendSpawner { + axembassy::spawner() + } + + pub fn ax_block_on(fut: F) -> F::Output { + axembassy::block_on(fut) + } +} diff --git a/api/arceos_api/src/imp/mod.rs b/api/arceos_api/src/imp/mod.rs index d4fb3c5010..3ba8292523 100644 --- a/api/arceos_api/src/imp/mod.rs +++ b/api/arceos_api/src/imp/mod.rs @@ -1,5 +1,6 @@ mod mem; mod task; +mod embassy_async; cfg_fs! { mod fs; @@ -49,6 +50,7 @@ pub use self::mem::*; pub use self::stdio::*; pub use self::task::*; pub use self::time::*; +pub use self::embassy_async::*; pub use axhal::misc::terminate as ax_terminate; pub use axio::PollState as AxPollState; diff --git a/api/arceos_api/src/lib.rs b/api/arceos_api/src/lib.rs index 0f4f9422c0..46a9264926 100644 --- a/api/arceos_api/src/lib.rs +++ b/api/arceos_api/src/lib.rs @@ -386,6 +386,40 @@ pub mod io { } } +/// Embassy runtime. +pub mod embassy_async { + use core::future::Future; + + define_api_type! { + @cfg "async-thread"; + pub type AxExecutor; + pub type AxSpawner; + pub type AxSendSpawner; + } + + define_api! { + @cfg "async-thread"; + pub fn ax_spawner() -> AxSendSpawner; + } + + #[cfg(feature = "async-thread")] + pub fn ax_block_on(fut: F) -> F::Output { + crate::imp::ax_block_on(fut) + } + + #[allow(unused_variables)] + #[cfg(all(feature = "dummy-if-not-enabled", not(feature = "async-thread")))] + pub fn ax_block_on(fut: F) -> F::Output { + unimplemented!(stringify!(ax_block_on)) + } + + define_api_type! { + @cfg "async-single"; + pub type AxExecutor; + pub type AxSpawner; + } +} + /// Re-exports of ArceOS modules. /// /// You should prefer to use other APIs rather than these modules. The modules @@ -396,7 +430,6 @@ pub mod modules { pub use axlog; pub use axruntime; pub use axsync; - pub use axembassy; #[cfg(feature = "alloc")] pub use axalloc; @@ -406,6 +439,8 @@ pub mod modules { pub use axdma; #[cfg(any(feature = "fs", feature = "net", feature = "display"))] pub use axdriver; + #[cfg(any(feature = "async-thread", feature = "async-single"))] + pub use axembassy; #[cfg(feature = "fs")] pub use axfs; #[cfg(feature = "paging")] diff --git a/api/arceos_api/src/macros.rs b/api/arceos_api/src/macros.rs index ae96825967..23224a957b 100644 --- a/api/arceos_api/src/macros.rs +++ b/api/arceos_api/src/macros.rs @@ -1,20 +1,19 @@ #![allow(unused_macros)] macro_rules! define_api_type { - ($( $(#[$attr:meta])* $vis:vis type $name:ident; )+) => { + ($( $(#[$attr:meta])* $vis:vis type $name:ident $(<$($generic:tt)*>)? ; )+) => { $( $vis use $crate::imp::$name; )+ }; - ( @cfg $feature:literal; $( $(#[$attr:meta])* $vis:vis type $name:ident; )+ ) => { + ( @cfg $feature:literal; $( $(#[$attr:meta])* $vis:vis type $name:ident $(<$($generic:tt)*>)? ; )+ ) => { $( #[cfg(feature = $feature)] $(#[$attr])* $vis use $crate::imp::$name; - #[cfg(all(feature = "dummy-if-not-enabled", not(feature = $feature)))] $(#[$attr])* - $vis struct $name; + $vis struct $name $(<$($generic)*>)? $(where $($generic)*: {})?; )+ }; } @@ -108,3 +107,20 @@ macro_rules! cfg_display { macro_rules! cfg_task { ($($item:item)*) => { _cfg_common!{ "multitask" $($item)* } } } + +macro_rules! cfg_async_thread { + ($($item:item)*) => { _cfg_common!{ "async-thread" $($item)* } } +} + +macro_rules! cfg_async_single { + ($($item:item)*) => { _cfg_common!{ "async-single" $($item)* } } +} + +macro_rules! cfg_async { + ($($item:item)*) => { + $( + #[cfg(any(feature = "async-thread", feature = "async-single"))] + $item + )* + } +} diff --git a/api/axfeat/Cargo.toml b/api/axfeat/Cargo.toml index 4dbbced4a2..5023c4c47e 100644 --- a/api/axfeat/Cargo.toml +++ b/api/axfeat/Cargo.toml @@ -43,8 +43,18 @@ sched_fifo = ["axtask/sched_fifo"] sched_rr = ["axtask/sched_rr", "irq"] sched_cfs = ["axtask/sched_cfs", "irq"] -# Embassy Timer -embassy-timer = ["axembassy/driver", "axruntime/embassy-timer"] +# Embassy asynchronous runtime with multithread support +async-thread = [ + "axembassy/driver", + "axembassy/executor-thread", + "axruntime/embassy-timer", +] +# Embassy asynchronous runtime depended on irq with single thread support +async-single = [ + "axembassy/driver", + "axembassy/executor-single", + "axruntime/embassy-timer", +] # File system fs = [ diff --git a/api/axfeat/src/lib.rs b/api/axfeat/src/lib.rs index 85fc2abb26..481d97ba9e 100644 --- a/api/axfeat/src/lib.rs +++ b/api/axfeat/src/lib.rs @@ -34,7 +34,9 @@ //! - `log-level-off`: Disable all logging. //! - `log-level-error`, `log-level-warn`, `log-level-info`, `log-level-debug`, //! `log-level-trace`: Keep logging only at the specified level or higher. -//! +//! - Embassy runtime +//! - `async-thread`: Enable Embassy asynchronous runtime with multithread support. +//! - `async-single`: Enable Embassy asynchronous runtime depenended on irq with single thread. //! [ArceOS]: https://github.com/arceos-org/arceos #![no_std] diff --git a/examples/embassy-local/Cargo.toml b/examples/embassy-local/Cargo.toml index d9cdca1ac8..bac4301623 100644 --- a/examples/embassy-local/Cargo.toml +++ b/examples/embassy-local/Cargo.toml @@ -5,10 +5,7 @@ edition.workspace = true [dependencies] axstd = { workspace = true, features = ["alloc", "multitask"], optional = true } +axasync = { workspace = true, features = ["thread"] } -embassy-futures = "0.1.1" -embassy-executor = { version = "0.7.0", features = [ - "nightly", - "executor-thread", -] } -embassy-time = { version = "0.4.0" } +embassy-executor = { git = "https://github.com/embassy-rs/embassy", branch = "main", default-features = false } +embassy-time = { git = "https://github.com/embassy-rs/embassy", branch = "main" } diff --git a/examples/embassy-local/src/main.rs b/examples/embassy-local/src/main.rs index 7e31d37aef..ffbbb416a3 100644 --- a/examples/embassy-local/src/main.rs +++ b/examples/embassy-local/src/main.rs @@ -6,36 +6,42 @@ #[cfg(feature = "axstd")] extern crate axstd as std; -use embassy_futures::yield_now; -use std::Executor; +use axasync::spawner; use std::time::Duration; use std::{ boxed::Box, thread::{self, sleep}, }; -fn tick(_sec: u64, busy_nano: u64) -> embassy_executor::SpawnToken { +fn busy_work() { + for _ in 0..1000 { + let mut x = 0; + for _ in 0..1000 { + x += 1; + } + } +} + +fn tick_raw(_sec: u64, busy_nano: u64) -> embassy_executor::SpawnToken { let task = Box::leak(Box::new(embassy_executor::raw::TaskStorage::new())); task.spawn(move || async move { for i in 0..10 { - println!("embassy tick {}/s :{}", _sec, i); - for _ in 0..busy_nano { - // Simulate some busy work - let _ = (0..1000).fold(0, |acc, x| acc + x); - } + println!("embassy tick: {}/s, {} times", _sec * i, i); + busy_work(); embassy_time::Timer::after_secs(_sec).await; } panic!("tick finished"); }) } -fn idle() -> embassy_executor::SpawnToken { - let task = Box::leak(Box::new(embassy_executor::raw::TaskStorage::new())); - task.spawn(move || async move { - loop { - yield_now().await; - } - }) +#[embassy_executor::task] +async fn tick(_sec: u64, busy_nano: u64) { + for i in 0..10 { + println!("embassy tick: {}/s, {} times", _sec * i, i); + busy_work(); + embassy_time::Timer::after_secs(_sec).await; + } + panic!("tick finished"); } #[cfg_attr(feature = "axstd", unsafe(no_mangle))] @@ -44,16 +50,15 @@ fn main() { for i in 1..4 { println!("spawned thread {}", i); thread::spawn(move || { - for j in 0..5{ - println!("spawn tick {}: {}", i, j); + for j in 0..5 { + println!("thread {} tick: {}/s {} times", i, j * i, j); sleep(Duration::from_millis(1000 * i as u64)); } - println!("spawned thread {} finished", i); + println!("thread {} finished", i); }); } - let exec = Box::leak(Box::new(Executor::new())); - exec.run(|s| { - // s.spawn(idle()).unwrap(); - s.spawn(tick(1, 0)).unwrap(); - }); + + spawner().spawn(tick(1, 0)).unwrap(); + // Avoid + sleep(Duration::from_millis(1000 * 15 as u64)); } diff --git a/examples/embassy-user/.axconfig.toml b/examples/embassy-user/.axconfig.toml deleted file mode 100644 index 42465c83b4..0000000000 --- a/examples/embassy-user/.axconfig.toml +++ /dev/null @@ -1,81 +0,0 @@ -# Architecture identifier. -arch = "riscv64" # str -# Platform identifier. -platform = "riscv64-qemu-virt" # str -# Number of CPUs -smp = 1 # uint -# Stack size of each task. -task-stack-size = 0x40000 # uint -# Number of timer ticks per second (Hz). A timer tick may contain several timer -# interrupts. -ticks-per-sec = 100 # uint - -# -# Device specifications -# -[devices] -# MMIO regions with format (`base_paddr`, `size`). -mmio-regions = [ - [0x0010_1000, 0x1000], - [0x0c00_0000, 0x21_0000], - [0x1000_0000, 0x1000], - [0x1000_1000, 0x8000], - [0x3000_0000, 0x1000_0000], - [0x4000_0000, 0x4000_0000] -] # [(uint, uint)] -# End PCI bus number (`bus-range` property in device tree). -pci-bus-end = 0xff # uint -# Base physical address of the PCIe ECAM space. -pci-ecam-base = 0x3000_0000 # uint -# PCI device memory ranges (`ranges` property in device tree). -pci-ranges = [ - [0x0300_0000, 0x1_0000], - [0x4000_0000, 0x4000_0000], - [0x4_0000_0000, 0x4_0000_0000] -] # [(uint, uint)] -# rtc@101000 { -# interrupts = <0x0b>; -# interrupt-parent = <0x03>; -# reg = <0x00 0x101000 0x00 0x1000>; -# compatible = "google,goldfish-rtc"; -# }; -# RTC (goldfish) Address -rtc-paddr = 0x10_1000 # uint -# Timer interrupt frequency in Hz. -timer-frequency = 10_000_000 # uint -# VirtIO MMIO regions with format (`base_paddr`, `size`). -virtio-mmio-regions = [ - [0x1000_1000, 0x1000], - [0x1000_2000, 0x1000], - [0x1000_3000, 0x1000], - [0x1000_4000, 0x1000], - [0x1000_5000, 0x1000], - [0x1000_6000, 0x1000], - [0x1000_7000, 0x1000], - [0x1000_8000, 0x1000] -] # [(uint, uint)] - -# -# Platform configs -# -[plat] -# Platform family. -family = "riscv64-qemu-virt" # str -# Kernel address space base. -kernel-aspace-base = "0xffff_ffc0_0000_0000" # uint -# Kernel address space size. -kernel-aspace-size = "0x0000_003f_ffff_f000" # uint -# Base physical address of the kernel image. -kernel-base-paddr = 0x8020_0000 # uint -# Base virtual address of the kernel image. -kernel-base-vaddr = "0xffff_ffc0_8020_0000" # uint -# Offset of bus address and phys address. some boards, the bus address is -# different from the physical address. -phys-bus-offset = 0 # uint -# Base address of the whole physical memory. -phys-memory-base = 0x8000_0000 # uint -# Size of the whole physical memory. (128M) -phys-memory-size = 0x800_0000 # uint -# Linear mapping offset, for quick conversions between physical and virtual -# addresses. -phys-virt-offset = "0xffff_ffc0_0000_0000" # uint diff --git a/examples/embassy-user/Cargo.toml b/examples/embassy-user/Cargo.toml deleted file mode 100644 index 5016d1ccfc..0000000000 --- a/examples/embassy-user/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "embassy-user" -authors = ["nostalgia "] -edition.workspace = true - -[dependencies] -axstd = { workspace = true, features = ["alloc", "multitask"], optional = true } - -embassy-futures = "0.1.1" -embassy-executor = { version = "0.7.0", features = [ - "nightly", - "executor-thread", -] } -embassy-time = { version = "0.4.0" } diff --git a/examples/embassy-user/src/executor.rs b/examples/embassy-user/src/executor.rs deleted file mode 100644 index 85f6af7dc6..0000000000 --- a/examples/embassy-user/src/executor.rs +++ /dev/null @@ -1,66 +0,0 @@ -use core::marker::PhantomData; -use embassy_executor::raw; -use std::sync::{Condvar, Mutex}; -use std::boxed::Box; - - -#[unsafe(export_name = "__pender")] -fn __pender(context: *mut ()) { - let signaler: &'static Signaler = unsafe { std::mem::transmute(context) }; - signaler.signal() -} - -pub struct Executor { - inner: raw::Executor, - not_send: PhantomData<*mut ()>, - signaler: &'static Signaler, -} - -impl Executor { - pub fn new() -> Self { - let signaler = Box::leak(Box::new(Signaler::new())); - Self { - inner: raw::Executor::new(signaler as *mut Signaler as *mut ()), - not_send: PhantomData, - signaler, - } - } - - pub fn run(&'static mut self, init: impl FnOnce(embassy_executor::Spawner)) -> ! { - init(self.inner.spawner()); - - loop { - unsafe { self.inner.poll() }; - self.signaler.wait() - } - } -} - -struct Signaler { - mutex: Mutex, - condvar: Condvar, -} - -impl Signaler { - fn new() -> Self { - Self { - mutex: Mutex::new(false), - condvar: Condvar::new(), - } - } - - fn signal(&self) { - let mut guard= self.mutex.lock(); - *guard = true; - self.condvar.notify_one(); - } - - fn wait(&self) { - let mut guard = self.mutex.lock(); - while !*guard { - guard = self.condvar.wait(guard); - } - *guard = false; - } -} - diff --git a/examples/embassy-user/src/main.rs b/examples/embassy-user/src/main.rs deleted file mode 100644 index fc002b44b1..0000000000 --- a/examples/embassy-user/src/main.rs +++ /dev/null @@ -1,47 +0,0 @@ -#![feature(impl_trait_in_assoc_type)] -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[macro_use] -#[cfg(feature = "axstd")] -extern crate axstd as std; - -use embassy_futures::yield_now; -use std::{boxed::Box, thread::{self, Thread}}; - -mod executor; - -fn tick(_sec: u64, f: fn()) -> embassy_executor::SpawnToken { - let task = Box::leak(Box::new(embassy_executor::raw::TaskStorage::new())); - task.spawn(move || async move { - for _ in 0..10 { - f(); - embassy_time::Timer::after_secs(_sec).await; - } - panic!("tick finished"); - }) -} - -fn idle() -> embassy_executor::SpawnToken { - let task = Box::leak(Box::new(embassy_executor::raw::TaskStorage::new())); - task.spawn(move || async move { - loop { - yield_now().await; - } - }) -} - -#[cfg_attr(feature = "axstd", unsafe(no_mangle))] -fn main() { - println!("Embassy Test"); - thread::spawn(|| { - for _ in 0..10 { - println!("spawn tick") - } - }); - let exec = Box::leak(Box::new(executor::Executor::new())); - exec.run(|s| { - // s.spawn(idle()).unwrap(); - s.spawn(tick(1, || println!("tick for 1 sec"))).unwrap(); - }); -} \ No newline at end of file diff --git a/modules/axembassy/Cargo.toml b/modules/axembassy/Cargo.toml index efff7a775f..a34475e1de 100644 --- a/modules/axembassy/Cargo.toml +++ b/modules/axembassy/Cargo.toml @@ -10,33 +10,43 @@ homepage.workspace = true driver = [ "dep:embassy-time-driver", "dep:embassy-time-queue-utils", - "dep:kspin", "dep:percpu", "axhal/irq", ] -executor = ["dep:embassy-executor"] -futures = ["dep:embassy-futures"] +# executor is thread dependent +executor-thread = [ + "dep:embassy-executor", + "dep:embassy-futures", + "dep:embassy-sync", + "axtask/multitask", +] + +executor-single = [ + "dep:embassy-executor", + "dep:embassy-futures", + "dep:embassy-sync", + "axhal/irq", +] -default = ["driver", "futures", "executor"] +default = ["driver"] [dependencies] axconfig = { workspace = true } axhal = { workspace = true, features = ["irq"] } axtask = { workspace = true } -embassy-time-driver = { version = "0.2.0", optional = true, features = [ +embassy-time-driver = { git = "https://github.com/embassy-rs/embassy", branch = "main", optional = true, features = [ # annotate explicitly # wait to be improved "tick-hz-100", ] } -embassy-time-queue-utils = { version = "0.1.0", optional = true } -embassy-executor = { version = "0.7.0", features = [ - "nightly", - "executor-thread", -], optional = true } -embassy-futures = { version = "0.1.1", optional = true } +embassy-time-queue-utils = { git = "https://github.com/embassy-rs/embassy", branch = "main", optional = true } +embassy-executor = { git = "https://github.com/embassy-rs/embassy", branch = "main", default-features = false, optional = true } +embassy-futures = { git = "https://github.com/embassy-rs/embassy", branch = "main", optional = true } +embassy-sync = { git = "https://github.com/embassy-rs/embassy", branch = "main", optional = true } -log = "=0.4.21" -kspin = { version = "0.1", optional = true } percpu = { version = "0.2", optional = true } +cfg-if = "1.0" +log = "=0.4.21" static_cell = "2.1.0" +kspin = "0.1" diff --git a/modules/axembassy/src/asynch.rs b/modules/axembassy/src/asynch.rs index e8404bf456..cfdd80b9ff 100644 --- a/modules/axembassy/src/asynch.rs +++ b/modules/axembassy/src/asynch.rs @@ -1,5 +1,3 @@ -#![deny(missing_docs)] - use core::{ cell::OnceCell, pin::Pin, @@ -39,10 +37,6 @@ fn wake(ctx: *const ()) { static VTABLE: RawWakerVTable = RawWakerVTable::new(|ctx| RawWaker::new(ctx, &VTABLE), wake, wake, wake); -/// Blocks the current task until the given future is ready. -/// -/// # Panics -/// /// Panics if not called in a thread task pub fn block_on(mut fut: F) -> F::Output { let mut fut = unsafe { Pin::new_unchecked(&mut fut) }; diff --git a/modules/axembassy/src/delegate.rs b/modules/axembassy/src/delegate.rs new file mode 100644 index 0000000000..c89d58b43d --- /dev/null +++ b/modules/axembassy/src/delegate.rs @@ -0,0 +1,236 @@ +use core::{ + marker::PhantomData, + ptr, + sync::atomic::{AtomicU8, Ordering}, +}; + +use embassy_executor::Spawner; +use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal}; + +/// A cell that can only be used on the executor that created it +pub struct SameExecutorCell { + /// The executor id + id: usize, + inner: T, +} + +impl SameExecutorCell { + /// Creates a new `SameExecutorCell` with the provided `inner` value and associates it + /// with the executor identified by the given `spawner`. + /// + /// # Arguments + /// + /// * `inner` - The value to be stored inside the cell. + /// * `spawner` - The spawner used to identify the executor, from which the cell can be accessed. + pub fn new(inner: T, spawner: Spawner) -> Self { + Self { + id: spawner.executor_id(), + inner, + } + } + + /// Creates a new `SameExecutorCell` with the provided `inner` value and associates it with the current executor. + pub async fn new_async(inner: T) -> Self { + let spawner = Spawner::for_current_executor().await; + SameExecutorCell::new(inner, spawner) + } + + /// Returns a reference to the inner value if the `spawner` matches the executor id associated with `self`. + pub fn get(&self, spawner: Spawner) -> Option<&T> { + if self.id == spawner.executor_id() { + Some(&self.inner) + } else { + None + } + } + + /// Returns a mutable reference to the inner value if the `spawner` matches the executor id + /// associated with `self`. + pub fn get_mut(&mut self, spawner: Spawner) -> Option<&mut T> { + if self.id == spawner.executor_id() { + Some(&mut self.inner) + } else { + None + } + } + + /// Returns a reference to the inner value by the spawner of current async closure + pub async fn get_async(&self) -> Option<&T> { + let spawner = Spawner::for_current_executor().await; + self.get(spawner) + } + + /// Returns a mutable reference to the inner value by the spawner of current async closure + pub async fn get_mut_async(&mut self) -> Option<&mut T> { + let spawner = Spawner::for_current_executor().await; + self.get_mut(spawner) + } + + /// Consumes the `SameExecutorCell`, returning the inner value if the provided `spawner` + /// matches the executor id associated with `self`. + /// + /// else returns `self` as recovery + pub fn into_inner(self, spawner: Spawner) -> Result { + if spawner.executor_id() == self.id { + Ok(self.inner) + } else { + Err(self) + } + } + + /// Consumes the `SameExecutorCell`, returning the inner value by the spawner of current async closure + /// + /// else returns `self` as recovery + pub async fn into_inner_async(self) -> Result { + let spawner = Spawner::for_current_executor().await; + self.into_inner(spawner) + } + + /// Returns the executor id + pub fn executor_id(&self) -> usize { + self.id + } +} + +impl Clone for SameExecutorCell { + fn clone(&self) -> Self { + Self { + id: self.id, + inner: self.inner.clone(), + } + } +} + +impl core::fmt::Debug for SameExecutorCell { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("SameExecutorCell") + .field("executor_id", &self.id) + .field("inner", &self.inner) // Only if T: Debug + .finish() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DelegateError { + LendInvalid, + WithInvalid, + ConsumedInvalid, +} + +#[repr(u8)] +pub enum DelegateState { + New = 0, + Lent = 1, + Consumed = 2, +} + +impl From for DelegateState { + fn from(value: u8) -> Self { + match value { + 0 => Self::New, + 1 => Self::Lent, + 2 => Self::Consumed, + _ => unreachable!(), + } + } +} + +type MutexSignal = Signal; + +pub struct Delegate { + send: MutexSignal>, + reply: MutexSignal<()>, + state: AtomicU8, + _not_send: PhantomData<*const ()>, +} + +unsafe impl Sync for Delegate {} + +impl Delegate { + #[must_use] + pub const fn new() -> Self { + Self { + send: Signal::new(), + reply: Signal::new(), + state: AtomicU8::new(DelegateState::New as u8), + _not_send: PhantomData, + } + } + + pub async fn lend<'a, 'b: 'a>(&'a self, target: &'b mut T) -> Result<(), DelegateError> { + use DelegateError::*; + use DelegateState::*; + + match self.state.compare_exchange( + New as u8, + Lent as u8, + core::sync::atomic::Ordering::AcqRel, + core::sync::atomic::Ordering::Acquire, + ) { + Ok(_) => {} + Err(_) => return Err(LendInvalid), + } + let sp = Spawner::for_current_executor().await; + let ptr = ptr::from_mut(target); + self.send.signal(SameExecutorCell::new(ptr, sp)); + + self.reply.wait().await; + let final_state = self.state.load(Ordering::Acquire); + if final_state != Consumed as u8 { + return Err(ConsumedInvalid); + } + Ok(()) + } + + pub async fn with(&self, func: impl FnOnce(&mut T) -> U) -> Result { + use DelegateError::*; + use DelegateState::*; + + let data = self.send.wait().await; + match self.state.compare_exchange( + Lent as u8, + Consumed as u8, + Ordering::AcqRel, + Ordering::Acquire, + ) { + Ok(_) => {} + Err(_) => return Err(WithInvalid), + } + + let sp = Spawner::for_current_executor().await; + let res = { + let ptr = unsafe { data.get(sp).unwrap().as_mut().unwrap() }; + func(ptr) + }; + + self.reply.signal(()); + Ok(res) + } + + pub fn reset(&self) { + use DelegateState::*; + + let cur_state = self.state.load(core::sync::atomic::Ordering::Acquire); + if cur_state == Lent as u8 { + panic!( + "Cannot reset Delegate while in LENT state: lend() called but with() has not completed." + ); + } + + // Case: + // 1. New: Refresh nothing. + // 2. Consumed: Refresh Send, Reset is `()`, refresh nothing. + if cur_state == New as u8 { + return; + } + + self.send.reset(); + self.state.store(New as u8, Ordering::Release); + } +} + +impl Default for Delegate { + fn default() -> Self { + Self::new() + } +} diff --git a/modules/axembassy/src/executor.rs b/modules/axembassy/src/executor.rs index 471f49ca7b..89d307eb6b 100644 --- a/modules/axembassy/src/executor.rs +++ b/modules/axembassy/src/executor.rs @@ -1,20 +1,11 @@ -use axtask::{park_current_task, unpark_task}; -use core::marker::PhantomData; -use core::sync::atomic::{AtomicBool, AtomicU64, Ordering}; -use core::u64; -use embassy_executor::{Spawner, raw}; -use log::{debug, info}; +use core::sync::atomic::{AtomicBool, Ordering}; +use embassy_executor::raw; -#[percpu::def_percpu] static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); #[unsafe(export_name = "__pender")] fn __pender(_context: *mut ()) { - SIGNAL_WORK_THREAD_MODE.with_current(|m| { - m.store(true, Ordering::SeqCst); - }); - let task_id = _context as u64; - unpark_task(task_id, true); + SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); } pub struct Executor { @@ -25,9 +16,8 @@ pub struct Executor { impl Executor { /// Create a new executor and initialize context with current task id pub fn new() -> Self { - let cur_id = axtask::current().id().as_u64(); Self { - inner: raw::Executor::new(cur_id as *mut ()), + inner: raw::Executor::new(core::ptr::null_mut()), not_send: PhantomData, } } @@ -44,13 +34,10 @@ impl Executor { loop { unsafe { self.inner.poll(); - let to_poll = SIGNAL_WORK_THREAD_MODE.with_current(|m| m.load(Ordering::Acquire)); - if to_poll { - SIGNAL_WORK_THREAD_MODE.with_current(|m| { - m.store(false, Ordering::SeqCst); - }); + if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) { + SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst); } else { - park_current_task(); + axhal::arch::wait_for_irqs(); } }; } diff --git a/modules/axembassy/src/executor_thread.rs b/modules/axembassy/src/executor_thread.rs new file mode 100644 index 0000000000..4bfbec4728 --- /dev/null +++ b/modules/axembassy/src/executor_thread.rs @@ -0,0 +1,57 @@ +use axtask::{park_current_task, unpark_task}; +use core::marker::PhantomData; +use core::sync::atomic::{AtomicBool, Ordering}; +use core::u64; +use embassy_executor::raw; + +#[percpu::def_percpu] +static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); + +#[unsafe(export_name = "__pender")] +fn __pender(_context: *mut ()) { + SIGNAL_WORK_THREAD_MODE.with_current(|m| { + m.store(true, Ordering::SeqCst); + }); + let id = _context as u64; + unpark_task(id, true); +} + +pub struct Executor { + inner: raw::Executor, + not_send: PhantomData<*mut ()>, +} + +impl Executor { + /// Create a new executor and initialize context with current task id + pub fn new() -> Self { + let cur_id = axtask::current().id().as_u64(); + Self { + inner: raw::Executor::new(cur_id as *mut ()), + not_send: PhantomData, + } + } + + /// Runs the executor. + /// + /// The `init` closure is called with a [`Spawner`] that spawns tasks on + /// this executor. Use it to spawn the initial task(s). After `init` returns, + /// the executor starts running the tasks. + /// + pub fn run(&'static mut self, init: impl FnOnce(embassy_executor::Spawner)) -> ! { + init(self.inner.spawner()); + + loop { + unsafe { + self.inner.poll(); + let to_poll = SIGNAL_WORK_THREAD_MODE.with_current(|m| m.load(Ordering::Acquire)); + if to_poll { + SIGNAL_WORK_THREAD_MODE.with_current(|m| { + m.store(false, Ordering::SeqCst); + }); + } else { + park_current_task(); + } + }; + } + } +} diff --git a/modules/axembassy/src/lib.rs b/modules/axembassy/src/lib.rs index e1707e17ec..dff3bcb0e5 100644 --- a/modules/axembassy/src/lib.rs +++ b/modules/axembassy/src/lib.rs @@ -1,51 +1,65 @@ -#![feature(impl_trait_in_assoc_type)] #![cfg_attr(not(test), no_std)] #![feature(doc_cfg)] +#![feature(doc_auto_cfg)] -extern crate alloc; -extern crate log; +cfg_if::cfg_if! { + if #[cfg(any(feature = "executor-thread", feature = "executor-single"))] { + extern crate alloc; + extern crate log; -#[cfg(feature = "executor")] -mod executor; -#[cfg(feature = "driver")] -mod time_driver; -// mod waker; -mod asynch; - -#[cfg(feature = "executor")] -pub use crate::asynch::{block_on, spawner}; -#[cfg(feature = "executor")] -pub use crate::executor::Executor; -use axtask::spawn_raw; -#[cfg(feature = "executor")] -#[doc(no_inline)] -pub use embassy_executor::*; -#[cfg(feature = "executor")] -#[doc(no_inline)] -pub use embassy_futures::*; + pub mod delegate; + pub mod asynch; -#[cfg(feature = "driver")] -pub use crate::time_driver::AxDriverAPI; + #[cfg(feature = "executor-thread")] + mod executor_thread; + #[cfg(feature = "executor-single")] + mod executor; -pub fn spawn_init() { - spawn_raw(init, "async".into(), 4096); -} + #[cfg(feature = "executor-thread")] + pub use crate::executor_thread::Executor; + #[cfg(feature = "executor-single")] + pub use crate::executor::Executor; -fn init() { - use static_cell::StaticCell; + pub use crate::asynch::{Spawner, SendSpawner}; + #[cfg(feature = "executor-thread")] + pub use crate::asynch::{spawner,block_on}; - static EXECUTOR: StaticCell = StaticCell::new(); - EXECUTOR - .init_with(Executor::new) - .run(|sp| sp.must_spawn(init_task())); -} + #[cfg(feature = "executor-thread")] + pub fn init_spawn() { + use axtask::spawn_raw; + spawn_raw(init, "async".into(), axconfig::TASK_STACK_SIZE); + } + + #[cfg(feature = "executor-thread")] + pub fn init() { + use crate::executor_thread::Executor; + use static_cell::StaticCell; -#[embassy_executor::task] -async fn init_task() { - use log::debug; + static EXECUTOR: StaticCell = StaticCell::new(); + EXECUTOR + .init_with(Executor::new) + .run(|sp| sp.must_spawn(init_task())); + } - let spawner = asynch::Spawner::for_current_executor().await; - asynch::set_spawner(spawner.make_send()); + #[cfg(feature = "executor-thread")] + #[embassy_executor::task] + async fn init_task() { + use axtask::unpark_task; + use log::info; - debug!("axembassy::init_task()"); + let spawner = asynch::Spawner::for_current_executor().await; + asynch::set_spawner(spawner.make_send()); + info!("spawner is set, unpark the main thread."); + unpark_task(2, true); + } + } } + +#[cfg(feature = "driver")] +mod time_driver; + +#[cfg(feature = "driver")] +pub use crate::time_driver::AxDriverAPI; + +#[cfg(all(feature = "executor-thread", feature = "executor-single"))] +compile_error!("feature `executor-thread` and `executor-single` are mutually exclusive"); diff --git a/modules/axembassy/src/waker/mod.rs b/modules/axembassy/src/waker/mod.rs deleted file mode 100644 index dc7d2dce2c..0000000000 --- a/modules/axembassy/src/waker/mod.rs +++ /dev/null @@ -1,126 +0,0 @@ -use alloc::collections::BTreeMap; -use alloc::sync::Arc; -use core::{ - pin::Pin, - sync::atomic::AtomicU64, - task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, -}; - -use axtask::{AxTaskRef, TaskId, current, park_current_task, unpark_task}; -use kspin::SpinNoIrq; - -static AX_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop); - -// unsafe fn clone(_data:*const ()) -> RawWaker { -// unsafe { Arc::increment_strong_count(_data as *const AxTaskRef) }; -// RawWaker::new(_data, &AX_WAKER_VTABLE) -// } - -// unsafe fn wake(_data:*const ()) { -// let task_ref = unsafe { Arc::from_raw(_data as *const AxTaskRef) }; -// let id = task_ref.id().as_u64(); - -// unpark_task(id); -// } - -// unsafe fn wake_by_ref(_data:*const ()) { -// let task_ref = unsafe { (_data as *const AxTaskRef).as_ref().unwrap() }; -// let id = task_ref.id().as_u64(); - -// unpark_task(id); -// } - -// unsafe fn drop(_data:*const ()) { -// unsafe { Arc::decrement_strong_count(_data as *const AxTaskRef) }; -// } -// -unsafe fn clone(_data: *const ()) -> RawWaker { - // trivial clone - RawWaker::new(_data, &AX_WAKER_VTABLE) -} - -unsafe fn wake(_data: *const ()) { - // Call Executor pender function - // signal_executor(); -} - -unsafe fn wake_by_ref(_data: *const ()) { - // Call Executor pender function - // signal_executor(); -} - -unsafe fn drop(_data: *const ()) { - // No resource to drop -} - -fn axtask_waker(task: &AxTaskRef) -> Waker { - let data = Arc::into_raw(task.clone()) as *const (); - let raw_waker = RawWaker::new(data, &AX_WAKER_VTABLE); - unsafe { Waker::from_raw(raw_waker) } -} - -fn executor_waker() -> Waker { - // No resource management - let data = core::ptr::null() as *const (); - let raw_waker = RawWaker::new(data, &AX_WAKER_VTABLE); - unsafe { Waker::from_raw(raw_waker) } -} - -/// Minimal Design -pub fn async_task_run(future: impl Future) { - let curr_task = current().as_task_ref().clone(); - let waker = axtask_waker(&curr_task); - let mut cx = Context::from_waker(&waker); - let mut pinned = core::pin::pin!(future); - - loop { - match pinned.as_mut().poll(&mut cx) { - Poll::Ready(()) => { - break; - } - Poll::Pending => { - // Yield the current task to allow other tasks to run - park_current_task(); - // Switch to the current task again - // Repeat the loop to poll - } - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct EventId(u64); - -static EVENT_ID: AtomicU64 = AtomicU64::new(0); - -impl EventId { - pub fn new() -> Self { - EventId(EVENT_ID.fetch_add(1, core::sync::atomic::Ordering::Relaxed)) - } -} - -impl From for EventId { - fn from(value: u64) -> Self { - EventId(value) - } -} - -type TaskWaker = (Waker, u64); -static PENDING_WAKERS: SpinNoIrq> = SpinNoIrq::new(BTreeMap::new()); - -fn register_waker(waker: Waker, task_id: u64) { - let id = EventId::new(); - PENDING_WAKERS.lock().insert(id, (waker, task_id)); -} - -fn unregister_waker(id: EventId) { - PENDING_WAKERS.lock().remove(&id); -} - -pub fn signal_event(id: EventId) { - let mut pending_wakers = PENDING_WAKERS.lock(); - if let Some((waker, task_id)) = pending_wakers.remove(&id) { - waker.wake_by_ref(); - unpark_task(task_id, true); - } -} diff --git a/modules/axruntime/src/lib.rs b/modules/axruntime/src/lib.rs index 13a81ccb8c..94c17d8e31 100644 --- a/modules/axruntime/src/lib.rs +++ b/modules/axruntime/src/lib.rs @@ -151,10 +151,10 @@ pub extern "C" fn rust_main(cpu_id: usize, dtb: usize) -> ! { axhal::platform_init(); #[cfg(feature = "multitask")] - axtask::init_scheduler(); - - #[cfg(feature = "embassy-timer")] - axembassy::spawn_init(); + { + axtask::init_scheduler(); + axembassy::init_spawn(); + } #[cfg(any(feature = "fs", feature = "net", feature = "display"))] { @@ -195,13 +195,14 @@ pub extern "C" fn rust_main(cpu_id: usize, dtb: usize) -> ! { core::hint::spin_loop(); } - // #[cfg(feature = "embassy-timer")] - // { - // use axembassy::init; - // init(); - // } - - unsafe { main() }; + unsafe { + #[cfg(feature = "multitask")] + { + // park main task to let embassy task initialize first + axtask::park_current_task() + } + main() + }; #[cfg(feature = "multitask")] axtask::exit(0); diff --git a/modules/axtask/src/api.rs b/modules/axtask/src/api.rs index 059c8e33d6..9fa3bae7c1 100644 --- a/modules/axtask/src/api.rs +++ b/modules/axtask/src/api.rs @@ -10,13 +10,14 @@ pub(crate) use crate::run_queue::{current_run_queue, select_run_queue}; pub use crate::task::{CurrentTask, TaskId, TaskInner}; #[doc(cfg(feature = "multitask"))] pub use crate::task_ext::{TaskExtMut, TaskExtRef}; -use crate::task_registry::{register_task, unregister_task}; #[doc(cfg(feature = "multitask"))] -pub use crate::wait_queue::WaitQueue; +pub use crate::task_registry::{find_task_by_id, park_current_task, unpark_task}; #[doc(cfg(feature = "multitask"))] -pub use crate::wait_queues::{Futex,futex_wait,futex_wake,futex_wake_all}; +pub use crate::wait_queue::WaitQueue; #[doc(cfg(feature = "multitask"))] -pub use crate::task_registry::{find_task_by_id, unpark_task, park_current_task}; +pub use crate::wait_queues::{Futex, futex_wait, futex_wake, futex_wake_all}; + +pub static THREAD_START_EVENT: crate::events::Event = crate::events::Event::new(); /// The reference type of a task. pub type AxTaskRef = Arc; @@ -108,7 +109,6 @@ pub fn on_timer_tick() { pub fn spawn_task(task: TaskInner) -> AxTaskRef { let task_ref = task.into_arc(); select_run_queue::(&task_ref).add_task(task_ref.clone()); - register_task(task_ref.clone()); task_ref } diff --git a/modules/axtask/src/events.rs b/modules/axtask/src/events.rs new file mode 100644 index 0000000000..b1ce321625 --- /dev/null +++ b/modules/axtask/src/events.rs @@ -0,0 +1,86 @@ +use kspin::SpinNoIrq; + +use crate::WaitQueue; + +pub struct Event { + state: SpinNoIrq, +} + +unsafe impl Sync for Event {} + +#[derive(Debug)] +enum LockState { + Unlocked, + Locked(WaitQueue), +} + +impl Default for LockState { + fn default() -> Self { + LockState::Locked(WaitQueue::new()) + } +} + +impl Event { + #[must_use] + pub const fn new() -> Self { + Self { + state: SpinNoIrq::new(LockState::Locked(WaitQueue::new())), + } + } + + #[must_use] + pub const fn new_set() -> Self { + Self { + state: SpinNoIrq::new(LockState::Unlocked), + } + } + + /// Return wether the [`Event`] is set or not + pub fn is_set(&self) -> bool { + match *self.state.lock() { + LockState::Unlocked => true, + _ => false, + } + } + + pub fn wait(&self) { + let state = &mut *self.state.lock(); + match state { + LockState::Unlocked => {} + &mut LockState::Locked(ref wq) => { + wq.wait(); + } + } + } + + /// Clears the event (non-blocking). + /// + /// If the event was set, it will be cleared and the function returns true. + /// If the event was unset, the function returns false. + pub fn clear(&self) -> bool { + let state = &mut *self.state.lock(); + match state { + LockState::Unlocked => { + *state = LockState::Locked(WaitQueue::new()); + true + } + LockState::Locked(_) => false, + } + } + + pub fn set(&self) { + let state = &mut *self.state.lock(); + match state { + LockState::Unlocked => {} + &mut LockState::Locked(ref wq) => { + wq.notify_all(true); + } + } + } +} + +impl Default for Event { + fn default() -> Self { + Self::new() + } +} diff --git a/modules/axtask/src/lib.rs b/modules/axtask/src/lib.rs index a1c1dcec67..98c565b6e0 100644 --- a/modules/axtask/src/lib.rs +++ b/modules/axtask/src/lib.rs @@ -47,6 +47,7 @@ cfg_if::cfg_if! { mod api; mod wait_queue; mod wait_queues; + mod events; #[cfg(feature = "irq")] mod timers; diff --git a/modules/axtask/src/run_queue.rs b/modules/axtask/src/run_queue.rs index 0843d4abed..0b402c3149 100644 --- a/modules/axtask/src/run_queue.rs +++ b/modules/axtask/src/run_queue.rs @@ -238,6 +238,8 @@ impl AxRunQueueRef<'_, G> { self.inner.cpu_id ); assert!(task.is_ready()); + // Register task in registry. + register_task(task.clone()); self.inner.scheduler.lock().add_task(task); } @@ -683,6 +685,7 @@ pub(crate) fn init() { // Put the subsequent execution into the `main` task. let main_task = TaskInner::new_init("main".into()).into_arc(); main_task.set_state(TaskState::Running); + // Register main task due to `add_task` isn't called. register_task(main_task.clone()); debug!( "main task registered: {}, id {}", @@ -691,21 +694,8 @@ pub(crate) fn init() { ); unsafe { CurrentTask::init_current(main_task) } - // // Pub the embassy executor into the `async` task. - // let async_task = - // TaskInner::new(axembassy::init, "async".into(), IDLE_TASK_STACK_SIZE).into_arc(); - // async_task.set_state(TaskState::Running); - // register_task(async_task.clone()); - // debug!( - // "embassy async task registered: {}, id {}", - // async_task.id_name(), - // async_task.id().as_u64() - // ); - RUN_QUEUE.with_current(|rq| { rq.init_once(AxRunQueue::new(cpu_id)); - // let rq_ = rq.get().unwrap(); - // rq_.scheduler.lock().add_task(async_task); }); unsafe { RUN_QUEUES[cpu_id].write(RUN_QUEUE.current_ref_mut_raw()); diff --git a/modules/axtask/src/task.rs b/modules/axtask/src/task.rs index 775897a3e6..82429d23c0 100644 --- a/modules/axtask/src/task.rs +++ b/modules/axtask/src/task.rs @@ -14,6 +14,7 @@ use axhal::arch::TaskContext; use axhal::tls::TlsArea; use crate::task_ext::AxTaskExt; +use crate::task_registry::register_task; use crate::{AxCpuMask, AxTask, AxTaskRef, WaitQueue}; /// A unique identifier for a thread. @@ -99,7 +100,8 @@ impl From for TaskState { 1 => Self::Running, 2 => Self::Ready, 3 => Self::Blocked, - 4 => Self::Exited, + 4 => Self::Parked, + 5 => Self::Exited, _ => unreachable!(), } } diff --git a/modules/axtask/src/wait_queue.rs b/modules/axtask/src/wait_queue.rs index ce8b21ddaa..c400d87e15 100644 --- a/modules/axtask/src/wait_queue.rs +++ b/modules/axtask/src/wait_queue.rs @@ -1,3 +1,5 @@ +use core::fmt; + use alloc::collections::VecDeque; use alloc::sync::Arc; @@ -203,6 +205,16 @@ impl WaitQueue { } } +impl fmt::Debug for WaitQueue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let wq = self.queue.lock(); + match wq.front() { + Some(task) => task.fmt(f), + None => f.write_str("empty"), + } + } +} + fn unblock_one_task(task: AxTaskRef, resched: bool) { // Mark task as not in wait queue. task.set_in_wait_queue(false); diff --git a/ulib/axasync/Cargo.toml b/ulib/axasync/Cargo.toml new file mode 100644 index 0000000000..c091563908 --- /dev/null +++ b/ulib/axasync/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "axasync" +version.workspace = true +edition.workspace = true +authors = [""] +description = "ArceOS user library with an interface similar to rust std" +license.workspace = true +homepage.workspace = true +repository = "https://github.com/arceos-org/arceos/tree/main/ulib/axasync" + +[features] +default = [] + +single = ["axfeat/async-single", "arceos_api/async-single"] +thread = ["axfeat/async-thread", "arceos_api/async-thread"] + +[dependencies] +axfeat = { workspace = true } +arceos_api = { workspace = true } + +embassy-executor = { git = "https://github.com/embassy-rs/embassy", branch = "main", default-features = false, optional = true } +embassy-futures = { version = "0.1.1", optional = true } +embassy-sync = { version = "0.7.0", optional = true } + +cfg-if = "1.0.0" +static_cell = "2.1.0" diff --git a/ulib/axasync/src/lib.rs b/ulib/axasync/src/lib.rs new file mode 100644 index 0000000000..f4baf61a11 --- /dev/null +++ b/ulib/axasync/src/lib.rs @@ -0,0 +1,11 @@ +#![cfg_attr(all(not(test), not(doc)), no_std)] +#![feature(doc_cfg)] +#![feature(doc_auto_cfg)] + +use arceos_api::embassy_async as api; + +#[cfg(any(feature = "thread", feature = "single"))] +pub use api::{AxExecutor as Executor, AxSpawner as Spawner}; + +#[cfg(feature = "thread")] +pub use api::{AxSendSpawner as SendSpawner, ax_block_on as block_on, ax_spawner as spawner}; diff --git a/ulib/axstd/Cargo.toml b/ulib/axstd/Cargo.toml index aea7fb6d2d..3323281909 100644 --- a/ulib/axstd/Cargo.toml +++ b/ulib/axstd/Cargo.toml @@ -45,9 +45,6 @@ sched_fifo = ["axfeat/sched_fifo"] sched_rr = ["axfeat/sched_rr"] sched_cfs = ["axfeat/sched_cfs"] -# Embassy Timer -embassy-timer = ["axfeat/embassy-timer"] - # File system fs = ["arceos_api/fs", "axfeat/fs"] myfs = ["arceos_api/myfs", "axfeat/myfs"] diff --git a/ulib/axstd/src/lib.rs b/ulib/axstd/src/lib.rs index 772b33c668..ce4824a17f 100644 --- a/ulib/axstd/src/lib.rs +++ b/ulib/axstd/src/lib.rs @@ -74,6 +74,4 @@ pub mod time; #[cfg(feature = "fs")] pub mod fs; #[cfg(feature = "net")] -pub mod net; - -pub use arceos_api::modules::axembassy::Executor; +pub mod net; \ No newline at end of file From a683d24570d853c5c11cb707a4567298c594da5c Mon Sep 17 00:00:00 2001 From: lvyuemeng Date: Mon, 2 Jun 2025 20:03:11 +0800 Subject: [PATCH 07/11] [feat]: fully construct interface of axasync for embassy --- Cargo.lock | 35 +++----- Cargo.toml | 3 +- api/axfeat/Cargo.toml | 4 + examples/embassy-local/Cargo.toml | 11 --- .../.axconfig.toml | 0 examples/embassy-single/Cargo.toml | 10 +++ examples/embassy-single/src/main.rs | 47 +++++++++++ examples/embassy-thread/.axconfig.toml | 81 +++++++++++++++++++ examples/embassy-thread/Cargo.toml | 10 +++ .../src/main.rs | 36 +++------ modules/axembassy/src/executor.rs | 2 + modules/axembassy/src/lib.rs | 16 ++-- modules/axembassy/src/time_driver.rs | 8 +- modules/axsync/src/lib.rs | 3 + ulib/axasync/Cargo.toml | 12 ++- ulib/axasync/src/lib.rs | 34 +++++++- 16 files changed, 234 insertions(+), 78 deletions(-) delete mode 100644 examples/embassy-local/Cargo.toml rename examples/{embassy-local => embassy-single}/.axconfig.toml (100%) create mode 100644 examples/embassy-single/Cargo.toml create mode 100644 examples/embassy-single/src/main.rs create mode 100644 examples/embassy-thread/.axconfig.toml create mode 100644 examples/embassy-thread/Cargo.toml rename examples/{embassy-local => embassy-thread}/src/main.rs (60%) diff --git a/Cargo.lock b/Cargo.lock index 84c5d40208..e617c917b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -247,8 +247,9 @@ dependencies = [ "axfeat", "cfg-if", "embassy-executor", - "embassy-futures 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "embassy-sync 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "embassy-futures", + "embassy-sync", + "embassy-time", "static_cell", ] @@ -390,8 +391,8 @@ dependencies = [ "axtask", "cfg-if", "embassy-executor", - "embassy-futures 0.1.1 (git+https://github.com/embassy-rs/embassy?branch=main)", - "embassy-sync 0.7.0 (git+https://github.com/embassy-rs/embassy?branch=main)", + "embassy-futures", + "embassy-sync", "embassy-time-driver", "embassy-time-queue-utils", "kspin", @@ -1042,32 +1043,24 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "embassy-futures" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067" - [[package]] name = "embassy-futures" version = "0.1.1" source = "git+https://github.com/embassy-rs/embassy?branch=main#c637ee7d79552d9b9bfa0c0f4199372975acc343" [[package]] -name = "embassy-local" +name = "embassy-single" version = "0.0.0" dependencies = [ "axasync", "axstd", "embassy-executor", - "embassy-time", ] [[package]] name = "embassy-sync" version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef1a8a1ea892f9b656de0295532ac5d8067e9830d49ec75076291fd6066b136" +source = "git+https://github.com/embassy-rs/embassy?branch=main#c637ee7d79552d9b9bfa0c0f4199372975acc343" dependencies = [ "cfg-if", "critical-section", @@ -1078,16 +1071,12 @@ dependencies = [ ] [[package]] -name = "embassy-sync" -version = "0.7.0" -source = "git+https://github.com/embassy-rs/embassy?branch=main#c637ee7d79552d9b9bfa0c0f4199372975acc343" +name = "embassy-thread" +version = "0.0.0" dependencies = [ - "cfg-if", - "critical-section", - "embedded-io-async", - "futures-sink", - "futures-util", - "heapless 0.8.0", + "axasync", + "axstd", + "embassy-executor", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0420d3482f..ca707bff6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,8 @@ members = [ "examples/httpserver", "examples/httpserver", "examples/shell", - "examples/embassy-local", + "examples/embassy-thread", + "examples/embassy-single", ] [workspace.package] diff --git a/api/axfeat/Cargo.toml b/api/axfeat/Cargo.toml index 5023c4c47e..b67b518fab 100644 --- a/api/axfeat/Cargo.toml +++ b/api/axfeat/Cargo.toml @@ -48,12 +48,16 @@ async-thread = [ "axembassy/driver", "axembassy/executor-thread", "axruntime/embassy-timer", + "multitask", + "irq", ] # Embassy asynchronous runtime depended on irq with single thread support async-single = [ "axembassy/driver", "axembassy/executor-single", "axruntime/embassy-timer", + "alloc", + "irq", ] # File system diff --git a/examples/embassy-local/Cargo.toml b/examples/embassy-local/Cargo.toml deleted file mode 100644 index bac4301623..0000000000 --- a/examples/embassy-local/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "embassy-local" -authors = ["nostalgia "] -edition.workspace = true - -[dependencies] -axstd = { workspace = true, features = ["alloc", "multitask"], optional = true } -axasync = { workspace = true, features = ["thread"] } - -embassy-executor = { git = "https://github.com/embassy-rs/embassy", branch = "main", default-features = false } -embassy-time = { git = "https://github.com/embassy-rs/embassy", branch = "main" } diff --git a/examples/embassy-local/.axconfig.toml b/examples/embassy-single/.axconfig.toml similarity index 100% rename from examples/embassy-local/.axconfig.toml rename to examples/embassy-single/.axconfig.toml diff --git a/examples/embassy-single/Cargo.toml b/examples/embassy-single/Cargo.toml new file mode 100644 index 0000000000..68fb900299 --- /dev/null +++ b/examples/embassy-single/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "embassy-single" +authors = ["nostalgia "] +edition.workspace = true + +[dependencies] +axstd = { workspace = true, optional = true } +axasync = { workspace = true, features = ["single", "time"] } + +embassy-executor = { git = "https://github.com/embassy-rs/embassy", branch = "main", default-features = false } diff --git a/examples/embassy-single/src/main.rs b/examples/embassy-single/src/main.rs new file mode 100644 index 0000000000..cdc5ec36da --- /dev/null +++ b/examples/embassy-single/src/main.rs @@ -0,0 +1,47 @@ +#![feature(impl_trait_in_assoc_type)] +#![cfg_attr(feature = "axstd", no_std)] +#![cfg_attr(feature = "axstd", no_main)] + +#[macro_use] +#[cfg(feature = "axstd")] +extern crate axstd as std; + +use axasync::cell::StaticCell; +use axasync::executor::Executor; +use axasync::time::Timer; +use core::hint::black_box; + +fn busy_work(nano: u64) -> u64 { + let mut total = 0; + for _ in 0..nano { + let mut x = 0; + for _ in 0..nano { + x += 1; + } + total = black_box(total + x); + } + total +} + +#[embassy_executor::task(pool_size = 4)] +async fn tick(_sec: u64, busy_nano: u64) { + for i in 0..10 { + println!("embassy tick {}: {}/s, {}", _sec, _sec * i, i); + busy_work(busy_nano); + Timer::after_secs(_sec).await; + } + panic!("tick finished"); +} + +static EXECUTOR: StaticCell = StaticCell::new(); + +#[cfg_attr(feature = "axstd", unsafe(no_mangle))] +fn main() { + println!("Embassy Test"); + let exec = EXECUTOR.init(Executor::new()); + exec.run(|sp| { + for i in 1..4 { + sp.spawn(tick(i, 0)).unwrap(); + } + }) +} diff --git a/examples/embassy-thread/.axconfig.toml b/examples/embassy-thread/.axconfig.toml new file mode 100644 index 0000000000..42465c83b4 --- /dev/null +++ b/examples/embassy-thread/.axconfig.toml @@ -0,0 +1,81 @@ +# Architecture identifier. +arch = "riscv64" # str +# Platform identifier. +platform = "riscv64-qemu-virt" # str +# Number of CPUs +smp = 1 # uint +# Stack size of each task. +task-stack-size = 0x40000 # uint +# Number of timer ticks per second (Hz). A timer tick may contain several timer +# interrupts. +ticks-per-sec = 100 # uint + +# +# Device specifications +# +[devices] +# MMIO regions with format (`base_paddr`, `size`). +mmio-regions = [ + [0x0010_1000, 0x1000], + [0x0c00_0000, 0x21_0000], + [0x1000_0000, 0x1000], + [0x1000_1000, 0x8000], + [0x3000_0000, 0x1000_0000], + [0x4000_0000, 0x4000_0000] +] # [(uint, uint)] +# End PCI bus number (`bus-range` property in device tree). +pci-bus-end = 0xff # uint +# Base physical address of the PCIe ECAM space. +pci-ecam-base = 0x3000_0000 # uint +# PCI device memory ranges (`ranges` property in device tree). +pci-ranges = [ + [0x0300_0000, 0x1_0000], + [0x4000_0000, 0x4000_0000], + [0x4_0000_0000, 0x4_0000_0000] +] # [(uint, uint)] +# rtc@101000 { +# interrupts = <0x0b>; +# interrupt-parent = <0x03>; +# reg = <0x00 0x101000 0x00 0x1000>; +# compatible = "google,goldfish-rtc"; +# }; +# RTC (goldfish) Address +rtc-paddr = 0x10_1000 # uint +# Timer interrupt frequency in Hz. +timer-frequency = 10_000_000 # uint +# VirtIO MMIO regions with format (`base_paddr`, `size`). +virtio-mmio-regions = [ + [0x1000_1000, 0x1000], + [0x1000_2000, 0x1000], + [0x1000_3000, 0x1000], + [0x1000_4000, 0x1000], + [0x1000_5000, 0x1000], + [0x1000_6000, 0x1000], + [0x1000_7000, 0x1000], + [0x1000_8000, 0x1000] +] # [(uint, uint)] + +# +# Platform configs +# +[plat] +# Platform family. +family = "riscv64-qemu-virt" # str +# Kernel address space base. +kernel-aspace-base = "0xffff_ffc0_0000_0000" # uint +# Kernel address space size. +kernel-aspace-size = "0x0000_003f_ffff_f000" # uint +# Base physical address of the kernel image. +kernel-base-paddr = 0x8020_0000 # uint +# Base virtual address of the kernel image. +kernel-base-vaddr = "0xffff_ffc0_8020_0000" # uint +# Offset of bus address and phys address. some boards, the bus address is +# different from the physical address. +phys-bus-offset = 0 # uint +# Base address of the whole physical memory. +phys-memory-base = 0x8000_0000 # uint +# Size of the whole physical memory. (128M) +phys-memory-size = 0x800_0000 # uint +# Linear mapping offset, for quick conversions between physical and virtual +# addresses. +phys-virt-offset = "0xffff_ffc0_0000_0000" # uint diff --git a/examples/embassy-thread/Cargo.toml b/examples/embassy-thread/Cargo.toml new file mode 100644 index 0000000000..818b3bd290 --- /dev/null +++ b/examples/embassy-thread/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "embassy-thread" +authors = ["nostalgia "] +edition.workspace = true + +[dependencies] +axstd = { workspace = true, features = ["multitask"], optional = true } +axasync = { workspace = true, features = ["thread", "time"] } + +embassy-executor = { git = "https://github.com/embassy-rs/embassy", branch = "main", default-features = false } diff --git a/examples/embassy-local/src/main.rs b/examples/embassy-thread/src/main.rs similarity index 60% rename from examples/embassy-local/src/main.rs rename to examples/embassy-thread/src/main.rs index ffbbb416a3..fff517919d 100644 --- a/examples/embassy-local/src/main.rs +++ b/examples/embassy-thread/src/main.rs @@ -6,40 +6,30 @@ #[cfg(feature = "axstd")] extern crate axstd as std; -use axasync::spawner; +use axasync::executor::spawner; +use axasync::time::Timer; +use core::hint::black_box; use std::time::Duration; -use std::{ - boxed::Box, - thread::{self, sleep}, -}; +use std::thread::{self, sleep}; -fn busy_work() { - for _ in 0..1000 { +fn busy_work(nano: u64) -> u64 { + let mut total = 0; + for _ in 0..nano { let mut x = 0; - for _ in 0..1000 { + for _ in 0..nano { x += 1; } + total = black_box(total + x); } -} - -fn tick_raw(_sec: u64, busy_nano: u64) -> embassy_executor::SpawnToken { - let task = Box::leak(Box::new(embassy_executor::raw::TaskStorage::new())); - task.spawn(move || async move { - for i in 0..10 { - println!("embassy tick: {}/s, {} times", _sec * i, i); - busy_work(); - embassy_time::Timer::after_secs(_sec).await; - } - panic!("tick finished"); - }) + total } #[embassy_executor::task] async fn tick(_sec: u64, busy_nano: u64) { for i in 0..10 { println!("embassy tick: {}/s, {} times", _sec * i, i); - busy_work(); - embassy_time::Timer::after_secs(_sec).await; + busy_work(busy_nano); + Timer::after_secs(_sec).await; } panic!("tick finished"); } @@ -59,6 +49,6 @@ fn main() { } spawner().spawn(tick(1, 0)).unwrap(); - // Avoid + // Avoid shut down immediately sleep(Duration::from_millis(1000 * 15 as u64)); } diff --git a/modules/axembassy/src/executor.rs b/modules/axembassy/src/executor.rs index 89d307eb6b..c2f0d8fd0a 100644 --- a/modules/axembassy/src/executor.rs +++ b/modules/axembassy/src/executor.rs @@ -1,4 +1,5 @@ use core::sync::atomic::{AtomicBool, Ordering}; +use core::marker::PhantomData; use embassy_executor::raw; static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); @@ -34,6 +35,7 @@ impl Executor { loop { unsafe { self.inner.poll(); + if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) { SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst); } else { diff --git a/modules/axembassy/src/lib.rs b/modules/axembassy/src/lib.rs index dff3bcb0e5..f80b26f856 100644 --- a/modules/axembassy/src/lib.rs +++ b/modules/axembassy/src/lib.rs @@ -7,22 +7,22 @@ cfg_if::cfg_if! { extern crate alloc; extern crate log; + mod asynch; pub mod delegate; - pub mod asynch; #[cfg(feature = "executor-thread")] mod executor_thread; - #[cfg(feature = "executor-single")] - mod executor; - #[cfg(feature = "executor-thread")] pub use crate::executor_thread::Executor; + #[cfg(feature = "executor-thread")] + pub use crate::asynch::{spawner,block_on,Spawner,SendSpawner}; + + #[cfg(feature = "executor-single")] + mod executor; #[cfg(feature = "executor-single")] pub use crate::executor::Executor; - - pub use crate::asynch::{Spawner, SendSpawner}; - #[cfg(feature = "executor-thread")] - pub use crate::asynch::{spawner,block_on}; + #[cfg(feature = "executor-single")] + pub use crate::asynch::Spawner; #[cfg(feature = "executor-thread")] pub fn init_spawn() { diff --git a/modules/axembassy/src/time_driver.rs b/modules/axembassy/src/time_driver.rs index bfe0f0c3d5..73c3f10b8b 100644 --- a/modules/axembassy/src/time_driver.rs +++ b/modules/axembassy/src/time_driver.rs @@ -66,23 +66,23 @@ impl AxDriver { let nanos_period = *self.periodic_interval_nanos.lock(); if nanos_next_interval < nanos_period { // only set timer if it is less than the periodic interval - set_oneshot_timer(ticks_to_nanos(ticks_next_at)); + set_oneshot_timer(nanos_next_at); } } } /// Dequeue expired timer and return nanos of next expiration pub fn next_expiration(&self, period: u64) -> u64 { - let queue_guard = AX_DRIVER.queue.lock(); + let queue_guard = self.queue.lock(); let mut queue = queue_guard.borrow_mut(); if *self.periodic_interval_nanos.lock() == 0 { *self.periodic_interval_nanos.lock() = period; } - let ticks_now = AX_DRIVER.now(); + let ticks_now = self.now(); let ticks_next_expired = queue.next_expiration(ticks_now); - let nanos_next_expired = nanos_to_ticks(ticks_next_expired); + let nanos_next_expired = ticks_to_nanos(ticks_next_expired); nanos_next_expired } } diff --git a/modules/axsync/src/lib.rs b/modules/axsync/src/lib.rs index 690ec5b26d..092731dde1 100644 --- a/modules/axsync/src/lib.rs +++ b/modules/axsync/src/lib.rs @@ -18,11 +18,14 @@ pub use kspin as spin; #[cfg(feature = "multitask")] mod mutex; +#[cfg(feature = "multitask")] mod condvar; #[cfg(feature = "multitask")] #[doc(cfg(feature = "multitask"))] pub use self::mutex::{Mutex, MutexGuard}; +#[cfg(feature = "multitask")] +#[doc(cfg(feature = "multitask"))] pub use self::condvar::Condvar; #[cfg(not(feature = "multitask"))] diff --git a/ulib/axasync/Cargo.toml b/ulib/axasync/Cargo.toml index c091563908..74d91c7ae1 100644 --- a/ulib/axasync/Cargo.toml +++ b/ulib/axasync/Cargo.toml @@ -11,16 +11,20 @@ repository = "https://github.com/arceos-org/arceos/tree/main/ulib/axasync" [features] default = [] -single = ["axfeat/async-single", "arceos_api/async-single"] -thread = ["axfeat/async-thread", "arceos_api/async-thread"] +single = ["axfeat/async-single", "arceos_api/async-single","dep:embassy-executor"] +thread = ["axfeat/async-thread", "arceos_api/async-thread","dep:embassy-executor"] + +time = ["dep:embassy-time"] +sync = ["dep:embassy-sync"] [dependencies] axfeat = { workspace = true } arceos_api = { workspace = true } embassy-executor = { git = "https://github.com/embassy-rs/embassy", branch = "main", default-features = false, optional = true } -embassy-futures = { version = "0.1.1", optional = true } -embassy-sync = { version = "0.7.0", optional = true } +embassy-futures = { git = "https://github.com/embassy-rs/embassy", branch = "main" } +embassy-sync = { git = "https://github.com/embassy-rs/embassy", branch = "main", optional = true } +embassy-time = { git = "https://github.com/embassy-rs/embassy", branch = "main",optional = true } cfg-if = "1.0.0" static_cell = "2.1.0" diff --git a/ulib/axasync/src/lib.rs b/ulib/axasync/src/lib.rs index f4baf61a11..180cf672a3 100644 --- a/ulib/axasync/src/lib.rs +++ b/ulib/axasync/src/lib.rs @@ -2,10 +2,36 @@ #![feature(doc_cfg)] #![feature(doc_auto_cfg)] -use arceos_api::embassy_async as api; +#[cfg(any(feature = "thread", feature = "single"))] +pub mod executor { + use arceos_api::embassy_async as api; + + pub use api::AxExecutor as Executor; + pub use embassy_executor::*; + + #[cfg(feature = "thread")] + pub use api::{ax_block_on as block_on, ax_spawner as spawner}; +} #[cfg(any(feature = "thread", feature = "single"))] -pub use api::{AxExecutor as Executor, AxSpawner as Spawner}; +pub use embassy_executor; + +#[cfg(feature = "time")] +pub mod time { + pub use embassy_time::*; +} + +#[cfg(feature = "sync")] +pub mod sync { + pub use embassy_sync::*; +} + +pub mod cell { + pub use static_cell::{ConstStaticCell, StaticCell}; +} + +#[cfg(not(any(feature = "thread", feature = "single")))] +compile_error!(r#"must select one of "executor-thread" or "executor-single""#); -#[cfg(feature = "thread")] -pub use api::{AxSendSpawner as SendSpawner, ax_block_on as block_on, ax_spawner as spawner}; +#[cfg(all(feature = "thread", feature = "single"))] +compile_error!(r#"feature "executor-thread" and "executor-single" are mutually exclusive"#); From d93484c551a8b12e2a7016c35f29611cc8932a92 Mon Sep 17 00:00:00 2001 From: lvyuemeng Date: Fri, 6 Jun 2025 23:13:15 +0800 Subject: [PATCH 08/11] [feat]: complete embassy-thread test fully --- Cargo.lock | 1 + examples/embassy-thread/Cargo.toml | 1 + examples/embassy-thread/src/main.rs | 133 +++++++++++++++++++---- modules/axembassy/src/executor_thread.rs | 4 +- modules/axembassy/src/time_driver.rs | 4 - ulib/axasync/src/lib.rs | 4 +- 6 files changed, 114 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e617c917b2..d61463f654 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1077,6 +1077,7 @@ dependencies = [ "axasync", "axstd", "embassy-executor", + "log", ] [[package]] diff --git a/examples/embassy-thread/Cargo.toml b/examples/embassy-thread/Cargo.toml index 818b3bd290..8721c9516c 100644 --- a/examples/embassy-thread/Cargo.toml +++ b/examples/embassy-thread/Cargo.toml @@ -8,3 +8,4 @@ axstd = { workspace = true, features = ["multitask"], optional = true } axasync = { workspace = true, features = ["thread", "time"] } embassy-executor = { git = "https://github.com/embassy-rs/embassy", branch = "main", default-features = false } +log = "=0.4.21" \ No newline at end of file diff --git a/examples/embassy-thread/src/main.rs b/examples/embassy-thread/src/main.rs index fff517919d..36aaa5fdcb 100644 --- a/examples/embassy-thread/src/main.rs +++ b/examples/embassy-thread/src/main.rs @@ -7,48 +7,133 @@ extern crate axstd as std; use axasync::executor::spawner; +use axasync::executor::yield_now; use axasync::time::Timer; use core::hint::black_box; -use std::time::Duration; use std::thread::{self, sleep}; +use std::time::Duration; + +fn busy_work(iters: u64) -> u64 { + let mut total = 0; + for _ in 0..iters { + total = black_box(total + 1); + total = black_box(total * 3 / 2); + } + black_box(total) +} -fn busy_work(nano: u64) -> u64 { +async fn async_busy_work(iters: u64) -> u64 { let mut total = 0; - for _ in 0..nano { - let mut x = 0; - for _ in 0..nano { - x += 1; + for _ in 0..iters { + total = black_box(total + 1); + total = black_box(total * 3 / 2); + yield_now().await; + } + black_box(total) +} + +macro_rules! task_loop { + ( + task_type: $task_type:literal, + id: $id:expr, + sleep: $sleep_fn:expr, + // millis restriction + millis: $millis:expr, + $(is_await: $await_tt:tt,)? + busy_work: $busy_work:expr, + busy_iters: $busy_iters:expr, + ) => { + use std::time::{Instant,Duration}; + use log; + use core::hint::black_box; + + let mut cnt = 0; + let mut last_report = Instant::now(); + let millis = Duration::from_millis($millis); + + loop { + let iter_start = Instant::now(); + cnt += 1; + + if $busy_iters > 0 { + let busy_start = Instant::now(); + let _res = black_box($busy_work($busy_iters)); + let busy_dur = Instant::now() - busy_start; + log::info!( + "{} {}: duration {}/ns", + $task_type, + $id, + busy_dur.as_nanos() + ) + } + + $sleep_fn($millis)$(.$await_tt)?; + + let iter_end = Instant::now(); + let iter_dur = iter_end - iter_start; + let full_dur = iter_end - last_report; + + log::info!( + "{} {}: Iteration {}, expected {}/ns, actual {}/ns, full {}/ns", + $task_type, + $id, + cnt, + millis.as_nanos(), + iter_dur.as_nanos(), + full_dur.as_nanos(), + ); + + last_report = iter_end; } - total = black_box(total + x); + }; +} + +#[embassy_executor::task(pool_size = 5)] +async fn async_tick(id: u64, millis: u64, busy_iters: u64) { + task_loop! { + task_type: "ASYNC_TASK_REPORT", + id:id, + sleep: |millis| async move {Timer::after_millis(millis).await}, + millis:millis, + is_await: await, + busy_work: async_busy_work, + busy_iters:busy_iters, } - total } -#[embassy_executor::task] -async fn tick(_sec: u64, busy_nano: u64) { - for i in 0..10 { - println!("embassy tick: {}/s, {} times", _sec * i, i); - busy_work(busy_nano); - Timer::after_secs(_sec).await; +fn thread_tick(id: u64, millis: u64, busy_iters: u64) { + task_loop! { + task_type: "NATIVE_THREAD", + id:id, + sleep: |millis| sleep(Duration::from_millis(millis)), + millis:millis, + busy_work: busy_work, + busy_iters:busy_iters, } - panic!("tick finished"); } +const NUM_THREADS: u64 = 5; +const NUM_TASKS: u64 = 5; +// const NUM_ITERS_THREADS: u64 = 1_000_000; +const NUM_ITERS_THREADS: u64 = 0; +// const NUM_ITERS_TASKS: u64 = 1000; +// const NUM_ITERS_TASKS: u64 = 1000_000; +const NUM_ITERS_TASKS: u64 = 0; + #[cfg_attr(feature = "axstd", unsafe(no_mangle))] fn main() { - println!("Embassy Test"); - for i in 1..4 { - println!("spawned thread {}", i); + log::info!("Embassy Test"); + for i in 1..NUM_THREADS { thread::spawn(move || { - for j in 0..5 { - println!("thread {} tick: {}/s {} times", i, j * i, j); - sleep(Duration::from_millis(1000 * i as u64)); - } - println!("thread {} finished", i); + thread_tick(i, i * 1000, NUM_ITERS_THREADS); }); } - spawner().spawn(tick(1, 0)).unwrap(); + for i in 1..NUM_TASKS { + spawner() + .spawn(async_tick(i, i * 1000, NUM_ITERS_TASKS)) + .unwrap(); + } // Avoid shut down immediately sleep(Duration::from_millis(1000 * 15 as u64)); } diff --git a/modules/axembassy/src/executor_thread.rs b/modules/axembassy/src/executor_thread.rs index 4bfbec4728..e89099a5e3 100644 --- a/modules/axembassy/src/executor_thread.rs +++ b/modules/axembassy/src/executor_thread.rs @@ -43,8 +43,8 @@ impl Executor { loop { unsafe { self.inner.poll(); - let to_poll = SIGNAL_WORK_THREAD_MODE.with_current(|m| m.load(Ordering::Acquire)); - if to_poll { + let polled = SIGNAL_WORK_THREAD_MODE.with_current(|m| m.load(Ordering::Acquire)); + if polled { SIGNAL_WORK_THREAD_MODE.with_current(|m| { m.store(false, Ordering::SeqCst); }); diff --git a/modules/axembassy/src/time_driver.rs b/modules/axembassy/src/time_driver.rs index 73c3f10b8b..dcdce5b252 100644 --- a/modules/axembassy/src/time_driver.rs +++ b/modules/axembassy/src/time_driver.rs @@ -8,10 +8,6 @@ use embassy_time_driver::TICK_HZ; use embassy_time_driver::{Driver, time_driver_impl}; use embassy_time_queue_utils::Queue; -/// Next scheduler tick -#[percpu::def_percpu] -static NANOS_NEXT_SCHED: SpinNoIrq = SpinNoIrq::new(0); - /// Manipulation of Global `AxDriver` pub struct AxDriverAPI; diff --git a/ulib/axasync/src/lib.rs b/ulib/axasync/src/lib.rs index 180cf672a3..26ead57f23 100644 --- a/ulib/axasync/src/lib.rs +++ b/ulib/axasync/src/lib.rs @@ -8,14 +8,12 @@ pub mod executor { pub use api::AxExecutor as Executor; pub use embassy_executor::*; + pub use embassy_futures::*; #[cfg(feature = "thread")] pub use api::{ax_block_on as block_on, ax_spawner as spawner}; } -#[cfg(any(feature = "thread", feature = "single"))] -pub use embassy_executor; - #[cfg(feature = "time")] pub mod time { pub use embassy_time::*; From 57e642d4b51fa7478df0d23483fc4bd2d5f2db63 Mon Sep 17 00:00:00 2001 From: lvyuemeng Date: Fri, 6 Jun 2025 23:14:51 +0800 Subject: [PATCH 09/11] [feat]: add analysis on embassy-thread --- .gitignore | 2 +- .../embassy-thread/analysis/.axconfig.toml | 81 +++++++++ examples/embassy-thread/analysis/analysis.py | 130 +++++++++++++ .../analysis/logs_100_000_000.txt | 171 ++++++++++++++++++ examples/embassy-thread/analysis/makefile | 27 +++ .../analysis/raw_logs_100_000_000.txt | 171 ++++++++++++++++++ .../analysis/summary_100_000_000.csv | 5 + examples/embassy-thread/src/main.rs | 13 +- 8 files changed, 594 insertions(+), 6 deletions(-) create mode 100644 examples/embassy-thread/analysis/.axconfig.toml create mode 100644 examples/embassy-thread/analysis/analysis.py create mode 100644 examples/embassy-thread/analysis/logs_100_000_000.txt create mode 100644 examples/embassy-thread/analysis/makefile create mode 100644 examples/embassy-thread/analysis/raw_logs_100_000_000.txt create mode 100644 examples/embassy-thread/analysis/summary_100_000_000.csv diff --git a/.gitignore b/.gitignore index 7838e7f45e..c3cea208f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ /target -examples/*/target +examples/**/target /.vscode .DS_Store *.asm diff --git a/examples/embassy-thread/analysis/.axconfig.toml b/examples/embassy-thread/analysis/.axconfig.toml new file mode 100644 index 0000000000..42465c83b4 --- /dev/null +++ b/examples/embassy-thread/analysis/.axconfig.toml @@ -0,0 +1,81 @@ +# Architecture identifier. +arch = "riscv64" # str +# Platform identifier. +platform = "riscv64-qemu-virt" # str +# Number of CPUs +smp = 1 # uint +# Stack size of each task. +task-stack-size = 0x40000 # uint +# Number of timer ticks per second (Hz). A timer tick may contain several timer +# interrupts. +ticks-per-sec = 100 # uint + +# +# Device specifications +# +[devices] +# MMIO regions with format (`base_paddr`, `size`). +mmio-regions = [ + [0x0010_1000, 0x1000], + [0x0c00_0000, 0x21_0000], + [0x1000_0000, 0x1000], + [0x1000_1000, 0x8000], + [0x3000_0000, 0x1000_0000], + [0x4000_0000, 0x4000_0000] +] # [(uint, uint)] +# End PCI bus number (`bus-range` property in device tree). +pci-bus-end = 0xff # uint +# Base physical address of the PCIe ECAM space. +pci-ecam-base = 0x3000_0000 # uint +# PCI device memory ranges (`ranges` property in device tree). +pci-ranges = [ + [0x0300_0000, 0x1_0000], + [0x4000_0000, 0x4000_0000], + [0x4_0000_0000, 0x4_0000_0000] +] # [(uint, uint)] +# rtc@101000 { +# interrupts = <0x0b>; +# interrupt-parent = <0x03>; +# reg = <0x00 0x101000 0x00 0x1000>; +# compatible = "google,goldfish-rtc"; +# }; +# RTC (goldfish) Address +rtc-paddr = 0x10_1000 # uint +# Timer interrupt frequency in Hz. +timer-frequency = 10_000_000 # uint +# VirtIO MMIO regions with format (`base_paddr`, `size`). +virtio-mmio-regions = [ + [0x1000_1000, 0x1000], + [0x1000_2000, 0x1000], + [0x1000_3000, 0x1000], + [0x1000_4000, 0x1000], + [0x1000_5000, 0x1000], + [0x1000_6000, 0x1000], + [0x1000_7000, 0x1000], + [0x1000_8000, 0x1000] +] # [(uint, uint)] + +# +# Platform configs +# +[plat] +# Platform family. +family = "riscv64-qemu-virt" # str +# Kernel address space base. +kernel-aspace-base = "0xffff_ffc0_0000_0000" # uint +# Kernel address space size. +kernel-aspace-size = "0x0000_003f_ffff_f000" # uint +# Base physical address of the kernel image. +kernel-base-paddr = 0x8020_0000 # uint +# Base virtual address of the kernel image. +kernel-base-vaddr = "0xffff_ffc0_8020_0000" # uint +# Offset of bus address and phys address. some boards, the bus address is +# different from the physical address. +phys-bus-offset = 0 # uint +# Base address of the whole physical memory. +phys-memory-base = 0x8000_0000 # uint +# Size of the whole physical memory. (128M) +phys-memory-size = 0x800_0000 # uint +# Linear mapping offset, for quick conversions between physical and virtual +# addresses. +phys-virt-offset = "0xffff_ffc0_0000_0000" # uint diff --git a/examples/embassy-thread/analysis/analysis.py b/examples/embassy-thread/analysis/analysis.py new file mode 100644 index 0000000000..d458aa36d8 --- /dev/null +++ b/examples/embassy-thread/analysis/analysis.py @@ -0,0 +1,130 @@ +import sys +import re +import csv +import os +from collections import defaultdict +from statistics import mean, stdev +from datetime import datetime + +LOG_PATTERNS = { + "async_report": { + "regex": r'ASYNC_TASK_REPORT (\d+): Iteration (\d+), expected (\d+)/ns, actual (\d+)/ns, full (\d+)/ns', + "id_key": "task_id", + "metrics": ["actual_ns", "full_ns"] + }, + "native_report": { + "regex": r'NATIVE_THREAD_REPORT (\d+): Iteration (\d+), expected (\d+)/ns, actual (\d+)/ns, full (\d+)/ns', + "id_key": "thread_id", + "metrics": ["actual_ns", "full_ns"] + } +} + +CSV_HEADERS = [ + "timestamp", + "log_type", + "metric_name", + "count", + "mean_absolute_deviation", + "std_deviation", + "min_deviation", + "max_deviation" +] + +def write_to_csv(deviation_data, log_path, csv_path): + timestamp = datetime.now().isoformat() + log_filename = os.path.basename(log_path) + + file_exists = os.path.exists(csv_path) + + try: + with open(csv_path, 'a', newline='') as csvfile: + writer = csv.writer(csvfile) + + # Write headers if file is new + if not file_exists: + writer.writerow(CSV_HEADERS) + + # Write data rows + for log_type, metrics in deviation_data.items(): + for metric_name, deviations in metrics.items(): + if deviations: # Only write if we have data + std_dev = stdev(deviations) if len(deviations) > 1 else 0 + + row = [ + timestamp, + log_type, + metric_name, + len(deviations), + round(mean(deviations),2), + round(std_dev,2), + min(deviations), + max(deviations) + ] + + writer.writerow(row) + + except Exception as e: + print(f"Error writing to CSV file '{csv_file_path}': {e}", file=sys.stderr) + sys.exit(1) + +def parse_log_file(path): + parsed_data = defaultdict(lambda: defaultdict(list)) + + patterns = {name: re.compile(config["regex"]) for name, config in LOG_PATTERNS.items()} + try: + with open(path, "r") as f: + for line in f: + for log_type, config in LOG_PATTERNS.items(): + match = patterns[log_type].search(line) + if match: + _id, _, expected, *metrics = map(int, match.groups()) + for key, value in zip(config["metrics"], metrics): + deviation = abs(value - expected) + parsed_data[log_type][key].append(deviation) + break + except FileNotFoundError: + print(f"Error: Log file '{path}' not found.", file=sys.stderr) + sys.exit(1) + except Exception as e: + print(f"An error occurred while parsing the log file: {e}", file=sys.stderr) + sys.exit(1) + + return parsed_data + +def summarize_deviation(deviation_data): + for log_type, metrics in deviation_data.items(): + print(f"--- {log_type} ---") + for metric_name, deviations in metrics.items(): + print(f" Metric: {metric_name}") + print(f" Count: {len(deviations)}") + print(f" Mean Absolute Deviation: {mean(deviations):.2f} ns") + print(f" Std Dev: {stdev(deviations):.2f} ns" if len(deviations) > 1 else " Std Dev: N/A") + print(f" Min: {min(deviations)} ns") + print(f" Max: {max(deviations)} ns") + print() + +def main(): + if len(sys.argv) not in [2, 3]: + print("Usage: python3 deviation_summary.py [output.csv]", file=sys.stderr) + print("If output.csv is not specified, defaults to 'deviation_summary.csv'", file=sys.stderr) + sys.exit(1) + + log_file_path = sys.argv[1] + csv_file_path = sys.argv[2] if len(sys.argv) == 3 else "summary.csv" + + try: + deviations = parse_log_file(sys.argv[1]) + + if not any(deviations.values()): + print("No matching log entries found in the file.", file=sys.stderr) + sys.exit(1) + + write_to_csv(deviations, log_file_path, csv_file_path) + + summarize_deviation(deviations) + except FileNotFoundError: + print(f"Error: File '{sys.argv[1]}' not found.", file=sys.stderr) + sys.exit(1) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/examples/embassy-thread/analysis/logs_100_000_000.txt b/examples/embassy-thread/analysis/logs_100_000_000.txt new file mode 100644 index 0000000000..429aa33dff --- /dev/null +++ b/examples/embassy-thread/analysis/logs_100_000_000.txt @@ -0,0 +1,171 @@ +make[1]: Entering directory '/home/nostalgia/Proj/RustProj/oscamp-arceos' +axconfig-gen configs/defconfig.toml configs/platforms/riscv64-qemu-virt.toml -w smp=1 -w arch=riscv64 -w platform=riscv64-qemu-virt -o "/home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/.axconfig.toml" -c "/home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/.axconfig.toml" + Building App: .., Arch: riscv64, Platform: riscv64-qemu-virt, App type: rust +cargo -C /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/../ build -Z unstable-options --target riscv64gc-unknown-none-elf --target-dir /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/target --release --features "axstd/log-level-info" +rust-objcopy --binary-architecture=riscv64 /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/..//.._riscv64-qemu-virt.elf --strip-all -O binary /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/..//.._riscv64-qemu-virt.bin + Running on qemu... +qemu-system-riscv64 -m 128M -smp 1 -machine virt -bios default -kernel /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/..//.._riscv64-qemu-virt.bin -nographic + +OpenSBI v1.5.1 + ____ _____ ____ _____ + / __ \ / ____| _ \_ _| + | | | |_ __ ___ _ __ | (___ | |_) || | + | | | | '_ \ / _ \ '_ \ \___ \| _ < | | + | |__| | |_) | __/ | | |____) | |_) || |_ + \____/| .__/ \___|_| |_|_____/|____/_____| + | | + |_| + +Platform Name : riscv-virtio,qemu +Platform Features : medeleg +Platform HART Count : 1 +Platform IPI Device : aclint-mswi +Platform Timer Device : aclint-mtimer @ 10000000Hz +Platform Console Device : uart8250 +Platform HSM Device : --- +Platform PMU Device : --- +Platform Reboot Device : syscon-reboot +Platform Shutdown Device : syscon-poweroff +Platform Suspend Device : --- +Platform CPPC Device : --- +Firmware Base : 0x80000000 +Firmware Size : 327 KB +Firmware RW Offset : 0x40000 +Firmware RW Size : 71 KB +Firmware Heap Offset : 0x49000 +Firmware Heap Size : 35 KB (total), 2 KB (reserved), 11 KB (used), 21 KB (free) +Firmware Scratch Size : 4096 B (total), 416 B (used), 3680 B (free) +Runtime SBI Version : 2.0 + +Domain0 Name : root +Domain0 Boot HART : 0 +Domain0 HARTs : 0* +Domain0 Region00 : 0x0000000000100000-0x0000000000100fff M: (I,R,W) S/U: (R,W) +Domain0 Region01 : 0x0000000010000000-0x0000000010000fff M: (I,R,W) S/U: (R,W) +Domain0 Region02 : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: () +Domain0 Region03 : 0x0000000080040000-0x000000008005ffff M: (R,W) S/U: () +Domain0 Region04 : 0x0000000080000000-0x000000008003ffff M: (R,X) S/U: () +Domain0 Region05 : 0x000000000c400000-0x000000000c5fffff M: (I,R,W) S/U: (R,W) +Domain0 Region06 : 0x000000000c000000-0x000000000c3fffff M: (I,R,W) S/U: (R,W) +Domain0 Region07 : 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X) +Domain0 Next Address : 0x0000000080200000 +Domain0 Next Arg1 : 0x0000000087e00000 +Domain0 Next Mode : S-mode +Domain0 SysReset : yes +Domain0 SysSuspend : yes + +Boot HART ID : 0 +Boot HART Domain : root +Boot HART Priv Version : v1.12 +Boot HART Base ISA : rv64imafdch +Boot HART ISA Extensions : sstc,zicntr,zihpm,zicboz,zicbom,sdtrig,svadu +Boot HART PMP Count : 16 +Boot HART PMP Granularity : 2 bits +Boot HART PMP Address Bits: 54 +Boot HART MHPM Info : 16 (0x0007fff8) +Boot HART Debug Triggers : 2 triggers +Boot HART MIDELEG : 0x0000000000001666 +Boot HART MEDELEG : 0x0000000000f0b509 + + d8888 .d88888b. .d8888b. + d88888 d88P" "Y88b d88P Y88b + d88P888 888 888 Y88b. + d88P 888 888d888 .d8888b .d88b. 888 888 "Y888b. + d88P 888 888P" d88P" d8P Y8b 888 888 "Y88b. + d88P 888 888 888 88888888 888 888 "888 + d8888888888 888 Y88b. Y8b. Y88b. .d88P Y88b d88P +d88P 888 888 "Y8888P "Y8888 "Y88888P" "Y8888P" + +arch = riscv64 +platform = riscv64-qemu-virt +target = riscv64gc-unknown-none-elf +build_mode = release +log_level = info +smp = 1 + +[ 0.050694 0 axruntime:130] Logging is enabled. +[ 0.051812 0 axruntime:131] Primary CPU 0 started, dtb = 0x87e00000. +[ 0.052271 0 axruntime:133] Found physcial memory regions: +[ 0.052769 0 axruntime:135] [PA:0x80200000, PA:0x8020e000) .text (READ | EXECUTE | RESERVED) +[ 0.053344 0 axruntime:135] [PA:0x8020e000, PA:0x80213000) .rodata (READ | RESERVED) +[ 0.053654 0 axruntime:135] [PA:0x80213000, PA:0x80216000) .data .tdata .tbss .percpu (READ | WRITE | RESERVED) +[ 0.054036 0 axruntime:135] [PA:0x80216000, PA:0x80256000) boot stack (READ | WRITE | RESERVED) +[ 0.054365 0 axruntime:135] [PA:0x80256000, PA:0x8025b000) .bss (READ | WRITE | RESERVED) +[ 0.054717 0 axruntime:135] [PA:0x8025b000, PA:0x88000000) free memory (READ | WRITE | FREE) +[ 0.055082 0 axruntime:135] [PA:0x101000, PA:0x102000) mmio (READ | WRITE | DEVICE | RESERVED) +[ 0.055422 0 axruntime:135] [PA:0xc000000, PA:0xc210000) mmio (READ | WRITE | DEVICE | RESERVED) +[ 0.055779 0 axruntime:135] [PA:0x10000000, PA:0x10001000) mmio (READ | WRITE | DEVICE | RESERVED) +[ 0.056121 0 axruntime:135] [PA:0x10001000, PA:0x10009000) mmio (READ | WRITE | DEVICE | RESERVED) +[ 0.056459 0 axruntime:135] [PA:0x30000000, PA:0x40000000) mmio (READ | WRITE | DEVICE | RESERVED) +[ 0.056817 0 axruntime:135] [PA:0x40000000, PA:0x80000000) mmio (READ | WRITE | DEVICE | RESERVED) +[ 0.057224 0 axruntime:220] Initialize global memory allocator... +[ 0.057516 0 axruntime:221] use TLSF allocator. +[ 0.059694 0 axruntime:150] Initialize platform devices... +[ 0.060215 0 axtask::api:79] Initialize scheduling... +[ 0.061812 0 axtask::api:85] use FIFO scheduler. +[ 0.062727 0 axruntime:179] Initialize interrupt handlers... +[ 0.063594 0 axruntime:191] Primary CPU 0 init OK. +[ 0.065425 0:4 axembassy:52] spawner is set, unpark the main thread. +[ 0.066107 0:2 embassy_thread:128] Embassy Test +[ 1.202912 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1134855400/ns +[ 2.346125 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: duration 1142355700/ns +[ 3.468000 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: duration 1121481700/ns +[ 4.621488 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: duration 1153057100/ns +[ 4.622148 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: duration 10000/ns +[ 4.622819 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: duration 200/ns +[ 4.623138 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 200/ns +[ 4.623407 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns +[ 4.623921 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: Iteration 1, expected 1000000000/ns, actual 4555756900/ns, full 4555786100/ns +[ 5.773063 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1148658700/ns +[ 5.773457 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: Iteration 1, expected 2000000000/ns, actual 4569689400/ns, full 4569689600/ns +[ 6.901089 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: duration 1127243200/ns +[ 6.901744 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 1, expected 2000000000/ns, actual 2278399000/ns, full 2278399200/ns +[ 6.902184 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 200/ns +[ 6.902440 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 1, expected 1000000000/ns, actual 2279032600/ns, full 2279032700/ns +[ 6.902837 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns +[ 6.903088 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: Iteration 1, expected 3000000000/ns, actual 4556571300/ns, full 4556571600/ns +[ 8.010697 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: duration 1107165200/ns +[ 8.011118 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: Iteration 2, expected 1000000000/ns, actual 3386668000/ns, full 3387387200/ns +[ 9.139399 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1127869600/ns +[ 9.139843 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 2, expected 2000000000/ns, actual 2237590000/ns, full 2238235900/ns +[ 9.140232 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 200/ns +[ 9.140595 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: Iteration 1, expected 4000000000/ns, actual 4518606800/ns, full 4518633600/ns +[ 9.141155 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: duration 100/ns +[ 9.141403 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 2, expected 1000000000/ns, actual 2238566100/ns, full 2238963200/ns +[ 9.141781 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns +[ 9.142023 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: Iteration 1, expected 3000000000/ns, actual 4519204600/ns, full 4519204800/ns +[ 9.142433 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: duration 100/ns +[ 9.142704 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: Iteration 1, expected 4000000000/ns, actual 5674283600/ns, full 5674283800/ns +[ 10.243878 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: duration 1100767600/ns +[ 10.244337 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: Iteration 2, expected 2000000000/ns, actual 4470491900/ns, full 4470879000/ns +[ 11.326935 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: duration 1082215700/ns +[ 11.327306 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 3, expected 2000000000/ns, actual 2187075700/ns, full 2187531900/ns +[ 11.327677 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 200/ns +[ 11.327919 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 3, expected 1000000000/ns, actual 2186138300/ns, full 2186516000/ns +[ 11.328308 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns +[ 11.328551 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: Iteration 3, expected 1000000000/ns, actual 3317023100/ns, full 3317479900/ns +[ 12.432108 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1103153400/ns +[ 12.432473 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: Iteration 2, expected 3000000000/ns, actual 5528992300/ns, full 5529385000/ns +[ 13.546997 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: duration 1114133400/ns +[ 13.547484 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 4, expected 2000000000/ns, actual 2219807900/ns, full 2220178600/ns +[ 13.547867 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 100/ns +[ 13.548111 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: Iteration 2, expected 4000000000/ns, actual 4406955900/ns, full 4407515700/ns +[ 13.548484 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: duration 100/ns +[ 13.548723 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 4, expected 1000000000/ns, actual 2220415100/ns, full 2220804400/ns +[ 13.549132 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns +[ 13.549374 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: Iteration 2, expected 3000000000/ns, actual 4406941600/ns, full 4407350700/ns +[ 13.549747 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: duration 100/ns +[ 13.549989 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: Iteration 3, expected 2000000000/ns, actual 3305272800/ns, full 3305653100/ns +[ 14.699531 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: duration 1149062200/ns +[ 14.699939 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: Iteration 4, expected 1000000000/ns, actual 3370984500/ns, full 3371386900/ns +[ 15.820545 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1119988300/ns +[ 15.820894 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: Iteration 2, expected 4000000000/ns, actual 6677785100/ns, full 6678190900/ns +[ 16.923241 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: duration 1101942000/ns +[ 16.923596 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: Iteration 3, expected 3000000000/ns, actual 3373847200/ns, full 3374220800/ns +[ 16.924002 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: duration 100/ns +[ 16.924251 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 5, expected 2000000000/ns, actual 3376385500/ns, full 3376768000/ns +[ 16.924628 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 100/ns +[ 16.924869 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 5, expected 1000000000/ns, actual 3375737000/ns, full 3376145800/ns +[ 16.925244 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns +[ 16.926066 0:2 axhal::platform::riscv64_qemu_virt::misc:3] Shutting down... +make[1]: Leaving directory '/home/nostalgia/Proj/RustProj/oscamp-arceos' diff --git a/examples/embassy-thread/analysis/makefile b/examples/embassy-thread/analysis/makefile new file mode 100644 index 0000000000..8b5d951d27 --- /dev/null +++ b/examples/embassy-thread/analysis/makefile @@ -0,0 +1,27 @@ +RUN_CMD = $(MAKE) -C ../../../ A=$(shell pwd)/../ ARCH=riscv64 run LOG=info + +ITER ?= 0 +BASE_NAME ?= logs +SUMMARY ?= summary + +RAW_LOGS = raw_$(BASE_NAME)_$(ITER).txt +CLEANED_LOGS = $(BASE_NAME)_$(ITER).txt +SUMMARY_CSV = $(SUMMARY)_$(ITER).csv + +all: run purify analyze + +run: + $(RUN_CMD) > $(RAW_LOGS) + +# purify the ansi chars +purify: run + sed -r 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' $(RAW_LOGS) | \ + sed -r 's/^\[ [0-9\.]+ [0-9:]+ [^\]]+\] (.*)/\1/' > $(CLEANED_LOGS) + +analyze: + python3 analysis.py $(CLEANED_LOGS) $(SUMMARY_CSV) + +clean: + rm -f $(CLEANED_LOGS) $(RAW_LOGS) + +.PHONY: run purify analyze clean \ No newline at end of file diff --git a/examples/embassy-thread/analysis/raw_logs_100_000_000.txt b/examples/embassy-thread/analysis/raw_logs_100_000_000.txt new file mode 100644 index 0000000000..47a6461976 --- /dev/null +++ b/examples/embassy-thread/analysis/raw_logs_100_000_000.txt @@ -0,0 +1,171 @@ +make[1]: Entering directory '/home/nostalgia/Proj/RustProj/oscamp-arceos' +axconfig-gen configs/defconfig.toml configs/platforms/riscv64-qemu-virt.toml -w smp=1 -w arch=riscv64 -w platform=riscv64-qemu-virt -o "/home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/.axconfig.toml" -c "/home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/.axconfig.toml" + Building App: .., Arch: riscv64, Platform: riscv64-qemu-virt, App type: rust +cargo -C /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/../ build -Z unstable-options --target riscv64gc-unknown-none-elf --target-dir /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/target --release --features "axstd/log-level-info" +rust-objcopy --binary-architecture=riscv64 /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/..//.._riscv64-qemu-virt.elf --strip-all -O binary /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/..//.._riscv64-qemu-virt.bin + Running on qemu... +qemu-system-riscv64 -m 128M -smp 1 -machine virt -bios default -kernel /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/..//.._riscv64-qemu-virt.bin -nographic + +OpenSBI v1.5.1 + ____ _____ ____ _____ + / __ \ / ____| _ \_ _| + | | | |_ __ ___ _ __ | (___ | |_) || | + | | | | '_ \ / _ \ '_ \ \___ \| _ < | | + | |__| | |_) | __/ | | |____) | |_) || |_ + \____/| .__/ \___|_| |_|_____/|____/_____| + | | + |_| + +Platform Name : riscv-virtio,qemu +Platform Features : medeleg +Platform HART Count : 1 +Platform IPI Device : aclint-mswi +Platform Timer Device : aclint-mtimer @ 10000000Hz +Platform Console Device : uart8250 +Platform HSM Device : --- +Platform PMU Device : --- +Platform Reboot Device : syscon-reboot +Platform Shutdown Device : syscon-poweroff +Platform Suspend Device : --- +Platform CPPC Device : --- +Firmware Base : 0x80000000 +Firmware Size : 327 KB +Firmware RW Offset : 0x40000 +Firmware RW Size : 71 KB +Firmware Heap Offset : 0x49000 +Firmware Heap Size : 35 KB (total), 2 KB (reserved), 11 KB (used), 21 KB (free) +Firmware Scratch Size : 4096 B (total), 416 B (used), 3680 B (free) +Runtime SBI Version : 2.0 + +Domain0 Name : root +Domain0 Boot HART : 0 +Domain0 HARTs : 0* +Domain0 Region00 : 0x0000000000100000-0x0000000000100fff M: (I,R,W) S/U: (R,W) +Domain0 Region01 : 0x0000000010000000-0x0000000010000fff M: (I,R,W) S/U: (R,W) +Domain0 Region02 : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: () +Domain0 Region03 : 0x0000000080040000-0x000000008005ffff M: (R,W) S/U: () +Domain0 Region04 : 0x0000000080000000-0x000000008003ffff M: (R,X) S/U: () +Domain0 Region05 : 0x000000000c400000-0x000000000c5fffff M: (I,R,W) S/U: (R,W) +Domain0 Region06 : 0x000000000c000000-0x000000000c3fffff M: (I,R,W) S/U: (R,W) +Domain0 Region07 : 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X) +Domain0 Next Address : 0x0000000080200000 +Domain0 Next Arg1 : 0x0000000087e00000 +Domain0 Next Mode : S-mode +Domain0 SysReset : yes +Domain0 SysSuspend : yes + +Boot HART ID : 0 +Boot HART Domain : root +Boot HART Priv Version : v1.12 +Boot HART Base ISA : rv64imafdch +Boot HART ISA Extensions : sstc,zicntr,zihpm,zicboz,zicbom,sdtrig,svadu +Boot HART PMP Count : 16 +Boot HART PMP Granularity : 2 bits +Boot HART PMP Address Bits: 54 +Boot HART MHPM Info : 16 (0x0007fff8) +Boot HART Debug Triggers : 2 triggers +Boot HART MIDELEG : 0x0000000000001666 +Boot HART MEDELEG : 0x0000000000f0b509 + + d8888 .d88888b. .d8888b. + d88888 d88P" "Y88b d88P Y88b + d88P888 888 888 Y88b. + d88P 888 888d888 .d8888b .d88b. 888 888 "Y888b. + d88P 888 888P" d88P" d8P Y8b 888 888 "Y88b. + d88P 888 888 888 88888888 888 888 "888 + d8888888888 888 Y88b. Y8b. Y88b. .d88P Y88b d88P +d88P 888 888 "Y8888P "Y8888 "Y88888P" "Y8888P" + +arch = riscv64 +platform = riscv64-qemu-virt +target = riscv64gc-unknown-none-elf +build_mode = release +log_level = info +smp = 1 + +[ 0.050694 0 axruntime:130] Logging is enabled. +[ 0.051812 0 axruntime:131] Primary CPU 0 started, dtb = 0x87e00000. +[ 0.052271 0 axruntime:133] Found physcial memory regions: +[ 0.052769 0 axruntime:135]  [PA:0x80200000, PA:0x8020e000) .text (READ | EXECUTE | RESERVED) +[ 0.053344 0 axruntime:135]  [PA:0x8020e000, PA:0x80213000) .rodata (READ | RESERVED) +[ 0.053654 0 axruntime:135]  [PA:0x80213000, PA:0x80216000) .data .tdata .tbss .percpu (READ | WRITE | RESERVED) +[ 0.054036 0 axruntime:135]  [PA:0x80216000, PA:0x80256000) boot stack (READ | WRITE | RESERVED) +[ 0.054365 0 axruntime:135]  [PA:0x80256000, PA:0x8025b000) .bss (READ | WRITE | RESERVED) +[ 0.054717 0 axruntime:135]  [PA:0x8025b000, PA:0x88000000) free memory (READ | WRITE | FREE) +[ 0.055082 0 axruntime:135]  [PA:0x101000, PA:0x102000) mmio (READ | WRITE | DEVICE | RESERVED) +[ 0.055422 0 axruntime:135]  [PA:0xc000000, PA:0xc210000) mmio (READ | WRITE | DEVICE | RESERVED) +[ 0.055779 0 axruntime:135]  [PA:0x10000000, PA:0x10001000) mmio (READ | WRITE | DEVICE | RESERVED) +[ 0.056121 0 axruntime:135]  [PA:0x10001000, PA:0x10009000) mmio (READ | WRITE | DEVICE | RESERVED) +[ 0.056459 0 axruntime:135]  [PA:0x30000000, PA:0x40000000) mmio (READ | WRITE | DEVICE | RESERVED) +[ 0.056817 0 axruntime:135]  [PA:0x40000000, PA:0x80000000) mmio (READ | WRITE | DEVICE | RESERVED) +[ 0.057224 0 axruntime:220] Initialize global memory allocator... +[ 0.057516 0 axruntime:221]  use TLSF allocator. +[ 0.059694 0 axruntime:150] Initialize platform devices... +[ 0.060215 0 axtask::api:79] Initialize scheduling... +[ 0.061812 0 axtask::api:85]  use FIFO scheduler. +[ 0.062727 0 axruntime:179] Initialize interrupt handlers... +[ 0.063594 0 axruntime:191] Primary CPU 0 init OK. +[ 0.065425 0:4 axembassy:52] spawner is set, unpark the main thread. +[ 0.066107 0:2 embassy_thread:128] Embassy Test +[ 1.202912 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1134855400/ns +[ 2.346125 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: duration 1142355700/ns +[ 3.468000 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: duration 1121481700/ns +[ 4.621488 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: duration 1153057100/ns +[ 4.622148 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: duration 10000/ns +[ 4.622819 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: duration 200/ns +[ 4.623138 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 200/ns +[ 4.623407 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns +[ 4.623921 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: Iteration 1, expected 1000000000/ns, actual 4555756900/ns, full 4555786100/ns +[ 5.773063 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1148658700/ns +[ 5.773457 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: Iteration 1, expected 2000000000/ns, actual 4569689400/ns, full 4569689600/ns +[ 6.901089 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: duration 1127243200/ns +[ 6.901744 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 1, expected 2000000000/ns, actual 2278399000/ns, full 2278399200/ns +[ 6.902184 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 200/ns +[ 6.902440 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 1, expected 1000000000/ns, actual 2279032600/ns, full 2279032700/ns +[ 6.902837 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns +[ 6.903088 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: Iteration 1, expected 3000000000/ns, actual 4556571300/ns, full 4556571600/ns +[ 8.010697 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: duration 1107165200/ns +[ 8.011118 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: Iteration 2, expected 1000000000/ns, actual 3386668000/ns, full 3387387200/ns +[ 9.139399 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1127869600/ns +[ 9.139843 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 2, expected 2000000000/ns, actual 2237590000/ns, full 2238235900/ns +[ 9.140232 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 200/ns +[ 9.140595 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: Iteration 1, expected 4000000000/ns, actual 4518606800/ns, full 4518633600/ns +[ 9.141155 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: duration 100/ns +[ 9.141403 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 2, expected 1000000000/ns, actual 2238566100/ns, full 2238963200/ns +[ 9.141781 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns +[ 9.142023 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: Iteration 1, expected 3000000000/ns, actual 4519204600/ns, full 4519204800/ns +[ 9.142433 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: duration 100/ns +[ 9.142704 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: Iteration 1, expected 4000000000/ns, actual 5674283600/ns, full 5674283800/ns +[ 10.243878 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: duration 1100767600/ns +[ 10.244337 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: Iteration 2, expected 2000000000/ns, actual 4470491900/ns, full 4470879000/ns +[ 11.326935 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: duration 1082215700/ns +[ 11.327306 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 3, expected 2000000000/ns, actual 2187075700/ns, full 2187531900/ns +[ 11.327677 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 200/ns +[ 11.327919 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 3, expected 1000000000/ns, actual 2186138300/ns, full 2186516000/ns +[ 11.328308 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns +[ 11.328551 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: Iteration 3, expected 1000000000/ns, actual 3317023100/ns, full 3317479900/ns +[ 12.432108 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1103153400/ns +[ 12.432473 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: Iteration 2, expected 3000000000/ns, actual 5528992300/ns, full 5529385000/ns +[ 13.546997 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: duration 1114133400/ns +[ 13.547484 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 4, expected 2000000000/ns, actual 2219807900/ns, full 2220178600/ns +[ 13.547867 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 100/ns +[ 13.548111 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: Iteration 2, expected 4000000000/ns, actual 4406955900/ns, full 4407515700/ns +[ 13.548484 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: duration 100/ns +[ 13.548723 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 4, expected 1000000000/ns, actual 2220415100/ns, full 2220804400/ns +[ 13.549132 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns +[ 13.549374 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: Iteration 2, expected 3000000000/ns, actual 4406941600/ns, full 4407350700/ns +[ 13.549747 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: duration 100/ns +[ 13.549989 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: Iteration 3, expected 2000000000/ns, actual 3305272800/ns, full 3305653100/ns +[ 14.699531 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: duration 1149062200/ns +[ 14.699939 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: Iteration 4, expected 1000000000/ns, actual 3370984500/ns, full 3371386900/ns +[ 15.820545 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1119988300/ns +[ 15.820894 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: Iteration 2, expected 4000000000/ns, actual 6677785100/ns, full 6678190900/ns +[ 16.923241 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: duration 1101942000/ns +[ 16.923596 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: Iteration 3, expected 3000000000/ns, actual 3373847200/ns, full 3374220800/ns +[ 16.924002 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: duration 100/ns +[ 16.924251 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 5, expected 2000000000/ns, actual 3376385500/ns, full 3376768000/ns +[ 16.924628 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 100/ns +[ 16.924869 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 5, expected 1000000000/ns, actual 3375737000/ns, full 3376145800/ns +[ 16.925244 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns +[ 16.926066 0:2 axhal::platform::riscv64_qemu_virt::misc:3] Shutting down... +make[1]: Leaving directory '/home/nostalgia/Proj/RustProj/oscamp-arceos' diff --git a/examples/embassy-thread/analysis/summary_100_000_000.csv b/examples/embassy-thread/analysis/summary_100_000_000.csv new file mode 100644 index 0000000000..94b3a08f11 --- /dev/null +++ b/examples/embassy-thread/analysis/summary_100_000_000.csv @@ -0,0 +1,5 @@ +timestamp,log_type,metric_name,count,mean_absolute_deviation,std_deviation,min_deviation,max_deviation +2025-06-07T13:59:11.082946,native_report,actual_ns,11,2310319900,618000176.29,1305272800,3555756900 +2025-06-07T13:59:11.082946,native_report,full_ns,11,2310608463.64,618005599.33,1305653100,3555786100 +2025-06-07T13:59:11.082946,async_report,actual_ns,15,921646886.67,651505893.62,187075700,2375737000 +2025-06-07T13:59:11.082946,async_report,full_ns,15,921966753.33,651480522.89,187531900,2376145800 diff --git a/examples/embassy-thread/src/main.rs b/examples/embassy-thread/src/main.rs index 36aaa5fdcb..e6f14cb662 100644 --- a/examples/embassy-thread/src/main.rs +++ b/examples/embassy-thread/src/main.rs @@ -103,7 +103,7 @@ async fn async_tick(id: u64, millis: u64, busy_iters: u64) { fn thread_tick(id: u64, millis: u64, busy_iters: u64) { task_loop! { - task_type: "NATIVE_THREAD", + task_type: "NATIVE_THREAD_REPORT", id:id, sleep: |millis| sleep(Duration::from_millis(millis)), millis:millis, @@ -114,11 +114,14 @@ fn thread_tick(id: u64, millis: u64, busy_iters: u64) { const NUM_THREADS: u64 = 5; const NUM_TASKS: u64 = 5; +// const NUM_ITERS_THREADS: u64 = 0; +// const NUM_ITERS_THREADS: u64 = 1_000; // const NUM_ITERS_THREADS: u64 = 1_000_000; -const NUM_ITERS_THREADS: u64 = 0; -// const NUM_ITERS_TASKS: u64 = 1000; -// const NUM_ITERS_TASKS: u64 = 1000_000; -const NUM_ITERS_TASKS: u64 = 0; +const NUM_ITERS_THREADS: u64 = 100_000_000; +// const NUM_ITERS_TASKS: u64 = 0; +// const NUM_ITERS_TASKS: u64 = 1_000; +// const NUM_ITERS_TASKS: u64 = 1_000_000; +const NUM_ITERS_TASKS: u64 = 100_000_000; #[cfg_attr(feature = "axstd", unsafe(no_mangle))] fn main() { From 8ae328d8f45cf5946ad4d4e474563c3c9a722ea2 Mon Sep 17 00:00:00 2001 From: lvyuemeng Date: Thu, 3 Jul 2025 09:29:23 +0800 Subject: [PATCH 10/11] [feat]: improve axembassy preempt feature --- Cargo.lock | 68 ++-- Cargo.toml | 2 +- api/arceos_api/Cargo.toml | 1 + api/arceos_api/src/imp/embassy_async.rs | 4 + api/arceos_api/src/lib.rs | 13 +- api/arceos_api/src/macros.rs | 4 + api/axfeat/Cargo.toml | 2 + .../.axconfig.toml | 0 examples/embassy-preempt/Cargo.toml | 24 ++ examples/embassy-preempt/src/main.rs | 348 ++++++++++++++++++ examples/embassy-single/Cargo.toml | 4 +- examples/embassy-single/src/main.rs | 2 +- examples/embassy-thread/Cargo.toml | 11 - .../embassy-thread/analysis/.axconfig.toml | 81 ---- examples/embassy-thread/analysis/analysis.py | 130 ------- .../analysis/logs_100_000_000.txt | 171 --------- examples/embassy-thread/analysis/makefile | 27 -- .../analysis/raw_logs_100_000_000.txt | 171 --------- .../analysis/summary_100_000_000.csv | 5 - examples/embassy-thread/src/main.rs | 142 ------- modules/axembassy/Cargo.toml | 16 +- modules/axembassy/src/asynch.rs | 49 ++- modules/axembassy/src/delegate.rs | 24 +- modules/axembassy/src/executor_thread.rs | 7 +- modules/axembassy/src/lib.rs | 59 ++- modules/axembassy/src/preempt.rs | 298 +++++++++++++++ modules/axembassy/src/time_driver.rs | 11 +- modules/axruntime/src/lib.rs | 8 +- modules/axtask/src/api.rs | 12 +- modules/axtask/src/events.rs | 86 ----- modules/axtask/src/lib.rs | 2 - modules/axtask/src/run_queue.rs | 38 +- modules/axtask/src/task.rs | 9 +- modules/axtask/src/task_registry.rs | 47 --- modules/axtask/src/wait_queues.rs | 2 +- ulib/axasync/Cargo.toml | 19 +- ulib/axasync/src/lib.rs | 12 +- 37 files changed, 859 insertions(+), 1050 deletions(-) rename examples/{embassy-thread => embassy-preempt}/.axconfig.toml (100%) create mode 100644 examples/embassy-preempt/Cargo.toml create mode 100644 examples/embassy-preempt/src/main.rs delete mode 100644 examples/embassy-thread/Cargo.toml delete mode 100644 examples/embassy-thread/analysis/.axconfig.toml delete mode 100644 examples/embassy-thread/analysis/analysis.py delete mode 100644 examples/embassy-thread/analysis/logs_100_000_000.txt delete mode 100644 examples/embassy-thread/analysis/makefile delete mode 100644 examples/embassy-thread/analysis/raw_logs_100_000_000.txt delete mode 100644 examples/embassy-thread/analysis/summary_100_000_000.csv delete mode 100644 examples/embassy-thread/src/main.rs create mode 100644 modules/axembassy/src/preempt.rs delete mode 100644 modules/axtask/src/events.rs delete mode 100644 modules/axtask/src/task_registry.rs diff --git a/Cargo.lock b/Cargo.lock index d61463f654..3990293602 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -279,7 +279,7 @@ dependencies = [ "axconfig-gen", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -388,6 +388,7 @@ version = "0.1.0" dependencies = [ "axconfig", "axhal", + "axsync", "axtask", "cfg-if", "embassy-executor", @@ -694,7 +695,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -843,7 +844,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -893,7 +894,7 @@ checksum = "70272a03a2cef15589bac05d3d15c023752f5f8f2da8be977d983a9d9e6250fb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -919,7 +920,7 @@ checksum = "9a49d5cd78b1c748184d41407b14a58af8403c13328ff2b9f49b0a418c24e3ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -943,7 +944,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -954,7 +955,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -986,7 +987,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -1040,7 +1041,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -1049,12 +1050,21 @@ version = "0.1.1" source = "git+https://github.com/embassy-rs/embassy?branch=main#c637ee7d79552d9b9bfa0c0f4199372975acc343" [[package]] -name = "embassy-single" +name = "embassy-preempt" version = "0.0.0" dependencies = [ "axasync", "axstd", "embassy-executor", + "log", +] + +[[package]] +name = "embassy-single" +version = "0.0.0" +dependencies = [ + "axasync", + "axstd", ] [[package]] @@ -1070,16 +1080,6 @@ dependencies = [ "heapless 0.8.0", ] -[[package]] -name = "embassy-thread" -version = "0.0.0" -dependencies = [ - "axasync", - "axstd", - "embassy-executor", - "log", -] - [[package]] name = "embassy-time" version = "0.4.0" @@ -1455,7 +1455,7 @@ checksum = "04d55ca5d5a14363da83bf3c33874b8feaa34653e760d5216d7ef9829c88001a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -1627,7 +1627,7 @@ checksum = "8a9f4cc54a2e471ff72f1499461ba381ad4eae9cbd60d29c258545b995e406e0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -1664,7 +1664,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d" dependencies = [ "proc-macro2", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -1686,7 +1686,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -1822,7 +1822,7 @@ checksum = "e8c4aa1ea1af6dcc83a61be12e8189f9b293c3ba5a487778a4cd89fb060fdbbc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -1995,9 +1995,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.101" +version = "2.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "f6397daf94fa90f058bd0fd88429dd9e5738999cca8d701813c80723add80462" dependencies = [ "proc-macro2", "quote", @@ -2021,7 +2021,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -2150,7 +2150,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", "wasm-bindgen-shared", ] @@ -2172,7 +2172,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2207,7 +2207,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -2218,7 +2218,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -2485,7 +2485,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -2496,5 +2496,5 @@ checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] diff --git a/Cargo.toml b/Cargo.toml index ca707bff6d..f76c43df19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,8 +31,8 @@ members = [ "examples/httpserver", "examples/httpserver", "examples/shell", - "examples/embassy-thread", "examples/embassy-single", + "examples/embassy-preempt", ] [workspace.package] diff --git a/api/arceos_api/Cargo.toml b/api/arceos_api/Cargo.toml index 2b9e0965aa..44da8282fc 100644 --- a/api/arceos_api/Cargo.toml +++ b/api/arceos_api/Cargo.toml @@ -23,6 +23,7 @@ display = ["dep:axdisplay", "dep:axdriver", "axfeat/display"] myfs = ["axfeat/myfs"] +async-preempt = ["async-thread", "axfeat/async-preempt"] async-thread = ["dep:axembassy", "axfeat/async-thread"] async-single = ["dep:axembassy", "axfeat/async-single"] diff --git a/api/arceos_api/src/imp/embassy_async.rs b/api/arceos_api/src/imp/embassy_async.rs index 62c459d517..0568cbb29b 100644 --- a/api/arceos_api/src/imp/embassy_async.rs +++ b/api/arceos_api/src/imp/embassy_async.rs @@ -14,3 +14,7 @@ cfg_async_thread! { axembassy::block_on(fut) } } + +cfg_async_preempt! { + pub use axembassy::PrioFuture as AxPrioFuture; +} diff --git a/api/arceos_api/src/lib.rs b/api/arceos_api/src/lib.rs index 46a9264926..9b2defa334 100644 --- a/api/arceos_api/src/lib.rs +++ b/api/arceos_api/src/lib.rs @@ -396,12 +396,17 @@ pub mod embassy_async { pub type AxSpawner; pub type AxSendSpawner; } - + define_api! { @cfg "async-thread"; pub fn ax_spawner() -> AxSendSpawner; } + #[cfg(feature = "async-preempt")] + pub use crate::imp::AxPrioFuture; + #[cfg(all(feature = "dummy-if-not-enabled", not(feature = "async-thread")))] + pub struct AxPrioFuture; + #[cfg(feature = "async-thread")] pub fn ax_block_on(fut: F) -> F::Output { crate::imp::ax_block_on(fut) @@ -439,7 +444,11 @@ pub mod modules { pub use axdma; #[cfg(any(feature = "fs", feature = "net", feature = "display"))] pub use axdriver; - #[cfg(any(feature = "async-thread", feature = "async-single"))] + #[cfg(any( + feature = "async-thread", + feature = "async-single", + feature = "async-preempt" + ))] pub use axembassy; #[cfg(feature = "fs")] pub use axfs; diff --git a/api/arceos_api/src/macros.rs b/api/arceos_api/src/macros.rs index 23224a957b..a9451e717e 100644 --- a/api/arceos_api/src/macros.rs +++ b/api/arceos_api/src/macros.rs @@ -108,6 +108,10 @@ macro_rules! cfg_task { ($($item:item)*) => { _cfg_common!{ "multitask" $($item)* } } } +macro_rules! cfg_async_preempt { + ($($item:item)*) => { _cfg_common!{ "async-preempt" $($item)* } } +} + macro_rules! cfg_async_thread { ($($item:item)*) => { _cfg_common!{ "async-thread" $($item)* } } } diff --git a/api/axfeat/Cargo.toml b/api/axfeat/Cargo.toml index b67b518fab..2fe6fd1b2d 100644 --- a/api/axfeat/Cargo.toml +++ b/api/axfeat/Cargo.toml @@ -43,6 +43,8 @@ sched_fifo = ["axtask/sched_fifo"] sched_rr = ["axtask/sched_rr", "irq"] sched_cfs = ["axtask/sched_cfs", "irq"] +# Embassy asynchronous runtime with multithread support and preemption +async-preempt = ["async-thread", "axembassy/executor-preempt"] # Embassy asynchronous runtime with multithread support async-thread = [ "axembassy/driver", diff --git a/examples/embassy-thread/.axconfig.toml b/examples/embassy-preempt/.axconfig.toml similarity index 100% rename from examples/embassy-thread/.axconfig.toml rename to examples/embassy-preempt/.axconfig.toml diff --git a/examples/embassy-preempt/Cargo.toml b/examples/embassy-preempt/Cargo.toml new file mode 100644 index 0000000000..c2a5d37413 --- /dev/null +++ b/examples/embassy-preempt/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "embassy-preempt" +authors = ["nostalgia "] +edition.workspace = true + +[features] +default = [] + +async-test = [] +thread-test = [] + +atomic-sum = [] +iter-delay = [] + +[dependencies] +axstd = { workspace = true, features = [ + "multitask", + "sched_cfs", + "alloc", +], optional = true } +axasync = { workspace = true, features = ["preempt", "time"] } + +embassy-executor = { git = "https://github.com/embassy-rs/embassy", branch = "main", default-features = false } +log = "=0.4.21" diff --git a/examples/embassy-preempt/src/main.rs b/examples/embassy-preempt/src/main.rs new file mode 100644 index 0000000000..2ec89fe066 --- /dev/null +++ b/examples/embassy-preempt/src/main.rs @@ -0,0 +1,348 @@ +#![feature(impl_trait_in_assoc_type)] +#![feature(type_alias_impl_trait)] +#![cfg_attr(feature = "axstd", no_std)] +#![cfg_attr(feature = "axstd", no_main)] + +#[macro_use] +#[cfg(feature = "axstd")] +extern crate axstd as std; + +extern crate alloc; + +use alloc::sync::Arc; +use axasync::executor::{PrioFuture, spawner, yield_now}; +use axasync::time::Timer; +use core::hint::black_box; +use core::sync::atomic::AtomicUsize; +use std::thread::{self, sleep}; +use std::time::Duration; + +macro_rules! work_loop { + ( + task_type: $task_type:literal, + id: $id:expr, + expected: $millis:expr, + volume: $volume:expr, + busy: {$($busy_tt:tt)*}, + sleep: {$($sleep_tt:tt)*}, + $(output: {$($output_tt:tt)*},)? + ) => { + use std::time::{Instant,Duration}; + use log; + use core::hint::black_box; + + let mut cnt = 0; + let mut last_report = Instant::now(); + let expected = Duration::from_millis($millis); + loop { + let iter_start = Instant::now(); + cnt += 1; + + $($busy_tt)* + $($sleep_tt)* + $($($output_tt)*)? + + let iter_end = Instant::now(); + let iter_dur = iter_end - iter_start; + let full_dur = iter_end - last_report; + + log::info!( + "{} {}: volume {}, works {}, times {}/s, iters {}, expected {}/ns, actual {}/ns, full {}/ns", + $task_type, + $id, + $volume, + NUM_ITERS, + TEST_SECS, + cnt, + expected.as_nanos(), + iter_dur.as_nanos(), + full_dur.as_nanos(), + ); + + last_report = iter_end; + } + }; +} + +macro_rules! prio_task { + ( + fn_name: $fn_name:ident, + task_type: $task_type:literal, + prios: $prios:expr, + pool_size: $pool_size:expr, + atomic, + ) => { + #[axasync::executor::task(pool_size = $pool_size)] + async fn $fn_name(id: u64, millis: u64, busy_iters: u64, iters: Arc) { + work_loop! { + task_type: $task_type, + id: id, + expected: millis, + volume: $pool_size, + busy: { + if busy_iters > 0 { + let _res = black_box(PrioFuture::new(async_busy_work(busy_iters), $prios).await); + } + }, + sleep: { + PrioFuture::new(Timer::after_millis(millis),$prios).await; + }, + output: { + iters.fetch_add(1,core::sync::atomic::Ordering::SeqCst); + }, + } + } + }; + ( + fn_name: $fn_name:ident, + task_type: $task_type:literal, + prios: $prios:expr, + pool_size: $pool_size:expr, + ) => ( + #[axasync::executor::task(pool_size = $pool_size)] + async fn $fn_name(id: u64, millis: u64, busy_iters: u64) { + work_loop! { + task_type: $task_type, + id: id, + expected: millis, + volume: $pool_size, + busy: { + if busy_iters > 0 { + let _res = black_box(PrioFuture::new(async_busy_work(busy_iters), $prios).await); + } + }, + sleep: { + PrioFuture::new(Timer::after_millis(millis),$prios).await; + }, + } + } + ) +} + +const HIGH_PRIOS: u8 = 1; +const LOW_PRIOS: u8 = 3; + +#[cfg(feature = "async-test")] +prio_task! { + fn_name: prio_tick_high, + task_type: "ASYNC_TASK_REPORT_HIGH", + prios: HIGH_PRIOS, + pool_size: NUM_HIGH_TASKS as usize, +} + +#[cfg(feature = "async-test")] +prio_task! { + fn_name: prio_tick_low, + task_type: "ASYNC_TASK_REPORT_LOW", + prios: LOW_PRIOS, + pool_size: NUM_LOW_TASKS as usize, +} + +#[cfg(feature = "async-test")] +prio_task! { + fn_name: prio_add_high, + task_type: "ASYNC_TASK_REPORT_HIGH", + prios: HIGH_PRIOS, + pool_size: NUM_HIGH_TASKS as usize, + atomic, +} + +#[cfg(feature = "async-test")] +prio_task! { + fn_name: prio_add_low, + task_type: "ASYNC_TASK_REPORT_LOW", + prios: LOW_PRIOS, + pool_size: NUM_LOW_TASKS as usize, + atomic, +} + +#[cfg(feature = "thread-test")] +fn thread_tick(id: u64, millis: u64, busy_iters: u64) { + work_loop! { + task_type: "NATIVE_THREAD_REPORT", + id:id, + expected: millis, + volume: NUM_THREADS, + busy: { + if busy_iters > 0 { + let _res = black_box(busy_work(busy_iters)); + } + }, + sleep: { + sleep(Duration::from_millis(millis)); + }, + output: {}, + } +} + +#[cfg(feature = "thread-test")] +fn thread_add(id: u64, millis: u64, busy_iters: u64, iters: Arc) { + work_loop! { + task_type: "NATIVE_THREAD_ATOMIC_REPORT", + id:id, + expected: millis, + volume: NUM_THREADS, + busy: { + if busy_iters > 0 { + let _res = black_box(busy_work(busy_iters)); + } + }, + sleep: { + sleep(Duration::from_millis(millis)); + }, + output: { + iters.fetch_add(1, core::sync::atomic::Ordering::SeqCst); + }, + } +} + +fn busy_work(iters: u64) -> u64 { + let mut total = 0; + for _ in 0..iters { + total = black_box(total + 1); + thread::yield_now(); + } + black_box(total) +} + +async fn async_busy_work(iters: u64) -> u64 { + let mut total = 0; + for _ in 0..iters { + total = black_box(total + 1); + yield_now().await; + } + black_box(total) +} + +// const NUM_THREADS: u64 = 30; +const NUM_THREADS: u64 = 50; +// const NUM_THREADS: u64 = 100; +// const NUM_THREADS: u64 = 125; +// const NUM_THREADS: u64 = 150; +// const NUM_THREADS: u64 = 175; +// +const NUM_HIGH_TASKS: u64 = 15; +// const NUM_HIGH_TASKS: u64 = 25; +// const NUM_HIGH_TASKS: u64 = 30; +// const NUM_HIGH_TASKS: u64 = 50; +// const NUM_HIGH_TASKS: u64 = 75; +// const NUM_HIGH_TASKS: u64 = 100; +// const NUM_HIGH_TASKS: u64 = 200; +// +const NUM_LOW_TASKS: u64 = 15; +// const NUM_LOW_TASKS: u64 = 25; +// const NUM_LOW_TASKS: u64 = 30; +// const NUM_LOW_TASKS: u64 = 50; +// const NUM_LOW_TASKS: u64 = 75; +// const NUM_LOW_TASKS: u64 = 100; +// const NUM_LOW_TASKS: u64 = 200; +// + +// const NUM_ITERS: u64 = 100; +// The num iters for volume delay +// const NUM_ITERS: u64 = 1000; +// const NUM_ITERS: u64 = 1_000_0; +// const NUM_ITERS: u64 = 1_000_00; +const NUM_ITERS: u64 = 10; +// const NUM_ITERS: u64 = 1_000_000_0; +// const NUM_ITERS: u64 = 100; +const TEST_SECS: u64 = 15; + +#[cfg_attr(feature = "axstd", unsafe(no_mangle))] +fn main() { + log::info!("Starting Test"); + let th_iters = Arc::new(AtomicUsize::new(0)); + let high_prio_iters = Arc::new(AtomicUsize::new(0)); + let low_prio_iters = Arc::new(AtomicUsize::new(0)); + + #[cfg(feature = "thread-test")] + for i in 1..NUM_THREADS { + #[cfg(feature = "atomic-sum")] + let th_iters = th_iters.clone(); + + thread::spawn(move || { + #[cfg(feature = "atomic-sum")] + { + thread_add(i, (i % 20 + 1), NUM_ITERS, th_iters); + } + #[cfg(feature = "iter-delay")] + { + thread_tick(i, (i % 20 + 1) * 1000, NUM_ITERS); + } + }); + } + + #[cfg(feature = "async-test")] + for i in 1..NUM_LOW_TASKS { + if i <= NUM_HIGH_TASKS { + #[cfg(feature = "atomic-sum")] + { + let high_prio_iters = high_prio_iters.clone(); + spawner().must_spawn(prio_add_high(i, (i % 20 + 1), NUM_ITERS, high_prio_iters)); + } + #[cfg(feature = "iter-delay")] + { + spawner() + .spawn(prio_tick_high(i, (i % 20 + 1) * 1000, NUM_ITERS)) + .unwrap(); + } + } + #[cfg(feature = "atomic-sum")] + { + let low_prio_iters = low_prio_iters.clone(); + spawner().must_spawn(prio_add_low( + i + NUM_HIGH_TASKS, + (i % 20 + 1), + NUM_ITERS, + low_prio_iters, + )); + } + #[cfg(feature = "iter-delay")] + { + spawner() + .spawn(prio_tick_low( + i + NUM_HIGH_TASKS, + (i % 20 + 1) * 1000, + NUM_ITERS, + )) + .unwrap(); + } + } + // Avoid shut down immediately + sleep(Duration::from_secs(TEST_SECS)); + + #[cfg(feature = "atomic-sum")] + { + let th_out = th_iters.load(core::sync::atomic::Ordering::Relaxed); + let high_out = high_prio_iters.load(core::sync::atomic::Ordering::Relaxed); + let low_out = low_prio_iters.load(core::sync::atomic::Ordering::Relaxed); + #[cfg(feature = "thread-test")] + log::info!( + "NATIVE_THREAD_REPORT: volume: {}, time: {}/s, works: {}, sum: {}, sum/s: {}", + NUM_THREADS, + TEST_SECS, + NUM_ITERS, + th_out, + th_out as u64 / TEST_SECS + ); + #[cfg(feature = "async-test")] + { + log::info!( + "ASYNC_TASK_REPORT_HIGH: volume: {}, time: {}/s, works: {}, sum: {}, sum/s: {}", + NUM_HIGH_TASKS, + TEST_SECS, + NUM_ITERS, + high_out, + high_out as u64 / TEST_SECS + ); + log::info!( + "ASYNC_TASK_REPORT_LOW: volume: {}, time: {}/s, works: {}, sum: {}, sum/s: {}", + NUM_LOW_TASKS, + TEST_SECS, + NUM_ITERS, + low_out, + low_out as u64 / TEST_SECS + ); + } + } +} diff --git a/examples/embassy-single/Cargo.toml b/examples/embassy-single/Cargo.toml index 68fb900299..09ac5981d0 100644 --- a/examples/embassy-single/Cargo.toml +++ b/examples/embassy-single/Cargo.toml @@ -5,6 +5,4 @@ edition.workspace = true [dependencies] axstd = { workspace = true, optional = true } -axasync = { workspace = true, features = ["single", "time"] } - -embassy-executor = { git = "https://github.com/embassy-rs/embassy", branch = "main", default-features = false } +axasync = { workspace = true, features = ["single", "time"] } \ No newline at end of file diff --git a/examples/embassy-single/src/main.rs b/examples/embassy-single/src/main.rs index cdc5ec36da..60c9201fb9 100644 --- a/examples/embassy-single/src/main.rs +++ b/examples/embassy-single/src/main.rs @@ -23,7 +23,7 @@ fn busy_work(nano: u64) -> u64 { total } -#[embassy_executor::task(pool_size = 4)] +#[axasync::executor::task(pool_size = 4)] async fn tick(_sec: u64, busy_nano: u64) { for i in 0..10 { println!("embassy tick {}: {}/s, {}", _sec, _sec * i, i); diff --git a/examples/embassy-thread/Cargo.toml b/examples/embassy-thread/Cargo.toml deleted file mode 100644 index 8721c9516c..0000000000 --- a/examples/embassy-thread/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "embassy-thread" -authors = ["nostalgia "] -edition.workspace = true - -[dependencies] -axstd = { workspace = true, features = ["multitask"], optional = true } -axasync = { workspace = true, features = ["thread", "time"] } - -embassy-executor = { git = "https://github.com/embassy-rs/embassy", branch = "main", default-features = false } -log = "=0.4.21" \ No newline at end of file diff --git a/examples/embassy-thread/analysis/.axconfig.toml b/examples/embassy-thread/analysis/.axconfig.toml deleted file mode 100644 index 42465c83b4..0000000000 --- a/examples/embassy-thread/analysis/.axconfig.toml +++ /dev/null @@ -1,81 +0,0 @@ -# Architecture identifier. -arch = "riscv64" # str -# Platform identifier. -platform = "riscv64-qemu-virt" # str -# Number of CPUs -smp = 1 # uint -# Stack size of each task. -task-stack-size = 0x40000 # uint -# Number of timer ticks per second (Hz). A timer tick may contain several timer -# interrupts. -ticks-per-sec = 100 # uint - -# -# Device specifications -# -[devices] -# MMIO regions with format (`base_paddr`, `size`). -mmio-regions = [ - [0x0010_1000, 0x1000], - [0x0c00_0000, 0x21_0000], - [0x1000_0000, 0x1000], - [0x1000_1000, 0x8000], - [0x3000_0000, 0x1000_0000], - [0x4000_0000, 0x4000_0000] -] # [(uint, uint)] -# End PCI bus number (`bus-range` property in device tree). -pci-bus-end = 0xff # uint -# Base physical address of the PCIe ECAM space. -pci-ecam-base = 0x3000_0000 # uint -# PCI device memory ranges (`ranges` property in device tree). -pci-ranges = [ - [0x0300_0000, 0x1_0000], - [0x4000_0000, 0x4000_0000], - [0x4_0000_0000, 0x4_0000_0000] -] # [(uint, uint)] -# rtc@101000 { -# interrupts = <0x0b>; -# interrupt-parent = <0x03>; -# reg = <0x00 0x101000 0x00 0x1000>; -# compatible = "google,goldfish-rtc"; -# }; -# RTC (goldfish) Address -rtc-paddr = 0x10_1000 # uint -# Timer interrupt frequency in Hz. -timer-frequency = 10_000_000 # uint -# VirtIO MMIO regions with format (`base_paddr`, `size`). -virtio-mmio-regions = [ - [0x1000_1000, 0x1000], - [0x1000_2000, 0x1000], - [0x1000_3000, 0x1000], - [0x1000_4000, 0x1000], - [0x1000_5000, 0x1000], - [0x1000_6000, 0x1000], - [0x1000_7000, 0x1000], - [0x1000_8000, 0x1000] -] # [(uint, uint)] - -# -# Platform configs -# -[plat] -# Platform family. -family = "riscv64-qemu-virt" # str -# Kernel address space base. -kernel-aspace-base = "0xffff_ffc0_0000_0000" # uint -# Kernel address space size. -kernel-aspace-size = "0x0000_003f_ffff_f000" # uint -# Base physical address of the kernel image. -kernel-base-paddr = 0x8020_0000 # uint -# Base virtual address of the kernel image. -kernel-base-vaddr = "0xffff_ffc0_8020_0000" # uint -# Offset of bus address and phys address. some boards, the bus address is -# different from the physical address. -phys-bus-offset = 0 # uint -# Base address of the whole physical memory. -phys-memory-base = 0x8000_0000 # uint -# Size of the whole physical memory. (128M) -phys-memory-size = 0x800_0000 # uint -# Linear mapping offset, for quick conversions between physical and virtual -# addresses. -phys-virt-offset = "0xffff_ffc0_0000_0000" # uint diff --git a/examples/embassy-thread/analysis/analysis.py b/examples/embassy-thread/analysis/analysis.py deleted file mode 100644 index d458aa36d8..0000000000 --- a/examples/embassy-thread/analysis/analysis.py +++ /dev/null @@ -1,130 +0,0 @@ -import sys -import re -import csv -import os -from collections import defaultdict -from statistics import mean, stdev -from datetime import datetime - -LOG_PATTERNS = { - "async_report": { - "regex": r'ASYNC_TASK_REPORT (\d+): Iteration (\d+), expected (\d+)/ns, actual (\d+)/ns, full (\d+)/ns', - "id_key": "task_id", - "metrics": ["actual_ns", "full_ns"] - }, - "native_report": { - "regex": r'NATIVE_THREAD_REPORT (\d+): Iteration (\d+), expected (\d+)/ns, actual (\d+)/ns, full (\d+)/ns', - "id_key": "thread_id", - "metrics": ["actual_ns", "full_ns"] - } -} - -CSV_HEADERS = [ - "timestamp", - "log_type", - "metric_name", - "count", - "mean_absolute_deviation", - "std_deviation", - "min_deviation", - "max_deviation" -] - -def write_to_csv(deviation_data, log_path, csv_path): - timestamp = datetime.now().isoformat() - log_filename = os.path.basename(log_path) - - file_exists = os.path.exists(csv_path) - - try: - with open(csv_path, 'a', newline='') as csvfile: - writer = csv.writer(csvfile) - - # Write headers if file is new - if not file_exists: - writer.writerow(CSV_HEADERS) - - # Write data rows - for log_type, metrics in deviation_data.items(): - for metric_name, deviations in metrics.items(): - if deviations: # Only write if we have data - std_dev = stdev(deviations) if len(deviations) > 1 else 0 - - row = [ - timestamp, - log_type, - metric_name, - len(deviations), - round(mean(deviations),2), - round(std_dev,2), - min(deviations), - max(deviations) - ] - - writer.writerow(row) - - except Exception as e: - print(f"Error writing to CSV file '{csv_file_path}': {e}", file=sys.stderr) - sys.exit(1) - -def parse_log_file(path): - parsed_data = defaultdict(lambda: defaultdict(list)) - - patterns = {name: re.compile(config["regex"]) for name, config in LOG_PATTERNS.items()} - try: - with open(path, "r") as f: - for line in f: - for log_type, config in LOG_PATTERNS.items(): - match = patterns[log_type].search(line) - if match: - _id, _, expected, *metrics = map(int, match.groups()) - for key, value in zip(config["metrics"], metrics): - deviation = abs(value - expected) - parsed_data[log_type][key].append(deviation) - break - except FileNotFoundError: - print(f"Error: Log file '{path}' not found.", file=sys.stderr) - sys.exit(1) - except Exception as e: - print(f"An error occurred while parsing the log file: {e}", file=sys.stderr) - sys.exit(1) - - return parsed_data - -def summarize_deviation(deviation_data): - for log_type, metrics in deviation_data.items(): - print(f"--- {log_type} ---") - for metric_name, deviations in metrics.items(): - print(f" Metric: {metric_name}") - print(f" Count: {len(deviations)}") - print(f" Mean Absolute Deviation: {mean(deviations):.2f} ns") - print(f" Std Dev: {stdev(deviations):.2f} ns" if len(deviations) > 1 else " Std Dev: N/A") - print(f" Min: {min(deviations)} ns") - print(f" Max: {max(deviations)} ns") - print() - -def main(): - if len(sys.argv) not in [2, 3]: - print("Usage: python3 deviation_summary.py [output.csv]", file=sys.stderr) - print("If output.csv is not specified, defaults to 'deviation_summary.csv'", file=sys.stderr) - sys.exit(1) - - log_file_path = sys.argv[1] - csv_file_path = sys.argv[2] if len(sys.argv) == 3 else "summary.csv" - - try: - deviations = parse_log_file(sys.argv[1]) - - if not any(deviations.values()): - print("No matching log entries found in the file.", file=sys.stderr) - sys.exit(1) - - write_to_csv(deviations, log_file_path, csv_file_path) - - summarize_deviation(deviations) - except FileNotFoundError: - print(f"Error: File '{sys.argv[1]}' not found.", file=sys.stderr) - sys.exit(1) - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/examples/embassy-thread/analysis/logs_100_000_000.txt b/examples/embassy-thread/analysis/logs_100_000_000.txt deleted file mode 100644 index 429aa33dff..0000000000 --- a/examples/embassy-thread/analysis/logs_100_000_000.txt +++ /dev/null @@ -1,171 +0,0 @@ -make[1]: Entering directory '/home/nostalgia/Proj/RustProj/oscamp-arceos' -axconfig-gen configs/defconfig.toml configs/platforms/riscv64-qemu-virt.toml -w smp=1 -w arch=riscv64 -w platform=riscv64-qemu-virt -o "/home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/.axconfig.toml" -c "/home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/.axconfig.toml" - Building App: .., Arch: riscv64, Platform: riscv64-qemu-virt, App type: rust -cargo -C /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/../ build -Z unstable-options --target riscv64gc-unknown-none-elf --target-dir /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/target --release --features "axstd/log-level-info" -rust-objcopy --binary-architecture=riscv64 /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/..//.._riscv64-qemu-virt.elf --strip-all -O binary /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/..//.._riscv64-qemu-virt.bin - Running on qemu... -qemu-system-riscv64 -m 128M -smp 1 -machine virt -bios default -kernel /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/..//.._riscv64-qemu-virt.bin -nographic - -OpenSBI v1.5.1 - ____ _____ ____ _____ - / __ \ / ____| _ \_ _| - | | | |_ __ ___ _ __ | (___ | |_) || | - | | | | '_ \ / _ \ '_ \ \___ \| _ < | | - | |__| | |_) | __/ | | |____) | |_) || |_ - \____/| .__/ \___|_| |_|_____/|____/_____| - | | - |_| - -Platform Name : riscv-virtio,qemu -Platform Features : medeleg -Platform HART Count : 1 -Platform IPI Device : aclint-mswi -Platform Timer Device : aclint-mtimer @ 10000000Hz -Platform Console Device : uart8250 -Platform HSM Device : --- -Platform PMU Device : --- -Platform Reboot Device : syscon-reboot -Platform Shutdown Device : syscon-poweroff -Platform Suspend Device : --- -Platform CPPC Device : --- -Firmware Base : 0x80000000 -Firmware Size : 327 KB -Firmware RW Offset : 0x40000 -Firmware RW Size : 71 KB -Firmware Heap Offset : 0x49000 -Firmware Heap Size : 35 KB (total), 2 KB (reserved), 11 KB (used), 21 KB (free) -Firmware Scratch Size : 4096 B (total), 416 B (used), 3680 B (free) -Runtime SBI Version : 2.0 - -Domain0 Name : root -Domain0 Boot HART : 0 -Domain0 HARTs : 0* -Domain0 Region00 : 0x0000000000100000-0x0000000000100fff M: (I,R,W) S/U: (R,W) -Domain0 Region01 : 0x0000000010000000-0x0000000010000fff M: (I,R,W) S/U: (R,W) -Domain0 Region02 : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: () -Domain0 Region03 : 0x0000000080040000-0x000000008005ffff M: (R,W) S/U: () -Domain0 Region04 : 0x0000000080000000-0x000000008003ffff M: (R,X) S/U: () -Domain0 Region05 : 0x000000000c400000-0x000000000c5fffff M: (I,R,W) S/U: (R,W) -Domain0 Region06 : 0x000000000c000000-0x000000000c3fffff M: (I,R,W) S/U: (R,W) -Domain0 Region07 : 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X) -Domain0 Next Address : 0x0000000080200000 -Domain0 Next Arg1 : 0x0000000087e00000 -Domain0 Next Mode : S-mode -Domain0 SysReset : yes -Domain0 SysSuspend : yes - -Boot HART ID : 0 -Boot HART Domain : root -Boot HART Priv Version : v1.12 -Boot HART Base ISA : rv64imafdch -Boot HART ISA Extensions : sstc,zicntr,zihpm,zicboz,zicbom,sdtrig,svadu -Boot HART PMP Count : 16 -Boot HART PMP Granularity : 2 bits -Boot HART PMP Address Bits: 54 -Boot HART MHPM Info : 16 (0x0007fff8) -Boot HART Debug Triggers : 2 triggers -Boot HART MIDELEG : 0x0000000000001666 -Boot HART MEDELEG : 0x0000000000f0b509 - - d8888 .d88888b. .d8888b. - d88888 d88P" "Y88b d88P Y88b - d88P888 888 888 Y88b. - d88P 888 888d888 .d8888b .d88b. 888 888 "Y888b. - d88P 888 888P" d88P" d8P Y8b 888 888 "Y88b. - d88P 888 888 888 88888888 888 888 "888 - d8888888888 888 Y88b. Y8b. Y88b. .d88P Y88b d88P -d88P 888 888 "Y8888P "Y8888 "Y88888P" "Y8888P" - -arch = riscv64 -platform = riscv64-qemu-virt -target = riscv64gc-unknown-none-elf -build_mode = release -log_level = info -smp = 1 - -[ 0.050694 0 axruntime:130] Logging is enabled. -[ 0.051812 0 axruntime:131] Primary CPU 0 started, dtb = 0x87e00000. -[ 0.052271 0 axruntime:133] Found physcial memory regions: -[ 0.052769 0 axruntime:135] [PA:0x80200000, PA:0x8020e000) .text (READ | EXECUTE | RESERVED) -[ 0.053344 0 axruntime:135] [PA:0x8020e000, PA:0x80213000) .rodata (READ | RESERVED) -[ 0.053654 0 axruntime:135] [PA:0x80213000, PA:0x80216000) .data .tdata .tbss .percpu (READ | WRITE | RESERVED) -[ 0.054036 0 axruntime:135] [PA:0x80216000, PA:0x80256000) boot stack (READ | WRITE | RESERVED) -[ 0.054365 0 axruntime:135] [PA:0x80256000, PA:0x8025b000) .bss (READ | WRITE | RESERVED) -[ 0.054717 0 axruntime:135] [PA:0x8025b000, PA:0x88000000) free memory (READ | WRITE | FREE) -[ 0.055082 0 axruntime:135] [PA:0x101000, PA:0x102000) mmio (READ | WRITE | DEVICE | RESERVED) -[ 0.055422 0 axruntime:135] [PA:0xc000000, PA:0xc210000) mmio (READ | WRITE | DEVICE | RESERVED) -[ 0.055779 0 axruntime:135] [PA:0x10000000, PA:0x10001000) mmio (READ | WRITE | DEVICE | RESERVED) -[ 0.056121 0 axruntime:135] [PA:0x10001000, PA:0x10009000) mmio (READ | WRITE | DEVICE | RESERVED) -[ 0.056459 0 axruntime:135] [PA:0x30000000, PA:0x40000000) mmio (READ | WRITE | DEVICE | RESERVED) -[ 0.056817 0 axruntime:135] [PA:0x40000000, PA:0x80000000) mmio (READ | WRITE | DEVICE | RESERVED) -[ 0.057224 0 axruntime:220] Initialize global memory allocator... -[ 0.057516 0 axruntime:221] use TLSF allocator. -[ 0.059694 0 axruntime:150] Initialize platform devices... -[ 0.060215 0 axtask::api:79] Initialize scheduling... -[ 0.061812 0 axtask::api:85] use FIFO scheduler. -[ 0.062727 0 axruntime:179] Initialize interrupt handlers... -[ 0.063594 0 axruntime:191] Primary CPU 0 init OK. -[ 0.065425 0:4 axembassy:52] spawner is set, unpark the main thread. -[ 0.066107 0:2 embassy_thread:128] Embassy Test -[ 1.202912 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1134855400/ns -[ 2.346125 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: duration 1142355700/ns -[ 3.468000 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: duration 1121481700/ns -[ 4.621488 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: duration 1153057100/ns -[ 4.622148 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: duration 10000/ns -[ 4.622819 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: duration 200/ns -[ 4.623138 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 200/ns -[ 4.623407 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns -[ 4.623921 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: Iteration 1, expected 1000000000/ns, actual 4555756900/ns, full 4555786100/ns -[ 5.773063 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1148658700/ns -[ 5.773457 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: Iteration 1, expected 2000000000/ns, actual 4569689400/ns, full 4569689600/ns -[ 6.901089 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: duration 1127243200/ns -[ 6.901744 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 1, expected 2000000000/ns, actual 2278399000/ns, full 2278399200/ns -[ 6.902184 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 200/ns -[ 6.902440 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 1, expected 1000000000/ns, actual 2279032600/ns, full 2279032700/ns -[ 6.902837 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns -[ 6.903088 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: Iteration 1, expected 3000000000/ns, actual 4556571300/ns, full 4556571600/ns -[ 8.010697 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: duration 1107165200/ns -[ 8.011118 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: Iteration 2, expected 1000000000/ns, actual 3386668000/ns, full 3387387200/ns -[ 9.139399 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1127869600/ns -[ 9.139843 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 2, expected 2000000000/ns, actual 2237590000/ns, full 2238235900/ns -[ 9.140232 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 200/ns -[ 9.140595 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: Iteration 1, expected 4000000000/ns, actual 4518606800/ns, full 4518633600/ns -[ 9.141155 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: duration 100/ns -[ 9.141403 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 2, expected 1000000000/ns, actual 2238566100/ns, full 2238963200/ns -[ 9.141781 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns -[ 9.142023 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: Iteration 1, expected 3000000000/ns, actual 4519204600/ns, full 4519204800/ns -[ 9.142433 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: duration 100/ns -[ 9.142704 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: Iteration 1, expected 4000000000/ns, actual 5674283600/ns, full 5674283800/ns -[ 10.243878 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: duration 1100767600/ns -[ 10.244337 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: Iteration 2, expected 2000000000/ns, actual 4470491900/ns, full 4470879000/ns -[ 11.326935 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: duration 1082215700/ns -[ 11.327306 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 3, expected 2000000000/ns, actual 2187075700/ns, full 2187531900/ns -[ 11.327677 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 200/ns -[ 11.327919 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 3, expected 1000000000/ns, actual 2186138300/ns, full 2186516000/ns -[ 11.328308 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns -[ 11.328551 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: Iteration 3, expected 1000000000/ns, actual 3317023100/ns, full 3317479900/ns -[ 12.432108 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1103153400/ns -[ 12.432473 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: Iteration 2, expected 3000000000/ns, actual 5528992300/ns, full 5529385000/ns -[ 13.546997 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: duration 1114133400/ns -[ 13.547484 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 4, expected 2000000000/ns, actual 2219807900/ns, full 2220178600/ns -[ 13.547867 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 100/ns -[ 13.548111 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: Iteration 2, expected 4000000000/ns, actual 4406955900/ns, full 4407515700/ns -[ 13.548484 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: duration 100/ns -[ 13.548723 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 4, expected 1000000000/ns, actual 2220415100/ns, full 2220804400/ns -[ 13.549132 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns -[ 13.549374 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: Iteration 2, expected 3000000000/ns, actual 4406941600/ns, full 4407350700/ns -[ 13.549747 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: duration 100/ns -[ 13.549989 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: Iteration 3, expected 2000000000/ns, actual 3305272800/ns, full 3305653100/ns -[ 14.699531 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: duration 1149062200/ns -[ 14.699939 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: Iteration 4, expected 1000000000/ns, actual 3370984500/ns, full 3371386900/ns -[ 15.820545 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1119988300/ns -[ 15.820894 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: Iteration 2, expected 4000000000/ns, actual 6677785100/ns, full 6678190900/ns -[ 16.923241 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: duration 1101942000/ns -[ 16.923596 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: Iteration 3, expected 3000000000/ns, actual 3373847200/ns, full 3374220800/ns -[ 16.924002 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: duration 100/ns -[ 16.924251 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 5, expected 2000000000/ns, actual 3376385500/ns, full 3376768000/ns -[ 16.924628 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 100/ns -[ 16.924869 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 5, expected 1000000000/ns, actual 3375737000/ns, full 3376145800/ns -[ 16.925244 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns -[ 16.926066 0:2 axhal::platform::riscv64_qemu_virt::misc:3] Shutting down... -make[1]: Leaving directory '/home/nostalgia/Proj/RustProj/oscamp-arceos' diff --git a/examples/embassy-thread/analysis/makefile b/examples/embassy-thread/analysis/makefile deleted file mode 100644 index 8b5d951d27..0000000000 --- a/examples/embassy-thread/analysis/makefile +++ /dev/null @@ -1,27 +0,0 @@ -RUN_CMD = $(MAKE) -C ../../../ A=$(shell pwd)/../ ARCH=riscv64 run LOG=info - -ITER ?= 0 -BASE_NAME ?= logs -SUMMARY ?= summary - -RAW_LOGS = raw_$(BASE_NAME)_$(ITER).txt -CLEANED_LOGS = $(BASE_NAME)_$(ITER).txt -SUMMARY_CSV = $(SUMMARY)_$(ITER).csv - -all: run purify analyze - -run: - $(RUN_CMD) > $(RAW_LOGS) - -# purify the ansi chars -purify: run - sed -r 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' $(RAW_LOGS) | \ - sed -r 's/^\[ [0-9\.]+ [0-9:]+ [^\]]+\] (.*)/\1/' > $(CLEANED_LOGS) - -analyze: - python3 analysis.py $(CLEANED_LOGS) $(SUMMARY_CSV) - -clean: - rm -f $(CLEANED_LOGS) $(RAW_LOGS) - -.PHONY: run purify analyze clean \ No newline at end of file diff --git a/examples/embassy-thread/analysis/raw_logs_100_000_000.txt b/examples/embassy-thread/analysis/raw_logs_100_000_000.txt deleted file mode 100644 index 47a6461976..0000000000 --- a/examples/embassy-thread/analysis/raw_logs_100_000_000.txt +++ /dev/null @@ -1,171 +0,0 @@ -make[1]: Entering directory '/home/nostalgia/Proj/RustProj/oscamp-arceos' -axconfig-gen configs/defconfig.toml configs/platforms/riscv64-qemu-virt.toml -w smp=1 -w arch=riscv64 -w platform=riscv64-qemu-virt -o "/home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/.axconfig.toml" -c "/home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/.axconfig.toml" - Building App: .., Arch: riscv64, Platform: riscv64-qemu-virt, App type: rust -cargo -C /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/../ build -Z unstable-options --target riscv64gc-unknown-none-elf --target-dir /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/target --release --features "axstd/log-level-info" -rust-objcopy --binary-architecture=riscv64 /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/..//.._riscv64-qemu-virt.elf --strip-all -O binary /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/..//.._riscv64-qemu-virt.bin - Running on qemu... -qemu-system-riscv64 -m 128M -smp 1 -machine virt -bios default -kernel /home/nostalgia/Proj/RustProj/oscamp-arceos/examples/embassy-thread/analysis/..//.._riscv64-qemu-virt.bin -nographic - -OpenSBI v1.5.1 - ____ _____ ____ _____ - / __ \ / ____| _ \_ _| - | | | |_ __ ___ _ __ | (___ | |_) || | - | | | | '_ \ / _ \ '_ \ \___ \| _ < | | - | |__| | |_) | __/ | | |____) | |_) || |_ - \____/| .__/ \___|_| |_|_____/|____/_____| - | | - |_| - -Platform Name : riscv-virtio,qemu -Platform Features : medeleg -Platform HART Count : 1 -Platform IPI Device : aclint-mswi -Platform Timer Device : aclint-mtimer @ 10000000Hz -Platform Console Device : uart8250 -Platform HSM Device : --- -Platform PMU Device : --- -Platform Reboot Device : syscon-reboot -Platform Shutdown Device : syscon-poweroff -Platform Suspend Device : --- -Platform CPPC Device : --- -Firmware Base : 0x80000000 -Firmware Size : 327 KB -Firmware RW Offset : 0x40000 -Firmware RW Size : 71 KB -Firmware Heap Offset : 0x49000 -Firmware Heap Size : 35 KB (total), 2 KB (reserved), 11 KB (used), 21 KB (free) -Firmware Scratch Size : 4096 B (total), 416 B (used), 3680 B (free) -Runtime SBI Version : 2.0 - -Domain0 Name : root -Domain0 Boot HART : 0 -Domain0 HARTs : 0* -Domain0 Region00 : 0x0000000000100000-0x0000000000100fff M: (I,R,W) S/U: (R,W) -Domain0 Region01 : 0x0000000010000000-0x0000000010000fff M: (I,R,W) S/U: (R,W) -Domain0 Region02 : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: () -Domain0 Region03 : 0x0000000080040000-0x000000008005ffff M: (R,W) S/U: () -Domain0 Region04 : 0x0000000080000000-0x000000008003ffff M: (R,X) S/U: () -Domain0 Region05 : 0x000000000c400000-0x000000000c5fffff M: (I,R,W) S/U: (R,W) -Domain0 Region06 : 0x000000000c000000-0x000000000c3fffff M: (I,R,W) S/U: (R,W) -Domain0 Region07 : 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X) -Domain0 Next Address : 0x0000000080200000 -Domain0 Next Arg1 : 0x0000000087e00000 -Domain0 Next Mode : S-mode -Domain0 SysReset : yes -Domain0 SysSuspend : yes - -Boot HART ID : 0 -Boot HART Domain : root -Boot HART Priv Version : v1.12 -Boot HART Base ISA : rv64imafdch -Boot HART ISA Extensions : sstc,zicntr,zihpm,zicboz,zicbom,sdtrig,svadu -Boot HART PMP Count : 16 -Boot HART PMP Granularity : 2 bits -Boot HART PMP Address Bits: 54 -Boot HART MHPM Info : 16 (0x0007fff8) -Boot HART Debug Triggers : 2 triggers -Boot HART MIDELEG : 0x0000000000001666 -Boot HART MEDELEG : 0x0000000000f0b509 - - d8888 .d88888b. .d8888b. - d88888 d88P" "Y88b d88P Y88b - d88P888 888 888 Y88b. - d88P 888 888d888 .d8888b .d88b. 888 888 "Y888b. - d88P 888 888P" d88P" d8P Y8b 888 888 "Y88b. - d88P 888 888 888 88888888 888 888 "888 - d8888888888 888 Y88b. Y8b. Y88b. .d88P Y88b d88P -d88P 888 888 "Y8888P "Y8888 "Y88888P" "Y8888P" - -arch = riscv64 -platform = riscv64-qemu-virt -target = riscv64gc-unknown-none-elf -build_mode = release -log_level = info -smp = 1 - -[ 0.050694 0 axruntime:130] Logging is enabled. -[ 0.051812 0 axruntime:131] Primary CPU 0 started, dtb = 0x87e00000. -[ 0.052271 0 axruntime:133] Found physcial memory regions: -[ 0.052769 0 axruntime:135]  [PA:0x80200000, PA:0x8020e000) .text (READ | EXECUTE | RESERVED) -[ 0.053344 0 axruntime:135]  [PA:0x8020e000, PA:0x80213000) .rodata (READ | RESERVED) -[ 0.053654 0 axruntime:135]  [PA:0x80213000, PA:0x80216000) .data .tdata .tbss .percpu (READ | WRITE | RESERVED) -[ 0.054036 0 axruntime:135]  [PA:0x80216000, PA:0x80256000) boot stack (READ | WRITE | RESERVED) -[ 0.054365 0 axruntime:135]  [PA:0x80256000, PA:0x8025b000) .bss (READ | WRITE | RESERVED) -[ 0.054717 0 axruntime:135]  [PA:0x8025b000, PA:0x88000000) free memory (READ | WRITE | FREE) -[ 0.055082 0 axruntime:135]  [PA:0x101000, PA:0x102000) mmio (READ | WRITE | DEVICE | RESERVED) -[ 0.055422 0 axruntime:135]  [PA:0xc000000, PA:0xc210000) mmio (READ | WRITE | DEVICE | RESERVED) -[ 0.055779 0 axruntime:135]  [PA:0x10000000, PA:0x10001000) mmio (READ | WRITE | DEVICE | RESERVED) -[ 0.056121 0 axruntime:135]  [PA:0x10001000, PA:0x10009000) mmio (READ | WRITE | DEVICE | RESERVED) -[ 0.056459 0 axruntime:135]  [PA:0x30000000, PA:0x40000000) mmio (READ | WRITE | DEVICE | RESERVED) -[ 0.056817 0 axruntime:135]  [PA:0x40000000, PA:0x80000000) mmio (READ | WRITE | DEVICE | RESERVED) -[ 0.057224 0 axruntime:220] Initialize global memory allocator... -[ 0.057516 0 axruntime:221]  use TLSF allocator. -[ 0.059694 0 axruntime:150] Initialize platform devices... -[ 0.060215 0 axtask::api:79] Initialize scheduling... -[ 0.061812 0 axtask::api:85]  use FIFO scheduler. -[ 0.062727 0 axruntime:179] Initialize interrupt handlers... -[ 0.063594 0 axruntime:191] Primary CPU 0 init OK. -[ 0.065425 0:4 axembassy:52] spawner is set, unpark the main thread. -[ 0.066107 0:2 embassy_thread:128] Embassy Test -[ 1.202912 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1134855400/ns -[ 2.346125 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: duration 1142355700/ns -[ 3.468000 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: duration 1121481700/ns -[ 4.621488 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: duration 1153057100/ns -[ 4.622148 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: duration 10000/ns -[ 4.622819 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: duration 200/ns -[ 4.623138 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 200/ns -[ 4.623407 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns -[ 4.623921 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: Iteration 1, expected 1000000000/ns, actual 4555756900/ns, full 4555786100/ns -[ 5.773063 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1148658700/ns -[ 5.773457 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: Iteration 1, expected 2000000000/ns, actual 4569689400/ns, full 4569689600/ns -[ 6.901089 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: duration 1127243200/ns -[ 6.901744 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 1, expected 2000000000/ns, actual 2278399000/ns, full 2278399200/ns -[ 6.902184 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 200/ns -[ 6.902440 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 1, expected 1000000000/ns, actual 2279032600/ns, full 2279032700/ns -[ 6.902837 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns -[ 6.903088 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: Iteration 1, expected 3000000000/ns, actual 4556571300/ns, full 4556571600/ns -[ 8.010697 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: duration 1107165200/ns -[ 8.011118 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: Iteration 2, expected 1000000000/ns, actual 3386668000/ns, full 3387387200/ns -[ 9.139399 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1127869600/ns -[ 9.139843 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 2, expected 2000000000/ns, actual 2237590000/ns, full 2238235900/ns -[ 9.140232 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 200/ns -[ 9.140595 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: Iteration 1, expected 4000000000/ns, actual 4518606800/ns, full 4518633600/ns -[ 9.141155 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: duration 100/ns -[ 9.141403 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 2, expected 1000000000/ns, actual 2238566100/ns, full 2238963200/ns -[ 9.141781 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns -[ 9.142023 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: Iteration 1, expected 3000000000/ns, actual 4519204600/ns, full 4519204800/ns -[ 9.142433 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: duration 100/ns -[ 9.142704 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: Iteration 1, expected 4000000000/ns, actual 5674283600/ns, full 5674283800/ns -[ 10.243878 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: duration 1100767600/ns -[ 10.244337 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: Iteration 2, expected 2000000000/ns, actual 4470491900/ns, full 4470879000/ns -[ 11.326935 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: duration 1082215700/ns -[ 11.327306 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 3, expected 2000000000/ns, actual 2187075700/ns, full 2187531900/ns -[ 11.327677 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 200/ns -[ 11.327919 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 3, expected 1000000000/ns, actual 2186138300/ns, full 2186516000/ns -[ 11.328308 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns -[ 11.328551 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: Iteration 3, expected 1000000000/ns, actual 3317023100/ns, full 3317479900/ns -[ 12.432108 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1103153400/ns -[ 12.432473 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: Iteration 2, expected 3000000000/ns, actual 5528992300/ns, full 5529385000/ns -[ 13.546997 0:7 embassy_thread:105] NATIVE_THREAD_REPORT 3: duration 1114133400/ns -[ 13.547484 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 4, expected 2000000000/ns, actual 2219807900/ns, full 2220178600/ns -[ 13.547867 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 100/ns -[ 13.548111 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: Iteration 2, expected 4000000000/ns, actual 4406955900/ns, full 4407515700/ns -[ 13.548484 0:4 embassy_thread:93] ASYNC_TASK_REPORT 4: duration 100/ns -[ 13.548723 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 4, expected 1000000000/ns, actual 2220415100/ns, full 2220804400/ns -[ 13.549132 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns -[ 13.549374 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: Iteration 2, expected 3000000000/ns, actual 4406941600/ns, full 4407350700/ns -[ 13.549747 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: duration 100/ns -[ 13.549989 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: Iteration 3, expected 2000000000/ns, actual 3305272800/ns, full 3305653100/ns -[ 14.699531 0:6 embassy_thread:105] NATIVE_THREAD_REPORT 2: duration 1149062200/ns -[ 14.699939 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: Iteration 4, expected 1000000000/ns, actual 3370984500/ns, full 3371386900/ns -[ 15.820545 0:5 embassy_thread:105] NATIVE_THREAD_REPORT 1: duration 1119988300/ns -[ 15.820894 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: Iteration 2, expected 4000000000/ns, actual 6677785100/ns, full 6678190900/ns -[ 16.923241 0:8 embassy_thread:105] NATIVE_THREAD_REPORT 4: duration 1101942000/ns -[ 16.923596 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: Iteration 3, expected 3000000000/ns, actual 3373847200/ns, full 3374220800/ns -[ 16.924002 0:4 embassy_thread:93] ASYNC_TASK_REPORT 3: duration 100/ns -[ 16.924251 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: Iteration 5, expected 2000000000/ns, actual 3376385500/ns, full 3376768000/ns -[ 16.924628 0:4 embassy_thread:93] ASYNC_TASK_REPORT 2: duration 100/ns -[ 16.924869 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: Iteration 5, expected 1000000000/ns, actual 3375737000/ns, full 3376145800/ns -[ 16.925244 0:4 embassy_thread:93] ASYNC_TASK_REPORT 1: duration 100/ns -[ 16.926066 0:2 axhal::platform::riscv64_qemu_virt::misc:3] Shutting down... -make[1]: Leaving directory '/home/nostalgia/Proj/RustProj/oscamp-arceos' diff --git a/examples/embassy-thread/analysis/summary_100_000_000.csv b/examples/embassy-thread/analysis/summary_100_000_000.csv deleted file mode 100644 index 94b3a08f11..0000000000 --- a/examples/embassy-thread/analysis/summary_100_000_000.csv +++ /dev/null @@ -1,5 +0,0 @@ -timestamp,log_type,metric_name,count,mean_absolute_deviation,std_deviation,min_deviation,max_deviation -2025-06-07T13:59:11.082946,native_report,actual_ns,11,2310319900,618000176.29,1305272800,3555756900 -2025-06-07T13:59:11.082946,native_report,full_ns,11,2310608463.64,618005599.33,1305653100,3555786100 -2025-06-07T13:59:11.082946,async_report,actual_ns,15,921646886.67,651505893.62,187075700,2375737000 -2025-06-07T13:59:11.082946,async_report,full_ns,15,921966753.33,651480522.89,187531900,2376145800 diff --git a/examples/embassy-thread/src/main.rs b/examples/embassy-thread/src/main.rs deleted file mode 100644 index e6f14cb662..0000000000 --- a/examples/embassy-thread/src/main.rs +++ /dev/null @@ -1,142 +0,0 @@ -#![feature(impl_trait_in_assoc_type)] -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[macro_use] -#[cfg(feature = "axstd")] -extern crate axstd as std; - -use axasync::executor::spawner; -use axasync::executor::yield_now; -use axasync::time::Timer; -use core::hint::black_box; -use std::thread::{self, sleep}; -use std::time::Duration; - -fn busy_work(iters: u64) -> u64 { - let mut total = 0; - for _ in 0..iters { - total = black_box(total + 1); - total = black_box(total * 3 / 2); - } - black_box(total) -} - -async fn async_busy_work(iters: u64) -> u64 { - let mut total = 0; - for _ in 0..iters { - total = black_box(total + 1); - total = black_box(total * 3 / 2); - yield_now().await; - } - black_box(total) -} - -macro_rules! task_loop { - ( - task_type: $task_type:literal, - id: $id:expr, - sleep: $sleep_fn:expr, - // millis restriction - millis: $millis:expr, - $(is_await: $await_tt:tt,)? - busy_work: $busy_work:expr, - busy_iters: $busy_iters:expr, - ) => { - use std::time::{Instant,Duration}; - use log; - use core::hint::black_box; - - let mut cnt = 0; - let mut last_report = Instant::now(); - let millis = Duration::from_millis($millis); - - loop { - let iter_start = Instant::now(); - cnt += 1; - - if $busy_iters > 0 { - let busy_start = Instant::now(); - let _res = black_box($busy_work($busy_iters)); - let busy_dur = Instant::now() - busy_start; - log::info!( - "{} {}: duration {}/ns", - $task_type, - $id, - busy_dur.as_nanos() - ) - } - - $sleep_fn($millis)$(.$await_tt)?; - - let iter_end = Instant::now(); - let iter_dur = iter_end - iter_start; - let full_dur = iter_end - last_report; - - log::info!( - "{} {}: Iteration {}, expected {}/ns, actual {}/ns, full {}/ns", - $task_type, - $id, - cnt, - millis.as_nanos(), - iter_dur.as_nanos(), - full_dur.as_nanos(), - ); - - last_report = iter_end; - } - }; -} - -#[embassy_executor::task(pool_size = 5)] -async fn async_tick(id: u64, millis: u64, busy_iters: u64) { - task_loop! { - task_type: "ASYNC_TASK_REPORT", - id:id, - sleep: |millis| async move {Timer::after_millis(millis).await}, - millis:millis, - is_await: await, - busy_work: async_busy_work, - busy_iters:busy_iters, - } -} - -fn thread_tick(id: u64, millis: u64, busy_iters: u64) { - task_loop! { - task_type: "NATIVE_THREAD_REPORT", - id:id, - sleep: |millis| sleep(Duration::from_millis(millis)), - millis:millis, - busy_work: busy_work, - busy_iters:busy_iters, - } -} - -const NUM_THREADS: u64 = 5; -const NUM_TASKS: u64 = 5; -// const NUM_ITERS_THREADS: u64 = 0; -// const NUM_ITERS_THREADS: u64 = 1_000; -// const NUM_ITERS_THREADS: u64 = 1_000_000; -const NUM_ITERS_THREADS: u64 = 100_000_000; -// const NUM_ITERS_TASKS: u64 = 0; -// const NUM_ITERS_TASKS: u64 = 1_000; -// const NUM_ITERS_TASKS: u64 = 1_000_000; -const NUM_ITERS_TASKS: u64 = 100_000_000; - -#[cfg_attr(feature = "axstd", unsafe(no_mangle))] -fn main() { - log::info!("Embassy Test"); - for i in 1..NUM_THREADS { - thread::spawn(move || { - thread_tick(i, i * 1000, NUM_ITERS_THREADS); - }); - } - - for i in 1..NUM_TASKS { - spawner() - .spawn(async_tick(i, i * 1000, NUM_ITERS_TASKS)) - .unwrap(); - } - // Avoid shut down immediately - sleep(Duration::from_millis(1000 * 15 as u64)); -} diff --git a/modules/axembassy/Cargo.toml b/modules/axembassy/Cargo.toml index a34475e1de..1595baa973 100644 --- a/modules/axembassy/Cargo.toml +++ b/modules/axembassy/Cargo.toml @@ -13,26 +13,24 @@ driver = [ "dep:percpu", "axhal/irq", ] -# executor is thread dependent -executor-thread = [ +embassy-utils = [ "dep:embassy-executor", "dep:embassy-futures", "dep:embassy-sync", - "axtask/multitask", ] -executor-single = [ - "dep:embassy-executor", - "dep:embassy-futures", - "dep:embassy-sync", - "axhal/irq", -] +# executor is in thread interaction +executor-preempt = ["executor-thread"] +executor-thread = ["embassy-utils", "axtask/multitask", "dep:axsync"] + +executor-single = ["embassy-utils", "axhal/irq"] default = ["driver"] [dependencies] axconfig = { workspace = true } axhal = { workspace = true, features = ["irq"] } +axsync = { workspace = true, features = ["multitask"], optional = true } axtask = { workspace = true } embassy-time-driver = { git = "https://github.com/embassy-rs/embassy", branch = "main", optional = true, features = [ diff --git a/modules/axembassy/src/asynch.rs b/modules/axembassy/src/asynch.rs index cfdd80b9ff..05789bb7cb 100644 --- a/modules/axembassy/src/asynch.rs +++ b/modules/axembassy/src/asynch.rs @@ -4,21 +4,52 @@ use core::{ task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, }; -use axtask::{park_current_task, unpark_task}; -use kspin::SpinNoIrq; +use axsync::Mutex; +use axtask::yield_now; pub use embassy_executor::{SendSpawner, Spawner}; -pub(crate) static SPAWNER: SpinNoIrq> = SpinNoIrq::new(OnceCell::new()); +pub(crate) static SPAWNER: Mutex> = Mutex::new(OnceCell::new()); + +fn init_spawn() { + use axtask::spawn_raw; + spawn_raw(init, "async".into(), axconfig::TASK_STACK_SIZE); +} + +fn init() { + use crate::executor_thread::Executor; + use static_cell::StaticCell; + + static EXECUTOR: StaticCell = StaticCell::new(); + EXECUTOR + .init_with(Executor::new) + .run(|sp| sp.must_spawn(init_task())); +} + +#[embassy_executor::task] +async fn init_task() { + use crate::asynch; + + let spawner = asynch::Spawner::for_current_executor().await; + asynch::set_spawner(spawner.make_send()); + log::info!("Initialize spawner... "); +} -/// Get a spawner for the system executor. -/// /// # Panics /// /// Panics if the system executor is not initialized. pub fn spawner() -> SendSpawner { let sp = SPAWNER.lock(); - *sp.get().unwrap() + if let Some(inner) = sp.get() { + *inner + } else { + drop(sp); + init_spawn(); + yield_now(); + // initialize the spawner if not + let sp = SPAWNER.lock(); + *sp.get().expect("Reinitialize the spawner failed") + } } /// Set the spawner for the system executor. @@ -30,8 +61,8 @@ pub(crate) fn set_spawner(spawner: SendSpawner) { } fn wake(ctx: *const ()) { - let id = ctx as u64; - unpark_task(id, true); + // let id = ctx as u64; + // unpark_task(id, true); } static VTABLE: RawWakerVTable = @@ -50,6 +81,6 @@ pub fn block_on(mut fut: F) -> F::Output { if let Poll::Ready(res) = fut.as_mut().poll(&mut ctx) { return res; } - park_current_task(); + yield_now(); } } diff --git a/modules/axembassy/src/delegate.rs b/modules/axembassy/src/delegate.rs index c89d58b43d..3e300964b0 100644 --- a/modules/axembassy/src/delegate.rs +++ b/modules/axembassy/src/delegate.rs @@ -157,6 +157,7 @@ impl Delegate { } } + /// lend pub async fn lend<'a, 'b: 'a>(&'a self, target: &'b mut T) -> Result<(), DelegateError> { use DelegateError::*; use DelegateState::*; @@ -182,11 +183,28 @@ impl Delegate { Ok(()) } + /// lend and reset + pub async fn lend_new<'a, 'b: 'a>(&'a self, target: &'b mut T) -> Result<(), DelegateError> { + match self.lend(target).await { + Ok(()) => { + self.reset(); + Ok(()) + } + Err(e) => Err(e), + } + } + pub async fn with(&self, func: impl FnOnce(&mut T) -> U) -> Result { use DelegateError::*; use DelegateState::*; let data = self.send.wait().await; + let sp = Spawner::for_current_executor().await; + let res = { + let ptr = unsafe { data.get(sp).unwrap().as_mut().unwrap() }; + func(ptr) + }; + match self.state.compare_exchange( Lent as u8, Consumed as u8, @@ -197,12 +215,6 @@ impl Delegate { Err(_) => return Err(WithInvalid), } - let sp = Spawner::for_current_executor().await; - let res = { - let ptr = unsafe { data.get(sp).unwrap().as_mut().unwrap() }; - func(ptr) - }; - self.reply.signal(()); Ok(res) } diff --git a/modules/axembassy/src/executor_thread.rs b/modules/axembassy/src/executor_thread.rs index e89099a5e3..b367c50865 100644 --- a/modules/axembassy/src/executor_thread.rs +++ b/modules/axembassy/src/executor_thread.rs @@ -1,7 +1,5 @@ -use axtask::{park_current_task, unpark_task}; use core::marker::PhantomData; use core::sync::atomic::{AtomicBool, Ordering}; -use core::u64; use embassy_executor::raw; #[percpu::def_percpu] @@ -12,8 +10,6 @@ fn __pender(_context: *mut ()) { SIGNAL_WORK_THREAD_MODE.with_current(|m| { m.store(true, Ordering::SeqCst); }); - let id = _context as u64; - unpark_task(id, true); } pub struct Executor { @@ -49,7 +45,8 @@ impl Executor { m.store(false, Ordering::SeqCst); }); } else { - park_current_task(); + // park_current_task(); + axtask::yield_now(); } }; } diff --git a/modules/axembassy/src/lib.rs b/modules/axembassy/src/lib.rs index f80b26f856..a2925d72e4 100644 --- a/modules/axembassy/src/lib.rs +++ b/modules/axembassy/src/lib.rs @@ -7,59 +7,46 @@ cfg_if::cfg_if! { extern crate alloc; extern crate log; - mod asynch; pub mod delegate; #[cfg(feature = "executor-thread")] mod executor_thread; #[cfg(feature = "executor-thread")] - pub use crate::executor_thread::Executor; + mod asynch; #[cfg(feature = "executor-thread")] - pub use crate::asynch::{spawner,block_on,Spawner,SendSpawner}; + mod executor_thread_exports { + pub use crate::executor_thread::Executor; + pub use crate::asynch::{spawner,block_on,Spawner,SendSpawner}; + #[cfg(feature = "executor-preempt")] + pub use crate::preempt::PrioFuture; + } + #[cfg(feature = "executor-thread")] + pub use executor_thread_exports::*; #[cfg(feature = "executor-single")] mod executor; #[cfg(feature = "executor-single")] - pub use crate::executor::Executor; - #[cfg(feature = "executor-single")] - pub use crate::asynch::Spawner; - - #[cfg(feature = "executor-thread")] - pub fn init_spawn() { - use axtask::spawn_raw; - spawn_raw(init, "async".into(), axconfig::TASK_STACK_SIZE); - } - - #[cfg(feature = "executor-thread")] - pub fn init() { - use crate::executor_thread::Executor; - use static_cell::StaticCell; - - static EXECUTOR: StaticCell = StaticCell::new(); - EXECUTOR - .init_with(Executor::new) - .run(|sp| sp.must_spawn(init_task())); - } - - #[cfg(feature = "executor-thread")] - #[embassy_executor::task] - async fn init_task() { - use axtask::unpark_task; - use log::info; - - let spawner = asynch::Spawner::for_current_executor().await; - asynch::set_spawner(spawner.make_send()); - info!("spawner is set, unpark the main thread."); - unpark_task(2, true); + mod executor_exports { + pub use crate::executor::Executor; + pub use crate::asynch::Spawner; } + #[cfg(feature = "executor-single")] + pub use executor_exports::*; } } +mod preempt; + #[cfg(feature = "driver")] mod time_driver; #[cfg(feature = "driver")] pub use crate::time_driver::AxDriverAPI; -#[cfg(all(feature = "executor-thread", feature = "executor-single"))] -compile_error!("feature `executor-thread` and `executor-single` are mutually exclusive"); +#[cfg(all( + any(feature = "executor-thread", feature = "executor-preempt"), + feature = "executor-single" +))] +compile_error!( + "feature `executor-thread`/`executor-preempt` and `executor-single` are mutually exclusive" +); diff --git a/modules/axembassy/src/preempt.rs b/modules/axembassy/src/preempt.rs new file mode 100644 index 0000000000..d0e12d6bcd --- /dev/null +++ b/modules/axembassy/src/preempt.rs @@ -0,0 +1,298 @@ +use alloc::collections::BTreeMap; +use axsync::Mutex; +use core::{ + pin::Pin, + sync::atomic::{AtomicU64, Ordering}, + task::{Context, Poll}, +}; + +/// Represents a user-defined priority, ranging from 0 to 255. +type UserPrio = u8; +const MIN_USER_PRIO: UserPrio = u8::MAX; +const MAX_USER_PRIO: UserPrio = u8::MIN; + +/// A fixed-point representation of priority to handle fractional values. +/// This type ensures consistent scaling and avoids magic numbers in calculations. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +struct Prio(u64); + +impl From for Prio { + fn from(value: UserPrio) -> Self { + // Scale the user-priority to the internal fixed-point representation. + Self((value as u64).saturating_mul(Prio::SCALING_FACTOR)) + } +} + +impl From for u64 { + fn from(prio: Prio) -> u64 { + prio.0 + } +} + +impl Prio { + const MAX_PRIO: Prio = Prio::raw_new(MAX_USER_PRIO as u64 * Prio::SCALING_FACTOR); + const MIN_PRIO: Prio = Prio::raw_new(MIN_USER_PRIO as u64 * Prio::SCALING_FACTOR); + /// The scaling factor for converting `UserPrio` to `Prio`'s internal `u64` representation. + const SCALING_FACTOR: u64 = 100; + + /// Weights for factors in priority adjustment. + const PRIO_EFFECT: u64 = 70; + const ACTIVE_EFFECT: u64 = 30; + + /// Clamping range for normalized factors. + const CLAMP_MIN: u64 = 10; + const CLAMP_MAX: u64 = 100; + + /// Tolerance range for priority check, as a percentage of the priority. + const TOL: u64 = 10; + + const fn raw_new(prio: u64) -> Self { + Self(prio) + } + + /// Returns the raw `u64` value of the priority. + pub const fn as_u64(&self) -> u64 { + self.0 + } + + /// Converts Prio to `UserPrio` (u8). + /// + /// Returns `None` if the priority overflows `UserPrio`. + pub const fn as_user_prio(&self) -> Option { + let prio = self.0.div_euclid(Prio::SCALING_FACTOR); + if prio > MIN_USER_PRIO as u64 { + None + } else { + Some(prio as u8) + } + } + + /// Normalizes a current value within a given bound to a range [CLAMP_MIN_FACTOR, CLAMP_MAX_FACTOR]. + /// + /// # Returns + /// `(norm_pos, norm_neg)` where: + /// - `norm_pos` indicates closeness to the lower bound (higher for values closer to low). + /// - `norm_neg` indicates closeness to the upper bound (higher for values closer to high). + pub fn norm_factor, G: Into>(bound: (F, F), cur: G) -> (u64, u64) { + let (mut low, mut high) = (bound.0.into(), bound.1.into()); + if low > high { + core::mem::swap(&mut low, &mut high); + } + let cur = cur.into(); + + if high == low { + // Avoid division by zero if bounds are the same + return (Prio::CLAMP_MAX, Prio::CLAMP_MAX); + } + + let range = high - low; + let norm_pos = ((cur - low).saturating_mul(Prio::CLAMP_MAX) / range) + .clamp(Prio::CLAMP_MIN, Prio::CLAMP_MAX); + let norm_neg = ((high - cur).saturating_mul(Prio::CLAMP_MAX) / range) + .clamp(Prio::CLAMP_MIN, Prio::CLAMP_MAX); + (norm_pos, norm_neg) + } + + /// Applies a weight to a normalized factor. + pub fn weight, G: Into>(factor: F, weight: G) -> u64 { + factor + .into() + .saturating_mul(weight.into()) + .div_euclid(Prio::CLAMP_MAX) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +struct FutureId(u64); + +impl FutureId { + pub fn new() -> Self { + static ID_COUNTER: AtomicU64 = AtomicU64::new(1); + Self(ID_COUNTER.fetch_add(1, Ordering::Relaxed)) + } + /// Convert the task ID to a `u64`. + pub const fn as_u64(&self) -> u64 { + self.0 + } +} + +pub struct PrioFuture { + inner: F, + id: FutureId, + prio: Prio, +} + +impl PrioFuture { + /// Creates a new `PrioFuture` with an initial user priority. + pub fn new(fut: F, prio: UserPrio) -> Self { + let id = FutureId::new(); + SCHEDULER.lock().insert(id, prio.into()); + Self { + inner: fut, + id, + prio: prio.into(), + } + } + + /// Sets a new user priority for the future. + pub fn set_prio(&mut self, prio: UserPrio) { + self.prio = prio.into(); + SCHEDULER.lock().insert(self.id, prio.into()); + } +} + +impl Future for PrioFuture { + type Output = F::Output; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let this = unsafe { self.get_unchecked_mut() }; + + let mut s = SCHEDULER.lock(); + let cur_prio = s.cur_prio; + let prio = this.prio; + let tol = Prio::weight(prio, Prio::TOL); + + s.adjust_cur_prio(prio); + + // If future prio > cur_prio + tolerance, park it + let threshold: u64 = prio.as_u64().saturating_sub(cur_prio); + if threshold > tol { + // info!("prio: {}, cur_prio: {}", this.prio, s.cur_prio); + s.park_future(this.id); + cx.waker().wake_by_ref(); + return Poll::Pending; + } else { + s.unpark_future(this.id); + } + + // SAFETY: Just projecting the pin + let inner = unsafe { Pin::new_unchecked(&mut this.inner) }; + match inner.poll(cx) { + Poll::Ready(output) => Poll::Ready(output), + Poll::Pending => Poll::Pending, + } + } +} + +impl Drop for PrioFuture { + fn drop(&mut self) { + SCHEDULER.lock().remove(self.id); + } +} + +static SCHEDULER: Mutex = Mutex::new(PrioScheduler::new()); + +type Active = usize; +type All = usize; +type PrioStatus = (Active, All); +type FutureInfo = (Prio, bool); // (pirority, is_active) +struct PrioScheduler { + pub cur_prio: u64, + tasks: BTreeMap, + status: BTreeMap, +} + +impl PrioScheduler { + pub const fn new() -> Self { + Self { + cur_prio: MIN_USER_PRIO as u64 * Prio::SCALING_FACTOR, + tasks: BTreeMap::new(), + status: BTreeMap::new(), + } + } + /// Parks a future, marking it as inactive. + pub fn park_future(&mut self, id: FutureId) { + if let Some((prio, true)) = self.tasks.get(&id) { + self.status.entry(*prio).and_modify(|(active, _)| { + *active = active.saturating_sub(1); + }); + self.tasks.insert(id, (*prio, false)); + } + } + /// Unparks a future, marking it as active. + pub fn unpark_future(&mut self, id: FutureId) { + if let Some((prio, false)) = self.tasks.get(&id) { + self.status.entry(*prio).and_modify(|(active, _)| { + *active += 1; + }); + self.tasks.insert(id, (*prio, true)); + } + } + + /// Return the highest and lowest priority in the active future + /// + /// # Output + /// + /// `(high, low)` + fn prio_range(&self) -> (Prio, Prio) { + let high = self + .status + .iter() + .filter(|(_, (active, _))| *active > 0) + .next() + .map(|(prio, _)| *prio) + .unwrap_or(Prio::MAX_PRIO); + let low = self + .status + .iter() + .filter(|(_, (active, _))| *active > 0) + .last() + .map(|(prio, _)| *prio) + .unwrap_or(Prio::MIN_PRIO); + (high, low) + } + + fn get_prio_status(&self, prio: Prio) -> PrioStatus { + self.status.get(&prio).cloned().unwrap_or((1, 1)) + } + pub fn adjust_cur_prio(&mut self, prio: Prio) { + let (active, all) = self.get_prio_status(prio); + let (_, norm_active) = Prio::norm_factor((all as u64, 0), active as u64); + + let (highest, lowest) = self.prio_range(); + let (norm_prio, _) = Prio::norm_factor((highest, lowest), prio); + + let prio: u64 = prio.into(); + let cur_prio = self.cur_prio.into(); + let factor = (Prio::weight(norm_prio, Prio::PRIO_EFFECT) + .saturating_add(Prio::weight(norm_active, Prio::ACTIVE_EFFECT))) + .clamp(Prio::CLAMP_MIN, Prio::CLAMP_MAX); + if prio > cur_prio { + self.cur_prio += Prio::weight(prio - cur_prio, factor); + } else { + self.cur_prio -= Prio::weight(cur_prio - prio, factor); + } + } + + pub fn insert(&mut self, id: FutureId, prio: Prio) { + self.status + .entry(prio) + .and_modify(|(active, all)| { + *active += 1; + *all += 1; + }) + .or_insert((1, 1)); + self.tasks + .entry(id) + .and_modify(|(old_prio, _)| { + self.status.entry(*old_prio).and_modify(|(_, cnt)| { + *cnt = cnt.saturating_sub(1); + }); + *old_prio = prio; + }) + .or_insert((prio, true)); + } + + pub fn remove(&mut self, id: FutureId) { + let Some((prio, activated)) = self.tasks.remove(&id) else { + return; + }; + self.status.entry(prio).and_modify(|(active, all)| { + if activated { + *active = active.saturating_sub(1); + } + *all = all.saturating_sub(1); + }); + self.status.retain(|_, (_, all)| *all > 0); + } +} diff --git a/modules/axembassy/src/time_driver.rs b/modules/axembassy/src/time_driver.rs index dcdce5b252..5cab7ddaa0 100644 --- a/modules/axembassy/src/time_driver.rs +++ b/modules/axembassy/src/time_driver.rs @@ -1,4 +1,5 @@ use core::cell::RefCell; +use core::sync::atomic::{AtomicU64,Ordering}; use core::task; use axhal::time::{self, NANOS_PER_SEC, set_oneshot_timer}; @@ -28,7 +29,7 @@ fn nanos_to_ticks(nanos: u64) -> u64 { struct AxDriver { queue: SpinNoIrq>, // static period interval - periodic_interval_nanos: SpinNoIrq, + period_nanos: AtomicU64, } time_driver_impl!(static AX_DRIVER: AxDriver = AxDriver::new()); @@ -37,7 +38,7 @@ impl AxDriver { pub const fn new() -> Self { AxDriver { queue: SpinNoIrq::new(RefCell::new(Queue::new())), - periodic_interval_nanos: SpinNoIrq::new(0), + period_nanos: AtomicU64::new(0), } } @@ -59,7 +60,7 @@ impl AxDriver { let ticks_next_at = queue.next_expiration(self.now()); let nanos_next_at = ticks_to_nanos(ticks_next_at); let nanos_next_interval = nanos_next_at - Self::nanos_now(); - let nanos_period = *self.periodic_interval_nanos.lock(); + let nanos_period = self.period_nanos.load(Ordering::Relaxed); if nanos_next_interval < nanos_period { // only set timer if it is less than the periodic interval set_oneshot_timer(nanos_next_at); @@ -71,9 +72,7 @@ impl AxDriver { pub fn next_expiration(&self, period: u64) -> u64 { let queue_guard = self.queue.lock(); let mut queue = queue_guard.borrow_mut(); - if *self.periodic_interval_nanos.lock() == 0 { - *self.periodic_interval_nanos.lock() = period; - } + self.period_nanos.store(period, Ordering::Release); let ticks_now = self.now(); diff --git a/modules/axruntime/src/lib.rs b/modules/axruntime/src/lib.rs index 94c17d8e31..a80c0c4a38 100644 --- a/modules/axruntime/src/lib.rs +++ b/modules/axruntime/src/lib.rs @@ -153,7 +153,6 @@ pub extern "C" fn rust_main(cpu_id: usize, dtb: usize) -> ! { #[cfg(feature = "multitask")] { axtask::init_scheduler(); - axembassy::init_spawn(); } #[cfg(any(feature = "fs", feature = "net", feature = "display"))] @@ -196,11 +195,6 @@ pub extern "C" fn rust_main(cpu_id: usize, dtb: usize) -> ! { } unsafe { - #[cfg(feature = "multitask")] - { - // park main task to let embassy task initialize first - axtask::park_current_task() - } main() }; @@ -260,9 +254,9 @@ fn init_interrupt() { while now_ns >= deadline { deadline = now_ns + PERIODIC_INTERVAL_NANOS; } - use axembassy::AxDriverAPI; #[cfg(feature = "embassy-timer")] { + use axembassy::AxDriverAPI; let next_expired = AxDriverAPI::next_expiration(PERIODIC_INTERVAL_NANOS); if deadline >= next_expired { deadline = next_expired; diff --git a/modules/axtask/src/api.rs b/modules/axtask/src/api.rs index 9fa3bae7c1..c79786cc30 100644 --- a/modules/axtask/src/api.rs +++ b/modules/axtask/src/api.rs @@ -11,14 +11,10 @@ pub use crate::task::{CurrentTask, TaskId, TaskInner}; #[doc(cfg(feature = "multitask"))] pub use crate::task_ext::{TaskExtMut, TaskExtRef}; #[doc(cfg(feature = "multitask"))] -pub use crate::task_registry::{find_task_by_id, park_current_task, unpark_task}; -#[doc(cfg(feature = "multitask"))] pub use crate::wait_queue::WaitQueue; #[doc(cfg(feature = "multitask"))] pub use crate::wait_queues::{Futex, futex_wait, futex_wake, futex_wake_all}; -pub static THREAD_START_EVENT: crate::events::Event = crate::events::Event::new(); - /// The reference type of a task. pub type AxTaskRef = Arc; @@ -210,13 +206,19 @@ pub fn exit(exit_code: i32) -> ! { current_run_queue::().exit_current(exit_code) } +/// Park the current task. +pub fn park_current_task() { + let mut cur_rq = current_run_queue::(); + cur_rq.park_current_task(); +} + /// The idle task routine. /// /// It runs an infinite loop that keeps calling [`yield_now()`]. pub fn run_idle() -> ! { loop { yield_now(); - debug!("idle task: waiting for IRQs..."); + // debug!("idle task: waiting for IRQs..."); #[cfg(feature = "irq")] axhal::arch::wait_for_irqs(); } diff --git a/modules/axtask/src/events.rs b/modules/axtask/src/events.rs deleted file mode 100644 index b1ce321625..0000000000 --- a/modules/axtask/src/events.rs +++ /dev/null @@ -1,86 +0,0 @@ -use kspin::SpinNoIrq; - -use crate::WaitQueue; - -pub struct Event { - state: SpinNoIrq, -} - -unsafe impl Sync for Event {} - -#[derive(Debug)] -enum LockState { - Unlocked, - Locked(WaitQueue), -} - -impl Default for LockState { - fn default() -> Self { - LockState::Locked(WaitQueue::new()) - } -} - -impl Event { - #[must_use] - pub const fn new() -> Self { - Self { - state: SpinNoIrq::new(LockState::Locked(WaitQueue::new())), - } - } - - #[must_use] - pub const fn new_set() -> Self { - Self { - state: SpinNoIrq::new(LockState::Unlocked), - } - } - - /// Return wether the [`Event`] is set or not - pub fn is_set(&self) -> bool { - match *self.state.lock() { - LockState::Unlocked => true, - _ => false, - } - } - - pub fn wait(&self) { - let state = &mut *self.state.lock(); - match state { - LockState::Unlocked => {} - &mut LockState::Locked(ref wq) => { - wq.wait(); - } - } - } - - /// Clears the event (non-blocking). - /// - /// If the event was set, it will be cleared and the function returns true. - /// If the event was unset, the function returns false. - pub fn clear(&self) -> bool { - let state = &mut *self.state.lock(); - match state { - LockState::Unlocked => { - *state = LockState::Locked(WaitQueue::new()); - true - } - LockState::Locked(_) => false, - } - } - - pub fn set(&self) { - let state = &mut *self.state.lock(); - match state { - LockState::Unlocked => {} - &mut LockState::Locked(ref wq) => { - wq.notify_all(true); - } - } - } -} - -impl Default for Event { - fn default() -> Self { - Self::new() - } -} diff --git a/modules/axtask/src/lib.rs b/modules/axtask/src/lib.rs index 98c565b6e0..acdc1bcabc 100644 --- a/modules/axtask/src/lib.rs +++ b/modules/axtask/src/lib.rs @@ -43,11 +43,9 @@ cfg_if::cfg_if! { mod run_queue; mod task; mod task_ext; - mod task_registry; mod api; mod wait_queue; mod wait_queues; - mod events; #[cfg(feature = "irq")] mod timers; diff --git a/modules/axtask/src/run_queue.rs b/modules/axtask/src/run_queue.rs index 0b402c3149..d01e495699 100644 --- a/modules/axtask/src/run_queue.rs +++ b/modules/axtask/src/run_queue.rs @@ -13,7 +13,6 @@ use scheduler::BaseScheduler; use axhal::cpu::this_cpu_id; use crate::task::{CurrentTask, TaskState}; -use crate::task_registry::{register_task, unregister_task}; use crate::wait_queue::WaitQueueGuard; use crate::{AxCpuMask, AxTaskRef, Scheduler, TaskInner, WaitQueue}; @@ -238,8 +237,6 @@ impl AxRunQueueRef<'_, G> { self.inner.cpu_id ); assert!(task.is_ready()); - // Register task in registry. - register_task(task.clone()); self.inner.scheduler.lock().add_task(task); } @@ -269,33 +266,6 @@ impl AxRunQueueRef<'_, G> { } } } - - /// Unpark one task by inserting it into the run queue. - /// - /// This function does nothing if the task is not in [`TaskState::Parked`], - /// which means the task is already unparked by other cores. - pub fn unpark_task(&mut self, task: AxTaskRef, resched: bool) { - let task_id_name = task.id_name(); - // Try to change the state of the task from `Parked` to `Ready`, - // if successful, the task will be put into this run queue, - // otherwise, the task is already unblocked by other cores. - // Note: - // target task can not be insert into the run queue until it finishes its scheduling process. - if self - .inner - .put_task_with_state(task, TaskState::Parked, resched) - { - // Since now, the task to be unblocked is in the `Ready` state. - let cpu_id = self.inner.cpu_id; - debug!("task unpark: {} on run_queue {}", task_id_name, cpu_id); - // Note: when the task is unblocked on another CPU's run queue, - // we just ignore the `resched` flag. - if resched && cpu_id == this_cpu_id() { - #[cfg(feature = "preempt")] - crate::current().set_preempt_pending(true); - } - } - } } /// Core functions of run queue. @@ -388,10 +358,6 @@ impl CurrentRunQueueRef<'_, G> { assert!(curr.is_running(), "task is not running: {:?}", curr.state()); assert!(!curr.is_idle()); - let task_id = curr.id().as_u64(); - unregister_task(task_id); - debug!("task {} unregistered", task_id); - if curr.is_init() { // Safety: it is called from `current_run_queue::().exit_current(exit_code)`, // which disabled IRQs and preemption. @@ -681,12 +647,10 @@ pub(crate) fn init() { IDLE_TASK.with_current(|i| { i.init_once(idle_task.into_arc()); }); - + // Put the subsequent execution into the `main` task. let main_task = TaskInner::new_init("main".into()).into_arc(); main_task.set_state(TaskState::Running); - // Register main task due to `add_task` isn't called. - register_task(main_task.clone()); debug!( "main task registered: {}, id {}", main_task.id_name(), diff --git a/modules/axtask/src/task.rs b/modules/axtask/src/task.rs index 82429d23c0..dfb2a844c0 100644 --- a/modules/axtask/src/task.rs +++ b/modules/axtask/src/task.rs @@ -14,7 +14,6 @@ use axhal::arch::TaskContext; use axhal::tls::TlsArea; use crate::task_ext::AxTaskExt; -use crate::task_registry::register_task; use crate::{AxCpuMask, AxTask, AxTaskRef, WaitQueue}; /// A unique identifier for a thread. @@ -32,11 +31,8 @@ pub(crate) enum TaskState { /// Task is blocked (in the wait queue or timer list), /// and it has finished its scheduling process, it can be wake up by `notify()` on any run queue safely. Blocked = 3, - /// Task is Suspended, - /// Not in wait queue. - Parked = 4, /// Task is exited and waiting for being dropped. - Exited = 5, + Exited = 4, } /// The inner task structure. @@ -100,8 +96,7 @@ impl From for TaskState { 1 => Self::Running, 2 => Self::Ready, 3 => Self::Blocked, - 4 => Self::Parked, - 5 => Self::Exited, + 4 => Self::Exited, _ => unreachable!(), } } diff --git a/modules/axtask/src/task_registry.rs b/modules/axtask/src/task_registry.rs deleted file mode 100644 index fb973cf81b..0000000000 --- a/modules/axtask/src/task_registry.rs +++ /dev/null @@ -1,47 +0,0 @@ -use alloc::collections::BTreeMap; - -use kernel_guard::NoPreemptIrqSave; -use kspin::SpinNoIrq; - -use crate::{AxTaskRef, current_run_queue, select_run_queue}; - -/// Task registry by task id -static TASK_REGISTRY: SpinNoIrq> = SpinNoIrq::new(BTreeMap::new()); - -/// Register a task to the task registry. -/// -/// Should be called in the process of task spawn. -pub fn register_task(task: AxTaskRef) { - let mut tasks = TASK_REGISTRY.lock(); - let id = task.id().as_u64(); - tasks.insert(id, task); - debug!("Task {} registered", id); -} - -/// Unregister a task from the task registry. -/// -/// Should be called in the process of task exit. -pub fn unregister_task(id: u64) { - let mut tasks = TASK_REGISTRY.lock(); - tasks.remove(&id); - debug!("Task {} unregistered", id); -} - -/// Find a task by its ID. -pub fn find_task_by_id(id: u64) -> Option { - let tasks = TASK_REGISTRY.lock(); - tasks.get(&id).cloned() -} - -/// Unpark a task by its id. -pub fn unpark_task(id: u64, resched: bool) { - if let Some(task) = find_task_by_id(id) { - select_run_queue::(&task).unpark_task(task, resched); - } -} - -/// Park the current task. -pub fn park_current_task() { - let mut cur_rq = current_run_queue::(); - cur_rq.park_current_task(); -} diff --git a/modules/axtask/src/wait_queues.rs b/modules/axtask/src/wait_queues.rs index c6dd44460b..970ecab8ea 100644 --- a/modules/axtask/src/wait_queues.rs +++ b/modules/axtask/src/wait_queues.rs @@ -53,7 +53,7 @@ pub fn futex_wait(futex: &Futex, expected: u32, timeout: Option) -> bo } #[cfg(not(feature = "irq"))] { - panic!("wait_timeout is not supported in this configuration"); + panic!("wait_timeout is not supported in without irq feature"); } } None => { diff --git a/ulib/axasync/Cargo.toml b/ulib/axasync/Cargo.toml index 74d91c7ae1..50ad4ee9f5 100644 --- a/ulib/axasync/Cargo.toml +++ b/ulib/axasync/Cargo.toml @@ -11,8 +11,21 @@ repository = "https://github.com/arceos-org/arceos/tree/main/ulib/axasync" [features] default = [] -single = ["axfeat/async-single", "arceos_api/async-single","dep:embassy-executor"] -thread = ["axfeat/async-thread", "arceos_api/async-thread","dep:embassy-executor"] +preempt = [ + "axfeat/async-preempt", + "arceos_api/async-preempt", + "thread", +] +thread = [ + "axfeat/async-thread", + "arceos_api/async-thread", + "dep:embassy-executor", +] +single = [ + "axfeat/async-single", + "arceos_api/async-single", + "dep:embassy-executor", +] time = ["dep:embassy-time"] sync = ["dep:embassy-sync"] @@ -24,7 +37,7 @@ arceos_api = { workspace = true } embassy-executor = { git = "https://github.com/embassy-rs/embassy", branch = "main", default-features = false, optional = true } embassy-futures = { git = "https://github.com/embassy-rs/embassy", branch = "main" } embassy-sync = { git = "https://github.com/embassy-rs/embassy", branch = "main", optional = true } -embassy-time = { git = "https://github.com/embassy-rs/embassy", branch = "main",optional = true } +embassy-time = { git = "https://github.com/embassy-rs/embassy", branch = "main", optional = true } cfg-if = "1.0.0" static_cell = "2.1.0" diff --git a/ulib/axasync/src/lib.rs b/ulib/axasync/src/lib.rs index 26ead57f23..cde40e95c0 100644 --- a/ulib/axasync/src/lib.rs +++ b/ulib/axasync/src/lib.rs @@ -2,14 +2,19 @@ #![feature(doc_cfg)] #![feature(doc_auto_cfg)] -#[cfg(any(feature = "thread", feature = "single"))] +#[cfg(any(feature = "thread", feature = "preempt", feature = "single"))] pub mod executor { use arceos_api::embassy_async as api; + pub use embassy_executor::{main, task}; + pub use api::AxExecutor as Executor; pub use embassy_executor::*; pub use embassy_futures::*; + #[cfg(feature = "preempt")] + pub use api::AxPrioFuture as PrioFuture; + #[cfg(feature = "thread")] pub use api::{ax_block_on as block_on, ax_spawner as spawner}; } @@ -28,8 +33,5 @@ pub mod cell { pub use static_cell::{ConstStaticCell, StaticCell}; } -#[cfg(not(any(feature = "thread", feature = "single")))] -compile_error!(r#"must select one of "executor-thread" or "executor-single""#); - -#[cfg(all(feature = "thread", feature = "single"))] +#[cfg(all(any(feature = "thread", feature = "preempt"), feature = "single"))] compile_error!(r#"feature "executor-thread" and "executor-single" are mutually exclusive"#); From a51ef37091a743a1808eb52e54060acd8e7ef2e0 Mon Sep 17 00:00:00 2001 From: lvyuemeng Date: Mon, 7 Jul 2025 16:46:20 +0800 Subject: [PATCH 11/11] [chore]: add related info --- modules/axembassy/src/asynch.rs | 5 ++- modules/axembassy/src/delegate.rs | 14 +++++- modules/axembassy/src/executor.rs | 41 +++++++++++++++--- modules/axembassy/src/executor_thread.rs | 54 ------------------------ modules/axembassy/src/lib.rs | 47 +++++++++++++-------- modules/axtask/src/api.rs | 6 --- modules/axtask/src/run_queue.rs | 14 ------ ulib/axasync/src/lib.rs | 2 - 8 files changed, 79 insertions(+), 104 deletions(-) delete mode 100644 modules/axembassy/src/executor_thread.rs diff --git a/modules/axembassy/src/asynch.rs b/modules/axembassy/src/asynch.rs index 05789bb7cb..bef6aeed8f 100644 --- a/modules/axembassy/src/asynch.rs +++ b/modules/axembassy/src/asynch.rs @@ -9,6 +9,7 @@ use axtask::yield_now; pub use embassy_executor::{SendSpawner, Spawner}; +/// Global spawner for multi-thread executor pub(crate) static SPAWNER: Mutex> = Mutex::new(OnceCell::new()); fn init_spawn() { @@ -17,7 +18,7 @@ fn init_spawn() { } fn init() { - use crate::executor_thread::Executor; + use crate::executor::Executor; use static_cell::StaticCell; static EXECUTOR: StaticCell = StaticCell::new(); @@ -60,7 +61,7 @@ pub(crate) fn set_spawner(spawner: SendSpawner) { let _ = sp.set(spawner); } -fn wake(ctx: *const ()) { +fn wake(_ctx: *const ()) { // let id = ctx as u64; // unpark_task(id, true); } diff --git a/modules/axembassy/src/delegate.rs b/modules/axembassy/src/delegate.rs index 3e300964b0..3183b1d957 100644 --- a/modules/axembassy/src/delegate.rs +++ b/modules/axembassy/src/delegate.rs @@ -148,6 +148,9 @@ unsafe impl Sync for Delegate {} impl Delegate { #[must_use] + /// Creates a new `Delegate` + /// + /// **NOT** thread safe and only executor safe pub const fn new() -> Self { Self { send: Signal::new(), @@ -157,7 +160,8 @@ impl Delegate { } } - /// lend + /// lend target `T` to other task in the same executor + /// with lifetime longer than delegate itself pub async fn lend<'a, 'b: 'a>(&'a self, target: &'b mut T) -> Result<(), DelegateError> { use DelegateError::*; use DelegateState::*; @@ -183,7 +187,10 @@ impl Delegate { Ok(()) } - /// lend and reset + /// lend target `T` to other task in the same executor + /// with lifetime longer than delegate itself + /// + /// reset state afterwards for reuse pub async fn lend_new<'a, 'b: 'a>(&'a self, target: &'b mut T) -> Result<(), DelegateError> { match self.lend(target).await { Ok(()) => { @@ -194,6 +201,8 @@ impl Delegate { } } + /// Returns a mutable reference to the inner value lent + /// by other task in the same executor pub async fn with(&self, func: impl FnOnce(&mut T) -> U) -> Result { use DelegateError::*; use DelegateState::*; @@ -219,6 +228,7 @@ impl Delegate { Ok(res) } + /// Reset the delegate to reuse pub fn reset(&self) { use DelegateState::*; diff --git a/modules/axembassy/src/executor.rs b/modules/axembassy/src/executor.rs index c2f0d8fd0a..6d425f0393 100644 --- a/modules/axembassy/src/executor.rs +++ b/modules/axembassy/src/executor.rs @@ -1,12 +1,23 @@ -use core::sync::atomic::{AtomicBool, Ordering}; use core::marker::PhantomData; +use core::sync::atomic::{AtomicBool, Ordering}; use embassy_executor::raw; -static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); +#[cfg(feature = "executor-single")] +static SIGNAL_SINGLE: AtomicBool = AtomicBool::new(false); + +#[cfg(feature = "executor-thread")] +#[percpu::def_percpu] +static SINGAL_THREAD: AtomicBool = AtomicBool::new(false); #[unsafe(export_name = "__pender")] fn __pender(_context: *mut ()) { - SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); + #[cfg(feature = "executor-single")] + SIGNAL_SINGLE.store(true, Ordering::SeqCst); + + #[cfg(feature = "executor-thread")] + SINGAL_THREAD.with_current(|m| { + m.store(true, Ordering::SeqCst); + }); } pub struct Executor { @@ -36,10 +47,26 @@ impl Executor { unsafe { self.inner.poll(); - if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) { - SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst); - } else { - axhal::arch::wait_for_irqs(); + #[cfg(feature = "executor-single")] + { + if SIGNAL_SINGLE.load(Ordering::SeqCst) { + SIGNAL_SINGLE.store(false, Ordering::SeqCst); + } else { + axhal::arch::wait_for_irqs(); + } + } + + #[cfg(feature = "executor-thread")] + { + let polled = SINGAL_THREAD.with_current(|m| m.load(Ordering::Acquire)); + if polled { + SINGAL_THREAD.with_current(|m| { + m.store(false, Ordering::Release); + }); + } else { + // park_current_task(); + axtask::yield_now(); + } } }; } diff --git a/modules/axembassy/src/executor_thread.rs b/modules/axembassy/src/executor_thread.rs deleted file mode 100644 index b367c50865..0000000000 --- a/modules/axembassy/src/executor_thread.rs +++ /dev/null @@ -1,54 +0,0 @@ -use core::marker::PhantomData; -use core::sync::atomic::{AtomicBool, Ordering}; -use embassy_executor::raw; - -#[percpu::def_percpu] -static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); - -#[unsafe(export_name = "__pender")] -fn __pender(_context: *mut ()) { - SIGNAL_WORK_THREAD_MODE.with_current(|m| { - m.store(true, Ordering::SeqCst); - }); -} - -pub struct Executor { - inner: raw::Executor, - not_send: PhantomData<*mut ()>, -} - -impl Executor { - /// Create a new executor and initialize context with current task id - pub fn new() -> Self { - let cur_id = axtask::current().id().as_u64(); - Self { - inner: raw::Executor::new(cur_id as *mut ()), - not_send: PhantomData, - } - } - - /// Runs the executor. - /// - /// The `init` closure is called with a [`Spawner`] that spawns tasks on - /// this executor. Use it to spawn the initial task(s). After `init` returns, - /// the executor starts running the tasks. - /// - pub fn run(&'static mut self, init: impl FnOnce(embassy_executor::Spawner)) -> ! { - init(self.inner.spawner()); - - loop { - unsafe { - self.inner.poll(); - let polled = SIGNAL_WORK_THREAD_MODE.with_current(|m| m.load(Ordering::Acquire)); - if polled { - SIGNAL_WORK_THREAD_MODE.with_current(|m| { - m.store(false, Ordering::SeqCst); - }); - } else { - // park_current_task(); - axtask::yield_now(); - } - }; - } - } -} diff --git a/modules/axembassy/src/lib.rs b/modules/axembassy/src/lib.rs index a2925d72e4..be40c9ef3a 100644 --- a/modules/axembassy/src/lib.rs +++ b/modules/axembassy/src/lib.rs @@ -1,3 +1,25 @@ +//! [ArceOS](https://github.com/arceos-org/arceos) embassy integration +//! +//! This module provides embassy asynchronous runtime integration, including +//! time driver, and executor with single-thread, multi-thread, preemptive(partially) +//! which are configurable by cargo features. +//! +//! # Cargo Features +//! +//! - `driver`: Enable time driver support. If it's enabled, time driver is used. +//! Usually used by `axruntime` module in `irq` initiation. +//! - `executor-single`: Use the [single-thread executor][1]. It also enables the +//! related utils modules. +//! - `executor-thread`: Use the [multi-thread executor][2]. It also enables the +//! related utils modules and enables the `multitask` feature if it is enabled. +//! - `executor-preempt`: Use the [preemptive executor][3]. It also enables the +//! related utils modules and enables the `executor-thread` feature if it is +//! enabled. +//! +//! [1]: single-thread executor +//! [2]: multi-thread executor(`spawner`, `block_on`) +//! [3]: preemptive executor(`PrioFuture`) + #![cfg_attr(not(test), no_std)] #![feature(doc_cfg)] #![feature(doc_auto_cfg)] @@ -7,30 +29,21 @@ cfg_if::cfg_if! { extern crate alloc; extern crate log; - pub mod delegate; - - #[cfg(feature = "executor-thread")] - mod executor_thread; - #[cfg(feature = "executor-thread")] mod asynch; - #[cfg(feature = "executor-thread")] - mod executor_thread_exports { - pub use crate::executor_thread::Executor; - pub use crate::asynch::{spawner,block_on,Spawner,SendSpawner}; - #[cfg(feature = "executor-preempt")] - pub use crate::preempt::PrioFuture; - } - #[cfg(feature = "executor-thread")] - pub use executor_thread_exports::*; + pub mod delegate; - #[cfg(feature = "executor-single")] mod executor; - #[cfg(feature = "executor-single")] mod executor_exports { pub use crate::executor::Executor; pub use crate::asynch::Spawner; + + #[cfg(feature = "executor-thread")] + pub use crate::asynch::{spawner,block_on,SendSpawner}; + + #[cfg(feature = "executor-preempt")] + pub use crate::preempt::PrioFuture; } - #[cfg(feature = "executor-single")] + pub use executor_exports::*; } } diff --git a/modules/axtask/src/api.rs b/modules/axtask/src/api.rs index c79786cc30..8466b6ac20 100644 --- a/modules/axtask/src/api.rs +++ b/modules/axtask/src/api.rs @@ -206,12 +206,6 @@ pub fn exit(exit_code: i32) -> ! { current_run_queue::().exit_current(exit_code) } -/// Park the current task. -pub fn park_current_task() { - let mut cur_rq = current_run_queue::(); - cur_rq.park_current_task(); -} - /// The idle task routine. /// /// It runs an infinite loop that keeps calling [`yield_now()`]. diff --git a/modules/axtask/src/run_queue.rs b/modules/axtask/src/run_queue.rs index d01e495699..562835e144 100644 --- a/modules/axtask/src/run_queue.rs +++ b/modules/axtask/src/run_queue.rs @@ -420,20 +420,6 @@ impl CurrentRunQueueRef<'_, G> { self.inner.resched(); } - /// Park the current task, and reschedule. - pub fn park_current_task(&mut self) { - let curr = &self.current_task; - assert!(curr.is_running()); - assert!(!curr.is_idle()); - - // Ensure preemption is disabled - #[cfg(feature = "preempt")] - assert!(curr.can_preempt(1)); - - curr.set_state(TaskState::Parked); - self.inner.resched(); - } - #[cfg(feature = "irq")] pub fn sleep_until(&mut self, deadline: axhal::time::TimeValue) { let curr = &self.current_task; diff --git a/ulib/axasync/src/lib.rs b/ulib/axasync/src/lib.rs index cde40e95c0..9a53537358 100644 --- a/ulib/axasync/src/lib.rs +++ b/ulib/axasync/src/lib.rs @@ -6,8 +6,6 @@ pub mod executor { use arceos_api::embassy_async as api; - pub use embassy_executor::{main, task}; - pub use api::AxExecutor as Executor; pub use embassy_executor::*; pub use embassy_futures::*;