1#![expect(unsafe_code)]
8
9use loan_cell::LoanCell;
10use parking_lot::Mutex;
11use slab::Slab;
12use std::fmt::Debug;
13use std::fmt::Display;
14use std::future::Future;
15use std::panic::Location;
16use std::pin::Pin;
17use std::sync::Arc;
18use std::sync::Weak;
19use std::sync::atomic::AtomicBool;
20use std::sync::atomic::AtomicU32;
21use std::sync::atomic::AtomicUsize;
22use std::sync::atomic::Ordering;
23
24pub type Task<T> = async_task::Task<T, TaskMetadata>;
26
27pub type Runnable = async_task::Runnable<TaskMetadata>;
29
30#[derive(Debug)]
35pub struct TaskMetadata {
36 name: Arc<str>,
37 location: &'static Location<'static>,
38 state: AtomicU32,
41 dropped: AtomicBool,
45 scheduler: Weak<dyn Schedule>,
46 id: AtomicUsize,
47 _no_pin: std::marker::PhantomPinned,
48}
49
50impl TaskMetadata {
51 const NO_ID: usize = !0;
52
53 #[track_caller]
54 fn new(name: Arc<str>) -> Self {
55 Self {
56 name,
57 location: Location::caller(),
58 state: AtomicU32::new(TASK_STATE_READY),
59 dropped: AtomicBool::new(false),
60 scheduler: Weak::<Scheduler>::new(),
61 id: AtomicUsize::new(Self::NO_ID),
62 _no_pin: std::marker::PhantomPinned,
63 }
64 }
65
66 fn register(self: Pin<&Self>) {
67 assert_eq!(self.id.load(Ordering::Relaxed), Self::NO_ID);
68 let id = TASK_LIST
72 .slab
73 .lock()
74 .insert(TaskMetadataPtr(self.get_ref()));
75 self.id.store(id, Ordering::Relaxed);
76 }
77
78 fn pend(&self) {
79 self.state.store(TASK_STATE_WAITING, Ordering::Relaxed);
80 }
81
82 fn done(&self) {
83 self.state.store(TASK_STATE_DONE, Ordering::Relaxed);
84 }
85
86 fn run(&self) {
87 self.state.store(TASK_STATE_RUNNING, Ordering::Relaxed);
88 }
89
90 pub fn name(&self) -> &Arc<str> {
92 &self.name
93 }
94
95 pub fn location(&self) -> &'static Location<'static> {
97 self.location
98 }
99
100 fn state(&self) -> TaskState {
102 let state = self.state.load(Ordering::Relaxed);
103 if self.dropped.load(Ordering::Relaxed) {
104 if state == TASK_STATE_DONE {
105 TaskState::Complete
106 } else {
107 TaskState::Cancelled
108 }
109 } else {
110 match self.state.load(Ordering::Relaxed) {
111 TASK_STATE_READY => TaskState::Ready,
112 TASK_STATE_WAITING => TaskState::Waiting,
113 TASK_STATE_RUNNING => TaskState::Running,
114 TASK_STATE_DONE => TaskState::Complete,
115 _ => unreachable!(),
116 }
117 }
118 }
119}
120
121impl Drop for TaskMetadata {
122 fn drop(&mut self) {
123 let id = self.id.load(Ordering::Relaxed);
124 if id != Self::NO_ID {
125 let _task = TASK_LIST.slab.lock().remove(id);
126 }
127 }
128}
129
130#[derive(Debug, Copy, Clone)]
131struct TaskMetadataPtr(*const TaskMetadata);
132
133const _: () = {
135 const fn assert_send_sync<T: Send + Sync>() {}
136 assert_send_sync::<TaskMetadata>();
137};
138
139unsafe impl Send for TaskMetadataPtr {}
141unsafe impl Sync for TaskMetadataPtr {}
143
144#[derive(Debug)]
146pub struct TaskQueue {
147 tasks: async_channel::Receiver<Runnable>,
148}
149
150#[derive(Debug)]
152pub struct Scheduler {
153 send: async_channel::Sender<Runnable>,
154 name: Mutex<Arc<str>>,
155}
156
157impl Scheduler {
158 pub fn set_name(&self, name: impl Into<Arc<str>>) {
160 *self.name.lock() = name.into();
161 }
162}
163
164impl Schedule for Scheduler {
165 fn schedule(&self, runnable: Runnable) {
166 let _ = self.send.try_send(runnable);
167 }
168
169 fn name(&self) -> Arc<str> {
170 self.name.lock().clone()
171 }
172}
173
174pub fn task_queue(name: impl Into<Arc<str>>) -> (TaskQueue, Scheduler) {
176 let (send, recv) = async_channel::unbounded();
177 (
178 TaskQueue { tasks: recv },
179 Scheduler {
180 send,
181 name: Mutex::new(name.into()),
182 },
183 )
184}
185
186impl TaskQueue {
187 pub async fn run(&mut self) {
191 while let Ok(task) = self.tasks.recv().await {
192 let _scheduler = task.metadata().scheduler.upgrade();
198 task.run();
199 }
200 }
201}
202
203pub trait Schedule: Send + Sync {
205 fn schedule(&self, runnable: Runnable);
207
208 fn name(&self) -> Arc<str>;
210}
211
212struct TaskFuture<'a, Fut> {
213 metadata: &'a TaskMetadata,
214 _scheduler: Arc<dyn Schedule>, future: Fut,
216}
217
218impl<'a, Fut: Future> TaskFuture<'a, Fut> {
219 fn new(metadata: Pin<&'a TaskMetadata>, scheduler: Arc<dyn Schedule>, future: Fut) -> Self {
220 metadata.register();
221 Self {
222 metadata: metadata.get_ref(),
223 _scheduler: scheduler,
224 future,
225 }
226 }
227
228 unsafe fn new_for_async_task(
239 metadata: &'a TaskMetadata,
240 scheduler: Arc<dyn Schedule>,
241 future: Fut,
242 ) -> TaskFuture<'static, Fut> {
243 let metadata = unsafe { Pin::new_unchecked(metadata) };
246 let this = Self::new(metadata, scheduler, future);
247 unsafe { std::mem::transmute::<TaskFuture<'a, Fut>, TaskFuture<'static, Fut>>(this) }
254 }
255}
256
257impl<Fut: Future> Future for TaskFuture<'_, Fut> {
258 type Output = Fut::Output;
259
260 fn poll(
261 self: Pin<&mut Self>,
262 cx: &mut std::task::Context<'_>,
263 ) -> std::task::Poll<Self::Output> {
264 let this = unsafe { self.get_unchecked_mut() };
267 this.metadata.run();
268 let future = unsafe { Pin::new_unchecked(&mut this.future) };
270 let r = CURRENT_TASK.with(|task| task.lend(this.metadata, || future.poll(cx)));
271 if r.is_pending() {
272 this.metadata.pend();
273 } else {
274 this.metadata.done();
275 }
276 r
277 }
278}
279
280impl<Fut> Drop for TaskFuture<'_, Fut> {
281 fn drop(&mut self) {
282 self.metadata.dropped.store(true, Ordering::Relaxed);
283 }
284}
285
286fn schedule(runnable: Runnable) {
287 let metadata = runnable.metadata();
288 metadata.state.store(TASK_STATE_READY, Ordering::Relaxed);
289 if let Some(scheduler) = metadata.scheduler.upgrade() {
290 scheduler.schedule(runnable);
291 }
292}
293
294pub trait Spawn: Send + Sync {
296 fn scheduler(&self, metadata: &TaskMetadata) -> Arc<dyn Schedule>;
298
299 #[track_caller]
301 fn spawn<T: 'static + Send>(
302 &self,
303 name: impl Into<Arc<str>>,
304 fut: impl Future<Output = T> + Send + 'static,
305 ) -> Task<T>
306 where
307 Self: Sized,
308 {
309 let mut metadata = TaskMetadata::new(name.into());
310 let scheduler = self.scheduler(&metadata);
311 metadata.scheduler = Arc::downgrade(&scheduler);
312 let (runnable, task) = async_task::Builder::new().metadata(metadata).spawn(
313 |metadata| {
314 unsafe { TaskFuture::new_for_async_task(metadata, scheduler, fut) }
316 },
317 schedule,
318 );
319 runnable.schedule();
320 task
321 }
322}
323
324pub trait SpawnLocal {
326 fn scheduler_local(&self, metadata: &TaskMetadata) -> Arc<dyn Schedule>;
328
329 #[track_caller]
331 fn spawn_local<T: 'static>(
332 &self,
333 name: impl Into<Arc<str>>,
334 fut: impl Future<Output = T> + 'static,
335 ) -> Task<T>
336 where
337 Self: Sized,
338 {
339 let mut metadata = TaskMetadata::new(name.into());
340 let scheduler = self.scheduler_local(&metadata);
341 metadata.scheduler = Arc::downgrade(&scheduler);
342 let (runnable, task) = async_task::Builder::new().metadata(metadata).spawn_local(
343 |metadata| {
344 unsafe { TaskFuture::new_for_async_task(metadata, scheduler, fut) }
346 },
347 schedule,
348 );
349 runnable.schedule();
350 task
351 }
352}
353
354thread_local! {
355 static CURRENT_TASK: LoanCell<TaskMetadata> = const { LoanCell::new() };
356}
357
358pub fn with_current_task_metadata<F: FnOnce(Option<&TaskMetadata>) -> R, R>(f: F) -> R {
360 CURRENT_TASK.with(|task| task.borrow(f))
361}
362
363impl<T: ?Sized + Spawn> Spawn for &'_ T {
364 fn scheduler(&self, metadata: &TaskMetadata) -> Arc<dyn Schedule> {
365 (*self).scheduler(metadata)
366 }
367}
368
369impl<T: ?Sized + Spawn> Spawn for Box<T> {
370 fn scheduler(&self, metadata: &TaskMetadata) -> Arc<dyn Schedule> {
371 self.as_ref().scheduler(metadata)
372 }
373}
374
375impl<T: ?Sized + Spawn> Spawn for Arc<T> {
376 fn scheduler(&self, metadata: &TaskMetadata) -> Arc<dyn Schedule> {
377 self.as_ref().scheduler(metadata)
378 }
379}
380
381impl<T: ?Sized + SpawnLocal> SpawnLocal for &'_ T {
382 fn scheduler_local(&self, metadata: &TaskMetadata) -> Arc<dyn Schedule> {
383 (*self).scheduler_local(metadata)
384 }
385}
386
387impl<T: ?Sized + SpawnLocal> SpawnLocal for Box<T> {
388 fn scheduler_local(&self, metadata: &TaskMetadata) -> Arc<dyn Schedule> {
389 self.as_ref().scheduler_local(metadata)
390 }
391}
392
393impl<T: ?Sized + SpawnLocal> SpawnLocal for Arc<T> {
394 fn scheduler_local(&self, metadata: &TaskMetadata) -> Arc<dyn Schedule> {
395 self.as_ref().scheduler_local(metadata)
396 }
397}
398
399const TASK_STATE_READY: u32 = 0;
400const TASK_STATE_WAITING: u32 = 1;
401const TASK_STATE_RUNNING: u32 = 2;
402const TASK_STATE_DONE: u32 = 3;
403
404#[derive(Debug, Copy, Clone)]
406#[repr(u64)]
407pub enum TaskState {
408 Ready,
410 Waiting,
412 Running,
414 Complete,
416 Cancelled,
418}
419
420impl Display for TaskState {
421 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
422 let s = match self {
423 TaskState::Ready => "ready",
424 TaskState::Waiting => "waiting",
425 TaskState::Running => "running",
426 TaskState::Complete => "complete",
427 TaskState::Cancelled => "cancelled",
428 };
429 f.pad(s)
430 }
431}
432
433pub struct TaskList {
435 slab: Mutex<Slab<TaskMetadataPtr>>,
436}
437
438static TASK_LIST: TaskList = TaskList::new();
439
440impl TaskList {
441 const fn new() -> Self {
442 Self {
443 slab: Mutex::new(Slab::new()),
444 }
445 }
446
447 pub fn global() -> &'static Self {
449 &TASK_LIST
450 }
451
452 pub fn tasks(&self) -> Vec<TaskData> {
454 let tasks = self.slab.lock();
455 tasks
456 .iter()
457 .map(|(id, task)| {
458 let task = unsafe { &*task.0 };
463 let scheduler = task.scheduler.upgrade().map(|s| s.name());
464 TaskData {
465 id,
466 name: task.name.clone(),
467 location: task.location,
468 state: task.state(),
469 executor: scheduler,
470 }
471 })
472 .collect()
473 }
474}
475
476#[derive(Debug)]
478pub struct TaskData {
479 id: usize,
480 name: Arc<str>,
481 location: &'static Location<'static>,
482 state: TaskState,
483 executor: Option<Arc<str>>,
484}
485
486impl TaskData {
487 pub fn id(&self) -> usize {
491 self.id
492 }
493
494 pub fn executor(&self) -> Option<&str> {
496 self.executor.as_deref()
497 }
498
499 pub fn name(&self) -> &str {
501 &self.name
502 }
503
504 pub fn location(&self) -> &'static Location<'static> {
506 self.location
507 }
508
509 pub fn state(&self) -> TaskState {
511 self.state
512 }
513}