Skip to main content

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}