@@ -13,6 +13,12 @@ use crate::state::*;
1313use crate :: utils:: { abort, abort_on_panic, max, Layout } ;
1414use crate :: Runnable ;
1515
16+ #[ cfg( feature = "std" ) ]
17+ pub ( crate ) type Panic = alloc:: boxed:: Box < dyn core:: any:: Any + Send + ' static > ;
18+
19+ #[ cfg( not( feature = "std" ) ) ]
20+ pub ( crate ) type Panic = core:: convert:: Infallible ;
21+
1622/// The vtable for a task.
1723pub ( crate ) struct TaskVTable {
1824 /// Schedules the task.
@@ -76,7 +82,7 @@ pub(crate) struct RawTask<F, T, S, M> {
7682 pub ( crate ) future : * mut F ,
7783
7884 /// The output of the future.
79- pub ( crate ) output : * mut T ,
85+ pub ( crate ) output : * mut Result < T , Panic > ,
8086}
8187
8288impl < F , T , S , M > Copy for RawTask < F , T , S , M > { }
@@ -97,7 +103,7 @@ impl<F, T, S, M> RawTask<F, T, S, M> {
97103 let layout_header = Layout :: new :: < Header < M > > ( ) ;
98104 let layout_s = Layout :: new :: < S > ( ) ;
99105 let layout_f = Layout :: new :: < F > ( ) ;
100- let layout_r = Layout :: new :: < T > ( ) ;
106+ let layout_r = Layout :: new :: < Result < T , Panic > > ( ) ;
101107
102108 // Compute the layout for `union { F, T }`.
103109 let size_union = max ( layout_f. size ( ) , layout_r. size ( ) ) ;
@@ -138,7 +144,7 @@ where
138144 pub ( crate ) fn allocate < ' a , Gen : FnOnce ( & ' a M ) -> F > (
139145 future : Gen ,
140146 schedule : S ,
141- metadata : M ,
147+ builder : crate :: Builder < M > ,
142148 ) -> NonNull < ( ) >
143149 where
144150 F : ' a ,
@@ -158,6 +164,12 @@ where
158164
159165 let raw = Self :: from_ptr ( ptr. as_ptr ( ) ) ;
160166
167+ let crate :: Builder {
168+ metadata,
169+ #[ cfg( feature = "std" ) ]
170+ propagate_panic,
171+ } = builder;
172+
161173 // Write the header as the first field of the task.
162174 ( raw. header as * mut Header < M > ) . write ( Header {
163175 state : AtomicUsize :: new ( SCHEDULED | TASK | REFERENCE ) ,
@@ -173,6 +185,8 @@ where
173185 layout_info : & Self :: TASK_LAYOUT ,
174186 } ,
175187 metadata,
188+ #[ cfg( feature = "std" ) ]
189+ propagate_panic,
176190 } ) ;
177191
178192 // Write the schedule function as the third field of the task.
@@ -199,7 +213,7 @@ where
199213 header : p as * const Header < M > ,
200214 schedule : p. add ( task_layout. offset_s ) as * const S ,
201215 future : p. add ( task_layout. offset_f ) as * mut F ,
202- output : p. add ( task_layout. offset_r ) as * mut T ,
216+ output : p. add ( task_layout. offset_r ) as * mut Result < T , Panic > ,
203217 }
204218 }
205219 }
@@ -525,8 +539,30 @@ where
525539
526540 // Poll the inner future, but surround it with a guard that closes the task in case polling
527541 // panics.
542+ // If available, we should also try to catch the panic so that it is propagated correctly.
528543 let guard = Guard ( raw) ;
529- let poll = <F as Future >:: poll ( Pin :: new_unchecked ( & mut * raw. future ) , cx) ;
544+
545+ // Panic propagation is not available for no_std.
546+ #[ cfg( not( feature = "std" ) ) ]
547+ let poll = <F as Future >:: poll ( Pin :: new_unchecked ( & mut * raw. future ) , cx) . map ( Ok ) ;
548+
549+ #[ cfg( feature = "std" ) ]
550+ let poll = {
551+ // Check if we should propagate panics.
552+ if ( * raw. header ) . propagate_panic {
553+ // Use catch_unwind to catch the panic.
554+ match std:: panic:: catch_unwind ( std:: panic:: AssertUnwindSafe ( || {
555+ <F as Future >:: poll ( Pin :: new_unchecked ( & mut * raw. future ) , cx)
556+ } ) ) {
557+ Ok ( Poll :: Ready ( v) ) => Poll :: Ready ( Ok ( v) ) ,
558+ Ok ( Poll :: Pending ) => Poll :: Pending ,
559+ Err ( e) => Poll :: Ready ( Err ( e) ) ,
560+ }
561+ } else {
562+ <F as Future >:: poll ( Pin :: new_unchecked ( & mut * raw. future ) , cx) . map ( Ok )
563+ }
564+ } ;
565+
530566 mem:: forget ( guard) ;
531567
532568 match poll {
0 commit comments