1#![forbid(unsafe_code)]
87
88use inspect::Inspect;
89use inspect::InspectMut;
90use pal_async::task::Spawn;
91use pal_async::task::Task;
92use parking_lot::Mutex;
93use std::future::Future;
94use std::future::poll_fn;
95use std::pin::Pin;
96use std::pin::pin;
97use std::sync::Arc;
98use std::sync::atomic::AtomicBool;
99use std::sync::atomic::Ordering;
100use std::task::Context;
101use std::task::Poll;
102use std::task::Waker;
103
104pub trait AsyncRun<S>: 'static + Send {
110 fn run(
130 &mut self,
131 stop: &mut StopTask<'_>,
132 _: &mut S,
133 ) -> impl Send + Future<Output = Result<(), Cancelled>>;
134}
135
136#[derive(Debug)]
146pub struct Cancelled;
147
148pub struct StopTask<'a> {
153 inner: &'a mut (dyn 'a + Send + Future<Output = ()> + Unpin),
154 requested: &'a AtomicBool,
155 outer_waker: Option<Waker>,
156}
157
158#[derive(Clone, Copy)]
163pub struct StopCheck<'a>(&'a AtomicBool);
164
165impl StopCheck<'_> {
166 #[inline]
168 pub fn check(&self) -> Result<(), Cancelled> {
169 if self.0.load(Ordering::Relaxed) {
170 Err(Cancelled)
171 } else {
172 Ok(())
173 }
174 }
175}
176
177struct StopTaskInner<'a, T, S> {
182 shared: &'a Shared<T, S>,
183}
184
185impl<T: AsyncRun<S>, S> Future for StopTaskInner<'_, T, S> {
186 type Output = ();
187
188 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
189 let mut shared = self.get_mut().shared.lock();
190 if !shared.calls.is_empty() || shared.stop {
191 return Poll::Ready(());
192 }
193 if shared
194 .inner_waker
195 .as_ref()
196 .is_none_or(|waker| !cx.waker().will_wake(waker))
197 {
198 shared.inner_waker = Some(cx.waker().clone());
199 }
200 Poll::Pending
201 }
202}
203
204impl<'a> StopTask<'a> {
205 pub async fn run_unstoppable<R>(f: impl AsyncFnOnce(&mut StopTask<'_>) -> R) -> R {
209 let requested = AtomicBool::new(false);
210 let mut pending = std::future::pending();
211 let mut stop = StopTask {
212 inner: &mut pending,
213 requested: &requested,
214 outer_waker: None,
215 };
216 f(&mut stop).await
217 }
218
219 #[inline]
228 pub fn check(&self) -> Result<(), Cancelled> {
229 StopCheck(self.requested).check()
230 }
231
232 pub fn check_handle(&self) -> Result<StopCheck<'a>, Cancelled> {
237 self.check()?;
238 Ok(StopCheck(self.requested))
239 }
240
241 pub async fn until_stopped<F: Future>(&mut self, fut: F) -> Result<F::Output, Cancelled> {
249 let mut fut = pin!(fut);
250
251 poll_fn(|cx| {
255 if let Err(cancelled) = self.check() {
256 Poll::Ready(Err(cancelled))
257 } else if let Poll::Ready(r) = fut.as_mut().poll(cx) {
258 Poll::Ready(Ok(r))
259 } else if self.poll_wait(cx).is_ready() {
260 Poll::Ready(Err(Cancelled))
261 } else {
262 Poll::Pending
263 }
264 })
265 .await
266 }
267
268 #[inline]
269 fn poll_wait(&mut self, cx: &mut Context<'_>) -> Poll<()> {
270 if self
273 .outer_waker
274 .as_ref()
275 .is_some_and(|waker| cx.waker().will_wake(waker))
276 {
277 return Poll::Pending;
278 }
279 if Pin::new(&mut self.inner).poll(cx).is_ready() {
280 return Poll::Ready(());
281 }
282 self.outer_waker = Some(cx.waker().clone());
283 if self.check().is_err() {
286 Poll::Ready(())
287 } else {
288 Poll::Pending
289 }
290 }
291}
292
293impl Future for StopTask<'_> {
294 type Output = ();
295
296 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
297 if self.check().is_err() {
298 Poll::Ready(())
299 } else {
300 self.poll_wait(cx)
301 }
302 }
303}
304
305pub struct TaskControl<T, S> {
317 inner: Inner<T, S>,
318}
319
320pub trait InspectTask<S>: AsyncRun<S> {
322 fn inspect(&self, req: inspect::Request<'_>, state: Option<&S>);
327}
328
329impl<T: InspectTask<S>, S> Inspect for TaskAndState<T, S> {
330 fn inspect(&self, req: inspect::Request<'_>) {
331 self.task.inspect(req, self.state.as_ref());
332 }
333}
334
335impl<T: InspectTask<S>, S> Inspect for TaskControl<T, S> {
336 fn inspect(&self, req: inspect::Request<'_>) {
337 match &self.inner {
338 Inner::NoState(task_and_state) => task_and_state.inspect(req),
339 Inner::WithState {
340 activity, shared, ..
341 } => match activity {
342 Activity::Stopped(task_and_state) => task_and_state.inspect(req),
343 Activity::Running => {
344 let deferred = req.defer();
345 Shared::push_call(
346 shared,
347 Box::new(|task_and_state| {
348 deferred.inspect(&task_and_state);
349 }),
350 )
351 }
352 },
353 Inner::Invalid => unreachable!(),
354 }
355 }
356}
357
358pub trait InspectTaskMut<T>: AsyncRun<T> {
360 fn inspect_mut(&mut self, req: inspect::Request<'_>, state: Option<&mut T>);
365}
366
367impl<T: InspectTaskMut<S>, S> InspectMut for TaskAndState<T, S> {
368 fn inspect_mut(&mut self, req: inspect::Request<'_>) {
369 self.task.inspect_mut(req, self.state.as_mut());
370 }
371}
372
373impl<T: InspectTaskMut<U>, U> InspectMut for TaskControl<T, U> {
374 fn inspect_mut(&mut self, req: inspect::Request<'_>) {
375 match &mut self.inner {
376 Inner::NoState(task_and_state) => task_and_state.inspect_mut(req),
377 Inner::WithState {
378 activity, shared, ..
379 } => match activity {
380 Activity::Stopped(task_and_state) => task_and_state.inspect_mut(req),
381 Activity::Running => {
382 let deferred = req.defer();
383 Shared::push_call(
384 shared,
385 Box::new(|task_and_state| {
386 deferred.inspect(task_and_state);
387 }),
388 );
389 }
390 },
391 Inner::Invalid => unreachable!(),
392 }
393 }
394}
395
396type CallFn<T, S> = Box<dyn FnOnce(&mut TaskAndState<T, S>) + Send>;
397
398enum Inner<T, S> {
399 NoState(Box<TaskAndState<T, S>>),
400 WithState {
401 activity: Activity<T, S>,
402 _backing_task: Task<()>,
403 shared: Arc<Shared<T, S>>,
404 },
405 Invalid,
406}
407
408struct TaskAndState<T, S> {
409 task: T,
410 state: Option<S>,
411 done: bool,
412}
413
414struct Shared<T, S> {
415 requested: AtomicBool,
418 inner: Mutex<SharedState<T, S>>,
419}
420
421struct SharedState<T, S> {
422 task_and_state: Option<Box<TaskAndState<T, S>>>,
423 calls: Vec<CallFn<T, S>>,
424 stop: bool,
425 outer_waker: Option<Waker>,
426 inner_waker: Option<Waker>,
427}
428
429impl<T, S> Shared<T, S> {
430 fn lock(&self) -> parking_lot::MutexGuard<'_, SharedState<T, S>> {
431 self.inner.lock()
432 }
433
434 fn push_call(this: &Self, f: CallFn<T, S>) {
435 let waker = {
436 let mut shared = this.lock();
437 shared.calls.push(f);
438 this.requested.store(true, Ordering::Relaxed);
439 shared.inner_waker.take()
440 };
441 if let Some(waker) = waker {
442 waker.wake();
443 }
444 }
445}
446
447enum Activity<T, S> {
448 Stopped(Box<TaskAndState<T, S>>),
449 Running,
450}
451
452impl<T: AsyncRun<S>, S: 'static + Send> TaskControl<T, S> {
453 pub fn new(task: T) -> Self {
456 Self {
457 inner: Inner::NoState(Box::new(TaskAndState {
458 task,
459 state: None,
460 done: false,
461 })),
462 }
463 }
464
465 pub fn has_state(&self) -> bool {
467 match &self.inner {
468 Inner::NoState(_) => false,
469 Inner::WithState { .. } => true,
470 Inner::Invalid => unreachable!(),
471 }
472 }
473
474 pub fn is_running(&self) -> bool {
476 match &self.inner {
477 Inner::NoState(_)
478 | Inner::WithState {
479 activity: Activity::Stopped { .. },
480 ..
481 } => false,
482 Inner::WithState {
483 activity: Activity::Running,
484 ..
485 } => true,
486 Inner::Invalid => unreachable!(),
487 }
488 }
489
490 #[track_caller]
494 pub fn task(&self) -> &T {
495 self.get().0
496 }
497
498 #[track_caller]
502 pub fn task_mut(&mut self) -> &mut T {
503 self.get_mut().0
504 }
505
506 #[track_caller]
510 pub fn state(&self) -> Option<&S> {
511 self.get().1
512 }
513
514 #[track_caller]
518 pub fn state_mut(&mut self) -> Option<&mut S> {
519 self.get_mut().1
520 }
521
522 #[track_caller]
526 pub fn get(&self) -> (&T, Option<&S>) {
527 let task_and_state = match &self.inner {
528 Inner::NoState(task_and_state) => task_and_state,
529 Inner::WithState {
530 activity: Activity::Stopped(task_and_state),
531 ..
532 } => task_and_state,
533 Inner::WithState {
534 activity: Activity::Running,
535 ..
536 } => panic!("attempt to access running task"),
537 Inner::Invalid => unreachable!(),
538 };
539 (&task_and_state.task, task_and_state.state.as_ref())
540 }
541
542 #[track_caller]
546 pub fn get_mut(&mut self) -> (&mut T, Option<&mut S>) {
547 let task_and_state = match &mut self.inner {
548 Inner::NoState(task_and_state) => task_and_state,
549 Inner::WithState {
550 activity: Activity::Stopped(task_and_state),
551 ..
552 } => task_and_state,
553 Inner::WithState {
554 activity: Activity::Running,
555 ..
556 } => panic!("attempt to access running task"),
557 Inner::Invalid => unreachable!(),
558 };
559 (&mut task_and_state.task, task_and_state.state.as_mut())
560 }
561
562 #[track_caller]
566 pub fn into_inner(self) -> (T, Option<S>) {
567 let task_and_state = match self.inner {
568 Inner::NoState(task_and_state) => task_and_state,
569 Inner::WithState {
570 activity: Activity::Stopped(task_and_state),
571 ..
572 } => task_and_state,
573 Inner::WithState {
574 activity: Activity::Running,
575 ..
576 } => panic!("attempt to extract running task"),
577 Inner::Invalid => unreachable!(),
578 };
579 (task_and_state.task, task_and_state.state)
580 }
581
582 pub fn update_with(&mut self, f: impl 'static + Send + FnOnce(&mut T, Option<&mut S>)) {
587 let f = |task_and_state: &mut TaskAndState<T, S>| {
588 f(&mut task_and_state.task, task_and_state.state.as_mut())
589 };
590 match &mut self.inner {
591 Inner::NoState(task_and_state) => f(task_and_state),
592 Inner::WithState {
593 activity, shared, ..
594 } => match activity {
595 Activity::Stopped(task_and_state) => f(task_and_state),
596 Activity::Running => Shared::push_call(shared, Box::new(f)),
597 },
598 Inner::Invalid => unreachable!(),
599 }
600 }
601
602 #[track_caller]
605 pub fn insert(&mut self, spawn: impl Spawn, name: impl Into<Arc<str>>, state: S) -> &mut S {
606 self.inner = match std::mem::replace(&mut self.inner, Inner::Invalid) {
607 Inner::NoState(mut task_and_state) => {
608 task_and_state.state = Some(state);
609 task_and_state.done = false;
610 let shared = Arc::new(Shared {
611 requested: AtomicBool::new(true),
612 inner: Mutex::new(SharedState {
613 task_and_state: None,
614 calls: Vec::new(),
615 stop: true,
616 outer_waker: None,
617 inner_waker: None,
618 }),
619 });
620 let backing_task = spawn.spawn(name, Self::run(shared.clone()));
621 Inner::WithState {
622 activity: Activity::Stopped(task_and_state),
623 _backing_task: backing_task,
624 shared,
625 }
626 }
627 Inner::WithState { .. } => panic!("attempt to insert already-present state"),
628 Inner::Invalid => unreachable!(),
629 };
630 self.state_mut().unwrap()
631 }
632
633 pub fn start(&mut self) -> bool {
639 match &mut self.inner {
640 Inner::WithState {
641 activity, shared, ..
642 } => match std::mem::replace(activity, Activity::Running) {
643 Activity::Stopped(task_and_state) => {
644 if task_and_state.done {
645 *activity = Activity::Stopped(task_and_state);
646 return false;
647 }
648 let waker = {
649 let mut state = shared.lock();
650 state.task_and_state = Some(task_and_state);
651 state.stop = false;
652 shared
653 .requested
654 .store(!state.calls.is_empty(), Ordering::Relaxed);
655 state.inner_waker.take()
656 };
657 if let Some(waker) = waker {
658 waker.wake();
659 }
660 true
661 }
662 Activity::Running => true,
663 },
664 Inner::NoState(_) => false,
665 Inner::Invalid => {
666 unreachable!()
667 }
668 }
669 }
670
671 async fn run(shared: Arc<Shared<T, S>>) {
672 let mut stop_source = StopTaskInner { shared: &shared };
673 let mut stop_task = StopTask {
674 inner: &mut stop_source,
675 requested: &shared.requested,
676 outer_waker: None,
677 };
678 let mut calls = Vec::new();
679 loop {
680 let (mut task_and_state, stop) = poll_fn(|cx| {
681 let mut state = shared.lock();
682 let has_work = state
683 .task_and_state
684 .as_ref()
685 .is_some_and(|ts| !state.calls.is_empty() || (!state.stop && !ts.done));
686 if !has_work {
687 state.inner_waker = Some(cx.waker().clone());
688 return Poll::Pending;
689 }
690 calls.append(&mut state.calls);
691 shared.requested.store(state.stop, Ordering::Relaxed);
694 Poll::Ready((state.task_and_state.take().unwrap(), state.stop))
695 })
696 .await;
697
698 for call in calls.drain(..) {
699 call(&mut task_and_state);
700 }
701
702 if !stop && !task_and_state.done {
703 stop_task.outer_waker = None;
706 if stop_task.check().is_ok() {
707 task_and_state.done = task_and_state
708 .task
709 .run(&mut stop_task, task_and_state.state.as_mut().unwrap())
710 .await
711 .is_ok();
712 }
713 }
714
715 let waker = {
716 let mut shared = shared.lock();
717 shared.task_and_state = Some(task_and_state);
718 shared.outer_waker.take()
719 };
720 if let Some(waker) = waker {
721 waker.wake();
722 }
723 }
724 }
725
726 pub fn poll_stop(&mut self, cx: &mut Context<'_>) -> Poll<bool> {
734 match &mut self.inner {
735 Inner::WithState {
736 activity, shared, ..
737 } => match activity {
738 Activity::Running => {
739 let mut state = shared.lock();
740 state.stop = true;
741 shared.requested.store(true, Ordering::Relaxed);
742 if state.task_and_state.is_none() || !state.calls.is_empty() {
743 state.outer_waker = Some(cx.waker().clone());
744 let waker = state.inner_waker.take();
745 drop(state);
746 if let Some(waker) = waker {
747 waker.wake();
748 }
749 return Poll::Pending;
750 }
751 let task_and_state = state.task_and_state.take().unwrap();
752 drop(state);
753 let done = task_and_state.done;
754 *activity = Activity::Stopped(task_and_state);
755 Poll::Ready(!done)
756 }
757 _ => Poll::Ready(false),
758 },
759 Inner::NoState(_) => Poll::Ready(false),
760 Inner::Invalid => unreachable!(),
761 }
762 }
763
764 pub async fn stop(&mut self) -> bool {
769 poll_fn(|cx| self.poll_stop(cx)).await
770 }
771
772 #[track_caller]
776 pub fn remove(&mut self) -> S {
777 match std::mem::replace(&mut self.inner, Inner::Invalid) {
778 Inner::WithState {
779 activity: Activity::Stopped(mut task_and_state),
780 ..
781 } => {
782 let state = task_and_state.state.take().unwrap();
783 self.inner = Inner::NoState(task_and_state);
784 state
785 }
786 Inner::NoState(_) => panic!("attempt to remove missing state"),
787 Inner::WithState { .. } => panic!("attempt to remove state from running task"),
788 Inner::Invalid => {
789 unreachable!()
790 }
791 }
792 }
793}
794
795#[cfg(test)]
796mod tests {
797 use super::AsyncRun;
798 use crate::Cancelled;
799 use crate::StopTask;
800 use crate::TaskControl;
801 use futures::FutureExt;
802 use pal_async::DefaultDriver;
803 use pal_async::async_test;
804 use parking_lot::Mutex;
805 use std::future::Future;
806 use std::pin::Pin;
807 use std::pin::pin;
808 use std::sync::Arc;
809 use std::sync::atomic::AtomicBool;
810 use std::sync::atomic::AtomicUsize;
811 use std::sync::atomic::Ordering;
812 use std::task::Context;
813 use std::task::Poll;
814 use std::task::Wake;
815 use std::task::Waker;
816
817 #[derive(Default)]
818 struct CheckSignal {
819 requested: AtomicBool,
820 polls: AtomicUsize,
821 waker: Mutex<Option<Waker>>,
822 request_during_registration: AtomicBool,
823 }
824
825 #[derive(Default)]
826 struct CountWake(AtomicUsize);
827
828 impl Wake for CountWake {
829 fn wake(self: Arc<Self>) {
830 self.0.fetch_add(1, Ordering::Relaxed);
831 }
832 }
833
834 impl CheckSignal {
835 fn notify(&self) {
836 let waker = self.waker.lock().clone();
837 if let Some(waker) = waker {
838 waker.wake();
839 }
840 }
841 }
842
843 struct CheckStop<'a>(&'a CheckSignal);
844
845 impl Future for CheckStop<'_> {
846 type Output = ();
847
848 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
849 self.0.polls.fetch_add(1, Ordering::Relaxed);
850 let old = self.0.waker.lock().replace(cx.waker().clone());
851 drop(old);
852 let requested = self.0.requested.load(Ordering::Relaxed);
853 if self
854 .0
855 .request_during_registration
856 .swap(false, Ordering::Relaxed)
857 {
858 self.0.requested.store(true, Ordering::Relaxed);
859 }
860 if requested {
861 Poll::Ready(())
862 } else {
863 Poll::Pending
864 }
865 }
866 }
867
868 async fn run_with_signal<R>(
869 signal: &CheckSignal,
870 f: impl AsyncFnOnce(&mut StopTask<'_>) -> R,
871 ) -> R {
872 let mut source = CheckStop(signal);
873 let mut stop = StopTask {
874 inner: &mut source,
875 requested: &signal.requested,
876 outer_waker: None,
877 };
878 f(&mut stop).await
879 }
880
881 #[test]
882 fn checks_observe_requests_without_polling_or_waker_registration() {
883 let signal = Arc::new(CheckSignal::default());
884 let result = run_with_signal(&signal, async |stop| {
885 let check = stop.check_handle().unwrap();
886 for _ in 0..1000 {
887 stop.check().unwrap();
888 check.check().unwrap();
889 stop.until_stopped(std::future::ready(())).await.unwrap();
890 }
891 assert_eq!(signal.polls.load(Ordering::Relaxed), 0);
892 assert!(signal.waker.lock().is_none());
893 assert!(stop.outer_waker.is_none());
894
895 signal.notify();
896 check.check().unwrap();
897 stop.check().unwrap();
898
899 signal.requested.store(true, Ordering::Relaxed);
900 assert!(check.check().is_err());
901 assert!(stop.check().is_err());
902 assert!(stop.check().is_err());
903 assert_eq!(signal.polls.load(Ordering::Relaxed), 0);
904 signal.requested.store(false, Ordering::Relaxed);
905 stop.check().unwrap();
906 signal.requested.store(true, Ordering::Relaxed);
907 assert!(stop.check().is_err());
908 })
909 .now_or_never();
910 assert!(result.is_some());
911 }
912
913 #[test]
914 fn interruptible_wait_prioritizes_stop_and_handles_noop_wakers() {
915 let signal = Arc::new(CheckSignal::default());
916 let result = run_with_signal(&signal, async |stop| {
917 {
918 let mut wait = pin!(stop.until_stopped(std::future::pending::<()>()));
919 assert!(
920 wait.as_mut()
921 .poll(&mut Context::from_waker(Waker::noop()))
922 .is_pending()
923 );
924 signal.requested.store(true, Ordering::Relaxed);
925 signal.notify();
926 assert!(matches!(
927 wait.as_mut().poll(&mut Context::from_waker(Waker::noop())),
928 Poll::Ready(Err(_))
929 ));
930 }
931 let work = std::future::poll_fn(|_| -> Poll<u32> {
932 panic!("ready stop must prevent polling work");
933 });
934 assert!(stop.until_stopped(work).await.is_err());
935 assert!(stop.check().is_err());
936 })
937 .now_or_never();
938 assert!(result.is_some());
939 }
940
941 #[test]
942 fn wait_caches_registration_and_tracks_executor_waker_changes() {
943 let signal = Arc::new(CheckSignal::default());
944 let count = Arc::new(CountWake::default());
945 let waker = Waker::from(count.clone());
946 let result = run_with_signal(&signal, async |stop| {
947 let mut cx = Context::from_waker(&waker);
948 assert!(Pin::new(&mut *stop).poll(&mut cx).is_pending());
949 signal.notify();
950 stop.check().unwrap();
951 assert!(Pin::new(&mut *stop).poll(&mut cx).is_pending());
952 assert_eq!(signal.polls.load(Ordering::Relaxed), 1);
953 let new_count = Arc::new(CountWake::default());
954 let new_waker = Waker::from(new_count.clone());
955 let mut cx = Context::from_waker(&new_waker);
956 assert!(Pin::new(&mut *stop).poll(&mut cx).is_pending());
957 assert_eq!(signal.polls.load(Ordering::Relaxed), 2);
958 signal.requested.store(true, Ordering::Relaxed);
959 signal.notify();
960 assert_eq!(count.0.load(Ordering::Relaxed), 1);
961 assert_eq!(new_count.0.load(Ordering::Relaxed), 1);
962 assert!(Pin::new(&mut *stop).poll(&mut cx).is_ready());
963 signal.requested.store(false, Ordering::Relaxed);
964 signal.waker.lock().take();
965 stop.outer_waker = None;
966 assert!(Pin::new(&mut *stop).poll(&mut cx).is_pending());
967 assert_eq!(signal.polls.load(Ordering::Relaxed), 3);
968 })
969 .now_or_never();
970 assert!(result.is_some());
971 }
972
973 #[test]
974 fn cached_wait_observes_stop_on_repoll_when_requested_during_work() {
975 let signal = CheckSignal::default();
976 let count = Arc::new(CountWake::default());
977 let waker = Waker::from(count.clone());
978 let result = run_with_signal(&signal, async |stop| {
979 let mut cx = Context::from_waker(&waker);
980 assert!(Pin::new(&mut *stop).poll(&mut cx).is_pending());
981 let mut polled = false;
982 let work = std::future::poll_fn(|_| -> Poll<()> {
983 assert!(!polled, "stop must prevent polling work again");
984 polled = true;
985 signal.requested.store(true, Ordering::Relaxed);
986 signal.waker.lock().take().unwrap().wake();
987 Poll::Pending
988 });
989 let mut wait = pin!(stop.until_stopped(work));
990 assert!(wait.as_mut().poll(&mut cx).is_pending());
991 assert_eq!(count.0.load(Ordering::Relaxed), 1);
992 assert!(matches!(wait.as_mut().poll(&mut cx), Poll::Ready(Err(_))));
993 assert_eq!(signal.polls.load(Ordering::Relaxed), 1);
994 })
995 .now_or_never();
996 assert!(result.is_some());
997 }
998
999 #[test]
1000 fn wait_observes_request_arriving_during_registration() {
1001 let signal = CheckSignal {
1002 request_during_registration: AtomicBool::new(true),
1003 ..Default::default()
1004 };
1005 let result = run_with_signal(&signal, async |stop| {
1006 let mut wait = pin!(stop.until_stopped(std::future::pending::<()>()));
1007 assert!(matches!(
1008 wait.as_mut().poll(&mut Context::from_waker(Waker::noop())),
1009 Poll::Ready(Err(_))
1010 ));
1011 })
1012 .now_or_never();
1013 assert!(result.is_some());
1014 }
1015
1016 #[async_test]
1017 async fn checks_interrupt_busy_workers_for_update_stop_and_restart(driver: DefaultDriver) {
1018 struct Busy {
1019 started: std::sync::mpsc::Sender<usize>,
1020 updates: usize,
1021 }
1022 impl AsyncRun<()> for Busy {
1023 async fn run(&mut self, stop: &mut StopTask<'_>, _: &mut ()) -> Result<(), Cancelled> {
1024 self.started.send(self.updates).unwrap();
1025 loop {
1026 stop.check()?;
1027 std::future::ready(()).await;
1028 }
1029 }
1030 }
1031 async fn stop_with_timeout(task: &mut TaskControl<Busy, ()>, driver: &DefaultDriver) {
1032 let mut timer = pal_async::timer::PolledTimer::new(driver);
1033 match futures::future::select(
1034 pin!(task.stop()),
1035 pin!(timer.sleep(std::time::Duration::from_secs(5))),
1036 )
1037 .await
1038 {
1039 futures::future::Either::Left((stopped, _)) => assert!(stopped),
1040 futures::future::Either::Right(_) => panic!("busy worker did not stop"),
1041 }
1042 }
1043
1044 let (_thread, worker_driver) = pal_async::DefaultPool::spawn_on_thread("busy-check-test");
1045 let (started, recv_started) = std::sync::mpsc::channel();
1046 let mut task = TaskControl::new(Busy {
1047 started,
1048 updates: 0,
1049 });
1050 task.insert(&worker_driver, "busy", ());
1051 assert!(task.start());
1052 recv_started
1053 .recv_timeout(std::time::Duration::from_secs(5))
1054 .unwrap();
1055 let (entered, recv_entered) = std::sync::mpsc::channel();
1056 let (release, recv_release) = std::sync::mpsc::channel();
1057 task.update_with(move |worker, _| {
1058 worker.updates += 1;
1059 entered.send(()).unwrap();
1060 recv_release
1061 .recv_timeout(std::time::Duration::from_secs(5))
1062 .unwrap();
1063 });
1064 recv_entered
1065 .recv_timeout(std::time::Duration::from_secs(5))
1066 .unwrap();
1067 task.update_with(|worker, _| worker.updates += 1);
1068 release.send(()).unwrap();
1069 let updates_at_restart = recv_started
1070 .recv_timeout(std::time::Duration::from_secs(5))
1071 .unwrap();
1072 stop_with_timeout(&mut task, &driver).await;
1073 assert_eq!(updates_at_restart, 2);
1074 assert_eq!(task.task().updates, 2);
1075 assert!(task.start());
1076 recv_started
1077 .recv_timeout(std::time::Duration::from_secs(5))
1078 .unwrap();
1079 stop_with_timeout(&mut task, &driver).await;
1080 assert_eq!(task.task().updates, 2);
1081 }
1082
1083 struct Foo(u32);
1084
1085 impl AsyncRun<bool> for Foo {
1086 async fn run(
1087 &mut self,
1088 stop: &mut StopTask<'_>,
1089 state: &mut bool,
1090 ) -> Result<(), Cancelled> {
1091 stop.until_stopped(async {
1092 self.0 += 1;
1093 if !*state {
1094 std::future::pending::<()>().await;
1095 }
1096 })
1097 .await
1098 }
1099 }
1100
1101 async fn yield_once() {
1102 let mut yielded = false;
1103 std::future::poll_fn(|cx| {
1104 if yielded {
1105 Poll::Ready(())
1106 } else {
1107 yielded = true;
1108 cx.waker().wake_by_ref();
1109 Poll::Pending
1110 }
1111 })
1112 .await
1113 }
1114
1115 #[async_test]
1116 async fn test(driver: DefaultDriver) {
1117 let mut t = TaskControl::new(Foo(5));
1118 t.insert(&driver, "test", false);
1119 t.remove();
1120 t.insert(&driver, "test", false);
1121 assert_eq!(t.task().0, 5);
1122 assert!(t.start());
1123 yield_once().await;
1124 assert!(t.stop().await);
1125 assert_eq!(t.task().0, 6);
1126 *t.state_mut().unwrap() = true;
1127 assert!(t.start());
1128 yield_once().await;
1129 assert!(!t.stop().await);
1130 assert_eq!(t.task().0, 7);
1131 assert!(!t.start());
1133 yield_once().await;
1134 assert!(!t.stop().await);
1135 assert_eq!(t.task().0, 7);
1136 }
1137
1138 #[async_test]
1139 async fn test_cancelled_stop(driver: DefaultDriver) {
1140 let mut t = TaskControl::new(Foo(5));
1141 t.insert(&driver, "test", false);
1142 assert!(t.start());
1143 yield_once().await;
1144 t.update_with(|t, _| t.0 += 1);
1145 assert!(t.stop().now_or_never().is_none());
1146 t.update_with(|t, _| t.0 += 1);
1147 assert!(t.stop().await);
1148 assert_eq!(t.task_mut().0, 8);
1149 }
1150
1151 #[async_test]
1152 async fn test_poll_stop(driver: DefaultDriver) {
1153 let mut t = TaskControl::new(Foo(5));
1154
1155 assert_eq!(
1157 std::future::poll_fn(|cx| Poll::Ready(t.poll_stop(cx))).await,
1158 Poll::Ready(false)
1159 );
1160
1161 t.insert(&driver, "test", false);
1162
1163 assert_eq!(
1165 std::future::poll_fn(|cx| Poll::Ready(t.poll_stop(cx))).await,
1166 Poll::Ready(false)
1167 );
1168
1169 assert!(t.start());
1170 yield_once().await;
1171
1172 let result = std::future::poll_fn(|cx| t.poll_stop(cx)).await;
1174 assert!(result); assert_eq!(t.task().0, 6);
1176
1177 assert_eq!(
1179 std::future::poll_fn(|cx| Poll::Ready(t.poll_stop(cx))).await,
1180 Poll::Ready(false)
1181 );
1182 }
1183}