[][src]Struct juggle::Wheel

pub struct Wheel<'futures> { /* fields omitted */ }

Single-thread async task scheduler with dynamic task state control. Implements Future.

This structure is useful when you want to divide single thread to share processing power among multiple task by cooperative multitasking.

Tasks are scheduled using round-robin algorithm without priority. Diagram below shows simplified scheduling process.

   Execute
      |
   +--v--+     +-----+-----+-----+-----+
   |     |     |     |     |     |     <---+
   | 0x0 | <-- | 0x8 | 0x9 | 0xA | 0xB |   |
   |     |     |     |     |     |     <-+ |
   +-----+ ... +-----+-----+-----+-----+ | |
      |                                  | |
      |                                  | |
  +---v---+                              | |
 /         \ YES                         | |
+ Runnable? +----------------------------+ |
 \         /                               |
  +-------+                                |
      | NO      +-----------------------+  |
      +---------> Wait for waking event |--+
                +-----------------------+

New and rescheduled tasks are added at the end of queue. Task on front is poped and executed. If task finishes or becomes cancelled then it is removed from scheduler, and if task is suspended then it is also removed but only from queue not the scheduler. Tasks that were blocked by some async event are checked periodically and when woken they are added at the end of queue, this might not happen immedialty after task is woken.

Managing tasks

You can spawn/suspend/resume/cancel any task as long as you have its identifier, and handle to this scheduler. Handle can be obtained from this object using that method, and task identifiers are returned from functions that spawn tasks (e.g spawn).

Be carefull tho with suspending tasks, if all become suspended then because of scheduler single-thread nature there is no way of resuming any. Such condition triggers SuspendError that is returned from future.

Examples

use juggle::*;
use alloc::collections::VecDeque;
use core::cell::RefCell;

async fn collect_temperature(queue: &RefCell<VecDeque<i32>>,handle: WheelHandle<'_>){
    loop{ // loop forever or until cancelled
        let temperature: i32 = read_temperature_sensor().await;
        queue.borrow_mut().push_back(temperature);
        yield_once!(); // give scheduler opportunity to execute other tasks
    }
}

async fn wait_for_timer(id: IdNum,queue: &RefCell<VecDeque<i32>>,handle: WheelHandle<'_>){
    init_timer();
    for _ in 0..5 {
        yield_while!(get_timer_value() < 200); // busy wait but also executes other tasks.
        process_data(&mut queue.borrow_mut());
        reset_timer();
    }
    handle.cancel(id); // cancel 'collect_temperature' task.
    shutdown_timer();
}

fn main(){
    let queue = &RefCell::new(VecDeque::new());
    let wheel = Wheel::new();
    let handle = wheel.handle(); // handle to manage tasks, can be cloned inside this thread

    let temp_id = handle.spawn(SpawnParams::default(),
                               collect_temperature(queue,handle.clone()));
    handle.spawn(SpawnParams::default(),
                 wait_for_timer(temp_id.unwrap(),queue,handle.clone()));

    // execute tasks
    smol::block_on(wheel).unwrap(); // or any other utility to block on future.
}

Implementations

impl<'futures> Wheel<'futures>[src]

pub fn new() -> Self[src]

Create new instance

pub fn handle(&self) -> &WheelHandle<'futures>[src]

Obtain reference to handle that is used to spawn/control tasks.

Any interaction with Wheel's content is done by handles. Handles works as reference counted pointers, they can be cloned to use inside tasks but cannot be shared between threads.

pub fn lock(self) -> LockedWheel<'futures>

Notable traits for LockedWheel<'futures>

impl<'futures> Future for LockedWheel<'futures> type Output = Result<(), SuspendError>;
[src]

Lock this wheel preventing all handles from affecting the tasks.

Transforms this instance into LockedWheel which is similar to Wheel but has no way of controlling tasks within it.

Panics

Panics if this method was called inside handle's method such as with_name.

Trait Implementations

impl<'futures> Debug for Wheel<'futures>[src]

impl<'futures> Default for Wheel<'futures>[src]

impl<'futures> Future for Wheel<'futures>[src]

type Output = Result<(), SuspendError>

The type of value produced on completion.

Auto Trait Implementations

impl<'futures> !RefUnwindSafe for Wheel<'futures>

impl<'futures> !Send for Wheel<'futures>

impl<'futures> !Sync for Wheel<'futures>

impl<'futures> Unpin for Wheel<'futures>

impl<'futures> !UnwindSafe for Wheel<'futures>

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<F> IntoFuture for F where
    F: Future
[src]

type Output = <F as Future>::Output

🔬 This is a nightly-only experimental API. (into_future)

The output that the future will produce on completion.

type Future = F

🔬 This is a nightly-only experimental API. (into_future)

Which kind of future are we turning this into?

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.