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
14#[derive(Debug)]
15pub struct Runtime {
19 stop: Cell<bool>,
20 queue: Arc<RunnableQueue>,
21}
22
23impl Runtime {
24 pub fn new(handle: Box<dyn Notify>) -> Self {
26 Self::builder().build(handle)
27 }
28
29 pub fn builder() -> RuntimeBuilder {
31 RuntimeBuilder::new()
32 }
33
34 #[allow(clippy::arc_with_non_send_sync)]
35 fn with_builder(builder: &RuntimeBuilder, handle: Box<dyn Notify>) -> Self {
36 Self {
37 stop: Cell::new(false),
38 queue: Arc::new(RunnableQueue::new(builder.event_interval, handle)),
39 }
40 }
41
42 pub fn with_current<T, F: FnOnce(&Self) -> T>(f: F) -> T {
48 #[cold]
49 fn not_in_neon_runtime() -> ! {
50 panic!("not in a neon runtime")
51 }
52
53 if CURRENT_RUNTIME.is_set() {
54 CURRENT_RUNTIME.with(f)
55 } else {
56 not_in_neon_runtime()
57 }
58 }
59
60 #[inline]
61 pub fn handle(&self) -> Handle {
63 Handle {
64 queue: self.queue.clone(),
65 }
66 }
67
68 pub fn spawn<F: Future + 'static>(&self, future: F) -> JoinHandle<F::Output> {
73 unsafe { self.spawn_unchecked(future) }
74 }
75
76 pub unsafe fn spawn_unchecked<F: Future>(&self, future: F) -> JoinHandle<F::Output> {
82 let queue = self.queue.clone();
83 let (runnable, task) = unsafe {
84 async_task::spawn_unchecked(future, move |runnable| {
85 queue.schedule(runnable);
86 })
87 };
88 runnable.schedule();
89 JoinHandle::new(task)
90 }
91
92 pub fn poll(&self) -> PollResult {
94 if self.stop.get() {
95 PollResult::Ready
96 } else if self.queue.run() {
97 PollResult::PollAgain
98 } else {
99 PollResult::Pending
100 }
101 }
102
103 pub fn block_on<F: Future>(&self, future: F, driver: &dyn Driver) -> F::Output {
111 self.stop.set(false);
112
113 CURRENT_RUNTIME.set(self, || {
114 let mut result = None;
115 unsafe {
116 self.spawn_unchecked(async {
117 result = Some(future.await);
118 self.stop.set(true);
119 let _ = self.queue.handle.notify();
120 });
121 }
122
123 ntex_error::set_backtrace_start_alt("src/raw.rs", 0);
124 driver.run(self).expect("Driver failed");
125 result.expect("Driver failed to poll")
126 })
127 }
128}
129
130impl Drop for Runtime {
131 fn drop(&mut self) {
132 CURRENT_RUNTIME.set(self, || {
133 self.queue.clear();
134 });
135 }
136}
137
138#[derive(Debug)]
139pub struct Handle {
141 queue: Arc<RunnableQueue>,
142}
143
144impl Handle {
145 pub fn current() -> Handle {
151 Runtime::with_current(Runtime::handle)
152 }
153
154 pub fn notify(&self) -> io::Result<()> {
156 self.queue.handle.notify()
157 }
158
159 pub fn spawn<F: Future + Send + 'static>(&self, future: F) -> JoinHandle<F::Output> {
164 let queue = self.queue.clone();
165 let schedule = move |runnable| {
166 queue.schedule(runnable);
167 };
168 let (runnable, task) = unsafe { async_task::spawn_unchecked(future, schedule) };
169 runnable.schedule();
170 JoinHandle::new(task)
171 }
172}
173
174impl Clone for Handle {
175 fn clone(&self) -> Self {
176 Self {
177 queue: self.queue.clone(),
178 }
179 }
180}
181
182#[derive(Debug)]
183struct RunnableQueue {
184 id: thread::ThreadId,
185 idle: Cell<bool>,
186 handle: Box<dyn Notify>,
187 event_interval: usize,
188 local_queue: UnsafeCell<VecDeque<Runnable>>,
189 sync_fixed_queue: Queue<ArrayBuffer<Runnable, 128>>,
190 sync_queue: SegQueue<Runnable>,
191}
192
193unsafe impl Send for RunnableQueue {}
194unsafe impl Sync for RunnableQueue {}
195
196impl RunnableQueue {
197 fn new(event_interval: usize, handle: Box<dyn Notify>) -> Self {
198 Self {
199 handle,
200 event_interval,
201 id: thread::current().id(),
202 idle: Cell::new(true),
203 local_queue: UnsafeCell::new(VecDeque::new()),
204 sync_fixed_queue: Queue::default(),
205 sync_queue: SegQueue::new(),
206 }
207 }
208
209 fn schedule(&self, runnable: Runnable) {
210 if self.id == thread::current().id() {
211 unsafe { (*self.local_queue.get()).push_back(runnable) };
212 if self.idle.get() {
213 self.idle.set(false);
214 self.handle.notify().ok();
215 }
216 } else {
217 let result = self.sync_fixed_queue.try_enqueue([runnable]);
218 if let Err(TryEnqueueError::InsufficientCapacity([runnable])) = result {
219 self.sync_queue.push(runnable);
220 }
221 self.handle.notify().ok();
222 }
223 }
224
225 fn run(&self) -> bool {
226 let local_queue = {
227 let q = unsafe { &mut *self.local_queue.get() };
228 for _ in 0..self.event_interval {
229 if let Some(task) = q.pop_front() {
230 task.run();
231 } else {
232 break;
233 }
234 }
235 !q.is_empty()
236 };
237
238 let sync_queue_fixed = match self.sync_fixed_queue.try_dequeue() {
239 Ok(buf) => {
240 for task in buf {
241 task.run();
242 }
243 false
244 }
245 Err(TryDequeueError::Empty | TryDequeueError::Closed) => false,
246 Err(_) => true,
247 };
248
249 let mut idx = self.event_interval;
250 let sync_queue = loop {
251 idx -= 1;
252 if idx == 0 {
253 break true;
254 }
255 if !self.sync_queue.is_empty()
256 && let Some(task) = self.sync_queue.pop()
257 {
258 task.run();
259 } else {
260 break false;
261 }
262 };
263
264 let more_tasks = local_queue || sync_queue_fixed || sync_queue;
265 if !more_tasks {
266 self.idle.set(true);
267 }
268 more_tasks
269 }
270
271 fn clear(&self) {
272 while self.sync_queue.pop().is_some() {}
273 while self.sync_fixed_queue.try_dequeue().is_ok() {}
274 unsafe { (*self.local_queue.get()).clear() };
275 }
276}
277
278#[derive(Debug, Clone)]
280pub struct RuntimeBuilder {
281 event_interval: usize,
282}
283
284impl Default for RuntimeBuilder {
285 fn default() -> Self {
286 Self::new()
287 }
288}
289
290impl RuntimeBuilder {
291 pub fn new() -> Self {
293 Self { event_interval: 61 }
294 }
295
296 pub fn event_interval(&mut self, val: usize) -> &mut Self {
301 self.event_interval = val;
302 self
303 }
304
305 pub fn build(&self, handle: Box<dyn Notify>) -> Runtime {
307 Runtime::with_builder(self, handle)
308 }
309}