1
1
use alloc:: alloc:: Layout ;
2
2
use core:: cell:: UnsafeCell ;
3
+ use core:: convert:: TryInto ;
3
4
use core:: future:: Future ;
4
5
use core:: mem:: { self , ManuallyDrop } ;
5
6
use core:: pin:: Pin ;
@@ -45,16 +46,22 @@ pub(crate) struct TaskVTable {
45
46
#[ derive( Clone , Copy ) ]
46
47
pub ( crate ) struct TaskLayout {
47
48
/// Memory layout of the whole task.
48
- pub ( crate ) layout : Layout ,
49
+ pub ( crate ) size : u32 ,
50
+ pub ( crate ) align : u32 ,
49
51
50
52
/// Offset into the task at which the schedule function is stored.
51
- pub ( crate ) offset_s : usize ,
53
+ pub ( crate ) offset_schedule : u32 ,
52
54
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
+ }
55
58
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
+ }
58
65
}
59
66
60
67
/// Raw pointers to the fields inside a task.
@@ -101,15 +108,14 @@ where
101
108
102
109
unsafe {
103
110
// 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 ( ) ) {
105
112
None => abort ( ) ,
106
113
Some ( p) => p,
107
114
} ;
108
115
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 {
113
119
state : AtomicUsize :: new ( SCHEDULED | TASK | REFERENCE ) ,
114
120
awaiter : UnsafeCell :: new ( None ) ,
115
121
vtable : & TaskVTable {
@@ -121,8 +127,11 @@ where
121
127
run : Self :: run,
122
128
clone_waker : Self :: clone_waker,
123
129
} ,
130
+ layout : task_layout,
124
131
} ) ;
125
132
133
+ let raw = Self :: from_ptr ( ptr. as_ptr ( ) ) ;
134
+
126
135
// Write the schedule function as the third field of the task.
127
136
( raw. schedule as * mut S ) . write ( schedule) ;
128
137
@@ -136,15 +145,18 @@ where
136
145
/// Creates a `RawTask` from a raw task pointer.
137
146
#[ inline]
138
147
pub ( crate ) fn from_ptr ( ptr : * const ( ) ) -> Self {
139
- let task_layout = Self :: task_layout ( ) ;
140
148
let p = ptr as * const u8 ;
149
+ let p_header = p as * const Header ;
141
150
142
151
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
+
143
155
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 ,
148
160
}
149
161
}
150
162
}
@@ -165,16 +177,20 @@ where
165
177
166
178
// Compute the layout for `Header` followed `S` and `union { F, T }`.
167
179
let layout = layout_header;
168
- let ( layout, offset_s ) = extend ( layout, layout_s) ;
180
+ let ( layout, offset_schedule ) = extend ( layout, layout_s) ;
169
181
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 ( ) ;
172
188
173
189
TaskLayout {
174
- layout ,
175
- offset_s ,
176
- offset_f ,
177
- offset_r ,
190
+ size ,
191
+ align ,
192
+ offset_schedule ,
193
+ offset_future_or_output ,
178
194
}
179
195
}
180
196
@@ -416,7 +432,6 @@ where
416
432
#[ inline]
417
433
unsafe fn destroy ( ptr : * const ( ) ) {
418
434
let raw = Self :: from_ptr ( ptr) ;
419
- let task_layout = Self :: task_layout ( ) ;
420
435
421
436
// We need a safeguard against panics because destructors can panic.
422
437
abort_on_panic ( || {
@@ -425,7 +440,7 @@ where
425
440
} ) ;
426
441
427
442
// 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 ( ) ) ;
429
444
}
430
445
431
446
/// Runs a task.
0 commit comments