pub struct StaticScheduler(/* private fields */);
Expand description
A statically-initialized scheduler implementation.
This type stores the core of the scheduler behind an &'static
reference,
which is passed into each task spawned on the scheduler. This means that, in
order to spawn tasks, the StaticScheduler
must be stored in a static
variable.
The use of a &'static
reference allows StaticScheduler
s to be used
without liballoc
. In addition, spawning and deallocating tasks is slightly
cheaper than when using the reference-counted Scheduler
type, because an
atomic reference count increment/decrement is not required.
§Usage
A StaticScheduler
may be created one of two ways, depending on how the
stub task used by the MPSC queue algorithm is created: either with a
statically-allocated stub task by using the
StaticScheduler::new_with_static_stub
function, or with a heap-allocated
stub task using StaticScheduler::new
or StaticScheduler::default
(which require the “alloc” feature).
The new_with_static_stub
function is a const fn
, which allows a
StaticScheduler
to be constructed directly in a static
initializer.
However, it requires the TaskStub
to be constructed manually by the
caller and passed in to initialize the scheduler. Furthermore, this function
is unsafe
to call, as it requires that the provided TaskStub
not be
used by any other StaticScheduler
instance, which the function cannot
ensure.
For example:
use maitake::scheduler::{self, StaticScheduler};
static SCHEDULER: StaticScheduler = {
// create a new static stub task *inside* the initializer for the
// `StaticScheduler`. since the stub task static cannot be referenced
// outside of this block, we can ensure that it is not used by any
// other calls to `StaticScheduler::new_with_static_stub`.
static STUB_TASK: scheduler::TaskStub = scheduler::TaskStub::new();
// now, create the scheduler itself:
unsafe {
// safety: creating the stub task inside the block used as an
// initializer expression for the scheduler static ensures that
// the stub task is not used by any other scheduler instance.
StaticScheduler::new_with_static_stub(&STUB_TASK)
}
};
// now, we can use the scheduler to spawn tasks:
SCHEDULER.spawn(async { /* ... */ });
The scheduler::new_static!
macro abstracts over the above code, allowing
a static StaticScheduler
to be initialized without requiring the caller to
manually write unsafe
code:
use maitake::scheduler::{self, StaticScheduler};
// this macro expands to code identical to the previous example.
static SCHEDULER: StaticScheduler = scheduler::new_static!();
// now, we can use the scheduler to spawn tasks:
SCHEDULER.spawn(async { /* ... */ });
Alternatively, the new
and default
constructors can be used to
create a new StaticScheduler
with a heap-allocated stub task. This does
not require the user to manually create a stub task and ensure that it is
not used by any other StaticScheduler
instances. However, these
constructors are not const fn
s and require the “alloc” feature
to be enabled.
Because StaticScheduler::new
and StaticScheduler::default
are not
const fn
s, but the scheduler must still be stored in a static
to be
used, some form of lazy initialization of the StaticScheduler
is necessary:
use maitake::scheduler::StaticScheduler;
use mycelium_util::sync::Lazy;
static SCHEDULER: Lazy<StaticScheduler> = Lazy::new(StaticScheduler::new);
// now, we can use the scheduler to spawn tasks:
SCHEDULER.spawn(async { /* ... */ });
Although the scheduler itself is no longer constructed in a const fn
static initializer in this case, storing it in a static
rather than an
Arc
still provides a minor performance benefit, as it avoids atomic
reference counting when spawning tasks.
Implementations§
Source§impl StaticScheduler
impl StaticScheduler
Sourcepub fn try_steal(
&self,
) -> Result<Stealer<'_, &'static StaticScheduler>, TryStealError>
pub fn try_steal( &self, ) -> Result<Stealer<'_, &'static StaticScheduler>, TryStealError>
Attempt to steal tasks from this scheduler’s run queue.
§Returns
Ok(
Stealer
`)) if tasks can be stolen from this scheduler’s queue.Err
(TryStealError::Empty
)
if there were no tasks in this scheduler’s run queue.Err
(TryStealError::Busy
)
if another worker was already stealing from this scheduler’s run queue.
Source§impl StaticScheduler
impl StaticScheduler
Sourcepub const DEFAULT_TICK_SIZE: usize = 256usize
pub const DEFAULT_TICK_SIZE: usize = 256usize
How many tasks are polled per call to StaticScheduler::tick
.
Chosen by fair dice roll, guaranteed to be random.
Sourcepub const unsafe fn new_with_static_stub(stub: &'static TaskStub) -> Self
pub const unsafe fn new_with_static_stub(stub: &'static TaskStub) -> Self
Create a StaticScheduler with a static “stub” task entity
This is used for creating a StaticScheduler as a static
variable.
§Safety
The “stub” provided must ONLY EVER be used for a single StaticScheduler. Re-using the stub for multiple schedulers may lead to undefined behavior.
For a safe alternative, consider using the new_static!
macro to
initialize a StaticScheduler
in a static
variable.
Sourcepub fn spawn_allocated<F, STO>(
&'static self,
task: STO::StoredTask,
) -> JoinHandle<F::Output> ⓘ
pub fn spawn_allocated<F, STO>( &'static self, task: STO::StoredTask, ) -> JoinHandle<F::Output> ⓘ
Spawn a pre-allocated task
This method is used to spawn a task that requires some bespoke
procedure of allocation, typically of a custom Storage
implementor.
See the documentation for the Storage
trait for more details on
using custom task storage.
This method returns a JoinHandle
that can be used to await the
task’s output. Dropping the JoinHandle
detaches the spawned task,
allowing it to run in the background without awaiting its output.
When tasks are spawned on a scheduler, the scheduler must be ticked in order to drive those tasks to completion. See the module-level documentation for more information on implementing a system’s run loop.
Sourcepub fn build_task<'a>(&'static self) -> Builder<'a, &'static Self>
pub fn build_task<'a>(&'static self) -> Builder<'a, &'static Self>
Returns a new task Builder
for configuring tasks prior to spawning
them on this scheduler.
Sourcepub fn current_task(&'static self) -> Option<TaskRef>
pub fn current_task(&'static self) -> Option<TaskRef>
Returns a TaskRef
referencing the task currently being polled by
this scheduler, if a task is currently being polled.
§Returns
-
Some
(
TaskRef
)
referencing the currently-polling task, if a task is currently being polled (i.e., the scheduler is ticking and the queue of scheduled tasks is non-empty). -
None
if the scheduler is not currently being polled (i.e., the scheduler is not ticking or its run queue is empty and all polls have completed).
Sourcepub fn tick(&'static self) -> Tick
pub fn tick(&'static self) -> Tick
Tick this scheduler, polling up to Self::DEFAULT_TICK_SIZE
tasks
from the scheduler’s run queue.
Only a single CPU core/thread may tick a given scheduler at a time. If
another call to tick
is in progress on a different core, this method
will immediately return.
See the module-level documentation for more information on using this function to implement a system’s run loop.
§Returns
A Tick
struct with data describing what occurred during the
scheduler tick.
Source§impl StaticScheduler
impl StaticScheduler
Sourcepub fn new() -> Self
pub fn new() -> Self
Returns a new StaticScheduler
with a heap-allocated stub task.
Unlike StaticScheduler::new_with_static_stub
, this is not a
const fn
, as it performs a heap allocation for the stub task.
However, the returned StaticScheduler
must still be stored in a
static
variable in order to be used.
This method is generally used with lazy initialization of the
scheduler static
.
Sourcepub fn spawn<F>(&'static self, future: F) -> JoinHandle<F::Output> ⓘ
pub fn spawn<F>(&'static self, future: F) -> JoinHandle<F::Output> ⓘ
Spawn a task.
This method returns a JoinHandle
that can be used to await the
task’s output. Dropping the JoinHandle
detaches the spawned task,
allowing it to run in the background without awaiting its output.
When tasks are spawned on a scheduler, the scheduler must be ticked in order to drive those tasks to completion. See the module-level documentation for more information on implementing a system’s run loop.
§Examples
Spawning a task and awaiting its output:
use maitake::scheduler::{self, StaticScheduler};
static SCHEDULER: StaticScheduler = scheduler::new_static!();
// spawn a new task, returning a `JoinHandle`.
let task = SCHEDULER.spawn(async move {
// ... do stuff ...
42
});
// spawn another task that awaits the output of the first task.
SCHEDULER.spawn(async move {
// await the `JoinHandle` future, which completes when the task
// finishes, and unwrap its output.
let output = task.await.expect("task is not cancelled");
assert_eq!(output, 42);
});
// run the scheduler, driving the spawned tasks to completion.
while SCHEDULER.tick().has_remaining {}
Spawning a task to run in the background, without awaiting its output:
use maitake::scheduler::{self, StaticScheduler};
static SCHEDULER: StaticScheduler = scheduler::new_static!();
// dropping the `JoinHandle` allows the task to run in the background
// without awaiting its output.
SCHEDULER.spawn(async move {
// ... do stuff ...
});
// run the scheduler, driving the spawned tasks to completion.
while SCHEDULER.tick().has_remaining {}
Trait Implementations§
Source§impl Debug for StaticScheduler
impl Debug for StaticScheduler
Source§impl Default for StaticScheduler
impl Default for StaticScheduler
Source§fn default() -> StaticScheduler
fn default() -> StaticScheduler
Source§impl Schedule for &'static StaticScheduler
impl Schedule for &'static StaticScheduler
Source§fn current_task(&self) -> Option<TaskRef>
fn current_task(&self) -> Option<TaskRef>
TaskRef
referencing the task currently being polled by
this scheduler, if a task is currently being polled.Source§fn build_task<'a>(&self) -> Builder<'a, Self>
fn build_task<'a>(&self) -> Builder<'a, Self>
Builder
for configuring tasks prior to spawning
them on this scheduler.