1use crate::{Instant, Priority, RunnableMeta, Scheduler, SessionId, Timer};
2use async_task::Runnable;
3use std::{
4 any::Any,
5 collections::HashMap,
6 future::Future,
7 marker::PhantomData,
8 mem::ManuallyDrop,
9 panic::Location,
10 pin::Pin,
11 rc::Rc,
12 sync::{
13 Arc, Mutex, Weak,
14 atomic::{AtomicBool, Ordering},
15 },
16 task::{Context, Poll, Waker},
17 thread::{self, ThreadId},
18 time::Duration,
19};
20
21pub type DedicatedFn = Box<
29 dyn FnOnce(LocalExecutor) -> Pin<Box<dyn Future<Output = Box<dyn Any + Send + Sync>> + 'static>>
30 + Send
31 + 'static,
32>;
33
34#[doc(hidden)]
37pub struct LocalTaskScope {
38 retiring: AtomicBool,
39 state: Mutex<LocalTaskState>,
40}
41
42struct LocalTaskState {
43 next_task_id: u64,
44 tasks: HashMap<u64, Option<Waker>>,
45 sealed: bool,
46}
47
48impl LocalTaskScope {
49 pub fn new() -> Self {
51 Self {
52 retiring: AtomicBool::new(false),
53 state: Mutex::new(LocalTaskState {
54 next_task_id: 0,
55 tasks: HashMap::new(),
56 sealed: false,
57 }),
58 }
59 }
60
61 pub fn is_retiring(&self) -> bool {
63 self.retiring.load(Ordering::Acquire)
64 }
65
66 pub fn live_task_count(&self) -> usize {
68 self.state
69 .lock()
70 .expect("local task scope poisoned")
71 .tasks
72 .len()
73 }
74
75 pub fn begin_retirement(&self) {
79 if self.retiring.swap(true, Ordering::AcqRel) {
80 return;
81 }
82 let wakers = {
83 let mut state = self.state.lock().expect("local task scope poisoned");
84 state
85 .tasks
86 .values_mut()
87 .filter_map(Option::take)
88 .collect::<Vec<_>>()
89 };
90 for waker in wakers {
91 waker.wake();
92 }
93 }
94
95 #[doc(hidden)]
100 pub fn seal_if_quiescent(&self) -> bool {
101 let mut state = self.state.lock().expect("local task scope poisoned");
102 if !self.is_retiring() || !state.tasks.is_empty() {
103 return false;
104 }
105 state.sealed = true;
106 true
107 }
108
109 fn register(&self) -> u64 {
110 let mut state = self.state.lock().expect("local task scope poisoned");
111 assert!(
112 !state.sealed,
113 "cannot spawn a local task after its owner scope has been sealed"
114 );
115 let id = state.next_task_id;
116 state.next_task_id = state
117 .next_task_id
118 .checked_add(1)
119 .expect("local task scope task ID overflow");
120 state.tasks.insert(id, None);
121 id
122 }
123
124 fn attach_waker(&self, id: u64, waker: Waker) {
125 let mut waker = Some(waker);
126 let replaced = {
127 let mut state = self.state.lock().expect("local task scope poisoned");
128 state
129 .tasks
130 .get_mut(&id)
131 .and_then(|entry| entry.replace(waker.take().unwrap()))
132 };
133 drop(replaced);
134 drop(waker);
135 }
136
137 fn unregister(&self, id: u64) {
138 let removed = self
139 .state
140 .lock()
141 .expect("local task scope poisoned")
142 .tasks
143 .remove(&id);
144 drop(removed);
145 }
146}
147
148impl Default for LocalTaskScope {
149 fn default() -> Self {
150 Self::new()
151 }
152}
153
154struct LocalTaskRegistration {
155 scope: Weak<LocalTaskScope>,
156 id: u64,
157}
158
159impl Drop for LocalTaskRegistration {
160 fn drop(&mut self) {
161 if let Some(scope) = self.scope.upgrade() {
162 scope.unregister(self.id);
163 }
164 }
165}
166
167struct RegisteredLocalFuture<F> {
168 future: F,
169 _registration: LocalTaskRegistration,
172}
173
174impl<F: Future> Future for RegisteredLocalFuture<F> {
175 type Output = F::Output;
176
177 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
178 unsafe { self.map_unchecked_mut(|this| &mut this.future) }.poll(cx)
180 }
181}
182
183#[derive(Clone)]
191pub struct LocalExecutor {
192 session_id: SessionId,
193 scheduler: Arc<dyn Scheduler>,
194 dispatch: Arc<dyn Fn(Runnable<RunnableMeta>) + Send + Sync>,
198 retirement: Option<Arc<LocalTaskScope>>,
199 dispatch_cancellation: Option<Arc<dyn Fn(Runnable<RunnableMeta>) + Send + Sync>>,
200 not_send: PhantomData<Rc<()>>,
201}
202
203impl LocalExecutor {
204 pub fn new(
212 session_id: SessionId,
213 scheduler: Arc<dyn Scheduler>,
214 dispatch: impl Fn(Runnable<RunnableMeta>) + Send + Sync + 'static,
215 ) -> Self {
216 Self {
217 session_id,
218 scheduler,
219 dispatch: Arc::new(dispatch),
220 retirement: None,
221 dispatch_cancellation: None,
222 not_send: PhantomData,
223 }
224 }
225
226 #[doc(hidden)]
230 pub fn new_with_scope(
231 session_id: SessionId,
232 scheduler: Arc<dyn Scheduler>,
233 scope: Arc<LocalTaskScope>,
234 dispatch: impl Fn(Runnable<RunnableMeta>) + Send + Sync + 'static,
235 dispatch_cancellation: impl Fn(Runnable<RunnableMeta>) + Send + Sync + 'static,
236 ) -> Self {
237 Self {
238 session_id,
239 scheduler,
240 dispatch: Arc::new(dispatch),
241 retirement: Some(scope),
242 dispatch_cancellation: Some(Arc::new(dispatch_cancellation)),
243 not_send: PhantomData,
244 }
245 }
246
247 #[doc(hidden)]
249 pub fn retirement_scope(&self) -> Option<Arc<LocalTaskScope>> {
250 self.retirement.clone()
251 }
252
253 pub fn session_id(&self) -> SessionId {
255 self.session_id
256 }
257
258 pub fn scheduler(&self) -> &Arc<dyn Scheduler> {
260 &self.scheduler
261 }
262
263 pub fn is_test(&self) -> bool {
265 self.scheduler.as_test().is_some()
266 }
267
268 #[track_caller]
275 pub fn spawn<F>(&self, future: F) -> Task<F::Output>
276 where
277 F: Future + 'static,
278 F::Output: 'static,
279 {
280 let dispatch = self.dispatch.clone();
281 self.spawn_with_dispatch(future, move |runnable| dispatch(runnable))
282 }
283
284 #[track_caller]
290 pub fn spawn_with_dispatch<F>(
291 &self,
292 future: F,
293 dispatch: impl Fn(Runnable<RunnableMeta>) + Send + Sync + 'static,
294 ) -> Task<F::Output>
295 where
296 F: Future + 'static,
297 F::Output: 'static,
298 {
299 let location = Location::caller();
300 let metadata = RunnableMeta {
301 location,
302 spawned: crate::SpawnTime(Instant::now()),
303 };
304 if let Some(scope) = self.retirement.clone() {
305 let id = scope.register();
306 let registration = LocalTaskRegistration {
307 scope: Arc::downgrade(&scope),
308 id,
309 };
310 let future = RegisteredLocalFuture {
311 future,
312 _registration: registration,
313 };
314 let cancellation = self
315 .dispatch_cancellation
316 .as_ref()
317 .expect("scoped executor must have a cancellation dispatcher")
318 .clone();
319 let normal_dispatch: Arc<dyn Fn(Runnable<RunnableMeta>) + Send + Sync> =
320 Arc::new(dispatch);
321 let scope_for_schedule = scope.clone();
322 let schedule: Arc<dyn Fn(Runnable<RunnableMeta>) + Send + Sync> =
323 Arc::new(move |runnable| {
324 if scope_for_schedule.is_retiring() {
325 cancellation(runnable);
326 } else {
327 normal_dispatch(runnable);
328 }
329 });
330 let (runnable, task) = spawn_local_with_source_location(
331 future,
332 move |runnable| schedule(runnable),
333 metadata,
334 );
335 scope.attach_waker(id, runnable.waker());
338 runnable.schedule();
339 Task(TaskState::Spawned(task))
340 } else {
341 let (runnable, task) = spawn_local_with_source_location(future, dispatch, metadata);
342 runnable.schedule();
343 Task(TaskState::Spawned(task))
344 }
345 }
346
347 #[cfg(not(target_family = "wasm"))]
358 pub fn block_on<Fut: Future>(&self, future: Fut) -> Fut::Output {
359 use std::cell::Cell;
360
361 let output = Cell::new(None);
362 let future = async {
363 output.set(Some(future.await));
364 };
365 let mut future = std::pin::pin!(future);
366
367 self.scheduler
368 .block(Some(self.session_id), future.as_mut(), None);
369
370 output.take().expect("block_on future did not complete")
371 }
372
373 #[cfg(not(target_family = "wasm"))]
380 pub fn block_with_timeout<Fut: Future>(
381 &self,
382 timeout: Duration,
383 future: Fut,
384 ) -> Result<Fut::Output, impl Future<Output = Fut::Output> + use<Fut>> {
385 use std::cell::Cell;
386
387 let output = Cell::new(None);
388 let mut future = Box::pin(future);
389
390 {
391 let future_ref = &mut future;
392 let wrapper = async {
393 output.set(Some(future_ref.await));
394 };
395 let mut wrapper = std::pin::pin!(wrapper);
396
397 self.scheduler
398 .block(Some(self.session_id), wrapper.as_mut(), Some(timeout));
399 }
400
401 match output.take() {
402 Some(value) => Ok(value),
403 None => Err(future),
404 }
405 }
406
407 #[track_caller]
409 pub fn timer(&self, duration: Duration) -> Timer {
410 self.scheduler.timer(duration)
411 }
412
413 pub fn now(&self) -> Instant {
418 self.scheduler.clock().now()
419 }
420
421 #[track_caller]
431 pub fn spawn_dedicated<F, Fut>(&self, f: F) -> Task<Fut::Output>
432 where
433 F: FnOnce(LocalExecutor) -> Fut + Send + 'static,
434 Fut: Future + 'static,
435 Fut::Output: Send + Sync + 'static,
436 {
437 self.scheduler
438 .clone()
439 .spawn_dedicated(box_dedicated(f))
440 .downcast::<Fut::Output>()
441 }
442}
443
444fn box_dedicated<F, Fut>(f: F) -> DedicatedFn
449where
450 F: FnOnce(LocalExecutor) -> Fut + Send + 'static,
451 Fut: Future + 'static,
452 Fut::Output: Send + Sync + 'static,
453{
454 Box::new(move |executor| {
455 Box::pin(async move { Box::new(f(executor).await) as Box<dyn Any + Send + Sync> })
456 })
457}
458
459#[derive(Clone)]
464pub struct BackgroundExecutor {
465 scheduler: Arc<dyn Scheduler>,
466}
467
468impl BackgroundExecutor {
469 pub fn new(scheduler: Arc<dyn Scheduler>) -> Self {
471 Self { scheduler }
472 }
473
474 #[track_caller]
481 pub fn spawn<F>(&self, future: F) -> Task<F::Output>
482 where
483 F: Future + Send + 'static,
484 F::Output: Send + 'static,
485 {
486 self.spawn_with_priority(Priority::default(), future)
487 }
488
489 #[track_caller]
494 pub fn spawn_with_priority<F>(&self, priority: Priority, future: F) -> Task<F::Output>
495 where
496 F: Future + Send + 'static,
497 F::Output: Send + 'static,
498 {
499 let schedule = self.schedule_with_priority(priority);
500 let location = Location::caller();
501 let (runnable, task) = async_task::Builder::new()
502 .metadata(RunnableMeta {
503 location,
504 spawned: crate::SpawnTime(Instant::now()),
505 })
506 .spawn(move |_| future, schedule);
507 runnable.schedule();
508 Task(TaskState::Spawned(task))
509 }
510
511 #[track_caller]
516 pub fn spawn_realtime<F>(&self, future: F) -> Task<F::Output>
517 where
518 F: Future + Send + 'static,
519 F::Output: Send + 'static,
520 {
521 let location = Location::caller();
522 let (tx, rx) = flume::bounded::<async_task::Runnable<RunnableMeta>>(1);
523
524 self.scheduler.spawn_realtime(Box::new(move || {
525 while let Ok(runnable) = rx.recv() {
526 runnable.run();
527 }
528 }));
529
530 let (runnable, task) = async_task::Builder::new()
531 .metadata(RunnableMeta {
532 location,
533 spawned: crate::SpawnTime(Instant::now()),
534 })
535 .spawn(
536 move |_| future,
537 move |runnable| {
538 let _ = tx.send(runnable);
539 },
540 );
541 runnable.schedule();
542 Task(TaskState::Spawned(task))
543 }
544
545 #[track_caller]
547 pub fn timer(&self, duration: Duration) -> Timer {
548 self.scheduler.timer(duration)
549 }
550
551 pub fn now(&self) -> Instant {
556 self.scheduler.clock().now()
557 }
558
559 pub fn scheduler(&self) -> &Arc<dyn Scheduler> {
561 &self.scheduler
562 }
563
564 pub fn is_test(&self) -> bool {
566 self.scheduler.as_test().is_some()
567 }
568
569 #[track_caller]
579 pub fn spawn_dedicated<F, Fut>(&self, f: F) -> Task<Fut::Output>
580 where
581 F: FnOnce(LocalExecutor) -> Fut + Send + 'static,
582 Fut: Future + 'static,
583 Fut::Output: Send + Sync + 'static,
584 {
585 self.scheduler
586 .clone()
587 .spawn_dedicated(box_dedicated(f))
588 .downcast::<Fut::Output>()
589 }
590
591 fn schedule_with_priority(
592 &self,
593 priority: Priority,
594 ) -> impl Fn(Runnable<RunnableMeta>) + Send + Sync + 'static {
595 let scheduler = Arc::downgrade(&self.scheduler);
596 move |runnable| {
597 if let Some(scheduler) = scheduler.upgrade() {
598 scheduler.schedule_background_with_priority(runnable, priority);
599 }
600 }
601 }
602}
603
604pub struct DedicatedExecutor {
617 sender: flume::Sender<Runnable<RunnableMeta>>,
618 _session: Task<()>,
619}
620
621impl DedicatedExecutor {
622 #[track_caller]
628 pub fn new(executor: &BackgroundExecutor) -> Self {
629 let (sender, receiver) = flume::unbounded::<Runnable<RunnableMeta>>();
630 let session = executor.spawn_dedicated(move |_executor| async move {
631 while let Ok(runnable) = receiver.recv_async().await {
632 runnable.run();
633 }
634 });
635 Self {
636 sender,
637 _session: session,
638 }
639 }
640
641 #[track_caller]
648 pub fn spawn<F>(&self, future: F) -> Task<F::Output>
649 where
650 F: Future + Send + 'static,
651 F::Output: Send + 'static,
652 {
653 let sender = self.sender.clone();
654 let (runnable, task) = async_task::Builder::new()
655 .metadata(RunnableMeta::new_with_callers_location())
656 .spawn(
657 move |_| future,
658 move |runnable| {
659 let _ = sender.send(runnable);
660 },
661 );
662 runnable.schedule();
663 Task(TaskState::Spawned(task))
664 }
665}
666
667#[must_use]
692pub struct Task<T>(TaskState<T>);
693
694enum TaskState<T> {
695 Ready(Option<T>),
697
698 Spawned(async_task::Task<T, RunnableMeta>),
700
701 Downcast {
705 inner: Box<Task<Box<dyn Any + Send + Sync>>>,
706 marker: PhantomData<fn() -> T>,
707 },
708
709 Rendezvous(RendezvousReceiver<T>),
713}
714
715enum RendezvousState<T> {
717 Pending(Option<Waker>),
719 Delivered(Task<T>),
721 Cancelled,
723 Detached,
725 Taken,
727}
728
729pub(crate) struct RendezvousReceiver<T> {
730 shared: Arc<parking_lot::Mutex<RendezvousState<T>>>,
731}
732
733impl<T> RendezvousReceiver<T> {
734 fn poll_take(&self, cx: &mut Context) -> Poll<Task<T>> {
735 let mut state = self.shared.lock();
736 match std::mem::replace(&mut *state, RendezvousState::Taken) {
737 RendezvousState::Delivered(task) => Poll::Ready(task),
738 RendezvousState::Pending(_) => {
739 *state = RendezvousState::Pending(Some(cx.waker().clone()));
740 Poll::Pending
741 }
742 RendezvousState::Cancelled | RendezvousState::Detached | RendezvousState::Taken => {
743 unreachable!("a rendezvous task was polled after its receiver was consumed")
744 }
745 }
746 }
747
748 fn is_ready(&self) -> bool {
749 match &*self.shared.lock() {
750 RendezvousState::Delivered(task) => task.is_ready(),
751 _ => false,
752 }
753 }
754
755 fn detach(self) {
756 let mut state = self.shared.lock();
757 match std::mem::replace(&mut *state, RendezvousState::Detached) {
758 RendezvousState::Delivered(task) => {
759 *state = RendezvousState::Taken;
760 drop(state);
761 task.detach();
762 }
763 RendezvousState::Pending(_) => {}
765 RendezvousState::Cancelled | RendezvousState::Detached | RendezvousState::Taken => {
766 unreachable!("a rendezvous task was detached after its receiver was consumed")
767 }
768 }
769 }
770}
771
772impl<T> Drop for RendezvousReceiver<T> {
773 fn drop(&mut self) {
774 let mut state = self.shared.lock();
775 match &*state {
776 RendezvousState::Pending(_) => *state = RendezvousState::Cancelled,
777 RendezvousState::Delivered(_) => {
778 let delivered = std::mem::replace(&mut *state, RendezvousState::Cancelled);
779 drop(state);
780 drop(delivered);
781 }
782 _ => {}
786 }
787 }
788}
789
790pub(crate) struct RendezvousSender<T> {
791 shared: Arc<parking_lot::Mutex<RendezvousState<T>>>,
792}
793
794impl<T> RendezvousSender<T> {
795 pub(crate) fn deliver(self, task: Task<T>) {
798 let mut state = self.shared.lock();
799 match std::mem::replace(&mut *state, RendezvousState::Delivered(task)) {
800 RendezvousState::Pending(waker) => {
801 drop(state);
802 if let Some(waker) = waker {
803 waker.wake();
804 }
805 }
806 RendezvousState::Cancelled => {
807 let delivered = std::mem::replace(&mut *state, RendezvousState::Cancelled);
808 drop(state);
809 drop(delivered);
810 }
811 RendezvousState::Detached => {
812 let RendezvousState::Delivered(task) =
813 std::mem::replace(&mut *state, RendezvousState::Detached)
814 else {
815 unreachable!("the delivered task was just stored");
816 };
817 drop(state);
818 task.detach();
819 }
820 RendezvousState::Delivered(_) | RendezvousState::Taken => {
821 unreachable!("a rendezvous task was delivered twice")
822 }
823 }
824 }
825}
826
827impl<T> Task<T> {
828 pub fn ready(val: T) -> Self {
842 Task(TaskState::Ready(Some(val)))
843 }
844
845 pub(crate) fn rendezvous() -> (Self, RendezvousSender<T>) {
850 let shared = Arc::new(parking_lot::Mutex::new(RendezvousState::Pending(None)));
851 (
852 Task(TaskState::Rendezvous(RendezvousReceiver {
853 shared: shared.clone(),
854 })),
855 RendezvousSender { shared },
856 )
857 }
858
859 pub fn from_async_task(task: async_task::Task<T, RunnableMeta>) -> Self {
864 Task(TaskState::Spawned(task))
865 }
866
867 pub fn is_ready(&self) -> bool {
881 match &self.0 {
882 TaskState::Ready(_) => true,
883 TaskState::Spawned(task) => task.is_finished(),
884 TaskState::Downcast { inner, .. } => inner.is_ready(),
885 TaskState::Rendezvous(receiver) => receiver.is_ready(),
886 }
887 }
888
889 pub fn detach(self) {
896 match self {
897 Task(TaskState::Ready(_)) => {}
898 Task(TaskState::Spawned(task)) => task.detach(),
899 Task(TaskState::Downcast { inner, .. }) => inner.detach(),
900 Task(TaskState::Rendezvous(receiver)) => receiver.detach(),
901 }
902 }
903
904 pub fn fallible(self) -> FallibleTask<T> {
909 FallibleTask(match self.0 {
910 TaskState::Ready(val) => FallibleTaskState::Ready(val),
911 TaskState::Spawned(task) => FallibleTaskState::Spawned(task.fallible()),
912 TaskState::Downcast { inner, .. } => FallibleTaskState::Downcast {
913 inner: Box::new(inner.fallible()),
914 marker: PhantomData,
915 },
916 TaskState::Rendezvous(receiver) => FallibleTaskState::Rendezvous(receiver),
917 })
918 }
919}
920
921impl Task<Box<dyn Any + Send + Sync>> {
922 pub fn downcast<T: Send + Sync + 'static>(self) -> Task<T> {
934 Task(TaskState::Downcast {
935 inner: Box::new(self),
936 marker: PhantomData,
937 })
938 }
939}
940
941impl<T> std::fmt::Debug for Task<T> {
942 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
943 match &self.0 {
944 TaskState::Ready(_) => f.debug_tuple("Task::Ready").finish(),
945 TaskState::Spawned(task) => f.debug_tuple("Task::Spawned").field(task).finish(),
946 TaskState::Downcast { inner, .. } => {
947 f.debug_tuple("Task::Downcast").field(inner).finish()
948 }
949 TaskState::Rendezvous(_) => f.debug_tuple("Task::Rendezvous").finish(),
950 }
951 }
952}
953
954#[must_use]
962pub struct FallibleTask<T>(FallibleTaskState<T>);
963
964enum FallibleTaskState<T> {
965 Ready(Option<T>),
967
968 Spawned(async_task::FallibleTask<T, RunnableMeta>),
970
971 Downcast {
973 inner: Box<FallibleTask<Box<dyn Any + Send + Sync>>>,
974 marker: PhantomData<fn() -> T>,
975 },
976
977 Rendezvous(RendezvousReceiver<T>),
979}
980
981impl<T> FallibleTask<T> {
982 pub fn ready(val: T) -> Self {
985 FallibleTask(FallibleTaskState::Ready(Some(val)))
986 }
987
988 pub fn detach(self) {
991 match self.0 {
992 FallibleTaskState::Ready(_) => {}
993 FallibleTaskState::Spawned(task) => task.detach(),
994 FallibleTaskState::Downcast { inner, .. } => inner.detach(),
995 FallibleTaskState::Rendezvous(receiver) => receiver.detach(),
996 }
997 }
998}
999
1000impl<T: 'static> Future for FallibleTask<T> {
1001 type Output = Option<T>;
1002
1003 fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
1004 let this = unsafe { self.get_unchecked_mut() };
1005 loop {
1006 match &mut this.0 {
1007 FallibleTaskState::Ready(val) => return Poll::Ready(val.take()),
1008 FallibleTaskState::Spawned(task) => return Pin::new(task).poll(cx),
1009 FallibleTaskState::Downcast { inner, .. } => {
1010 return match Pin::new(inner.as_mut()).poll(cx) {
1011 Poll::Ready(Some(boxed_any)) => Poll::Ready(Some(
1012 *boxed_any
1013 .downcast::<T>()
1014 .expect("FallibleTask::poll: downcast type mismatch"),
1015 )),
1016 Poll::Ready(None) => Poll::Ready(None),
1017 Poll::Pending => Poll::Pending,
1018 };
1019 }
1020 FallibleTaskState::Rendezvous(receiver) => match receiver.poll_take(cx) {
1021 Poll::Ready(task) => {
1022 this.0 = task.fallible().0;
1023 continue;
1024 }
1025 Poll::Pending => return Poll::Pending,
1026 },
1027 }
1028 }
1029 }
1030}
1031
1032impl<T> std::fmt::Debug for FallibleTask<T> {
1033 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1034 match &self.0 {
1035 FallibleTaskState::Ready(_) => f.debug_tuple("FallibleTask::Ready").finish(),
1036 FallibleTaskState::Spawned(task) => {
1037 f.debug_tuple("FallibleTask::Spawned").field(task).finish()
1038 }
1039 FallibleTaskState::Downcast { inner, .. } => f
1040 .debug_tuple("FallibleTask::Downcast")
1041 .field(inner)
1042 .finish(),
1043 FallibleTaskState::Rendezvous(_) => f.debug_tuple("FallibleTask::Rendezvous").finish(),
1044 }
1045 }
1046}
1047
1048impl<T: 'static> Future for Task<T> {
1049 type Output = T;
1050
1051 fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
1052 let this = unsafe { self.get_unchecked_mut() };
1053 loop {
1054 match &mut this.0 {
1055 TaskState::Ready(val) => return Poll::Ready(val.take().unwrap()),
1056 TaskState::Spawned(task) => return Pin::new(task).poll(cx),
1057 TaskState::Downcast { inner, .. } => {
1058 return match Pin::new(inner.as_mut()).poll(cx) {
1059 Poll::Ready(boxed_any) => Poll::Ready(
1060 *boxed_any
1061 .downcast::<T>()
1062 .expect("Task::poll: downcast type mismatch"),
1063 ),
1064 Poll::Pending => Poll::Pending,
1065 };
1066 }
1067 TaskState::Rendezvous(receiver) => match receiver.poll_take(cx) {
1068 Poll::Ready(task) => {
1069 this.0 = task.0;
1070 continue;
1071 }
1072 Poll::Pending => return Poll::Pending,
1073 },
1074 }
1075 }
1076 }
1077}
1078
1079#[track_caller]
1081fn spawn_local_with_source_location<Fut, S>(
1082 future: Fut,
1083 schedule: S,
1084 metadata: RunnableMeta,
1085) -> (
1086 async_task::Runnable<RunnableMeta>,
1087 async_task::Task<Fut::Output, RunnableMeta>,
1088)
1089where
1090 Fut: Future + 'static,
1091 Fut::Output: 'static,
1092 S: async_task::Schedule<RunnableMeta> + Send + Sync + 'static,
1093{
1094 #[inline]
1095 fn thread_id() -> ThreadId {
1096 std::thread_local! {
1097 static ID: ThreadId = thread::current().id();
1098 }
1099 ID.try_with(|id| *id)
1100 .unwrap_or_else(|_| thread::current().id())
1101 }
1102
1103 struct Checked<F> {
1104 id: ThreadId,
1105 inner: ManuallyDrop<F>,
1106 location: &'static Location<'static>,
1107 }
1108
1109 impl<F> Drop for Checked<F> {
1110 fn drop(&mut self) {
1111 assert_eq!(
1112 self.id,
1113 thread_id(),
1114 "local task dropped by a thread that didn't spawn it. Task spawned at {}",
1115 self.location
1116 );
1117 unsafe { ManuallyDrop::drop(&mut self.inner) };
1121 }
1122 }
1123
1124 impl<F: Future> Future for Checked<F> {
1125 type Output = F::Output;
1126
1127 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1128 let this = unsafe { self.get_unchecked_mut() };
1132 assert!(
1133 this.id == thread_id(),
1134 "local task polled by a thread that didn't spawn it. Task spawned at {}",
1135 this.location
1136 );
1137 unsafe { Pin::new_unchecked(&mut *this.inner).poll(cx) }
1142 }
1143 }
1144
1145 let location = metadata.location;
1146
1147 let future = move |_| Checked {
1148 id: thread_id(),
1149 inner: ManuallyDrop::new(future),
1150 location,
1151 };
1152
1153 let builder = async_task::Builder::new().metadata(metadata);
1154 unsafe { builder.spawn_unchecked(future, schedule) }
1158}
1159
1160#[cfg(test)]
1161mod local_task_scope_tests {
1162 use super::*;
1163 use crate::TestScheduler;
1164 use std::{
1165 collections::VecDeque,
1166 sync::{Arc, Mutex},
1167 task::{Poll, Waker},
1168 thread::ThreadId,
1169 };
1170
1171 type Queue = Arc<Mutex<VecDeque<Runnable<RunnableMeta>>>>;
1172
1173 fn queue() -> Queue {
1174 Arc::new(Mutex::new(VecDeque::new()))
1175 }
1176
1177 fn pop(queue: &Queue) -> Runnable<RunnableMeta> {
1178 queue.lock().unwrap().pop_front().expect("queued runnable")
1179 }
1180
1181 fn executor(scope: Arc<LocalTaskScope>, normal: Queue, cancellation: Queue) -> LocalExecutor {
1182 let scheduler: Arc<dyn Scheduler> =
1183 Arc::new(TestScheduler::new(crate::TestSchedulerConfig::default()));
1184 LocalExecutor::new_with_scope(
1185 SessionId::new(0),
1186 scheduler,
1187 scope,
1188 move |runnable| normal.lock().unwrap().push_back(runnable),
1189 move |runnable| cancellation.lock().unwrap().push_back(runnable),
1190 )
1191 }
1192
1193 struct DropOnThread {
1194 dropped_on: Arc<Mutex<Option<ThreadId>>>,
1195 }
1196
1197 impl Drop for DropOnThread {
1198 fn drop(&mut self) {
1199 *self.dropped_on.lock().unwrap() = Some(std::thread::current().id());
1200 }
1201 }
1202
1203 #[test]
1204 fn sealed_scope_late_waker_cannot_dispatch_or_drop_local_work_off_owner() {
1205 let owner = std::thread::current().id();
1206 let scope = Arc::new(LocalTaskScope::new());
1207 let normal = queue();
1208 let cancellation = queue();
1209 let executor = executor(scope.clone(), normal.clone(), cancellation.clone());
1210 let saved_waker = Arc::new(Mutex::new(None::<Waker>));
1211 let dropped_on = Arc::new(Mutex::new(None));
1212
1213 let task = {
1214 let saved_waker = saved_waker.clone();
1215 let dropped_on = dropped_on.clone();
1216 executor.spawn(async move {
1217 let _probe = DropOnThread { dropped_on };
1218 futures::future::poll_fn(move |cx| {
1219 *saved_waker.lock().unwrap() = Some(cx.waker().clone());
1220 Poll::<()>::Pending
1221 })
1222 .await;
1223 })
1224 };
1225 task.detach();
1226 pop(&normal).run();
1227 assert_eq!(scope.live_task_count(), 1);
1228
1229 let late_waker = saved_waker.lock().unwrap().clone().unwrap();
1230 scope.begin_retirement();
1231 drop(pop(&cancellation));
1232
1233 assert_eq!(scope.live_task_count(), 0);
1234 assert_eq!(*dropped_on.lock().unwrap(), Some(owner));
1235 assert!(scope.seal_if_quiescent());
1236 std::thread::spawn(move || late_waker.wake())
1237 .join()
1238 .expect("late wake thread");
1239 assert!(cancellation.lock().unwrap().is_empty());
1240 }
1241
1242 #[test]
1243 fn completion_unregisters_task_and_spawn_after_retirement_is_canceled() {
1244 let scope = Arc::new(LocalTaskScope::new());
1245 let normal = queue();
1246 let cancellation = queue();
1247 let executor = executor(scope.clone(), normal.clone(), cancellation.clone());
1248
1249 executor.spawn(async { 42 }).detach();
1250 pop(&normal).run();
1251 assert_eq!(scope.live_task_count(), 0);
1252
1253 scope.begin_retirement();
1254 executor.spawn(async { 7 }).detach();
1255 assert!(normal.lock().unwrap().is_empty());
1256 assert_eq!(scope.live_task_count(), 1);
1257 drop(pop(&cancellation));
1258 assert_eq!(scope.live_task_count(), 0);
1259 }
1260
1261 #[test]
1262 fn custom_idle_dispatch_is_bypassed_during_retirement() {
1263 let scope = Arc::new(LocalTaskScope::new());
1264 let normal = queue();
1265 let cancellation = queue();
1266 let executor = executor(scope.clone(), normal, cancellation.clone());
1267 let idle = queue();
1268 let idle_dispatches = Arc::new(std::sync::atomic::AtomicUsize::new(0));
1269 let pending_waker = Arc::new(Mutex::new(None::<Waker>));
1270
1271 let task = {
1272 let idle_dispatches = idle_dispatches.clone();
1273 let idle = idle.clone();
1274 let pending_waker = pending_waker.clone();
1275 executor.spawn_with_dispatch(
1276 async move {
1277 futures::future::poll_fn(move |cx| {
1278 *pending_waker.lock().unwrap() = Some(cx.waker().clone());
1279 Poll::<()>::Pending
1280 })
1281 .await;
1282 },
1283 move |runnable| {
1284 idle_dispatches.fetch_add(1, Ordering::SeqCst);
1285 idle.lock().unwrap().push_back(runnable);
1286 },
1287 )
1288 };
1289 task.detach();
1290 pop(&idle).run();
1291 assert_eq!(idle_dispatches.load(Ordering::SeqCst), 1);
1292
1293 scope.begin_retirement();
1294 drop(pop(&cancellation));
1295 assert_eq!(idle_dispatches.load(Ordering::SeqCst), 1);
1296 assert_eq!(scope.live_task_count(), 0);
1297 }
1298}
1299
1300#[cfg(test)]
1301mod sealed_scope_tests {
1302 use super::*;
1303 use crate::TestScheduler;
1304 use std::{
1305 collections::VecDeque,
1306 sync::{Arc, Mutex},
1307 thread::ThreadId,
1308 };
1309
1310 #[test]
1311 fn sealed_scope_rejects_new_spawns_and_drops_input_on_owner() {
1312 let owner = std::thread::current().id();
1313 let scope = Arc::new(LocalTaskScope::new());
1314 scope.begin_retirement();
1315 assert!(scope.seal_if_quiescent());
1316
1317 let normal = Arc::new(Mutex::new(VecDeque::new()));
1318 let cancellation = Arc::new(Mutex::new(VecDeque::new()));
1319 let scheduler: Arc<dyn Scheduler> =
1320 Arc::new(TestScheduler::new(crate::TestSchedulerConfig::default()));
1321 let executor = LocalExecutor::new_with_scope(
1322 SessionId::new(1),
1323 scheduler,
1324 scope,
1325 {
1326 let normal = normal.clone();
1327 move |runnable| normal.lock().unwrap().push_back(runnable)
1328 },
1329 {
1330 let cancellation = cancellation.clone();
1331 move |runnable| cancellation.lock().unwrap().push_back(runnable)
1332 },
1333 );
1334 let dropped_on = Arc::new(Mutex::new(None::<ThreadId>));
1335 let probe = {
1336 let dropped_on = dropped_on.clone();
1337 struct Probe(Arc<Mutex<Option<ThreadId>>>);
1338 impl Drop for Probe {
1339 fn drop(&mut self) {
1340 *self.0.lock().unwrap() = Some(std::thread::current().id());
1341 }
1342 }
1343 Probe(dropped_on)
1344 };
1345 let future = async move {
1346 let _probe = probe;
1347 };
1348 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1349 executor.spawn(future).detach();
1350 }));
1351
1352 assert!(result.is_err());
1353 assert_eq!(*dropped_on.lock().unwrap(), Some(owner));
1354 assert!(normal.lock().unwrap().is_empty());
1355 assert!(cancellation.lock().unwrap().is_empty());
1356 }
1357}