Fix typos, and other cosmetic stuff

This commit is contained in:
Philipp Mildenberger 2024-10-22 20:12:03 +02:00
parent d73f158b43
commit 3dbcc4ed34
No known key found for this signature in database
GPG Key ID: D2480C382214FD8E

View File

@ -24,8 +24,8 @@ pub async fn cancelable_future<T>(
#[derive(Default, Debug)] #[derive(Default, Debug)]
struct Shared { struct Shared {
state: AtomicU64, state: AtomicU64,
// notify has some features that we don't really need here because it // `Notify` has some features that we don't really need here because it
// supports waking single tasks (notify_one) and does it's own (more // supports waking single tasks (`notify_one`) and does its own (more
// complicated) state tracking, we could reimplement the waiter linked list // complicated) state tracking, we could reimplement the waiter linked list
// with modest effort and reduce memory consumption by one word/8 bytes and // with modest effort and reduce memory consumption by one word/8 bytes and
// reduce code complexity/number of atomic operations. // reduce code complexity/number of atomic operations.
@ -48,16 +48,16 @@ fn num_running(&self) -> u32 {
(self.state.load(Relaxed) >> 32) as u32 (self.state.load(Relaxed) >> 32) as u32
} }
/// increments the generation count and sets num_running /// Increments the generation count and sets `num_running`
/// to the provided value, this operation is not with /// to the provided value, this operation is not with
/// regard to the generation counter (doesn't use fetch_add) /// regard to the generation counter (doesn't use `fetch_add`)
/// so the calling code must ensure it cannot execute concurrently /// so the calling code must ensure it cannot execute concurrently
/// to maintain correctness (but not safety) /// to maintain correctness (but not safety)
fn inc_generation(&self, num_running: u32) -> (u32, u32) { fn inc_generation(&self, num_running: u32) -> (u32, u32) {
let state = self.state.load(Relaxed); let state = self.state.load(Relaxed);
let generation = state as u32; let generation = state as u32;
let prev_running = (state >> 32) as u32; let prev_running = (state >> 32) as u32;
// no need to create a new generation if the refcount is zero (fastaph) // no need to create a new generation if the refcount is zero (fastpath)
if prev_running == 0 && num_running == 0 { if prev_running == 0 && num_running == 0 {
return (generation, 0); return (generation, 0);
} }
@ -99,7 +99,7 @@ fn dec_running(&self, generation: u32) {
break; break;
} }
let num_running = (state >> 32) as u32; let num_running = (state >> 32) as u32;
// running can't be zero here, that would mean we misscounted somewhere // running can't be zero here, that would mean we miscounted somewhere
assert_ne!(num_running, 0); assert_ne!(num_running, 0);
let off = 1 << 32; let off = 1 << 32;
let res = self let res = self
@ -113,15 +113,16 @@ fn dec_running(&self, generation: u32) {
} }
} }
// this intentionally doesn't implement clone and requires amutable reference // This intentionally doesn't implement `Clone` and requires a mutable reference
// for cancelation to avoid races (in inc_generation) // for cancelation to avoid races (in inc_generation).
/// A task controller allows managing a single subtask enabling the contorller /// A task controller allows managing a single subtask enabling the controller
/// to cancel the subtask and to check wether it is still running. For efficency /// to cancel the subtask and to check whether it is still running.
/// reasons the controller can be reused/restarted, in that case the previous
/// task is automatically cancelled.
/// ///
/// If the controller is dropped the subtasks are automatically canceled. /// For efficiency reasons the controller can be reused/restarted,
/// in that case the previous task is automatically canceled.
///
/// If the controller is dropped, the subtasks are automatically canceled.
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct TaskController { pub struct TaskController {
shared: Arc<Shared>, shared: Arc<Shared>,
@ -131,20 +132,20 @@ impl TaskController {
pub fn new() -> Self { pub fn new() -> Self {
TaskController::default() TaskController::default()
} }
/// Cancels the active task (handle) /// Cancels the active task (handle).
/// ///
/// returns wether any tasks were still running before the canellation /// Returns whether any tasks were still running before the cancelation.
pub fn cancel(&mut self) -> bool { pub fn cancel(&mut self) -> bool {
self.shared.inc_generation(0).1 != 0 self.shared.inc_generation(0).1 != 0
} }
/// checks wether there are any task handles /// Checks whether there are any task handles
/// that haven't been dropped (or canceled) yet /// that haven't been dropped (or canceled) yet.
pub fn is_running(&self) -> bool { pub fn is_running(&self) -> bool {
self.shared.num_running() != 0 self.shared.num_running() != 0
} }
/// Starts a new task and cancels the previous task (handles) /// Starts a new task and cancels the previous task (handles).
pub fn restart(&mut self) -> TaskHandle { pub fn restart(&mut self) -> TaskHandle {
TaskHandle { TaskHandle {
generation: self.shared.inc_generation(1).0, generation: self.shared.inc_generation(1).0,
@ -159,15 +160,16 @@ fn drop(&mut self) {
} }
} }
/// A handle that is used to link a task with a task controller, it can be /// A handle that is used to link a task with a task controller.
/// used to cancel async futures very efficently but can also be checked for
/// cancaellation very quickly (single atomic read) in blocking code. The
/// handle can be cheaply cloned (referenced counted).
/// ///
/// The TaskController can check wether a task is "running" by inspecting the /// It can be used to cancel async futures very efficiently but can also be checked for
/// refcount of the (current) tasks handeles. Therefore, if that information /// cancelation very quickly (single atomic read) in blocking code.
/// is important ensure that the handle is not dropped until the task fully /// The handle can be cheaply cloned (reference counted).
/// completes ///
/// The TaskController can check whether a task is "running" by inspecting the
/// refcount of the (current) tasks handles. Therefore, if that information
/// is important, ensure that the handle is not dropped until the task fully
/// completes.
pub struct TaskHandle { pub struct TaskHandle {
shared: Arc<Shared>, shared: Arc<Shared>,
generation: u32, generation: u32,
@ -190,8 +192,8 @@ fn drop(&mut self) {
} }
impl TaskHandle { impl TaskHandle {
/// waits until [`TaskController::cancel`] is called for the corresponding /// Waits until [`TaskController::cancel`] is called for the corresponding
/// [`TaskController`]. Immidietly returns if `cancel` was already called since /// [`TaskController`]. Immediately returns if `cancel` was already called since
pub async fn canceled(&self) { pub async fn canceled(&self) {
let notified = self.shared.notify.notified(); let notified = self.shared.notify.notified();
if !self.is_canceled() { if !self.is_canceled() {
@ -214,7 +216,7 @@ mod tests {
use crate::{cancelable_future, TaskController}; use crate::{cancelable_future, TaskController};
#[test] #[test]
fn immidiate_cancel() { fn immediate_cancel() {
let mut controller = TaskController::new(); let mut controller = TaskController::new();
let handle = controller.restart(); let handle = controller.restart();
controller.cancel(); controller.cancel();