minimal_executor/local_pool_busy.rs
1use alloc::sync::{Arc, Weak};
2use futures::future::LocalFutureObj;
3use futures::{FutureExt};
4use core::task::{Poll};
5use crossbeam::queue::ArrayQueue;
6use futures::task::UnsafeFutureObj;
7use crate::poll_fn;
8use futures::future::FutureObj;
9use futures::task::Spawn;
10use futures::task::SpawnError;
11
12/// A single-threaded task pool for polling futures to completion.
13///
14/// This executor allows you to multiplex any number of tasks onto a single
15/// thread. It's appropriate to poll strictly I/O-bound futures that do very
16/// little work in between I/O actions.
17///
18/// To get a handle to the pool that implements
19/// [`Spawn`](futures_task::Spawn), use the
20/// [`spawner()`](LocalPool::spawner) method. Because the executor is
21/// single-threaded, it supports a special form of task spawning for non-`Send`
22/// futures, via [`spawn_local_obj`](futures_task::LocalSpawn::spawn_local_obj).
23#[derive(Debug)]
24pub struct LocalPool<'a, Ret = ()> {
25 pool: Arc<ArrayQueue<LocalFutureObj<'a, Ret>>>,
26}
27
28
29#[derive(Clone)]
30pub struct Spawner<'a, Ret> {
31 tx: Weak<ArrayQueue<LocalFutureObj<'a, Ret>>>,
32}
33
34
35impl<'a> Spawner<'a, ()> {
36 pub fn spawn<F>(&self, f: F) -> Result<(), SpawnError>
37 where F: UnsafeFutureObj<'a, ()> + Send {
38 let tx = self.tx.upgrade().ok_or(SpawnError::shutdown())?;
39 tx.push(LocalFutureObj::new(f)).expect("Queue full");
40 Ok(())
41 }
42}
43
44
45impl Spawn for Spawner<'static, ()> {
46 fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
47 let tx = self.tx.upgrade().ok_or(SpawnError::shutdown())?;
48 tx.push(future.into()).expect("Queue full");
49 Ok(())
50 }
51}
52
53
54impl<'a, Ret> LocalPool<'a, Ret> {
55 /// Create a new, empty pool of tasks.
56 pub fn new(cap: usize) -> Self {
57 Self {
58 pool: Arc::new(ArrayQueue::new(cap)),
59 }
60 }
61
62 pub fn spawner(&self) -> Spawner<'a, Ret> {
63 Spawner {
64 tx: Arc::downgrade(&self.pool),
65 }
66 }
67 pub fn spawn<F>(&mut self, f: F)
68 where F: UnsafeFutureObj<'a, Ret> {
69 self.pool.push(LocalFutureObj::new(f)).expect("Queue full");
70 }
71 /// Run all tasks in the pool to completion.
72 ///
73 /// ```rust
74 ///
75 /// use minimal_executor::LocalPool;
76 ///
77 /// let mut pool: LocalPool<'_, ()> = LocalPool::new();
78 ///
79 /// // ... spawn some initial tasks using `spawn.spawn()` or `spawn.spawn_local()`
80 ///
81 /// // run *all* tasks in the pool to completion, including any newly-spawned ones.
82 /// pool.run();
83 /// ```
84 ///
85 /// The function will block the calling thread until *all* tasks in the pool
86 /// are complete, including any spawned while running existing tasks.
87 pub fn run(&mut self) -> alloc::vec::Vec<Ret> {
88 let mut results = alloc::vec::Vec::new();
89 loop {
90 let ret = self.poll_once();
91
92 // no queued tasks; we may be done
93 match ret {
94 Poll::Pending => {}
95 Poll::Ready(None) => break,
96 Poll::Ready(Some(r)) => { results.push(r); }
97 }
98 }
99 results
100 }
101
102 /// Runs all tasks and returns after completing one future or until no more progress
103 /// can be made. Returns `true` if one future was completed, `false` otherwise.
104 ///
105 /// ```rust
106 ///
107 /// use futures::task::LocalSpawnExt;
108 /// use futures::future::{ready, pending};
109 /// use minimal_executor::LocalPool;
110 ///
111 /// let mut pool: LocalPool<'_, ()> = LocalPool::new();
112 /// pool.spawn(Box::pin(ready(())));
113 /// pool.spawn(Box::pin(ready(())));
114 /// pool.spawn(Box::pin(pending()));
115 ///
116 /// // Run the two ready tasks and return true for them.
117 /// pool.try_run_one(); // returns true after completing one of the ready futures
118 /// pool.try_run_one(); // returns true after completing the other ready future
119 ///
120 /// // the remaining task can not be completed
121 /// assert!(pool.try_run_one().is_pending()); // returns false
122 /// ```
123 ///
124 /// This function will not block the calling thread and will return the moment
125 /// that there are no tasks left for which progress can be made or after exactly one
126 /// task was completed; Remaining incomplete tasks in the pool can continue with
127 /// further use of one of the pool's run or poll methods.
128 /// Though only one task will be completed, progress may be made on multiple tasks.
129 pub fn try_run_one(&mut self) -> Poll<Ret> {
130 let ret = self.poll_though();
131 match ret {
132 Poll::Ready(Some(ret)) => {
133 Poll::Ready(ret)
134 }
135 Poll::Ready(None) => {
136 Poll::Pending
137 }
138 Poll::Pending => {
139 Poll::Pending
140 }
141 }
142 }
143
144 pub fn poll_though(&mut self) -> Poll<Option<Ret>> {
145 let len = self.pool.len();
146 if len == 0 {
147 return Poll::Ready(None);
148 }
149 poll_fn(|cx| {
150 for _ in 0..len {
151 if let Some(mut future) = self.pool.pop() {
152 match future.poll_unpin(cx) {
153 Poll::Pending => {
154 self.pool.push(future).expect("Queue full");
155 }
156 Poll::Ready(ret) => {
157 return Poll::Ready(Some(ret));
158 }
159 }
160 }
161 }
162 Poll::Pending
163 })
164 }
165 pub fn poll_once(&mut self) -> Poll<Option<Ret>> {
166 if let Some(mut future) = self.pool.pop() {
167 match poll_fn(|cx| future.poll_unpin(cx)) {
168 Poll::Pending => {
169 self.pool.push(future).expect("Queue full");
170 Poll::Pending
171 }
172 Poll::Ready(ret) => {
173 Poll::Ready(Some(ret))
174 }
175 }
176 } else {
177 Poll::Ready(None)
178 }
179 }
180}
181