11use alloc:: alloc:: Layout ;
22use core:: cell:: UnsafeCell ;
3+ use core:: convert:: TryInto ;
34use core:: future:: Future ;
45use core:: mem:: { self , ManuallyDrop } ;
56use core:: pin:: Pin ;
@@ -45,16 +46,22 @@ pub(crate) struct TaskVTable {
4546#[ derive( Clone , Copy ) ]
4647pub ( crate ) struct TaskLayout {
4748 /// Memory layout of the whole task.
48- pub ( crate ) layout : Layout ,
49+ pub ( crate ) size : u32 ,
50+ pub ( crate ) align : u32 ,
4951
5052 /// Offset into the task at which the schedule function is stored.
51- pub ( crate ) offset_s : usize ,
53+ pub ( crate ) offset_schedule : u32 ,
5254
53- /// Offset into the task at which the future is stored.
54- pub ( crate ) offset_f : usize ,
55+ /// Offset into the task at which the future or the output is stored.
56+ pub ( crate ) offset_future_or_output : u32 ,
57+ }
5558
56- /// Offset into the task at which the output is stored.
57- pub ( crate ) offset_r : usize ,
59+ impl TaskLayout {
60+ #[ inline]
61+ fn layout ( self ) -> Layout {
62+ // This is safe because `size` and `align` always come for a valid `Layout` value.
63+ unsafe { Layout :: from_size_align_unchecked ( self . size as usize , self . align as usize ) }
64+ }
5865}
5966
6067/// Raw pointers to the fields inside a task.
@@ -101,15 +108,14 @@ where
101108
102109 unsafe {
103110 // Allocate enough space for the entire task.
104- let ptr = match NonNull :: new ( alloc:: alloc:: alloc ( task_layout. layout ) as * mut ( ) ) {
111+ let ptr = match NonNull :: new ( alloc:: alloc:: alloc ( task_layout. layout ( ) ) as * mut ( ) ) {
105112 None => abort ( ) ,
106113 Some ( p) => p,
107114 } ;
108115
109- let raw = Self :: from_ptr ( ptr. as_ptr ( ) ) ;
110-
111- // Write the header as the first field of the task.
112- ( raw. header as * mut Header ) . write ( Header {
116+ // Write the header as the first field of the task. The header must be initialized
117+ // before `Self::from_ptr()` can be called.
118+ ( ptr. as_ptr ( ) as * mut Header ) . write ( Header {
113119 state : AtomicUsize :: new ( SCHEDULED | TASK | REFERENCE ) ,
114120 awaiter : UnsafeCell :: new ( None ) ,
115121 vtable : & TaskVTable {
@@ -121,8 +127,11 @@ where
121127 run : Self :: run,
122128 clone_waker : Self :: clone_waker,
123129 } ,
130+ layout : task_layout,
124131 } ) ;
125132
133+ let raw = Self :: from_ptr ( ptr. as_ptr ( ) ) ;
134+
126135 // Write the schedule function as the third field of the task.
127136 ( raw. schedule as * mut S ) . write ( schedule) ;
128137
@@ -136,15 +145,18 @@ where
136145 /// Creates a `RawTask` from a raw task pointer.
137146 #[ inline]
138147 pub ( crate ) fn from_ptr ( ptr : * const ( ) ) -> Self {
139- let task_layout = Self :: task_layout ( ) ;
140148 let p = ptr as * const u8 ;
149+ let p_header = p as * const Header ;
141150
142151 unsafe {
152+ let offset_schedule = ( * p_header) . layout . offset_schedule as usize ;
153+ let offset_future_or_output = ( * p_header) . layout . offset_future_or_output as usize ;
154+
143155 Self {
144- header : p as * const Header ,
145- schedule : p. add ( task_layout . offset_s ) as * const S ,
146- future : p. add ( task_layout . offset_f ) as * mut F ,
147- output : p. add ( task_layout . offset_r ) as * mut T ,
156+ header : p_header ,
157+ schedule : p. add ( offset_schedule ) as * const S ,
158+ future : p. add ( offset_future_or_output ) as * mut F ,
159+ output : p. add ( offset_future_or_output ) as * mut T ,
148160 }
149161 }
150162 }
@@ -165,16 +177,20 @@ where
165177
166178 // Compute the layout for `Header` followed `S` and `union { F, T }`.
167179 let layout = layout_header;
168- let ( layout, offset_s ) = extend ( layout, layout_s) ;
180+ let ( layout, offset_schedule ) = extend ( layout, layout_s) ;
169181 let ( layout, offset_union) = extend ( layout, layout_union) ;
170- let offset_f = offset_union;
171- let offset_r = offset_union;
182+
183+ // Converting to `u32` is unlikely to fail.
184+ let size: u32 = layout. size ( ) . try_into ( ) . unwrap ( ) ;
185+ let align: u32 = layout. align ( ) . try_into ( ) . unwrap ( ) ;
186+ let offset_schedule: u32 = offset_schedule. try_into ( ) . unwrap ( ) ;
187+ let offset_future_or_output: u32 = offset_union. try_into ( ) . unwrap ( ) ;
172188
173189 TaskLayout {
174- layout ,
175- offset_s ,
176- offset_f ,
177- offset_r ,
190+ size ,
191+ align ,
192+ offset_schedule ,
193+ offset_future_or_output ,
178194 }
179195 }
180196
@@ -416,7 +432,6 @@ where
416432 #[ inline]
417433 unsafe fn destroy ( ptr : * const ( ) ) {
418434 let raw = Self :: from_ptr ( ptr) ;
419- let task_layout = Self :: task_layout ( ) ;
420435
421436 // We need a safeguard against panics because destructors can panic.
422437 abort_on_panic ( || {
@@ -425,7 +440,7 @@ where
425440 } ) ;
426441
427442 // Finally, deallocate the memory reserved by the task.
428- alloc:: alloc:: dealloc ( ptr as * mut u8 , task_layout . layout ) ;
443+ alloc:: alloc:: dealloc ( ptr as * mut u8 , ( * raw . header ) . layout . layout ( ) ) ;
429444 }
430445
431446 /// Runs a task.
0 commit comments