1use crate::future::Future;
2use crate::runtime::task::core::{Core, Trailer};
3use crate::runtime::task::{Cell, Harness, Header, Id, Schedule, State};
4#[cfg(tokio_unstable)]
5use std::panic::Location;
6use std::ptr::NonNull;
7use std::task::{Poll, Waker};
8
9#[derive(Clone)]
11pub(crate) struct RawTask {
12 ptr: NonNull<Header>,
13}
14
15pub(super) struct Vtable {
16 pub(super) poll: unsafe fn(NonNull<Header>),
18
19 pub(super) schedule: unsafe fn(NonNull<Header>),
21
22 pub(super) dealloc: unsafe fn(NonNull<Header>),
24
25 pub(super) try_read_output: unsafe fn(NonNull<Header>, *mut (), &Waker),
27
28 pub(super) drop_join_handle_slow: unsafe fn(NonNull<Header>),
30
31 pub(super) drop_abort_handle: unsafe fn(NonNull<Header>),
33
34 pub(super) shutdown: unsafe fn(NonNull<Header>),
36
37 pub(super) trailer_offset: usize,
39
40 pub(super) scheduler_offset: usize,
42
43 pub(super) id_offset: usize,
45
46 #[cfg(tokio_unstable)]
48 pub(super) spawn_location_offset: usize,
49}
50
51pub(super) fn vtable<T: Future, S: Schedule>() -> &'static Vtable {
53 &Vtable {
54 poll: poll::<T, S>,
55 schedule: schedule::<S>,
56 dealloc: dealloc::<T, S>,
57 try_read_output: try_read_output::<T, S>,
58 drop_join_handle_slow: drop_join_handle_slow::<T, S>,
59 drop_abort_handle: drop_abort_handle::<T, S>,
60 shutdown: shutdown::<T, S>,
61 trailer_offset: OffsetHelper::<T, S>::TRAILER_OFFSET,
62 scheduler_offset: OffsetHelper::<T, S>::SCHEDULER_OFFSET,
63 id_offset: OffsetHelper::<T, S>::ID_OFFSET,
64 #[cfg(tokio_unstable)]
65 spawn_location_offset: OffsetHelper::<T, S>::SPAWN_LOCATION_OFFSET,
66 }
67}
68
69struct OffsetHelper<T, S>(T, S);
75impl<T: Future, S: Schedule> OffsetHelper<T, S> {
76 const TRAILER_OFFSET: usize = get_trailer_offset(
80 std::mem::size_of::<Header>(),
81 std::mem::size_of::<Core<T, S>>(),
82 std::mem::align_of::<Core<T, S>>(),
83 std::mem::align_of::<Trailer>(),
84 );
85
86 const SCHEDULER_OFFSET: usize = get_core_offset(
89 std::mem::size_of::<Header>(),
90 std::mem::align_of::<Core<T, S>>(),
91 );
92
93 const ID_OFFSET: usize = get_id_offset(
94 std::mem::size_of::<Header>(),
95 std::mem::align_of::<Core<T, S>>(),
96 std::mem::size_of::<S>(),
97 std::mem::align_of::<Id>(),
98 );
99
100 #[cfg(tokio_unstable)]
101 const SPAWN_LOCATION_OFFSET: usize = get_spawn_location_offset(
102 std::mem::size_of::<Header>(),
103 std::mem::align_of::<Core<T, S>>(),
104 std::mem::size_of::<S>(),
105 std::mem::align_of::<Id>(),
106 std::mem::size_of::<Id>(),
107 std::mem::align_of::<&'static Location<'static>>(),
108 );
109}
110
111const fn get_trailer_offset(
117 header_size: usize,
118 core_size: usize,
119 core_align: usize,
120 trailer_align: usize,
121) -> usize {
122 let mut offset = header_size;
123
124 let core_misalign = offset % core_align;
125 if core_misalign > 0 {
126 offset += core_align - core_misalign;
127 }
128 offset += core_size;
129
130 let trailer_misalign = offset % trailer_align;
131 if trailer_misalign > 0 {
132 offset += trailer_align - trailer_misalign;
133 }
134
135 offset
136}
137
138const fn get_core_offset(header_size: usize, core_align: usize) -> usize {
144 let mut offset = header_size;
145
146 let core_misalign = offset % core_align;
147 if core_misalign > 0 {
148 offset += core_align - core_misalign;
149 }
150
151 offset
152}
153
154const fn get_id_offset(
160 header_size: usize,
161 core_align: usize,
162 scheduler_size: usize,
163 id_align: usize,
164) -> usize {
165 let mut offset = get_core_offset(header_size, core_align);
166 offset += scheduler_size;
167
168 let id_misalign = offset % id_align;
169 if id_misalign > 0 {
170 offset += id_align - id_misalign;
171 }
172
173 offset
174}
175
176#[cfg(tokio_unstable)]
182const fn get_spawn_location_offset(
183 header_size: usize,
184 core_align: usize,
185 scheduler_size: usize,
186 id_align: usize,
187 id_size: usize,
188 spawn_location_align: usize,
189) -> usize {
190 let mut offset = get_id_offset(header_size, core_align, scheduler_size, id_align);
191 offset += id_size;
192
193 let spawn_location_misalign = offset % spawn_location_align;
194 if spawn_location_misalign > 0 {
195 offset += spawn_location_align - spawn_location_misalign;
196 }
197
198 offset
199}
200
201impl RawTask {
202 pub(super) fn new<T, S>(
203 task: T,
204 scheduler: S,
205 id: Id,
206 _spawned_at: super::SpawnLocation,
207 ) -> RawTask
208 where
209 T: Future,
210 S: Schedule,
211 {
212 let ptr = Box::into_raw(Cell::<_, S>::new(
213 task,
214 scheduler,
215 State::new(),
216 id,
217 #[cfg(tokio_unstable)]
218 _spawned_at.0,
219 ));
220 let ptr = unsafe { NonNull::new_unchecked(ptr.cast()) };
221
222 RawTask { ptr }
223 }
224
225 pub(super) unsafe fn from_raw(ptr: NonNull<Header>) -> RawTask {
226 RawTask { ptr }
227 }
228
229 pub(super) fn header_ptr(&self) -> NonNull<Header> {
230 self.ptr
231 }
232
233 pub(super) fn trailer_ptr(&self) -> NonNull<Trailer> {
234 unsafe { Header::get_trailer(self.ptr) }
235 }
236
237 pub(super) fn header(&self) -> &Header {
239 unsafe { self.ptr.as_ref() }
240 }
241
242 pub(super) fn trailer(&self) -> &Trailer {
244 unsafe { &*self.trailer_ptr().as_ptr() }
245 }
246
247 pub(super) fn state(&self) -> &State {
249 &self.header().state
250 }
251
252 pub(crate) fn poll(self) {
254 let vtable = self.header().vtable;
255 unsafe { (vtable.poll)(self.ptr) }
256 }
257
258 pub(super) fn schedule(self) {
259 let vtable = self.header().vtable;
260 unsafe { (vtable.schedule)(self.ptr) }
261 }
262
263 pub(super) fn dealloc(self) {
264 let vtable = self.header().vtable;
265 unsafe {
266 (vtable.dealloc)(self.ptr);
267 }
268 }
269
270 pub(super) unsafe fn try_read_output(self, dst: *mut (), waker: &Waker) {
273 let vtable = self.header().vtable;
274 (vtable.try_read_output)(self.ptr, dst, waker);
275 }
276
277 pub(super) fn drop_join_handle_slow(self) {
278 let vtable = self.header().vtable;
279 unsafe { (vtable.drop_join_handle_slow)(self.ptr) }
280 }
281
282 pub(super) fn drop_abort_handle(self) {
283 let vtable = self.header().vtable;
284 unsafe { (vtable.drop_abort_handle)(self.ptr) }
285 }
286
287 pub(super) fn shutdown(self) {
288 let vtable = self.header().vtable;
289 unsafe { (vtable.shutdown)(self.ptr) }
290 }
291
292 pub(super) fn ref_inc(self) {
296 self.header().state.ref_inc();
297 }
298
299 pub(crate) unsafe fn get_queue_next(self) -> Option<RawTask> {
305 self.header()
306 .queue_next
307 .with(|ptr| *ptr)
308 .map(|p| RawTask::from_raw(p))
309 }
310
311 pub(crate) unsafe fn set_queue_next(self, val: Option<RawTask>) {
317 self.header().set_next(val.map(|task| task.ptr));
318 }
319}
320
321impl Copy for RawTask {}
322
323unsafe fn poll<T: Future, S: Schedule>(ptr: NonNull<Header>) {
324 let harness = Harness::<T, S>::from_raw(ptr);
325 harness.poll();
326}
327
328unsafe fn schedule<S: Schedule>(ptr: NonNull<Header>) {
329 use crate::runtime::task::{Notified, Task};
330
331 let scheduler = Header::get_scheduler::<S>(ptr);
332 scheduler
333 .as_ref()
334 .schedule(Notified(Task::from_raw(ptr.cast())));
335}
336
337unsafe fn dealloc<T: Future, S: Schedule>(ptr: NonNull<Header>) {
338 let harness = Harness::<T, S>::from_raw(ptr);
339 harness.dealloc();
340}
341
342unsafe fn try_read_output<T: Future, S: Schedule>(
343 ptr: NonNull<Header>,
344 dst: *mut (),
345 waker: &Waker,
346) {
347 let out = &mut *(dst as *mut Poll<super::Result<T::Output>>);
348
349 let harness = Harness::<T, S>::from_raw(ptr);
350 harness.try_read_output(out, waker);
351}
352
353unsafe fn drop_join_handle_slow<T: Future, S: Schedule>(ptr: NonNull<Header>) {
354 let harness = Harness::<T, S>::from_raw(ptr);
355 harness.drop_join_handle_slow();
356}
357
358unsafe fn drop_abort_handle<T: Future, S: Schedule>(ptr: NonNull<Header>) {
359 let harness = Harness::<T, S>::from_raw(ptr);
360 harness.drop_reference();
361}
362
363unsafe fn shutdown<T: Future, S: Schedule>(ptr: NonNull<Header>) {
364 let harness = Harness::<T, S>::from_raw(ptr);
365 harness.shutdown();
366}