1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//! A standard implementation of a Waker + Blocker pair -- a basic wait event.
//!
//! This crate directly By standalone, we mean that this crate does not depend on tasking infrastructure
//! (e.g., the `task` crate) directly, meaning it is usable in the `task` crate.
//! This works by accepts generic actions (closures) for waking the [Waker](core::task::Waker)
//! and blocking the [Blocker].

#![no_std]
#![feature(negative_impls)]

extern crate alloc;

use task::{ScheduleOnDrop, TaskRef};

/// Creates a new waker and blocker pair that are associated with each other.
///
/// The blocker can be used to block the current task until the waker is woken.
pub fn new_waker() -> (core::task::Waker, Blocker) {
    let curr_task = task::get_my_current_task() 
        .expect("waker::new_waker(): failed to get current task");
    let task_to_block = curr_task.clone();
    let wake_action = move || {
        let _ = curr_task.unblock();
    };
    let (waker, blocker_generic) = waker_generic::new_waker(wake_action);
    (
        waker,
        Blocker {
            blocker_generic,
            task_to_block,
        }
    )
}

/// A blocker that blocks until the associated waker is woken.
///
/// To obtain a `Blocker` and its associated [`core::task::Waker`], call [`new_waker()`].
///
/// `Blocker` will block the current task; thus, it doesn't implement [`Send`] or [`Sync`]
/// to ensure that it cannot be sent to other tasks.
pub struct Blocker {
    blocker_generic: waker_generic::Blocker,
    task_to_block: TaskRef,
}
impl !Send for Blocker {}
impl !Sync for Blocker {}

impl Blocker {
    /// Blocks the current task by putting it to sleep until the associated waker is woken.
    ///
    /// If the waker was already woken prior to this function being called,
    /// it will return immediately.
    ///
    /// After this function returns, the inner state of the blocker+waker pair
    /// will have been reset to its initial "unwoken" state, enabling them to be re-used.
    /// In other words, this function can be called again, at which point it will
    /// block until the waker is woken again.
    pub fn block(&self) {
        let block_action = || {
            let _ = self.task_to_block.block();
            ScheduleOnDrop { }
        };
        self.blocker_generic.block(block_action)
    }
}