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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// This file is part of yash, an extended POSIX shell.
// Copyright (C) 2024 WATANABE Yuki
//! `yash-executor` is a library for running concurrent tasks in a
//! single-threaded context. This crate supports `no_std` configurations but
//! requires the `alloc` crate.
//!
//! The [`Executor`] provided by this crate can be instantiated more than once
//! to run multiple sets of tasks concurrently. Each executor maintains its
//! own set of tasks and does not share tasks with other executors. This is
//! different from other executor implementations that use a global or
//! thread-local executor.
//!
//! This crate is free of locks and atomic operations at the cost of
//! [unsafe spawning](Executor::spawn_pinned). Wakers used in this crate are
//! thread-unsafe and not guarded by locks or atomics, so you must ensure that
//! wakers are not shared between threads.
//!
//! ```
//! # use yash_executor::Executor;
//! # use yash_executor::forwarder::TryReceiveError;
//! let executor = Executor::new();
//!
//! // Spawn a task that returns 42
//! let receiver = unsafe { executor.spawn(async { 42 }) };
//!
//! // The task is not yet complete
//! assert_eq!(receiver.try_receive(), Err(TryReceiveError::NotSent));
//!
//! // Run the executor until the task is complete
//! executor.run_until_stalled();
//!
//! // Now we have the result
//! assert_eq!(receiver.try_receive(), Ok(42));
//! ```
//!
//! [`Spawner`]s provide a subset of the functionality of [`Executor`] to allow
//! spawning tasks without access to the full executor. It is useful for adding
//! tasks from within another task without creating cyclic dependencies, which
//! can cause memory leaks.
//!
//! The [`forwarder`] module provides utilities for forwarding the result of a
//! future to another future. The [`forwarder`](forwarder::forwarder) function
//! creates a pair of [`Sender`] and [`Receiver`] that share an internal state
//! to communicate the result of a future. A `Receiver` is also returned from
//! the [`Executor::spawn`] method to receive the result of a future.
//!
//! [`Sender`]: forwarder::Sender
//! [`Receiver`]: forwarder::Receiver
extern crate alloc;
use Box;
use VecDeque;
use ;
use RefCell;
use Debug;
use Pin;
/// Interface for running concurrent tasks
///
/// You call the [`spawn_pinned`](Self::spawn_pinned) or [`spawn`](Self::spawn)
/// method to add a task to the executor. Just adding a task to the executor
/// does not run it. You need to call the [`step`](Self::step) or
/// [`run_until_stalled`](Self::run_until_stalled) method to run the tasks.
///
/// `Executor` implements `Clone` but all clones share the same set of tasks.
/// Separately created `Executor` instances do not share tasks.
/// Interface for spawning tasks
///
/// `Spawner` provides a subset of the functionality of `Executor` to allow
/// spawning tasks without access to the full executor.
///
/// `Spawner` instances can be cloned and share the same executor state.
/// `Spawner`s maintain a weak reference to the executor state, so they do not
/// prevent the executor from being dropped. If the executor is dropped, the
/// `Spawner` will not be able to spawn any more tasks.
///
/// To obtain a `Spawner` from an `Executor`, use the [`Executor::spawner`]
/// method. The [`dead`](Self::dead) and `default` functions return a `Spawner`
/// that can never spawn tasks.
///
/// ```
/// # use yash_executor::Executor;
/// let executor = Executor::new();
/// let spawner = executor.spawner();
/// let final_receiver = unsafe {
/// executor.spawn(async move {
/// let receiver_1 = spawner.spawn(async { 1 }).unwrap();
/// let receiver_2 = spawner.spawn(async { 2 }).unwrap();
/// receiver_2.await + receiver_1.await
/// })
/// };
/// executor.run_until_stalled();
/// assert_eq!(final_receiver.try_receive(), Ok(3));
/// ```
/// Internal state of the executor
/// State of a task to be executed
pub use SpawnError;