async_task/runnable.rs
1use core::fmt;
2use core::future::Future;
3use core::marker::PhantomData;
4use core::mem;
5use core::ptr::NonNull;
6use core::sync::atomic::Ordering;
7use core::task::Waker;
8
9use crate::header::Header;
10use crate::header::HeaderWithMetadata;
11use crate::raw::drop_ref;
12use crate::raw::{allocate_task, RawTask};
13use crate::state::*;
14use crate::Task;
15
16mod sealed {
17 use super::*;
18 pub trait Sealed<M> {}
19
20 impl<M, F> Sealed<M> for F where F: Fn(Runnable<M>) {}
21
22 impl<M, F> Sealed<M> for WithInfo<F> where F: Fn(Runnable<M>, ScheduleInfo) {}
23}
24
25/// A builder that creates a new task.
26#[derive(Debug)]
27pub struct Builder<M> {
28 /// The metadata associated with the task.
29 pub(crate) metadata: M,
30
31 /// Whether or not a panic that occurs in the task should be propagated.
32 #[cfg(feature = "std")]
33 pub(crate) propagate_panic: bool,
34}
35
36impl<M: Default> Default for Builder<M> {
37 fn default() -> Self {
38 Builder::new().metadata(M::default())
39 }
40}
41
42/// Extra scheduling information that can be passed to the scheduling function.
43///
44/// The data source of this struct is directly from the actual implementation
45/// of the crate itself, different from [`Runnable`]'s metadata, which is
46/// managed by the caller.
47///
48/// # Examples
49///
50/// ```
51/// use async_task::{Runnable, ScheduleInfo, WithInfo};
52/// use std::sync::{Arc, Mutex};
53///
54/// // The future inside the task.
55/// let future = async {
56/// println!("Hello, world!");
57/// };
58///
59/// // If the task gets woken up while running, it will be sent into this channel.
60/// let (s, r) = flume::unbounded();
61/// // Otherwise, it will be placed into this slot.
62/// let lifo_slot = Arc::new(Mutex::new(None));
63/// let schedule = move |runnable: Runnable, info: ScheduleInfo| {
64/// if info.woken_while_running {
65/// s.send(runnable).unwrap()
66/// } else {
67/// let last = lifo_slot.lock().unwrap().replace(runnable);
68/// if let Some(last) = last {
69/// s.send(last).unwrap()
70/// }
71/// }
72/// };
73///
74/// // Create the actual scheduler to be spawned with some future.
75/// let scheduler = WithInfo(schedule);
76/// // Create a task with the future and the scheduler.
77/// let (runnable, task) = async_task::spawn(future, scheduler);
78/// ```
79#[derive(Debug, Copy, Clone)]
80#[non_exhaustive]
81pub struct ScheduleInfo {
82 /// Indicates whether the task gets woken up while running.
83 ///
84 /// It is set to true usually because the task has yielded itself to the
85 /// scheduler.
86 pub woken_while_running: bool,
87}
88
89impl ScheduleInfo {
90 pub(crate) fn new(woken_while_running: bool) -> Self {
91 ScheduleInfo {
92 woken_while_running,
93 }
94 }
95}
96
97/// The trait for scheduling functions.
98pub trait Schedule<M = ()>: sealed::Sealed<M> {
99 /// Marks the start of a wake, cancellation, or explicit schedule.
100 ///
101 /// Called before the state transition that commits the attempt to enqueue a runnable.
102 /// Paired with [`end_schedule`](Self::end_schedule) when that attempt returns, including
103 /// when it does not publish a runnable.
104 #[inline]
105 fn begin_schedule(&self) {}
106
107 /// Runs after the task is marked scheduled and before [`schedule`](Self::schedule).
108 ///
109 /// [`begin_schedule`](Self::begin_schedule) for this attempt has already run.
110 #[inline]
111 fn before_enqueue(&self) {}
112
113 /// The actual scheduling procedure.
114 fn schedule(&self, runnable: Runnable<M>, info: ScheduleInfo);
115
116 /// Pairs with [`begin_schedule`](Self::begin_schedule).
117 #[inline]
118 fn end_schedule(&self) {}
119}
120
121/// Scheduling callbacks for an executor that has to observe shutdown.
122///
123/// `begin` and `end` bracket a whole wake. `before_enqueue` runs after the task is marked
124/// scheduled and before `schedule` receives the runnable.
125#[doc(hidden)]
126pub struct ScheduleParts<B, P, F, E> {
127 begin: B,
128 before_enqueue: P,
129 schedule: F,
130 end: E,
131}
132
133impl<B, P, F, E> ScheduleParts<B, P, F, E> {
134 /// Combines the four callbacks into one [`Schedule`] value.
135 pub fn new(begin: B, before_enqueue: P, schedule: F, end: E) -> Self {
136 Self {
137 begin,
138 before_enqueue,
139 schedule,
140 end,
141 }
142 }
143}
144
145impl<B, P, F, E> fmt::Debug for ScheduleParts<B, P, F, E> {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 f.write_str("ScheduleParts { .. }")
148 }
149}
150
151impl<M, B, P, F, E> sealed::Sealed<M> for ScheduleParts<B, P, F, E> {}
152
153impl<M, B, P, F, E> Schedule<M> for ScheduleParts<B, P, F, E>
154where
155 B: Fn(),
156 P: Fn(),
157 F: Fn(Runnable<M>),
158 E: Fn(),
159{
160 fn begin_schedule(&self) {
161 (self.begin)();
162 }
163
164 fn before_enqueue(&self) {
165 (self.before_enqueue)();
166 }
167
168 fn schedule(&self, runnable: Runnable<M>, _: ScheduleInfo) {
169 (self.schedule)(runnable);
170 }
171
172 fn end_schedule(&self) {
173 (self.end)();
174 }
175}
176
177impl<M, F> Schedule<M> for F
178where
179 F: Fn(Runnable<M>),
180{
181 fn schedule(&self, runnable: Runnable<M>, _: ScheduleInfo) {
182 self(runnable)
183 }
184}
185
186/// Pass a scheduling function with more scheduling information - a.k.a.
187/// [`ScheduleInfo`].
188///
189/// Sometimes, it's useful to pass the runnable's state directly to the
190/// scheduling function, such as whether it's woken up while running. The
191/// scheduler can thus use the information to determine its scheduling
192/// strategy.
193///
194/// The data source of [`ScheduleInfo`] is directly from the actual
195/// implementation of the crate itself, different from [`Runnable`]'s metadata,
196/// which is managed by the caller.
197///
198/// # Examples
199///
200/// ```
201/// use async_task::{ScheduleInfo, WithInfo};
202/// use std::sync::{Arc, Mutex};
203///
204/// // The future inside the task.
205/// let future = async {
206/// println!("Hello, world!");
207/// };
208///
209/// // If the task gets woken up while running, it will be sent into this channel.
210/// let (s, r) = flume::unbounded();
211/// // Otherwise, it will be placed into this slot.
212/// let lifo_slot = Arc::new(Mutex::new(None));
213/// let schedule = move |runnable, info: ScheduleInfo| {
214/// if info.woken_while_running {
215/// s.send(runnable).unwrap()
216/// } else {
217/// let last = lifo_slot.lock().unwrap().replace(runnable);
218/// if let Some(last) = last {
219/// s.send(last).unwrap()
220/// }
221/// }
222/// };
223///
224/// // Create a task with the future and the schedule function.
225/// let (runnable, task) = async_task::spawn(future, WithInfo(schedule));
226/// ```
227#[derive(Debug)]
228pub struct WithInfo<F>(pub F);
229
230impl<F> From<F> for WithInfo<F> {
231 fn from(value: F) -> Self {
232 WithInfo(value)
233 }
234}
235
236impl<M, F> Schedule<M> for WithInfo<F>
237where
238 F: Fn(Runnable<M>, ScheduleInfo),
239{
240 fn schedule(&self, runnable: Runnable<M>, info: ScheduleInfo) {
241 (self.0)(runnable, info)
242 }
243}
244
245impl Builder<()> {
246 /// Creates a new task builder.
247 ///
248 /// By default, this task builder has no metadata. Use the [`metadata`] method to
249 /// set the metadata.
250 ///
251 /// # Examples
252 ///
253 /// ```
254 /// use async_task::Builder;
255 ///
256 /// let (runnable, task) = Builder::new().spawn(|()| async {}, |_| {});
257 /// ```
258 pub fn new() -> Builder<()> {
259 Builder {
260 metadata: (),
261 #[cfg(feature = "std")]
262 propagate_panic: false,
263 }
264 }
265
266 /// Adds metadata to the task.
267 ///
268 /// In certain cases, it may be useful to associate some metadata with a task. For instance,
269 /// you may want to associate a name with a task, or a priority for a priority queue. This
270 /// method allows the user to attach arbitrary metadata to a task that is available through
271 /// the [`Runnable`] or the [`Task`].
272 ///
273 /// # Examples
274 ///
275 /// This example creates an executor that associates a "priority" number with each task, and
276 /// then runs the tasks in order of priority.
277 ///
278 /// ```
279 /// use async_task::{Builder, Runnable};
280 /// use once_cell::sync::Lazy;
281 /// use std::cmp;
282 /// use std::collections::BinaryHeap;
283 /// use std::sync::Mutex;
284 ///
285 /// # smol::future::block_on(async {
286 /// /// A wrapper around a `Runnable<usize>` that implements `Ord` so that it can be used in a
287 /// /// priority queue.
288 /// struct TaskWrapper(Runnable<usize>);
289 ///
290 /// impl PartialEq for TaskWrapper {
291 /// fn eq(&self, other: &Self) -> bool {
292 /// self.0.metadata() == other.0.metadata()
293 /// }
294 /// }
295 ///
296 /// impl Eq for TaskWrapper {}
297 ///
298 /// impl PartialOrd for TaskWrapper {
299 /// fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
300 /// Some(self.cmp(other))
301 /// }
302 /// }
303 ///
304 /// impl Ord for TaskWrapper {
305 /// fn cmp(&self, other: &Self) -> cmp::Ordering {
306 /// self.0.metadata().cmp(other.0.metadata())
307 /// }
308 /// }
309 ///
310 /// static EXECUTOR: Lazy<Mutex<BinaryHeap<TaskWrapper>>> = Lazy::new(|| {
311 /// Mutex::new(BinaryHeap::new())
312 /// });
313 ///
314 /// let schedule = |runnable| {
315 /// EXECUTOR.lock().unwrap().push(TaskWrapper(runnable));
316 /// };
317 ///
318 /// // Spawn a few tasks with different priorities.
319 /// let spawn_task = move |priority| {
320 /// let (runnable, task) = Builder::new().metadata(priority).spawn(
321 /// move |_| async move { priority },
322 /// schedule,
323 /// );
324 /// runnable.schedule();
325 /// task
326 /// };
327 ///
328 /// let t1 = spawn_task(1);
329 /// let t2 = spawn_task(2);
330 /// let t3 = spawn_task(3);
331 ///
332 /// // Run the tasks in order of priority.
333 /// let mut metadata_seen = vec![];
334 /// while let Some(TaskWrapper(runnable)) = EXECUTOR.lock().unwrap().pop() {
335 /// metadata_seen.push(*runnable.metadata());
336 /// runnable.run();
337 /// }
338 ///
339 /// assert_eq!(metadata_seen, vec![3, 2, 1]);
340 /// assert_eq!(t1.await, 1);
341 /// assert_eq!(t2.await, 2);
342 /// assert_eq!(t3.await, 3);
343 /// # });
344 /// ```
345 pub fn metadata<M>(self, metadata: M) -> Builder<M> {
346 Builder {
347 metadata,
348 #[cfg(feature = "std")]
349 propagate_panic: self.propagate_panic,
350 }
351 }
352}
353
354// Use a macro to brute force inlining to minimize stack copies of potentially
355// large futures.
356macro_rules! spawn_unchecked {
357 ($f:tt, $s:tt, $m:tt, $builder:ident, $schedule:ident, $raw:ident => $future:block) => {{
358 let ptr = allocate_task!($f, $s, $m, $builder, $schedule, $raw => $future);
359
360 #[allow(unused_unsafe)]
361 // SAFETY: The task was just allocated above.
362 let runnable = unsafe { Runnable::from_raw(ptr) };
363 let task = Task {
364 ptr,
365 _marker: PhantomData,
366 };
367 (runnable, task)
368 }};
369}
370
371impl<M> Builder<M> {
372 /// Propagates panics that occur in the task.
373 ///
374 /// When this is `true`, panics that occur in the task will be propagated to the caller of
375 /// the [`Task`]. When this is false, no special action is taken when a panic occurs in the
376 /// task, meaning that the caller of [`Runnable::run`] will observe a panic.
377 ///
378 /// This is only available when the `std` feature is enabled. By default, this is `false`.
379 ///
380 /// # Examples
381 ///
382 /// ```
383 /// use async_task::Builder;
384 /// use futures_lite::future::poll_fn;
385 /// use std::future::Future;
386 /// use std::panic;
387 /// use std::pin::Pin;
388 /// use std::task::{Context, Poll};
389 ///
390 /// fn did_panic<F: FnOnce()>(f: F) -> bool {
391 /// panic::catch_unwind(panic::AssertUnwindSafe(f)).is_err()
392 /// }
393 ///
394 /// # smol::future::block_on(async {
395 /// let (runnable1, mut task1) = Builder::new()
396 /// .propagate_panic(true)
397 /// .spawn(|()| async move { panic!() }, |_| {});
398 ///
399 /// let (runnable2, mut task2) = Builder::new()
400 /// .propagate_panic(false)
401 /// .spawn(|()| async move { panic!() }, |_| {});
402 ///
403 /// assert!(!did_panic(|| { runnable1.run(); }));
404 /// assert!(did_panic(|| { runnable2.run(); }));
405 ///
406 /// let waker = poll_fn(|cx| Poll::Ready(cx.waker().clone())).await;
407 /// let mut cx = Context::from_waker(&waker);
408 /// assert!(did_panic(|| { let _ = Pin::new(&mut task1).poll(&mut cx); }));
409 /// assert!(did_panic(|| { let _ = Pin::new(&mut task2).poll(&mut cx); }));
410 /// # });
411 /// ```
412 #[cfg(feature = "std")]
413 pub fn propagate_panic(self, propagate_panic: bool) -> Builder<M> {
414 Builder {
415 metadata: self.metadata,
416 propagate_panic,
417 }
418 }
419
420 /// Creates a new task.
421 ///
422 /// The returned [`Runnable`] is used to poll the `future`, and the [`Task`] is used to await its
423 /// output.
424 ///
425 /// Method [`run()`][`Runnable::run()`] polls the task's future once. Then, the [`Runnable`]
426 /// vanishes and only reappears when its [`Waker`] wakes the task, thus scheduling it to be run
427 /// again.
428 ///
429 /// When the task is woken, its [`Runnable`] is passed to the `schedule` function.
430 /// The `schedule` function should not attempt to run the [`Runnable`] nor to drop it. Instead, it
431 /// should push it into a task queue so that it can be processed later.
432 ///
433 /// If you need to spawn a future that does not implement [`Send`] or isn't `'static`, consider
434 /// using [`spawn_local()`] or [`spawn_unchecked()`] instead.
435 ///
436 /// # Examples
437 ///
438 /// ```
439 /// use async_task::Builder;
440 ///
441 /// // The future inside the task.
442 /// let future = async {
443 /// println!("Hello, world!");
444 /// };
445 ///
446 /// // A function that schedules the task when it gets woken up.
447 /// let (s, r) = flume::unbounded();
448 /// let schedule = move |runnable| s.send(runnable).unwrap();
449 ///
450 /// // Create a task with the future and the schedule function.
451 /// let (runnable, task) = Builder::new().spawn(|()| future, schedule);
452 /// ```
453 ///
454 /// Metadata that is `Send + Sync + 'static` still spawns:
455 ///
456 /// ```
457 /// use async_task::Builder;
458 ///
459 /// let (runnable, task) = Builder::new().metadata(1u32).spawn(
460 /// |meta| {
461 /// let value = *meta;
462 /// async move { value }
463 /// },
464 /// |_| {},
465 /// );
466 /// runnable.run();
467 /// assert_eq!(smol::future::block_on(task), 1);
468 /// ```
469 ///
470 /// ```compile_fail,E0277
471 /// use std::rc::Rc;
472 /// use async_task::Builder;
473 ///
474 /// let _ = Builder::new()
475 /// .metadata(Rc::new(1u8))
476 /// .spawn(|_| async {}, |_| {});
477 /// ```
478 ///
479 /// ```compile_fail,E0521
480 /// use async_task::Builder;
481 ///
482 /// fn spawn_borrowed(value: &u8) {
483 /// let _ = Builder::new()
484 /// .metadata(value)
485 /// .spawn(|_| async {}, |_| {});
486 /// }
487 /// ```
488 pub fn spawn<F, Fut, S>(self, future: F, schedule: S) -> (Runnable<M>, Task<Fut::Output, M>)
489 where
490 F: FnOnce(&M) -> Fut,
491 Fut: Future + Send + 'static,
492 Fut::Output: Send + 'static,
493 S: Schedule<M> + Send + Sync + 'static,
494 M: Send + Sync + 'static,
495 {
496 unsafe {
497 spawn_unchecked!(Fut, S, M, self, schedule, raw => { future(&(*raw.header).metadata) })
498 }
499 }
500
501 /// Creates a new thread-local task.
502 ///
503 /// This function is same as [`spawn()`], except it does not require [`Send`] on `future`. If the
504 /// [`Runnable`] is used or dropped on another thread, a panic will occur.
505 ///
506 /// This function is only available when the `std` feature for this crate is enabled.
507 ///
508 /// # Examples
509 ///
510 /// ```
511 /// use async_task::{Builder, Runnable};
512 /// use flume::{Receiver, Sender};
513 /// use std::rc::Rc;
514 ///
515 /// thread_local! {
516 /// // A queue that holds scheduled tasks.
517 /// static QUEUE: (Sender<Runnable>, Receiver<Runnable>) = flume::unbounded();
518 /// }
519 ///
520 /// // Make a non-Send future.
521 /// let msg: Rc<str> = "Hello, world!".into();
522 /// let future = async move {
523 /// println!("{}", msg);
524 /// };
525 ///
526 /// // A function that schedules the task when it gets woken up.
527 /// let s = QUEUE.with(|(s, _)| s.clone());
528 /// let schedule = move |runnable| s.send(runnable).unwrap();
529 ///
530 /// // Create a task with the future and the schedule function.
531 /// let (runnable, task) = Builder::new().spawn_local(move |()| future, schedule);
532 /// ```
533 ///
534 /// ```compile_fail,E0277
535 /// use std::rc::Rc;
536 /// use async_task::Builder;
537 ///
538 /// let _ = Builder::new()
539 /// .metadata(Rc::new(1u8))
540 /// .spawn_local(|_| async {}, |_| {});
541 /// ```
542 ///
543 /// ```compile_fail,E0521
544 /// use async_task::Builder;
545 ///
546 /// fn spawn_borrowed(value: &u8) {
547 /// let _ = Builder::new()
548 /// .metadata(value)
549 /// .spawn_local(|_| async {}, |_| {});
550 /// }
551 /// ```
552 #[cfg(feature = "std")]
553 pub fn spawn_local<F, Fut, S>(
554 self,
555 future: F,
556 schedule: S,
557 ) -> (Runnable<M>, Task<Fut::Output, M>)
558 where
559 F: FnOnce(&M) -> Fut,
560 Fut: Future + 'static,
561 Fut::Output: 'static,
562 S: Schedule<M> + Send + Sync + 'static,
563 M: Send + Sync + 'static,
564 {
565 use std::mem::ManuallyDrop;
566 use std::pin::Pin;
567 use std::task::{Context, Poll};
568 use std::thread::{self, ThreadId};
569
570 #[inline]
571 fn thread_id() -> ThreadId {
572 std::thread_local! {
573 static ID: ThreadId = thread::current().id();
574 }
575 ID.try_with(|id| *id)
576 .unwrap_or_else(|_| thread::current().id())
577 }
578
579 struct Checked<F> {
580 id: ThreadId,
581 inner: ManuallyDrop<F>,
582 }
583
584 impl<F> Drop for Checked<F> {
585 fn drop(&mut self) {
586 let id = self.id;
587 assert!(
588 id == thread_id(),
589 "local task dropped by a thread that didn't spawn it"
590 );
591 unsafe {
592 ManuallyDrop::drop(&mut self.inner);
593 }
594 }
595 }
596
597 impl<F: Future> Future for Checked<F> {
598 type Output = F::Output;
599
600 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
601 unsafe {
602 let me = self.get_unchecked_mut();
603 assert!(
604 me.id == thread_id(),
605 "local task polled by a thread that didn't spawn it"
606 );
607 Pin::new_unchecked(&mut *me.inner).poll(cx)
608 }
609 }
610 }
611
612 // Wrap the future into one that checks which thread it's on.
613 let future = move |meta| {
614 let future = future(meta);
615
616 Checked {
617 id: thread_id(),
618 inner: ManuallyDrop::new(future),
619 }
620 };
621
622 unsafe { self.spawn_unchecked(future, schedule) }
623 }
624
625 /// Creates a new task without [`Send`], [`Sync`], and `'static` bounds.
626 ///
627 /// This function is same as [`spawn()`], except it does not require [`Send`], [`Sync`], and
628 /// `'static` on `future`, `schedule`, and the metadata.
629 ///
630 /// # Safety
631 ///
632 /// - If `Fut` is not [`Send`], its [`Runnable`] must be used and dropped on the original
633 /// thread.
634 /// - If `Fut` is not `'static`, borrowed non-metadata variables must outlive its [`Runnable`].
635 /// - If `schedule` is not [`Send`] and [`Sync`], all instances of the [`Runnable`]'s [`Waker`]
636 /// must be used and dropped on the original thread.
637 /// - If `schedule` is not `'static`, borrowed variables must outlive all instances of the
638 /// [`Runnable`]'s [`Waker`].
639 /// - If `M` is not [`Send`] + [`Sync`], every waker must be used and dropped on the thread
640 /// that spawned the task, because a waker runs the schedule function and may drop `M`.
641 /// - If `M` is not `'static`, data borrowed by `M` must outlive the task allocation. A
642 /// [`Waker`] from [`Runnable::waker`] keeps that allocation, and `M`, alive after the
643 /// [`Runnable`] and [`Task`] have been dropped.
644 ///
645 /// # Examples
646 ///
647 /// ```
648 /// use async_task::Builder;
649 ///
650 /// // The future inside the task.
651 /// let future = async {
652 /// println!("Hello, world!");
653 /// };
654 ///
655 /// // If the task gets woken up, it will be sent into this channel.
656 /// let (s, r) = flume::unbounded();
657 /// let schedule = move |runnable| s.send(runnable).unwrap();
658 ///
659 /// // Create a task with the future and the schedule function.
660 /// let (runnable, task) = unsafe { Builder::new().spawn_unchecked(move |()| future, schedule) };
661 /// ```
662 pub unsafe fn spawn_unchecked<'a, F, Fut, S>(
663 self,
664 future: F,
665 schedule: S,
666 ) -> (Runnable<M>, Task<Fut::Output, M>)
667 where
668 F: FnOnce(&'a M) -> Fut,
669 Fut: Future + 'a,
670 S: Schedule<M>,
671 M: 'a,
672 {
673 spawn_unchecked!(Fut, S, M, self, schedule, raw => { future(&(*raw.header).metadata) })
674 }
675}
676
677/// Creates a new task.
678///
679/// The returned [`Runnable`] is used to poll the `future`, and the [`Task`] is used to await its
680/// output.
681///
682/// Method [`run()`][`Runnable::run()`] polls the task's future once. Then, the [`Runnable`]
683/// vanishes and only reappears when its [`Waker`] wakes the task, thus scheduling it to be run
684/// again.
685///
686/// When the task is woken, its [`Runnable`] is passed to the `schedule` function.
687/// The `schedule` function should not attempt to run the [`Runnable`] nor to drop it. Instead, it
688/// should push it into a task queue so that it can be processed later.
689///
690/// If you need to spawn a future that does not implement [`Send`] or isn't `'static`, consider
691/// using [`spawn_local()`] or [`spawn_unchecked()`] instead.
692///
693/// # Examples
694///
695/// ```
696/// // The future inside the task.
697/// let future = async {
698/// println!("Hello, world!");
699/// };
700///
701/// // A function that schedules the task when it gets woken up.
702/// let (s, r) = flume::unbounded();
703/// let schedule = move |runnable| s.send(runnable).unwrap();
704///
705/// // Create a task with the future and the schedule function.
706/// let (runnable, task) = async_task::spawn(future, schedule);
707/// ```
708pub fn spawn<F, S>(future: F, schedule: S) -> (Runnable, Task<F::Output>)
709where
710 F: Future + Send + 'static,
711 F::Output: Send + 'static,
712 S: Schedule + Send + Sync + 'static,
713{
714 let builder = Builder::new();
715 unsafe { spawn_unchecked!(F, S, (), builder, schedule, raw => { future }) }
716}
717
718/// Creates a new thread-local task.
719///
720/// This function is same as [`spawn()`], except it does not require [`Send`] on `future`. If the
721/// [`Runnable`] is used or dropped on another thread, a panic will occur.
722///
723/// This function is only available when the `std` feature for this crate is enabled.
724///
725/// # Examples
726///
727/// ```
728/// use async_task::Runnable;
729/// use flume::{Receiver, Sender};
730/// use std::rc::Rc;
731///
732/// thread_local! {
733/// // A queue that holds scheduled tasks.
734/// static QUEUE: (Sender<Runnable>, Receiver<Runnable>) = flume::unbounded();
735/// }
736///
737/// // Make a non-Send future.
738/// let msg: Rc<str> = "Hello, world!".into();
739/// let future = async move {
740/// println!("{}", msg);
741/// };
742///
743/// // A function that schedules the task when it gets woken up.
744/// let s = QUEUE.with(|(s, _)| s.clone());
745/// let schedule = move |runnable| s.send(runnable).unwrap();
746///
747/// // Create a task with the future and the schedule function.
748/// let (runnable, task) = async_task::spawn_local(future, schedule);
749/// ```
750#[cfg(feature = "std")]
751pub fn spawn_local<F, S>(future: F, schedule: S) -> (Runnable, Task<F::Output>)
752where
753 F: Future + 'static,
754 F::Output: 'static,
755 S: Schedule + Send + Sync + 'static,
756{
757 Builder::new().spawn_local(move |()| future, schedule)
758}
759
760/// Creates a new task without [`Send`], [`Sync`], and `'static` bounds.
761///
762/// This function is same as [`spawn()`], except it does not require [`Send`], [`Sync`], and
763/// `'static` on `future` and `schedule`.
764///
765/// # Safety
766///
767/// - If `future` is not [`Send`], its [`Runnable`] must be used and dropped on the original
768/// thread.
769/// - If `future` is not `'static`, borrowed variables must outlive its [`Runnable`].
770/// - If `schedule` is not [`Send`] and [`Sync`], all instances of the [`Runnable`]'s [`Waker`]
771/// must be used and dropped on the original thread.
772/// - If `schedule` is not `'static`, borrowed variables must outlive all instances of the
773/// [`Runnable`]'s [`Waker`].
774///
775/// # Examples
776///
777/// ```
778/// // The future inside the task.
779/// let future = async {
780/// println!("Hello, world!");
781/// };
782///
783/// // If the task gets woken up, it will be sent into this channel.
784/// let (s, r) = flume::unbounded();
785/// let schedule = move |runnable| s.send(runnable).unwrap();
786///
787/// // Create a task with the future and the schedule function.
788/// let (runnable, task) = unsafe { async_task::spawn_unchecked(future, schedule) };
789/// ```
790pub unsafe fn spawn_unchecked<F, S>(future: F, schedule: S) -> (Runnable, Task<F::Output>)
791where
792 F: Future,
793 S: Schedule,
794{
795 let builder = Builder::new();
796 spawn_unchecked!(F, S, (), builder, schedule, raw => { future })
797}
798
799/// A handle to a runnable task.
800///
801/// Every spawned task has a single [`Runnable`] handle, which only exists when the task is
802/// scheduled for running.
803///
804/// Method [`run()`][`Runnable::run()`] polls the task's future once. Then, the [`Runnable`]
805/// vanishes and only reappears when its [`Waker`] wakes the task, thus scheduling it to be run
806/// again.
807///
808/// Dropping a [`Runnable`] cancels the task, which means its future won't be polled again, and
809/// awaiting the [`Task`] after that will result in a panic.
810///
811/// # Examples
812///
813/// ```
814/// use async_task::Runnable;
815/// use once_cell::sync::Lazy;
816/// use std::{panic, thread};
817///
818/// // A simple executor.
819/// static QUEUE: Lazy<flume::Sender<Runnable>> = Lazy::new(|| {
820/// let (sender, receiver) = flume::unbounded::<Runnable>();
821/// thread::spawn(|| {
822/// for runnable in receiver {
823/// let _ignore_panic = panic::catch_unwind(|| runnable.run());
824/// }
825/// });
826/// sender
827/// });
828///
829/// // Create a task with a simple future.
830/// let schedule = |runnable| QUEUE.send(runnable).unwrap();
831/// let (runnable, task) = async_task::spawn(async { 1 + 2 }, schedule);
832///
833/// // Schedule the task and await its output.
834/// runnable.schedule();
835/// assert_eq!(smol::future::block_on(task), 3);
836/// ```
837pub struct Runnable<M = ()> {
838 /// A pointer to the heap-allocated task.
839 pub(crate) ptr: NonNull<()>,
840
841 /// A marker capturing generic type `M`.
842 pub(crate) _marker: PhantomData<M>,
843}
844
845unsafe impl<M: Send + Sync> Send for Runnable<M> {}
846unsafe impl<M: Send + Sync> Sync for Runnable<M> {}
847
848#[cfg(feature = "std")]
849impl<M> std::panic::UnwindSafe for Runnable<M> {}
850#[cfg(feature = "std")]
851impl<M> std::panic::RefUnwindSafe for Runnable<M> {}
852
853impl<M> Runnable<M> {
854 /// Get the metadata associated with this task.
855 ///
856 /// Tasks can be created with a metadata object associated with them; by default, this
857 /// is a `()` value. See the [`Builder::metadata()`] method for more information.
858 pub fn metadata(&self) -> &M {
859 &self.header_with_metadata().metadata
860 }
861
862 /// Schedules the task.
863 ///
864 /// This is a convenience method that passes the [`Runnable`] to the schedule function.
865 ///
866 /// # Examples
867 ///
868 /// ```
869 /// // A function that schedules the task when it gets woken up.
870 /// let (s, r) = flume::unbounded();
871 /// let schedule = move |runnable| s.send(runnable).unwrap();
872 ///
873 /// // Create a task with a simple future and the schedule function.
874 /// let (runnable, task) = async_task::spawn(async {}, schedule);
875 ///
876 /// // Schedule the task.
877 /// assert_eq!(r.len(), 0);
878 /// runnable.schedule();
879 /// assert_eq!(r.len(), 1);
880 /// # let handle = std::thread::spawn(move || { for runnable in r { runnable.run(); }});
881 /// # smol::future::block_on(task);
882 /// # handle.join().unwrap();
883 /// ```
884 pub fn schedule(self) {
885 let ptr = self.ptr.as_ptr();
886 let header = ptr as *const Header;
887 mem::forget(self);
888
889 unsafe {
890 ((*header).vtable.schedule)(ptr, ScheduleInfo::new(false));
891 }
892 }
893
894 /// Runs the task by polling its future.
895 ///
896 /// Returns `true` if the task was woken while running, in which case the [`Runnable`] gets
897 /// rescheduled at the end of this method invocation. Otherwise, returns `false` and the
898 /// [`Runnable`] vanishes until the task is woken.
899 /// The return value is just a hint: `true` usually indicates that the task has yielded, i.e.
900 /// it woke itself and then gave the control back to the executor.
901 ///
902 /// If the [`Task`] handle was dropped or if [`cancel()`][`Task::cancel()`] was called, then
903 /// this method simply destroys the task.
904 ///
905 /// If the polled future panics, this method propagates the panic, and awaiting the [`Task`]
906 /// after that will also result in a panic.
907 ///
908 /// # Examples
909 ///
910 /// ```
911 /// // A function that schedules the task when it gets woken up.
912 /// let (s, r) = flume::unbounded();
913 /// let schedule = move |runnable| s.send(runnable).unwrap();
914 ///
915 /// // Create a task with a simple future and the schedule function.
916 /// let (runnable, task) = async_task::spawn(async { 1 + 2 }, schedule);
917 ///
918 /// // Run the task and check its output.
919 /// runnable.run();
920 /// assert_eq!(smol::future::block_on(task), 3);
921 /// ```
922 pub fn run(self) -> bool {
923 let ptr = self.ptr.as_ptr();
924 let header = ptr as *const Header;
925 mem::forget(self);
926
927 unsafe { ((*header).vtable.run)(ptr) }
928 }
929
930 /// Returns a waker associated with this task.
931 ///
932 /// # Examples
933 ///
934 /// ```
935 /// use smol::future;
936 ///
937 /// // A function that schedules the task when it gets woken up.
938 /// let (s, r) = flume::unbounded();
939 /// let schedule = move |runnable| s.send(runnable).unwrap();
940 ///
941 /// // Create a task with a simple future and the schedule function.
942 /// let (runnable, task) = async_task::spawn(future::pending::<()>(), schedule);
943 ///
944 /// // Take a waker and run the task.
945 /// let waker = runnable.waker();
946 /// runnable.run();
947 ///
948 /// // Reschedule the task by waking it.
949 /// assert_eq!(r.len(), 0);
950 /// waker.wake();
951 /// assert_eq!(r.len(), 1);
952 /// # let handle = std::thread::spawn(move || { for runnable in r { runnable.run(); }});
953 /// # smol::future::block_on(task.cancel()); // cancel because the future is future::pending
954 /// # handle.join().unwrap();
955 /// ```
956 pub fn waker(&self) -> Waker {
957 unsafe {
958 let raw_waker = Header::clone_waker(self.ptr.as_ptr());
959 Waker::from_raw(raw_waker)
960 }
961 }
962
963 fn header(&self) -> &Header {
964 unsafe { &*(self.ptr.as_ptr() as *const Header) }
965 }
966
967 fn header_with_metadata(&self) -> &HeaderWithMetadata<M> {
968 unsafe { &*(self.ptr.as_ptr() as *const HeaderWithMetadata<M>) }
969 }
970
971 /// Converts this task into a raw pointer.
972 ///
973 /// To avoid a memory leak the pointer must be converted back to a Runnable using [`Runnable<M>::from_raw`][from_raw].
974 ///
975 /// `into_raw` does not change the state of the [`Task`], but there is no guarantee that it will be in the same state after calling [`Runnable<M>::from_raw`][from_raw],
976 /// as the corresponding [`Task`] might have been dropped or cancelled.
977 ///
978 /// # Examples
979 ///
980 /// ```rust
981 /// use async_task::{Runnable, spawn};
982 ///
983 /// let (runnable, task) = spawn(async {}, |_| {});
984 /// let runnable_pointer = runnable.into_raw();
985 ///
986 /// unsafe {
987 /// // Convert back to an `Runnable` to prevent leak.
988 /// let runnable = Runnable::<()>::from_raw(runnable_pointer);
989 /// runnable.run();
990 /// // Further calls to `Runnable::from_raw(runnable_pointer)` would be memory-unsafe.
991 /// }
992 /// // The memory was freed when `x` went out of scope above, so `runnable_pointer` is now dangling!
993 /// ```
994 /// [from_raw]: #method.from_raw
995 pub fn into_raw(self) -> NonNull<()> {
996 let ptr = self.ptr;
997 mem::forget(self);
998 ptr
999 }
1000
1001 /// Converts a raw pointer into a Runnable.
1002 ///
1003 /// # Safety
1004 ///
1005 /// This method should only be used with raw pointers returned from [`Runnable<M>::into_raw`][into_raw].
1006 /// It is not safe to use the provided pointer once it is passed to `from_raw`.
1007 /// Crucially, it is unsafe to call `from_raw` multiple times with the same pointer - even if the resulting [`Runnable`] is not used -
1008 /// as internally `async-task` uses reference counting.
1009 ///
1010 /// It is however safe to call [`Runnable<M>::into_raw`][into_raw] on a [`Runnable`] created with `from_raw` or
1011 /// after the [`Task`] associated with a given Runnable has been dropped or cancelled.
1012 ///
1013 /// The state of the [`Runnable`] created with `from_raw` is not specified.
1014 ///
1015 /// # Examples
1016 ///
1017 /// ```rust
1018 /// use async_task::{Runnable, spawn};
1019 ///
1020 /// let (runnable, task) = spawn(async {}, |_| {});
1021 /// let runnable_pointer = runnable.into_raw();
1022 ///
1023 /// drop(task);
1024 /// unsafe {
1025 /// // Convert back to an `Runnable` to prevent leak.
1026 /// let runnable = Runnable::<()>::from_raw(runnable_pointer);
1027 /// let did_poll = runnable.run();
1028 /// assert!(!did_poll);
1029 /// // Further calls to `Runnable::from_raw(runnable_pointer)` would be memory-unsafe.
1030 /// }
1031 /// // The memory was freed when `x` went out of scope above, so `runnable_pointer` is now dangling!
1032 /// ```
1033 ///
1034 /// [into_raw]: #method.into_raw
1035 pub unsafe fn from_raw(ptr: NonNull<()>) -> Self {
1036 Self {
1037 ptr,
1038 _marker: Default::default(),
1039 }
1040 }
1041}
1042
1043impl<M> Drop for Runnable<M> {
1044 fn drop(&mut self) {
1045 let ptr = self.ptr.as_ptr();
1046 let header = self.header();
1047
1048 unsafe {
1049 let mut state = header.state.load(Ordering::Acquire);
1050
1051 loop {
1052 // If the task has been completed or closed, it can't be canceled.
1053 if state & (COMPLETED | CLOSED) != 0 {
1054 break;
1055 }
1056
1057 // Mark the task as closed.
1058 match header.state.compare_exchange_weak(
1059 state,
1060 state | CLOSED,
1061 Ordering::AcqRel,
1062 Ordering::Acquire,
1063 ) {
1064 Ok(_) => break,
1065 Err(s) => state = s,
1066 }
1067 }
1068
1069 // Drop the future.
1070 (header.vtable.drop_future)(ptr, header.vtable.layout_info);
1071
1072 // Mark the task as unscheduled.
1073 let state = header.state.fetch_and(!SCHEDULED, Ordering::AcqRel);
1074
1075 // Notify the awaiter that the future has been dropped.
1076 if state & AWAITER != 0 {
1077 (*header).notify(None);
1078 }
1079
1080 // Drop the task reference.
1081 drop_ref(ptr);
1082 }
1083 }
1084}
1085
1086impl<M: fmt::Debug> fmt::Debug for Runnable<M> {
1087 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1088 let ptr = self.ptr.as_ptr();
1089 let header = ptr as *const HeaderWithMetadata<M>;
1090
1091 f.debug_struct("Runnable")
1092 .field("header", unsafe { &(*header) })
1093 .finish()
1094 }
1095}