1use std::cell::{Cell, UnsafeCell};
2use std::collections::VecDeque;
3use std::{future::Future, io, sync::Arc, thread};
4
5use async_task::Runnable;
6use crossbeam_queue::SegQueue;
7use swap_buffer_queue::error::{TryDequeueError, TryEnqueueError};
8use swap_buffer_queue::{Queue, buffer::ArrayBuffer};
9
10use crate::{driver::Driver, driver::Notify, driver::PollResult, handle::JoinHandle};
11
12scoped_tls::scoped_thread_local!(static CURRENT_RUNTIME: Runtime);
13
14thread_local!(static THREAD_ID: thread::ThreadId = thread::current().id());
15
16fn current_thread_id() -> thread::ThreadId {
18 THREAD_ID.with(|id| *id)
19}
20
21#[derive(Debug)]
22pub struct Runtime {
26 stop: Cell<bool>,
27 queue: Arc<RunnableQueue>,
28}
29
30impl Runtime {
31 pub fn new(handle: Box<dyn Notify>) -> Self {
33 Self::builder().build(handle)
34 }
35
36 pub fn builder() -> RuntimeBuilder {
38 RuntimeBuilder::new()
39 }
40
41 #[allow(clippy::arc_with_non_send_sync)]
42 fn with_builder(builder: &RuntimeBuilder, handle: Box<dyn Notify>) -> Self {
43 Self {
44 stop: Cell::new(false),
45 queue: Arc::new(RunnableQueue::new(builder.event_interval, handle)),
46 }
47 }
48
49 pub fn with_current<T, F: FnOnce(&Self) -> T>(f: F) -> T {
55 #[cold]
56 fn not_in_neon_runtime() -> ! {
57 panic!("not in a neon runtime")
58 }
59
60 if CURRENT_RUNTIME.is_set() {
61 CURRENT_RUNTIME.with(f)
62 } else {
63 not_in_neon_runtime()
64 }
65 }
66
67 #[inline]
68 pub fn handle(&self) -> Handle {
70 Handle {
71 queue: self.queue.clone(),
72 }
73 }
74
75 pub fn spawn<F: Future + 'static>(&self, future: F) -> JoinHandle<F::Output> {
80 unsafe { self.spawn_unchecked(future) }
81 }
82
83 pub unsafe fn spawn_unchecked<F: Future>(&self, future: F) -> JoinHandle<F::Output> {
89 let queue = self.queue.clone();
90 let (runnable, task) = unsafe {
91 async_task::spawn_unchecked(future, move |runnable| {
92 queue.schedule(runnable);
93 })
94 };
95 runnable.schedule();
96 JoinHandle::new(task)
97 }
98
99 pub fn poll(&self) -> PollResult {
101 if self.stop.get() {
102 PollResult::Ready
103 } else if self.queue.run() {
104 PollResult::PollAgain
105 } else {
106 PollResult::Pending
107 }
108 }
109
110 pub fn block_on<F: Future>(&self, future: F, driver: &dyn Driver) -> F::Output {
118 self.stop.set(false);
119
120 CURRENT_RUNTIME.set(self, || {
121 let mut result = None;
122 unsafe {
123 self.spawn_unchecked(async {
124 result = Some(future.await);
125 self.stop.set(true);
126 let _ = self.queue.handle.notify();
127 });
128 }
129
130 ntex_error::set_backtrace_start_alt("src/raw.rs", 0);
131 driver.run(self).expect("Driver failed");
132 result.expect("Driver failed to poll")
133 })
134 }
135}
136
137impl Drop for Runtime {
138 fn drop(&mut self) {
139 CURRENT_RUNTIME.set(self, || {
140 self.queue.clear();
141 });
142 }
143}
144
145#[derive(Debug)]
146pub struct Handle {
148 queue: Arc<RunnableQueue>,
149}
150
151impl Handle {
152 pub fn current() -> Handle {
158 Runtime::with_current(Runtime::handle)
159 }
160
161 pub fn notify(&self) -> io::Result<()> {
163 self.queue.handle.notify()
164 }
165
166 pub fn spawn<F: Future + Send + 'static>(&self, future: F) -> JoinHandle<F::Output> {
171 let queue = self.queue.clone();
172 let schedule = move |runnable| {
173 queue.schedule(runnable);
174 };
175 let (runnable, task) = unsafe { async_task::spawn_unchecked(future, schedule) };
176 runnable.schedule();
177 JoinHandle::new(task)
178 }
179}
180
181impl Clone for Handle {
182 fn clone(&self) -> Self {
183 Self {
184 queue: self.queue.clone(),
185 }
186 }
187}
188
189#[derive(Debug)]
190struct RunnableQueue {
191 id: thread::ThreadId,
192 idle: Cell<bool>,
193 handle: Box<dyn Notify>,
194 event_interval: usize,
195 local_queue: UnsafeCell<VecDeque<Runnable>>,
196 sync_fixed_queue: Queue<ArrayBuffer<Runnable, 128>>,
197 sync_queue: SegQueue<Runnable>,
198}
199
200unsafe impl Send for RunnableQueue {}
201unsafe impl Sync for RunnableQueue {}
202
203impl RunnableQueue {
204 fn new(event_interval: usize, handle: Box<dyn Notify>) -> Self {
205 Self {
206 handle,
207 event_interval,
208 id: current_thread_id(),
209 idle: Cell::new(true),
210 local_queue: UnsafeCell::new(VecDeque::new()),
211 sync_fixed_queue: Queue::default(),
212 sync_queue: SegQueue::new(),
213 }
214 }
215
216 fn schedule(&self, runnable: Runnable) {
217 if self.id == current_thread_id() {
218 unsafe { (*self.local_queue.get()).push_back(runnable) };
219 if self.idle.get() {
220 self.idle.set(false);
221 self.handle.notify().ok();
222 }
223 } else {
224 let result = self.sync_fixed_queue.try_enqueue([runnable]);
225 if let Err(TryEnqueueError::InsufficientCapacity([runnable])) = result {
226 self.sync_queue.push(runnable);
227 }
228 self.handle.notify().ok();
229 }
230 }
231
232 fn run(&self) -> bool {
233 let local_queue = {
236 for _ in 0..self.event_interval {
237 if let Some(task) = self.pop_local() {
238 task.run();
239 } else {
240 break;
241 }
242 }
243 unsafe { !(*self.local_queue.get()).is_empty() }
244 };
245
246 let sync_queue_fixed = match self.sync_fixed_queue.try_dequeue() {
247 Ok(buf) => {
248 for task in buf {
249 task.run();
250 }
251 false
252 }
253 Err(TryDequeueError::Empty | TryDequeueError::Closed) => false,
254 Err(_) => true,
255 };
256
257 let sync_queue = {
258 for _ in 0..self.event_interval {
259 if let Some(task) = self.sync_queue.pop() {
260 task.run();
261 } else {
262 break;
263 }
264 }
265 !self.sync_queue.is_empty()
266 };
267
268 let more_tasks = local_queue || sync_queue_fixed || sync_queue;
269 if !more_tasks {
270 self.idle.set(true);
271 }
272 more_tasks
273 }
274
275 fn clear(&self) {
276 while self.sync_queue.pop().is_some() {}
277 while self.sync_fixed_queue.try_dequeue().is_ok() {}
278 while let Some(task) = self.pop_local() {
280 drop(task);
281 }
282 }
283
284 fn pop_local(&self) -> Option<Runnable> {
285 unsafe { (*self.local_queue.get()).pop_front() }
286 }
287}
288
289#[derive(Debug, Clone)]
291pub struct RuntimeBuilder {
292 event_interval: usize,
293}
294
295impl Default for RuntimeBuilder {
296 fn default() -> Self {
297 Self::new()
298 }
299}
300
301impl RuntimeBuilder {
302 pub fn new() -> Self {
304 Self { event_interval: 61 }
305 }
306
307 pub fn event_interval(&mut self, val: usize) -> &mut Self {
313 self.event_interval = val.max(1);
314 self
315 }
316
317 pub fn build(&self, handle: Box<dyn Notify>) -> Runtime {
319 Runtime::with_builder(self, handle)
320 }
321}
322
323#[cfg(test)]
324mod tests {
325 use std::task::{Poll, Waker};
326 use std::{cell::RefCell, future::poll_fn, rc::Rc};
327
328 use super::*;
329
330 #[derive(Debug)]
331 struct NoopNotify;
332
333 impl Notify for NoopNotify {
334 fn notify(&self) -> io::Result<()> {
335 Ok(())
336 }
337 }
338
339 struct WakeOnDrop(Rc<RefCell<Option<Waker>>>);
340
341 impl Drop for WakeOnDrop {
342 fn drop(&mut self) {
343 if let Some(w) = self.0.borrow_mut().take() {
344 w.wake();
345 }
346 }
347 }
348
349 #[test]
350 fn schedule_while_running() {
351 let rt = Runtime::new(Box::new(NoopNotify));
352 let done = Rc::new(RefCell::new(0));
353 let done2 = done.clone();
354 rt.spawn(async move {
355 let h = Runtime::with_current(|rt| rt.spawn(async { 1 }));
357 *done2.borrow_mut() = h.await.unwrap();
358 })
359 .detach();
360 CURRENT_RUNTIME.set(&rt, || while rt.poll() == PollResult::PollAgain {});
361 assert_eq!(*done.borrow(), 1);
362 }
363
364 #[test]
365 fn event_interval() {
366 use std::sync::atomic::{AtomicUsize, Ordering};
367
368 for val in [0, 1] {
369 let rt = Runtime::builder()
370 .event_interval(val)
371 .build(Box::new(NoopNotify));
372 assert_eq!(rt.poll(), PollResult::Pending);
373
374 rt.spawn(async {}).detach();
375 rt.spawn(async {}).detach();
376 assert_eq!(rt.poll(), PollResult::PollAgain);
377 assert_eq!(rt.poll(), PollResult::Pending);
378 }
379
380 let rt = Runtime::builder()
382 .event_interval(1)
383 .build(Box::new(NoopNotify));
384 let cnt = Arc::new(AtomicUsize::new(0));
385 let hnd = rt.handle();
386 let cnt2 = cnt.clone();
387 std::thread::spawn(move || {
388 for _ in 0..130 {
389 let cnt = cnt2.clone();
390 hnd.spawn(async move {
391 cnt.fetch_add(1, Ordering::Relaxed);
392 })
393 .detach();
394 }
395 })
396 .join()
397 .unwrap();
398 assert_eq!(rt.poll(), PollResult::PollAgain);
399 assert_eq!(cnt.load(Ordering::Relaxed), 129);
400 assert_eq!(rt.poll(), PollResult::Pending);
401 assert_eq!(cnt.load(Ordering::Relaxed), 130);
402 }
403
404 #[test]
405 fn schedule_while_clearing() {
406 let rt = Runtime::new(Box::new(NoopNotify));
407 let waker = Rc::new(RefCell::new(None));
408 let waker2 = waker.clone();
409 rt.spawn(poll_fn(move |cx| {
410 *waker2.borrow_mut() = Some(cx.waker().clone());
411 Poll::<()>::Pending
412 }))
413 .detach();
414 assert_eq!(rt.poll(), PollResult::Pending);
415 assert!(waker.borrow().is_some());
416
417 let guard = WakeOnDrop(waker.clone());
419 rt.spawn(async move {
420 let _g = guard;
421 })
422 .detach();
423 rt.spawn(async {}).detach();
424 drop(rt);
425 assert!(waker.borrow().is_none());
426 assert_eq!(Rc::strong_count(&waker), 1);
428 }
429}