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 {
149 Runtime::with_current(Runtime::handle)
150 }
151
152 pub fn notify(&self) -> io::Result<()> {
154 self.queue.handle.notify()
155 }
156
157 pub fn spawn<F: Future + Send + 'static>(&self, future: F) -> JoinHandle<F::Output> {
162 let queue = self.queue.clone();
163 let schedule = move |runnable| {
164 queue.schedule(runnable);
165 };
166 let (runnable, task) = unsafe { async_task::spawn_unchecked(future, schedule) };
167 runnable.schedule();
168 JoinHandle::new(task)
169 }
170}
171
172impl Clone for Handle {
173 fn clone(&self) -> Self {
174 Self {
175 queue: self.queue.clone(),
176 }
177 }
178}
179
180#[derive(Debug)]
181struct RunnableQueue {
182 id: thread::ThreadId,
183 idle: Cell<bool>,
184 handle: Box<dyn Notify>,
185 event_interval: usize,
186 local_queue: UnsafeCell<VecDeque<Runnable>>,
187 sync_fixed_queue: Queue<ArrayBuffer<Runnable, 128>>,
188 sync_queue: SegQueue<Runnable>,
189}
190
191unsafe impl Send for RunnableQueue {}
192unsafe impl Sync for RunnableQueue {}
193
194impl RunnableQueue {
195 fn new(event_interval: usize, handle: Box<dyn Notify>) -> Self {
196 Self {
197 handle,
198 event_interval,
199 id: thread::current().id(),
200 idle: Cell::new(true),
201 local_queue: UnsafeCell::new(VecDeque::new()),
202 sync_fixed_queue: Queue::default(),
203 sync_queue: SegQueue::new(),
204 }
205 }
206
207 fn schedule(&self, runnable: Runnable) {
208 if self.id == thread::current().id() {
209 unsafe { (*self.local_queue.get()).push_back(runnable) };
210 if self.idle.get() {
211 self.idle.set(false);
212 self.handle.notify().ok();
213 }
214 } else {
215 let result = self.sync_fixed_queue.try_enqueue([runnable]);
216 if let Err(TryEnqueueError::InsufficientCapacity([runnable])) = result {
217 self.sync_queue.push(runnable);
218 }
219 self.handle.notify().ok();
220 }
221 }
222
223 fn run(&self) -> bool {
224 let local_queue = {
225 let q = unsafe { &mut *self.local_queue.get() };
226 for _ in 0..self.event_interval {
227 if let Some(task) = q.pop_front() {
228 task.run();
229 } else {
230 break;
231 }
232 }
233 !q.is_empty()
234 };
235
236 let sync_queue_fixed = match self.sync_fixed_queue.try_dequeue() {
237 Ok(buf) => {
238 for task in buf {
239 task.run();
240 }
241 false
242 }
243 Err(TryDequeueError::Empty | TryDequeueError::Closed) => false,
244 Err(_) => true,
245 };
246
247 let mut idx = self.event_interval;
248 let sync_queue = loop {
249 idx -= 1;
250 if idx == 0 {
251 break true;
252 }
253 if !self.sync_queue.is_empty()
254 && let Some(task) = self.sync_queue.pop()
255 {
256 task.run();
257 } else {
258 break false;
259 }
260 };
261
262 let more_tasks = local_queue || sync_queue_fixed || sync_queue;
263 if !more_tasks {
264 self.idle.set(true);
265 }
266 more_tasks
267 }
268
269 fn clear(&self) {
270 while self.sync_queue.pop().is_some() {}
271 while self.sync_fixed_queue.try_dequeue().is_ok() {}
272 unsafe { (*self.local_queue.get()).clear() };
273 }
274}
275
276#[derive(Debug, Clone)]
278pub struct RuntimeBuilder {
279 event_interval: usize,
280}
281
282impl Default for RuntimeBuilder {
283 fn default() -> Self {
284 Self::new()
285 }
286}
287
288impl RuntimeBuilder {
289 pub fn new() -> Self {
291 Self { event_interval: 61 }
292 }
293
294 pub fn event_interval(&mut self, val: usize) -> &mut Self {
299 self.event_interval = val;
300 self
301 }
302
303 pub fn build(&self, handle: Box<dyn Notify>) -> Runtime {
305 Runtime::with_builder(self, handle)
306 }
307}