Skip to main content

ExecutorState

Struct ExecutorState 

Source
pub struct ExecutorState {
Show 14 fields pub state_owner: String, pub wakeup_priority: PriorityOrder, pub global_tasks: SharedTaskQueue, pub current_task: Rc<RefCell<Option<Entry>>>, pub local_tasks: Rc<RefCell<EntryList<BoxedExecutionIterator>>>, pub task_graph: Rc<RefCell<HashMap<Entry, Entry>>>, pub packed_tasks: Rc<RefCell<HashMap<Entry, bool>>>, pub processing: Rc<RefCell<VecDeque<Entry>>>, pub rng: Rc<RefCell<ChaCha8Rng>>, pub sleepers: Sleepers<Sleepable>, pub idler: Rc<RefCell<IdleMan>>, pub depends_true_violations: Rc<RefCell<HashMap<Entry, u32>>>, pub root: Ctx, pub task_ctx: Rc<RefCell<HashMap<Entry, Ctx>>>,
}
Expand description

Underlying state of an executor. It is the inner structure used by a LocalExecutorEngine to manage all relevant tasks it takes on.

It’s important to note that if a task panic, so will the ExecutorState which can’t be restored and all tasks owned will be lost, so its important you always handle panic in the actual task itself by using either the DoNext, CollectNext and OnNext and if you implement your own ExecutionIterator to ensure to follow the pattern demonstrated in those implementations to correctly handle panic from tasks even at the trade of some runtime cost from Mutex which allow you use std::panic::catch_unwind.

Fields§

§state_owner: String§wakeup_priority: PriorityOrder

what priority should waking task be placed.

§global_tasks: SharedTaskQueue

global_tasks are the shared tasks coming from the main thread they generally will always come in fifo order and will be processed in the order received.

§current_task: Rc<RefCell<Option<Entry>>>

indicates the current task currently being handled for safety checks.

§local_tasks: Rc<RefCell<EntryList<BoxedExecutionIterator>>>

tasks owned by the executor which should be processed first before taking on the next task from the global queue, task generally come in here from the current task taking from the global queue. This allows us keep the overall execution of any async iterator within the same thread and keep a one thread execution.

§task_graph: Rc<RefCell<HashMap<Entry, Entry>>>

task_graph provides dependency mapping of a Task (Key) lifted by another Task (Value) allowing us to go from lifted task to it’s tree of dependents.

§packed_tasks: Rc<RefCell<HashMap<Entry, bool>>>

map used to identify that a task was packed.

§processing: Rc<RefCell<VecDeque<Entry>>>

the queue used for performing perioritization, usually the global task taking will first be stored in the local tasks list and have it’s related Entry pointer added into the queue for prioritization, and we will never take any new tasks from the global queue until all the entries in this queue is empty, this ensures we can consistently complete every received tasks till it finishes.

§rng: Rc<RefCell<ChaCha8Rng>>

this provides consistent and repeatable random number generation this is exposed by the executor to it’s callers via scopes or direct use that lets you borrow a random number that always produces the same sets of values when given the same seed for repeatability.

§sleepers: Sleepers<Sleepable>

sleepers contain a means to register tasks currently being executed as sleeping, forcing the executing to either in a single threaded environment like WebAssembly spin endlessly until one of them is ready for progress once the sleeper indicate the task is ready for waking up.

Each executor may treat these differently in that they may process one task at a time until completion or concurrently process multiple tasks at a time with allotted time slot between them.

§idler: Rc<RefCell<IdleMan>>

sleepy provides a managed indicator of how many times we’ve been idle and recommends how much sleep should the executor take next.

§depends_true_violations: Rc<RefCell<HashMap<Entry, u32>>>

Track consecutive State::Depends(true) violations per entry. After DEPENDS_TRUE_PANIC_THRESHOLD consecutive violations, the task panics.

§root: Ctx

The engine-owned root Ctx. Forked once per ExecutionIterator when a task enters the engine; each fork is stored in task_ctx and shared (by value clone) with the task on every poll.

§task_ctx: Rc<RefCell<HashMap<Entry, Ctx>>>

Per-entry Ctx fork: one per ExecutionIterator, keyed by its Entry.

Implementations§

Source§

impl ExecutorState

Source

pub fn new( state_owner: String, global_tasks: SharedTaskQueue, wakeup_priority: PriorityOrder, rng: ChaCha8Rng, idler: IdleMan, ) -> Self

Source§

impl ExecutorState

Source

pub fn get_rng(&self) -> Rc<RefCell<ChaCha8Rng>>

Returns a borrowed immutable

Source

pub fn get_task_dependents(&self, target: Entry) -> Vec<Entry>

Returns the list of other task dependent on this giving tasks and their dependents in order.

Source

pub fn is_packed(&self, target: &Entry) -> bool

Returns true/false indicative if the provided task entry is considered packed.

Source

pub fn wake_up(&self, target: Entry)

wake_up adds the entry into the list of wakers that should be woken up by the executor.

§Design Note (Feature 01: Sleeper Lifecycle Safety)

Includes defensive check to skip stale entries that no longer exist in local_tasks. This prevents panics when a sleeper matures after its associated task was combined/removed. See remove_sleepers_for_entry for the full stale sleeper lifecycle explanation.

Source

pub fn wakeup_ready_sleepers(&self)

next_wakeup checks all registered sleepers to see if they matured to the age of being woken up and placed back into the processing queue.

Source

pub fn number_of_sleepers(&self) -> usize

Source

pub fn number_of_depends_true_violations(&self) -> usize

How many tasks currently have a streak of Depends on an already-ready signal (see DEPENDS_TRUE_PANIC_THRESHOLD).

Source

pub fn has_sleeping_tasks(&self) -> bool

Source

pub fn time_until_next_wakeup(&self) -> Option<Duration>

Returns the duration until the next sleeper wakes up.

Used for sleeper-aware yielding - when no work is available, threads can sleep until the earliest sleeper deadline instead of using a fixed yield duration.

Returns None if no sleepers are registered. Returns Duration::ZERO if a sleeper is already past its deadline.

Source

pub fn has_local_tasks(&self) -> bool

Returns True/False indicative if the executor has any local task still processing

Source

pub fn has_active_tasks(&self) -> bool

Returns if there is any local task is active which means:

  1. Not sleeping
  2. In local task queue
Source

pub fn has_inflight_task(&self) -> bool

Returns true/false if processing queue has task.

Source

pub fn has_incoming_global_tasks(&self) -> bool

Source

pub fn has_runnable_work(&self) -> bool

Whether this worker has real work to run on the current tick — an active task, an in-flight (processing-queue) task, or a global task waiting to be acquired.

When this is false the worker is kept alive solely by sleeping tasks and is busy-spinning schedule_and_do_work until one of them becomes ready.

Source

pub fn total_inprocess_tasks(&self) -> usize

Returns totla

Source

pub fn total_sleeping_tasks(&self) -> usize

Source

pub fn total_tasks(&self) -> usize

Returns the total in queue regardless of sleeping or in-progress.

Source

pub fn total_active_tasks(&self) -> usize

Returns the total remaining tasks that are active and not sleeping.

§Design Note

Uses saturating_sub to prevent underflow panic when sleepers reference entries that have been removed (stale sleeper entries). This can happen when a task sleeps, then spawns a child via SpawnFinished and gets combined into a new task. The old entry is removed but its sleeper remains until cleaned up.

Source

pub fn remove_sleepers_for_entry(&self, entry: &Entry)

Removes any sleepers referencing the given entry.

§Design Note (Feature 01: Sleeper Lifecycle Safety)

Must be called when a task is removed to prevent stale sleeper entries. Stale entries occur when:

  1. Task A sleeps (registered in sleepers with entry E)
  2. Task A spawns child via SpawnFinished, gets combined into new task
  3. Old entry E is removed from local_tasks via take()
  4. Sleeper for E remains in sleepers -> stale entry
  5. When sleeper matures, wake_up tries to process non-existent entry -> panic

Calling this before take() prevents the stale entry issue. This was the root cause of the “entry must always have a task attached” panic.

Source

pub fn schedule_next(&self) -> ScheduleOutcome

schedule_next will attempt to pull a new task from the global queue if no task is pending on the local queue and if so returns true to indicate success else a false to indicate no task was taking from the global queue as the local queue had a task or no task was found.

Source

pub fn request_global_task(&self) -> ProgressIndicator

Source

pub fn schedule_and_do_work( &self, engine: BoxedExecutionEngine, ) -> ProgressIndicator

Source

pub fn check_processing_queue(&self) -> Option<ProgressIndicator>

Source

pub fn do_work(&self, engine: BoxedExecutionEngine) -> ProgressIndicator

do_work attempts to call the current iterator to progress executing the next operation internally till it’s ready for work to begin.

§Panics
  1. Will panic if when popping from the processing queue, we fail to get the top entry as at this point work should be in queue before do_work is called.
Source§

impl ExecutorState

Source

pub fn sequenced( &self, task: BoxedExecutionIterator, parent: Entry, ) -> AnyResult<SpawnInfo, ExecutorError>

sequenced defers from the ExecutorState::lift method where instead we create a co-linked sequential loop between the parent (via its entry id) creating this task and itself.

Where the parent will be pulled and used to create a DualSequeunceChildAndParentLinkedTask executor which will trigger the child then the parent in sequence.

This means the currently processed task that might have called ExecutorState::lift since the executor will only ever execute a singular task each time (even if it concurrently) processes them (based on their operating semantics).

But even if its from outside a task, understand the new task will take priority till it’s done.

Returns:

The result of the spawn operation with the SpawnInfo containing the key details of parent and child and what type of operation was performed.

Source

pub fn lift( &self, task: BoxedExecutionIterator, parent: Option<Entry>, ) -> AnyResult<SpawnInfo, ExecutorError>

lift defers from the ExecutorState::schedule method where instead when adding the task into the local queue but also lifts the task as the highest priority task to be processed.

This if the parent is supplied should create a FinishChildBeforeParentTask executor which will process the child until its done then move to the parent in sequence.

This means the currently processed task that might have called ExecutorState::lift since the executor will only ever execute a singular task each time (even if it concurrently) processes them (based on their operating semantics).

But even if its from outside a task, understand the new task will take priority till it’s done.

Source

pub fn schedule( &self, task: BoxedExecutionIterator, ) -> AnyResult<SpawnInfo, ExecutorError>

schedule appends the provided task into the end of the local task queue which then gets processed accordingly when its turns comes up once all previous tasks and it’s sub-tasks have been resolved.

Scheduled tasks do not create relationships at all any task can schedule new task to the executor and it never affects its execution or priority.

Source§

impl ExecutorState

Source

pub fn broadcast(&self, task: GlobalTask) -> AnyResult<SpawnInfo, ExecutorError>

Delivers a task (Iterator) type to the global execution queue and in such a case you do not have an handle to the task as we no more have control as to where it gets allocated.

Trait Implementations§

Source§

impl Clone for ExecutorState

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ExecutorState

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

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

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more