1#![allow(unsafe_op_in_unsafe_fn)]
9
10use crate::future::Future;
11use crate::runtime::task::core::{Core, Trailer};
12use crate::runtime::task::{Cell, Harness, Header, Id, Schedule, State};
13#[cfg(tokio_unstable)]
14use std::panic::Location;
15use std::ptr::NonNull;
16use std::task::{Poll, Waker};
17
18#[derive(Clone)]
20pub(crate) struct RawTask {
21 ptr: NonNull<Header>,
22}
23
24pub(super) struct Vtable {
25 pub(super) poll: unsafe fn(NonNull<Header>),
27
28 pub(super) schedule: unsafe fn(NonNull<Header>),
30
31 pub(super) dealloc: unsafe fn(NonNull<Header>),
33
34 pub(super) try_read_output: unsafe fn(NonNull<Header>, *mut (), &Waker),
36
37 pub(super) drop_join_handle_slow: unsafe fn(NonNull<Header>),
39
40 pub(super) drop_abort_handle: unsafe fn(NonNull<Header>),
42
43 pub(super) shutdown: unsafe fn(NonNull<Header>),
45
46 pub(super) trailer_offset: usize,
48
49 pub(super) scheduler_offset: usize,
51
52 pub(super) id_offset: usize,
54
55 #[cfg(tokio_unstable)]
57 pub(super) spawn_location_offset: usize,
58}
59
60pub(super) fn vtable<T: Future, S: Schedule>() -> &'static Vtable {
62 &Vtable {
63 poll: poll::<T, S>,
64 schedule: schedule::<S>,
65 dealloc: dealloc::<T, S>,
66 try_read_output: try_read_output::<T, S>,
67 drop_join_handle_slow: drop_join_handle_slow::<T, S>,
68 drop_abort_handle: drop_abort_handle::<T, S>,
69 shutdown: shutdown::<T, S>,
70 trailer_offset: OffsetHelper::<T, S>::TRAILER_OFFSET,
71 scheduler_offset: OffsetHelper::<T, S>::SCHEDULER_OFFSET,
72 id_offset: OffsetHelper::<T, S>::ID_OFFSET,
73 #[cfg(tokio_unstable)]
74 spawn_location_offset: OffsetHelper::<T, S>::SPAWN_LOCATION_OFFSET,
75 }
76}
77
78struct OffsetHelper<T, S>(T, S);
84impl<T: Future, S: Schedule> OffsetHelper<T, S> {
85 const TRAILER_OFFSET: usize = get_trailer_offset(
89 std::mem::size_of::<Header>(),
90 std::mem::size_of::<Core<T, S>>(),
91 std::mem::align_of::<Core<T, S>>(),
92 std::mem::align_of::<Trailer>(),
93 );
94
95 const SCHEDULER_OFFSET: usize = get_core_offset(
98 std::mem::size_of::<Header>(),
99 std::mem::align_of::<Core<T, S>>(),
100 );
101
102 const ID_OFFSET: usize = get_id_offset(
103 std::mem::size_of::<Header>(),
104 std::mem::align_of::<Core<T, S>>(),
105 std::mem::size_of::<S>(),
106 std::mem::align_of::<Id>(),
107 );
108
109 #[cfg(tokio_unstable)]
110 const SPAWN_LOCATION_OFFSET: usize = get_spawn_location_offset(
111 std::mem::size_of::<Header>(),
112 std::mem::align_of::<Core<T, S>>(),
113 std::mem::size_of::<S>(),
114 std::mem::align_of::<Id>(),
115 std::mem::size_of::<Id>(),
116 std::mem::align_of::<&'static Location<'static>>(),
117 );
118}
119
120const fn get_trailer_offset(
126 header_size: usize,
127 core_size: usize,
128 core_align: usize,
129 trailer_align: usize,
130) -> usize {
131 let mut offset = header_size;
132
133 let core_misalign = offset % core_align;
134 if core_misalign > 0 {
135 offset += core_align - core_misalign;
136 }
137 offset += core_size;
138
139 let trailer_misalign = offset % trailer_align;
140 if trailer_misalign > 0 {
141 offset += trailer_align - trailer_misalign;
142 }
143
144 offset
145}
146
147const fn get_core_offset(header_size: usize, core_align: usize) -> usize {
153 let mut offset = header_size;
154
155 let core_misalign = offset % core_align;
156 if core_misalign > 0 {
157 offset += core_align - core_misalign;
158 }
159
160 offset
161}
162
163const fn get_id_offset(
169 header_size: usize,
170 core_align: usize,
171 scheduler_size: usize,
172 id_align: usize,
173) -> usize {
174 let mut offset = get_core_offset(header_size, core_align);
175 offset += scheduler_size;
176
177 let id_misalign = offset % id_align;
178 if id_misalign > 0 {
179 offset += id_align - id_misalign;
180 }
181
182 offset
183}
184
185#[cfg(tokio_unstable)]
191const fn get_spawn_location_offset(
192 header_size: usize,
193 core_align: usize,
194 scheduler_size: usize,
195 id_align: usize,
196 id_size: usize,
197 spawn_location_align: usize,
198) -> usize {
199 let mut offset = get_id_offset(header_size, core_align, scheduler_size, id_align);
200 offset += id_size;
201
202 let spawn_location_misalign = offset % spawn_location_align;
203 if spawn_location_misalign > 0 {
204 offset += spawn_location_align - spawn_location_misalign;
205 }
206
207 offset
208}
209
210impl RawTask {
211 pub(super) fn new<T, S>(
212 task: T,
213 scheduler: S,
214 id: Id,
215 _spawned_at: super::SpawnLocation,
216 ) -> RawTask
217 where
218 T: Future,
219 S: Schedule,
220 {
221 let ptr = Box::into_raw(Cell::<_, S>::new(
222 task,
223 scheduler,
224 State::new(),
225 id,
226 #[cfg(tokio_unstable)]
227 _spawned_at.0,
228 ));
229 let ptr = unsafe { NonNull::new_unchecked(ptr.cast()) };
230
231 RawTask { ptr }
232 }
233
234 pub(super) unsafe fn from_raw(ptr: NonNull<Header>) -> RawTask {
238 RawTask { ptr }
239 }
240
241 pub(super) fn header_ptr(&self) -> NonNull<Header> {
242 self.ptr
243 }
244
245 cfg_taskdump! {
246 pub(super) fn header_ptr_ref(&self) -> &NonNull<Header> {
247 &self.ptr
248 }
249 }
250
251 pub(super) fn trailer_ptr(&self) -> NonNull<Trailer> {
252 unsafe { Header::get_trailer(self.ptr) }
253 }
254
255 pub(super) fn header(&self) -> &Header {
257 unsafe { self.ptr.as_ref() }
258 }
259
260 pub(super) fn trailer(&self) -> &Trailer {
262 unsafe { &*self.trailer_ptr().as_ptr() }
263 }
264
265 pub(super) fn state(&self) -> &State {
267 &self.header().state
268 }
269
270 pub(crate) fn poll(self) {
272 let vtable = self.header().vtable;
273 unsafe { (vtable.poll)(self.ptr) }
274 }
275
276 pub(super) fn schedule(self) {
277 let vtable = self.header().vtable;
278 unsafe { (vtable.schedule)(self.ptr) }
279 }
280
281 pub(super) fn dealloc(self) {
282 let vtable = self.header().vtable;
283 unsafe {
284 (vtable.dealloc)(self.ptr);
285 }
286 }
287
288 pub(super) unsafe fn try_read_output<O>(self, dst: *mut Poll<super::Result<O>>, waker: &Waker) {
291 let vtable = self.header().vtable;
292 (vtable.try_read_output)(self.ptr, dst as *mut _, waker);
293 }
294
295 pub(super) fn drop_join_handle_slow(self) {
296 let vtable = self.header().vtable;
297 unsafe { (vtable.drop_join_handle_slow)(self.ptr) }
298 }
299
300 pub(super) fn drop_abort_handle(self) {
301 let vtable = self.header().vtable;
302 unsafe { (vtable.drop_abort_handle)(self.ptr) }
303 }
304
305 pub(super) fn shutdown(self) {
306 let vtable = self.header().vtable;
307 unsafe { (vtable.shutdown)(self.ptr) }
308 }
309
310 pub(super) fn ref_inc(self) {
314 self.header().state.ref_inc();
315 }
316
317 pub(crate) unsafe fn get_queue_next(self) -> Option<RawTask> {
323 self.header()
324 .queue_next
325 .with(|ptr| *ptr)
326 .map(|p| RawTask::from_raw(p))
327 }
328
329 pub(crate) unsafe fn set_queue_next(self, val: Option<RawTask>) {
335 self.header().set_next(val.map(|task| task.ptr));
336 }
337}
338
339impl Copy for RawTask {}
340
341unsafe fn poll<T: Future, S: Schedule>(ptr: NonNull<Header>) {
342 let harness = Harness::<T, S>::from_raw(ptr);
343 harness.poll();
344}
345
346unsafe fn schedule<S: Schedule>(ptr: NonNull<Header>) {
347 use crate::runtime::task::{Notified, Task};
348
349 let scheduler = Header::get_scheduler::<S>(ptr);
350 scheduler
351 .as_ref()
352 .schedule(Notified(Task::from_raw(ptr.cast())));
353}
354
355unsafe fn dealloc<T: Future, S: Schedule>(ptr: NonNull<Header>) {
356 let harness = Harness::<T, S>::from_raw(ptr);
357 harness.dealloc();
358}
359
360unsafe fn try_read_output<T: Future, S: Schedule>(
361 ptr: NonNull<Header>,
362 dst: *mut (),
363 waker: &Waker,
364) {
365 let out = &mut *(dst as *mut Poll<super::Result<T::Output>>);
366
367 let harness = Harness::<T, S>::from_raw(ptr);
368 harness.try_read_output(out, waker);
369}
370
371unsafe fn drop_join_handle_slow<T: Future, S: Schedule>(ptr: NonNull<Header>) {
372 let harness = Harness::<T, S>::from_raw(ptr);
373 harness.drop_join_handle_slow();
374}
375
376unsafe fn drop_abort_handle<T: Future, S: Schedule>(ptr: NonNull<Header>) {
377 let harness = Harness::<T, S>::from_raw(ptr);
378 harness.drop_reference();
379}
380
381unsafe fn shutdown<T: Future, S: Schedule>(ptr: NonNull<Header>) {
382 let harness = Harness::<T, S>::from_raw(ptr);
383 harness.shutdown();
384}