1
1
use alloc:: alloc:: Layout as StdLayout ;
2
2
use core:: cell:: UnsafeCell ;
3
3
use core:: future:: Future ;
4
+ use core:: marker:: PhantomData ;
4
5
use core:: mem:: { self , ManuallyDrop } ;
5
6
use core:: pin:: Pin ;
6
7
use core:: ptr:: NonNull ;
@@ -64,9 +65,9 @@ pub(crate) struct TaskLayout {
64
65
}
65
66
66
67
/// Raw pointers to the fields inside a task.
67
- pub ( crate ) struct RawTask < F , T , S > {
68
+ pub ( crate ) struct RawTask < F , T , S , M > {
68
69
/// The task header.
69
- pub ( crate ) header : * const Header ,
70
+ pub ( crate ) header : * const Header < M > ,
70
71
71
72
/// The schedule function.
72
73
pub ( crate ) schedule : * const S ,
@@ -78,22 +79,22 @@ pub(crate) struct RawTask<F, T, S> {
78
79
pub ( crate ) output : * mut T ,
79
80
}
80
81
81
- impl < F , T , S > Copy for RawTask < F , T , S > { }
82
+ impl < F , T , S , M > Copy for RawTask < F , T , S , M > { }
82
83
83
- impl < F , T , S > Clone for RawTask < F , T , S > {
84
+ impl < F , T , S , M > Clone for RawTask < F , T , S , M > {
84
85
fn clone ( & self ) -> Self {
85
86
* self
86
87
}
87
88
}
88
89
89
- impl < F , T , S > RawTask < F , T , S > {
90
+ impl < F , T , S , M > RawTask < F , T , S , M > {
90
91
const TASK_LAYOUT : Option < TaskLayout > = Self :: eval_task_layout ( ) ;
91
92
92
93
/// Computes the memory layout for a task.
93
94
#[ inline]
94
95
const fn eval_task_layout ( ) -> Option < TaskLayout > {
95
96
// Compute the layouts for `Header`, `S`, `F`, and `T`.
96
- let layout_header = Layout :: new :: < Header > ( ) ;
97
+ let layout_header = Layout :: new :: < Header < M > > ( ) ;
97
98
let layout_s = Layout :: new :: < S > ( ) ;
98
99
let layout_f = Layout :: new :: < F > ( ) ;
99
100
let layout_r = Layout :: new :: < T > ( ) ;
@@ -119,10 +120,10 @@ impl<F, T, S> RawTask<F, T, S> {
119
120
}
120
121
}
121
122
122
- impl < F , T , S > RawTask < F , T , S >
123
+ impl < F , T , S , M > RawTask < F , T , S , M >
123
124
where
124
125
F : Future < Output = T > ,
125
- S : Fn ( Runnable ) ,
126
+ S : Fn ( Runnable < M > ) ,
126
127
{
127
128
const RAW_WAKER_VTABLE : RawWakerVTable = RawWakerVTable :: new (
128
129
Self :: clone_waker,
@@ -134,7 +135,15 @@ where
134
135
/// Allocates a task with the given `future` and `schedule` function.
135
136
///
136
137
/// It is assumed that initially only the `Runnable` and the `Task` exist.
137
- pub ( crate ) fn allocate ( future : F , schedule : S ) -> NonNull < ( ) > {
138
+ pub ( crate ) fn allocate < ' a , Gen : FnOnce ( & ' a M ) -> F > (
139
+ future : Gen ,
140
+ schedule : S ,
141
+ metadata : M ,
142
+ ) -> NonNull < ( ) >
143
+ where
144
+ F : ' a ,
145
+ M : ' a ,
146
+ {
138
147
// Compute the layout of the task for allocation. Abort if the computation fails.
139
148
//
140
149
// n.b. notgull: task_layout now automatically aborts instead of panicking
@@ -150,7 +159,7 @@ where
150
159
let raw = Self :: from_ptr ( ptr. as_ptr ( ) ) ;
151
160
152
161
// Write the header as the first field of the task.
153
- ( raw. header as * mut Header ) . write ( Header {
162
+ ( raw. header as * mut Header < M > ) . write ( Header {
154
163
state : AtomicUsize :: new ( SCHEDULED | TASK | REFERENCE ) ,
155
164
awaiter : UnsafeCell :: new ( None ) ,
156
165
vtable : & TaskVTable {
@@ -163,11 +172,15 @@ where
163
172
clone_waker : Self :: clone_waker,
164
173
layout_info : & Self :: TASK_LAYOUT ,
165
174
} ,
175
+ metadata,
166
176
} ) ;
167
177
168
178
// Write the schedule function as the third field of the task.
169
179
( raw. schedule as * mut S ) . write ( schedule) ;
170
180
181
+ // Generate the future, now that the metadata has been pinned in place.
182
+ let future = abort_on_panic ( || future ( & ( * raw. header ) . metadata ) ) ;
183
+
171
184
// Write the future as the fourth field of the task.
172
185
raw. future . write ( future) ;
173
186
@@ -183,7 +196,7 @@ where
183
196
184
197
unsafe {
185
198
Self {
186
- header : p as * const Header ,
199
+ header : p as * const Header < M > ,
187
200
schedule : p. add ( task_layout. offset_s ) as * const S ,
188
201
future : p. add ( task_layout. offset_f ) as * mut F ,
189
202
output : p. add ( task_layout. offset_r ) as * mut T ,
@@ -319,6 +332,7 @@ where
319
332
// still alive.
320
333
let task = Runnable {
321
334
ptr : NonNull :: new_unchecked ( ptr as * mut ( ) ) ,
335
+ _marker : PhantomData ,
322
336
} ;
323
337
( * raw. schedule ) ( task) ;
324
338
}
@@ -410,6 +424,7 @@ where
410
424
411
425
let task = Runnable {
412
426
ptr : NonNull :: new_unchecked ( ptr as * mut ( ) ) ,
427
+ _marker : PhantomData ,
413
428
} ;
414
429
( * raw. schedule ) ( task) ;
415
430
}
@@ -442,6 +457,9 @@ where
442
457
443
458
// We need a safeguard against panics because destructors can panic.
444
459
abort_on_panic ( || {
460
+ // Drop the header along with the metadata.
461
+ ( raw. header as * mut Header < M > ) . drop_in_place ( ) ;
462
+
445
463
// Drop the schedule function.
446
464
( raw. schedule as * mut S ) . drop_in_place ( ) ;
447
465
} ) ;
@@ -625,15 +643,15 @@ where
625
643
return false ;
626
644
627
645
/// A guard that closes the task if polling its future panics.
628
- struct Guard < F , T , S > ( RawTask < F , T , S > )
646
+ struct Guard < F , T , S , M > ( RawTask < F , T , S , M > )
629
647
where
630
648
F : Future < Output = T > ,
631
- S : Fn ( Runnable ) ;
649
+ S : Fn ( Runnable < M > ) ;
632
650
633
- impl < F , T , S > Drop for Guard < F , T , S >
651
+ impl < F , T , S , M > Drop for Guard < F , T , S , M >
634
652
where
635
653
F : Future < Output = T > ,
636
- S : Fn ( Runnable ) ,
654
+ S : Fn ( Runnable < M > ) ,
637
655
{
638
656
fn drop ( & mut self ) {
639
657
let raw = self . 0 ;
@@ -648,7 +666,7 @@ where
648
666
if state & CLOSED != 0 {
649
667
// The thread that closed the task didn't drop the future because it
650
668
// was running so now it's our responsibility to do so.
651
- RawTask :: < F , T , S > :: drop_future ( ptr) ;
669
+ RawTask :: < F , T , S , M > :: drop_future ( ptr) ;
652
670
653
671
// Mark the task as not running and not scheduled.
654
672
( * raw. header )
@@ -662,7 +680,7 @@ where
662
680
}
663
681
664
682
// Drop the task reference.
665
- RawTask :: < F , T , S > :: drop_ref ( ptr) ;
683
+ RawTask :: < F , T , S , M > :: drop_ref ( ptr) ;
666
684
667
685
// Notify the awaiter that the future has been dropped.
668
686
if let Some ( w) = awaiter {
@@ -680,7 +698,7 @@ where
680
698
) {
681
699
Ok ( state) => {
682
700
// Drop the future because the task is now closed.
683
- RawTask :: < F , T , S > :: drop_future ( ptr) ;
701
+ RawTask :: < F , T , S , M > :: drop_future ( ptr) ;
684
702
685
703
// Take the awaiter out.
686
704
let mut awaiter = None ;
@@ -689,7 +707,7 @@ where
689
707
}
690
708
691
709
// Drop the task reference.
692
- RawTask :: < F , T , S > :: drop_ref ( ptr) ;
710
+ RawTask :: < F , T , S , M > :: drop_ref ( ptr) ;
693
711
694
712
// Notify the awaiter that the future has been dropped.
695
713
if let Some ( w) = awaiter {
0 commit comments