From 89fdc745c9c9d57ee55bafd71f948913497bd69c Mon Sep 17 00:00:00 2001 From: lett Date: Tue, 3 Jun 2025 21:59:21 +0800 Subject: [PATCH 1/2] add "rust-toolchain.toml" from https://github.com/arceos-org/arceos/ sync ci.yml to rust-toolchain.toml --- .github/workflows/ci.yml | 11 +++++++++-- rust-toolchain.toml | 12 ++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 rust-toolchain.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6bab917..41ffeb6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,8 +8,15 @@ jobs: strategy: fail-fast: false matrix: - rust-toolchain: [nightly] - targets: [x86_64-unknown-linux-gnu, x86_64-unknown-none, riscv64gc-unknown-none-elf, aarch64-unknown-none-softfloat] + rust-toolchain: [nightly-2025-05-20] + targets: + - x86_64-unknown-none + - riscv64gc-unknown-none-elf + - aarch64-unknown-none + - aarch64-unknown-none-softfloat + - loongarch64-unknown-none + - loongarch64-unknown-none-softfloat + steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..7c4bd47 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,12 @@ +[toolchain] +profile = "minimal" +channel = "nightly-2025-05-20" +components = ["rust-src", "llvm-tools", "rustfmt", "clippy"] +targets = [ + "x86_64-unknown-none", + "riscv64gc-unknown-none-elf", + "aarch64-unknown-none", + "aarch64-unknown-none-softfloat", + "loongarch64-unknown-none", + "loongarch64-unknown-none-softfloat", +] \ No newline at end of file From 8ff065e27255073233714bf9c92b1d5435b6064c Mon Sep 17 00:00:00 2001 From: lett Date: Tue, 3 Jun 2025 23:13:31 +0800 Subject: [PATCH 2/2] Improve code documentation --- README.md | 17 ++++++++++++----- src/lib.rs | 48 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 59595ab..70220a1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,14 @@ [![Docs.rs](https://docs.rs/handler_table/badge.svg)](https://docs.rs/handler_table) [![CI](https://github.com/arceos-org/handler_table/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/arceos-org/handler_table/actions/workflows/ci.yml) -A lock-free table of event handlers. +A lock-free, `no_std`, fixed-capacity table of event handlers. + +## Features + +- no_std, no heap allocation +- Lock-free registration, unregistration and invocation +- Generic capacity `N` known at compile time +- Suitable for bare-metal and OS-kernel contexts ## Examples @@ -13,12 +20,12 @@ use handler_table::HandlerTable; static TABLE: HandlerTable<8> = HandlerTable::new(); -TABLE.register_handler(0, || { +assert!(TABLE.register_handler(0, || { println!("Hello, event 0!"); -}); -TABLE.register_handler(1, || { +})); +assert!(TABLE.register_handler(1, || { println!("Hello, event 1!"); -}); +})); assert!(TABLE.handle(0)); // print "Hello, event 0!" assert!(!TABLE.handle(2)); // unregistered diff --git a/src/lib.rs b/src/lib.rs index 36394be..e16b766 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,28 +5,36 @@ use core::sync::atomic::{AtomicUsize, Ordering}; /// The type of an event handler. /// -/// Currently no arguments and return values are supported. +/// Currently, only no arguments and return values are supported. pub type Handler = fn(); /// A lock-free table of event handlers. /// -/// It internally uses an array of `AtomicUsize` to store the handlers. +/// Internally stores up to `N` function pointers in an array of `AtomicUsize`. +/// All operations are O(1), and are safe for concurrent use in `no_std`. +/// +/// # Type Parameters +/// - `N`: Number of handler slots (must be > 0). pub struct HandlerTable { handlers: [AtomicUsize; N], } impl HandlerTable { - /// Creates a new handler table with all entries empty. + /// Creates a new `HandlerTable` with all slots empty. pub const fn new() -> Self { Self { handlers: [const { AtomicUsize::new(0) }; N], } } - /// Registers a handler for the given index. + /// Attempts to register `handler` in slot `idx`. + /// + /// - `idx`: Slot index (0 ≤ `idx` < `N`). + /// - `handler`: Function pointer to register. /// - /// Returns `true` if the registration succeeds, `false` if the index is out - /// of bounds or the handler is already registered. + /// # Returns + /// - `true` if the slot was empty and registration succeeded. + /// - `false` if `idx` is out of range or the slot was already occupied. pub fn register_handler(&self, idx: usize, handler: Handler) -> bool { if idx >= N { return false; @@ -36,9 +44,17 @@ impl HandlerTable { .is_ok() } - /// Unregisters the handler for the given index. + /// Unregisters and returns the handler in slot `idx`. + /// + /// # Parameters + /// - `idx`: Slot index (0 ≤ `idx` < `N`). + /// + /// # Returns + /// - `Some(handler)` if a handler was registered. + /// - `None` if `idx` is out of range or the slot was empty. /// - /// Returns the existing handler if it is registered, `None` otherwise. + /// # Concurrency + /// Lock-free and thread-safe: uses atomic swap. pub fn unregister_handler(&self, idx: usize) -> Option { if idx >= N { return None; @@ -51,10 +67,20 @@ impl HandlerTable { } } - /// Handles the event with the given index. + /// Invokes the handler in slot `idx`. + /// + /// # Parameters + /// - `idx`: Slot index (0 ≤ `idx` < `N`). + /// + /// # Returns + /// - `true` if a handler was found and called. + /// - `false` if `idx` is out of range or the slot was empty. + /// + /// # Concurrency + /// Lock-free and thread-safe: uses atomic load. /// - /// Returns `true` if the event is handled, `false` if no handler is - /// registered for the given index. + /// # Panics + /// Panics if the handler itself panics. pub fn handle(&self, idx: usize) -> bool { if idx >= N { return false;