vortex_io/runtime/
single.rs1use std::rc::Rc;
5use std::rc::Weak as RcWeak;
6use std::sync::Arc;
7
8use async_executor::LocalExecutor;
9use futures::Stream;
10use futures::StreamExt;
11use futures::channel::oneshot;
12use futures::future::BoxFuture;
13use futures::stream::LocalBoxStream;
14use parking_lot::Mutex;
15use vortex_error::vortex_panic;
16
17use crate::runtime::AbortHandle;
18use crate::runtime::AbortHandleRef;
19use crate::runtime::BlockingRuntime;
20use crate::runtime::Executor;
21use crate::runtime::Handle;
22use crate::runtime::abort::TaskAbortHandle;
23use crate::runtime::platform;
24
25pub struct SingleThreadRuntime {
36 sender: Arc<Sender>,
37 executor: Rc<LocalExecutor<'static>>,
38}
39
40impl Default for SingleThreadRuntime {
41 fn default() -> Self {
42 let executor = Rc::new(LocalExecutor::new());
43 let sender = Arc::new(Sender::new(&executor));
44 Self { sender, executor }
45 }
46}
47
48struct Sender {
49 scheduling: kanal::Sender<SpawnAsync<'static>>,
50 cpu: kanal::Sender<SpawnSync<'static>>,
51 blocking: kanal::Sender<SpawnSync<'static>>,
52}
53
54impl Sender {
55 fn new(local: &Rc<LocalExecutor<'static>>) -> Self {
56 let (scheduling_send, scheduling_recv) = kanal::unbounded::<SpawnAsync>();
57 let (cpu_send, cpu_recv) = kanal::unbounded::<SpawnSync>();
58 let (blocking_send, blocking_recv) = kanal::unbounded::<SpawnSync>();
59
60 let weak_local = Rc::downgrade(local);
63
64 let weak_local2 = RcWeak::clone(&weak_local);
66 local
67 .spawn(async move {
68 while let Ok(spawn) = scheduling_recv.as_async().recv().await {
69 if let Some(local) = weak_local2.upgrade() {
70 drop(
72 spawn
73 .task_callback
74 .send(TaskAbortHandle::new_handle(local.spawn(spawn.future))),
75 );
76 }
77 }
78 })
79 .detach();
80
81 let weak_local2 = RcWeak::clone(&weak_local);
83 local
84 .spawn(async move {
85 while let Ok(spawn) = cpu_recv.as_async().recv().await {
86 if let Some(local) = weak_local2.upgrade() {
87 let work = spawn.sync;
88 drop(spawn.task_callback.send(TaskAbortHandle::new_handle(
90 local.spawn(async move { work() }),
91 )));
92 }
93 }
94 })
95 .detach();
96
97 let weak_local2 = RcWeak::clone(&weak_local);
99 local
100 .spawn(async move {
101 while let Ok(spawn) = blocking_recv.as_async().recv().await {
102 if let Some(local) = weak_local2.upgrade() {
103 let work = spawn.sync;
104 drop(spawn.task_callback.send(TaskAbortHandle::new_handle(
106 local.spawn(async move { work() }),
107 )));
108 }
109 }
110 })
111 .detach();
112
113 Self {
114 scheduling: scheduling_send,
115 cpu: cpu_send,
116 blocking: blocking_send,
117 }
118 }
119}
120
121impl Executor for Sender {
126 fn spawn(&self, future: BoxFuture<'static, ()>) -> AbortHandleRef {
127 let (send, recv) = oneshot::channel();
128 if let Err(e) = self.scheduling.send(SpawnAsync {
129 future,
130 task_callback: send,
131 }) {
132 vortex_panic!("Executor missing: {}", e);
133 }
134 Box::new(LazyAbortHandle {
135 task: Mutex::new(recv),
136 })
137 }
138
139 fn spawn_cpu(&self, cpu: Box<dyn FnOnce() + Send + 'static>) -> AbortHandleRef {
140 let (send, recv) = oneshot::channel();
141 if let Err(e) = self.cpu.send(SpawnSync {
142 sync: cpu,
143 task_callback: send,
144 }) {
145 vortex_panic!("Executor missing: {}", e);
146 }
147 Box::new(LazyAbortHandle {
148 task: Mutex::new(recv),
149 })
150 }
151
152 fn spawn_blocking_io(&self, work: Box<dyn FnOnce() + Send + 'static>) -> AbortHandleRef {
153 let (send, recv) = oneshot::channel();
154 if let Err(e) = self.blocking.send(SpawnSync {
155 sync: work,
156 task_callback: send,
157 }) {
158 vortex_panic!("Executor missing: {}", e);
159 }
160 Box::new(LazyAbortHandle {
161 task: Mutex::new(recv),
162 })
163 }
164}
165
166impl BlockingRuntime for SingleThreadRuntime {
167 type BlockingIterator<'a, R: 'a> = SingleThreadIterator<'a, R>;
168
169 fn handle(&self) -> Handle {
170 let executor: Arc<dyn Executor> = Arc::clone(&self.sender) as Arc<dyn Executor>;
171 Handle::new(Arc::downgrade(&executor))
172 }
173
174 fn block_on<Fut, R>(&self, fut: Fut) -> R
175 where
176 Fut: Future<Output = R>,
177 {
178 platform::block_on(self.executor.run(fut))
179 }
180
181 fn block_on_stream<'a, S, R>(&self, stream: S) -> Self::BlockingIterator<'a, R>
182 where
183 S: Stream<Item = R> + Send + 'a,
184 R: Send + 'a,
185 {
186 SingleThreadIterator {
187 executor: Rc::clone(&self.executor),
188 stream: stream.boxed_local(),
189 }
190 }
191}
192
193pub fn block_on<F, Fut, R>(f: F) -> R
198where
199 F: FnOnce(Handle) -> Fut,
200 Fut: Future<Output = R>,
201{
202 let runtime = SingleThreadRuntime::default();
203 let handle = runtime.handle();
204 runtime.block_on(f(handle))
205}
206
207pub fn block_on_stream<'a, F, S, R>(f: F) -> SingleThreadIterator<'a, R>
209where
210 F: FnOnce(Handle) -> S,
211 S: Stream<Item = R> + Send + Unpin + 'a,
212 R: Send + 'a,
213{
214 let runtime = SingleThreadRuntime::default();
215 let handle = runtime.handle();
216 runtime.block_on_stream(f(handle))
217}
218
219struct SpawnAsync<'rt> {
231 future: BoxFuture<'rt, ()>,
232 task_callback: oneshot::Sender<AbortHandleRef>,
233}
234
235struct SpawnSync<'rt> {
237 sync: Box<dyn FnOnce() + Send + 'rt>,
238 task_callback: oneshot::Sender<AbortHandleRef>,
239}
240
241struct LazyAbortHandle {
242 task: Mutex<oneshot::Receiver<AbortHandleRef>>,
243}
244
245impl AbortHandle for LazyAbortHandle {
246 fn abort(self: Box<Self>) {
247 if let Ok(Some(task)) = self.task.lock().try_recv() {
249 task.abort()
250 }
251 }
252}
253
254pub struct SingleThreadIterator<'a, T> {
256 executor: Rc<LocalExecutor<'static>>,
257 stream: LocalBoxStream<'a, T>,
258}
259
260impl<T> Iterator for SingleThreadIterator<'_, T> {
261 type Item = T;
262
263 fn next(&mut self) -> Option<Self::Item> {
264 let fut = self.stream.next();
265 platform::block_on(self.executor.run(fut))
266 }
267}
268
269#[cfg(test)]
270mod tests {
271 use std::sync::Arc;
272 use std::sync::atomic::AtomicUsize;
273 use std::sync::atomic::Ordering;
274
275 use futures::FutureExt;
276
277 use crate::runtime::BlockingRuntime;
278 use crate::runtime::single::SingleThreadRuntime;
279 use crate::runtime::single::block_on;
280
281 #[test]
282 fn test_drive_simple_future() {
283 let result = SingleThreadRuntime::default().block_on(async { 123 }.boxed_local());
284 assert_eq!(result, 123);
285 }
286
287 #[test]
288 fn test_spawn_cpu_task() {
289 let counter = Arc::new(AtomicUsize::new(0));
290 let c = Arc::clone(&counter);
291
292 block_on(|handle| async move {
293 handle
294 .spawn_cpu(move || {
295 c.fetch_add(1, Ordering::SeqCst);
296 })
297 .await
298 });
299
300 assert_eq!(counter.load(Ordering::SeqCst), 1);
301 }
302}