fuchsia_async/runtime/fuchsia/executor/atomic_future.rs
1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5pub mod hooks;
6pub mod spawnable_future;
7
8use crate::ScopeHandle;
9use futures::ready;
10use std::future::Future;
11use std::hash::{Hash, Hasher};
12use std::marker::PhantomData;
13use std::mem::ManuallyDrop;
14use std::ops::Deref;
15use std::pin::Pin;
16use std::ptr::NonNull;
17use std::sync::atomic::Ordering::{Acquire, Relaxed, Release};
18use std::sync::atomic::{AtomicUsize, Ordering};
19use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
20
21/// A lock-free thread-safe future.
22//
23// The debugger knows the layout so that async backtraces work, so if this changes the debugger
24// might need to be changed too.
25//
26// This is `repr(C)` so that we can cast between `NonNull<Meta>` and `NonNull<AtomicFuture<F>>`.
27//
28// LINT.IfChange
29#[repr(C)]
30struct AtomicFuture<F: Future> {
31 meta: Meta,
32
33 // `future` is safe to access after successfully clearing the INACTIVE state bit and the `DONE`
34 // state bit isn't set.
35 future: FutureOrResult<F>,
36}
37// LINT.ThenChange(//src/developer/debug/zxdb/console/commands/verb_async_backtrace.cc)
38
39/// A lock-free thread-safe future. The handles can be cloned.
40#[derive(Debug)]
41pub struct AtomicFutureHandle<'a>(NonNull<Meta>, PhantomData<&'a ()>);
42
43/// `AtomicFutureHandle` is safe to access from multiple threads at once.
44unsafe impl Sync for AtomicFutureHandle<'_> {}
45unsafe impl Send for AtomicFutureHandle<'_> {}
46
47impl Drop for AtomicFutureHandle<'_> {
48 fn drop(&mut self) {
49 self.meta().release();
50 }
51}
52
53impl Clone for AtomicFutureHandle<'_> {
54 fn clone(&self) -> Self {
55 self.meta().retain();
56 Self(self.0, PhantomData)
57 }
58}
59
60impl PartialEq for AtomicFutureHandle<'_> {
61 fn eq(&self, other: &Self) -> bool {
62 self.0 == other.0
63 }
64}
65
66impl Eq for AtomicFutureHandle<'_> {}
67
68impl Hash for AtomicFutureHandle<'_> {
69 fn hash<H: Hasher>(&self, state: &mut H) {
70 self.0.hash(state);
71 }
72}
73
74struct Meta {
75 vtable: &'static VTable,
76
77 // Holds the reference count and state bits (INACTIVE, READY, etc.).
78 state: AtomicUsize,
79
80 scope: Option<ScopeHandle>,
81}
82
83impl Meta {
84 // # Safety
85 //
86 // This mints a handle with the 'static lifetime, so this should only be called from
87 // `AtomicFutureHandle<'static>`.
88 unsafe fn wake(&self) {
89 if self.state.fetch_or(READY, Relaxed) & (INACTIVE | READY | DONE) == INACTIVE {
90 self.retain();
91 self.scope().executor().task_is_ready(AtomicFutureHandle(self.into(), PhantomData));
92 }
93 }
94
95 // Returns true if a guard should be acquired.
96 //
97 // # Safety
98 //
99 // This mints a handle with the 'static lifetime, so this should only be called from
100 // `AtomicFutureHandle<'static>`.
101 unsafe fn wake_with_active_guard(&self) -> bool {
102 let old = self.state.fetch_or(READY | WITH_ACTIVE_GUARD, Relaxed);
103 if old & (INACTIVE | READY | DONE) == INACTIVE {
104 self.retain();
105 self.scope().executor().task_is_ready(AtomicFutureHandle(self.into(), PhantomData));
106 }
107
108 // If the task is DONE, the guard won't be released, so we must let the caller know.
109 old & (DONE | WITH_ACTIVE_GUARD) == 0
110 }
111
112 fn scope(&self) -> &ScopeHandle {
113 self.scope.as_ref().unwrap()
114 }
115
116 fn retain(&self) {
117 let old = self.state.fetch_add(1, Relaxed) & REF_COUNT_MASK;
118 assert!(old != REF_COUNT_MASK);
119 }
120
121 fn release(&self) {
122 // This can be Relaxed because there is a barrier in the drop function.
123 let old = self.state.fetch_sub(1, Relaxed) & REF_COUNT_MASK;
124 if old == 1 {
125 // SAFETY: This is safe because we just released the last reference.
126 unsafe {
127 (self.vtable.drop)(self.into());
128 }
129 } else {
130 // Check for underflow.
131 assert!(old > 0);
132 }
133 }
134
135 // # Safety
136 //
137 // The caller must know that the future has completed.
138 unsafe fn drop_result(&self, ordering: Ordering) {
139 // It's possible for this to race with another thread so we only drop the result if we are
140 // successful in setting the RESULT_TAKEN bit.
141 if self.state.fetch_or(RESULT_TAKEN, ordering) & RESULT_TAKEN == 0 {
142 unsafe { (self.vtable.drop_result)(self.into()) };
143 }
144 }
145}
146
147struct VTable {
148 /// Drops the atomic future.
149 ///
150 /// # Safety
151 ///
152 /// The caller must ensure there are no other references i.e. the reference count should be
153 /// zero.
154 // zxdb uses this method to figure out the concrete type of the future.
155 // LINT.IfChange
156 drop: unsafe fn(NonNull<Meta>),
157 // LINT.ThenChange(//src/developer/debug/zxdb/console/commands/verb_async_backtrace.cc)
158 /// Drops the future.
159 ///
160 /// # Safety
161 ///
162 /// The caller must ensure the future hasn't been dropped.
163 drop_future: unsafe fn(NonNull<Meta>),
164 /// Polls the future.
165 ///
166 /// # Safety
167 ///
168 /// The caller must ensure the future hasn't been dropped and has exclusive access.
169 poll: unsafe fn(NonNull<Meta>, cx: &mut Context<'_>) -> Poll<()>,
170
171 /// Gets the result.
172 ///
173 /// # Safety
174 ///
175 /// The caller must ensure the future is finished and the result hasn't been taken or dropped.
176 get_result: unsafe fn(NonNull<Meta>) -> *const (),
177
178 /// Drops the result.
179 ///
180 /// # Safety
181 ///
182 /// The caller must ensure the future is finished and the result hasn't already been taken or
183 /// dropped.
184 drop_result: unsafe fn(NonNull<Meta>),
185}
186
187union FutureOrResult<F: Future> {
188 future: ManuallyDrop<F>,
189 result: ManuallyDrop<F::Output>,
190}
191
192impl<F: Future> AtomicFuture<F> {
193 const VTABLE: VTable = VTable {
194 drop: Self::drop,
195 drop_future: Self::drop_future,
196 poll: Self::poll,
197 get_result: Self::get_result,
198 drop_result: Self::drop_result,
199 };
200
201 unsafe fn drop(meta: NonNull<Meta>) {
202 drop(unsafe { Box::from_raw(meta.cast::<Self>().as_mut()) });
203 }
204
205 unsafe fn poll(meta: NonNull<Meta>, cx: &mut Context<'_>) -> Poll<()> {
206 let future = &mut unsafe { meta.cast::<Self>().as_mut() }.future;
207 let result = ready!(unsafe { Pin::new_unchecked(&mut *future.future) }.poll(cx));
208 // This might panic which will leave ourselves in a bad state. We deal with this by
209 // aborting (see below).
210 unsafe { ManuallyDrop::drop(&mut future.future) };
211 future.result = ManuallyDrop::new(result);
212 Poll::Ready(())
213 }
214
215 unsafe fn drop_future(meta: NonNull<Meta>) {
216 unsafe { ManuallyDrop::drop(&mut meta.cast::<Self>().as_mut().future.future) };
217 }
218
219 unsafe fn get_result(meta: NonNull<Meta>) -> *const () {
220 unsafe { &*meta.cast::<Self>().as_mut().future.result as *const F::Output as *const () }
221 }
222
223 unsafe fn drop_result(meta: NonNull<Meta>) {
224 unsafe { ManuallyDrop::drop(&mut meta.cast::<Self>().as_mut().future.result) };
225 }
226}
227
228/// State Bits
229//
230// Exclusive access is gained by clearing this bit.
231const INACTIVE: usize = 1 << 63;
232
233// Set to indicate the future needs to be polled again.
234const READY: usize = 1 << 62;
235
236// Terminal state: the future is dropped upon entry to this state. When in this state, other bits
237// can be set, including READY (which has no meaning).
238const DONE: usize = 1 << 61;
239
240// The task has been detached.
241const DETACHED: usize = 1 << 60;
242
243// The task has been cancelled.
244const ABORTED: usize = 1 << 59;
245
246// The task has an active guard that should be dropped when the task is next polled.
247const WITH_ACTIVE_GUARD: usize = 1 << 58;
248
249// The result has been taken.
250const RESULT_TAKEN: usize = 1 << 57;
251
252// The task is low priority.
253const LOW_PRIORITY: usize = 1 << 56;
254
255// The mask for the ref count.
256const REF_COUNT_MASK: usize = LOW_PRIORITY - 1;
257
258/// The result of a call to `try_poll`.
259/// This indicates the result of attempting to `poll` the future.
260pub enum AttemptPollResult {
261 /// The future was polled, but did not complete.
262 Pending,
263 /// The future was polled and finished by this thread.
264 /// This result is normally used to trigger garbage-collection of the future.
265 IFinished,
266 /// The future was already completed by another thread.
267 SomeoneElseFinished,
268 /// The future was polled, did not complete, but it is woken whilst it is polled so it
269 /// should be polled again.
270 Yield,
271 /// The future was aborted.
272 Aborted,
273}
274
275/// The result of calling the `abort_and_detach` function.
276#[must_use]
277pub enum AbortAndDetachResult {
278 /// The future has finished; it can be dropped.
279 Done,
280
281 /// The future needs to be added to a run queue to be aborted.
282 AddToRunQueue,
283
284 /// The future is soon to be aborted and nothing needs to be done.
285 Pending,
286}
287
288impl<'a> AtomicFutureHandle<'a> {
289 /// Create a new `AtomicFuture`.
290 pub(crate) fn new<F: Future + Send + 'a>(scope: Option<ScopeHandle>, future: F) -> Self
291 where
292 F::Output: Send + 'a,
293 {
294 // SAFETY: This is safe because the future and output are both Send.
295 unsafe { Self::new_local(scope, future) }
296 }
297
298 /// Create a new `AtomicFuture` from a !Send future.
299 ///
300 /// # Safety
301 ///
302 /// The caller must uphold the Send requirements.
303 pub(crate) unsafe fn new_local<F: Future + 'a>(scope: Option<ScopeHandle>, future: F) -> Self
304 where
305 F::Output: 'a,
306 {
307 Self(
308 NonNull::from_mut(Box::leak(Box::new(AtomicFuture {
309 meta: Meta {
310 vtable: &AtomicFuture::<F>::VTABLE,
311 // The future is inactive and we start with a single reference.
312 state: AtomicUsize::new(1 | INACTIVE),
313 scope,
314 },
315 future: FutureOrResult { future: ManuallyDrop::new(future) },
316 })))
317 .cast::<Meta>(),
318 PhantomData,
319 )
320 }
321
322 fn meta(&self) -> &Meta {
323 // SAFETY: This is safe because we hold a reference count.
324 unsafe { self.0.as_ref() }
325 }
326
327 /// Returns the future's ID.
328 ///
329 /// The ID is only valid so long as there exists at least one live handle.
330 pub fn id(&self) -> usize {
331 // We use the address of the metadata as the ID since we know it's a stable heap address.
332 // We can't use Pin to guarantee it never moves because the actual pointer to the
333 // AtomicFuture is stored as a NonNull<Meta>.
334 //
335 // See https://github.com/rust-lang/rust/issues/54815 for an upstream feature request that
336 // would let us encode this in the types.
337 self.meta() as *const Meta as usize
338 }
339
340 /// Returns the associated scope.
341 pub fn scope(&self) -> &ScopeHandle {
342 self.meta().scope()
343 }
344
345 /// Attempt to poll the underlying future.
346 ///
347 /// `try_poll` ensures that the future is polled at least once more
348 /// unless it has already finished.
349 pub(crate) fn try_poll(&self, cx: &mut Context<'_>) -> AttemptPollResult {
350 let meta = self.meta();
351 let has_active_guard = loop {
352 // Attempt to acquire sole responsibility for polling the future (by clearing the
353 // INACTIVE bit) and also clear the READY and WITH_ACTIVE_GUARD bits at the same time.
354 // We clear both so that we can track if they are set again whilst we are polling.
355 let old = meta.state.fetch_and(!(INACTIVE | READY | WITH_ACTIVE_GUARD), Acquire);
356 assert_ne!(old & REF_COUNT_MASK, 0);
357 if old & DONE != 0 {
358 // If the DONE bit is set, the WITH_ACTIVE_GUARD bit should be ignored; it may or
359 // may not be set, but it doesn't reflect whether an active guard is held so even
360 // though we just cleared it, we shouldn't release a guard here.
361 return AttemptPollResult::SomeoneElseFinished;
362 }
363 let has_active_guard = old & WITH_ACTIVE_GUARD != 0;
364 if old & INACTIVE != 0 {
365 // We are now the (only) active worker, proceed to poll...
366 if old & ABORTED != 0 {
367 if has_active_guard {
368 meta.scope().release_cancel_guard();
369 }
370 // The future was aborted.
371 // SAFETY: We have exclusive access.
372 unsafe {
373 self.drop_future_unchecked();
374 }
375 return AttemptPollResult::Aborted;
376 }
377 break has_active_guard;
378 }
379 // Future was already active; this shouldn't really happen because we shouldn't be
380 // polling it from multiple threads at the same time. Still, we handle it by setting
381 // the READY bit so that it gets polled again. We do this regardless of whether we
382 // cleared the READY bit above.
383 let old2 = meta.state.fetch_or(READY | (old & WITH_ACTIVE_GUARD), Relaxed);
384
385 if old2 & DONE != 0 {
386 // If `has_active_guard` is true, we are responsible for releasing a guard since it
387 // means we cleared the `WITH_ACTIVE_GUARD` bit.
388 if has_active_guard {
389 meta.scope().release_cancel_guard();
390 }
391 return AttemptPollResult::SomeoneElseFinished;
392 }
393
394 if has_active_guard && old2 & WITH_ACTIVE_GUARD != 0 {
395 // Within the small window, something else gave this task an active guard, so we
396 // must return one of them.
397 meta.scope().release_cancel_guard();
398 }
399
400 // If the future is still active, or the future was already marked as ready, we can
401 // just return and it will get polled again.
402 if old2 & INACTIVE == 0 || old2 & READY != 0 {
403 return AttemptPollResult::Pending;
404 }
405 // The worker finished, and we marked the future as ready, so we must try again because
406 // the future won't be in a run queue.
407 };
408
409 // We cannot recover from panics.
410 let bomb = Bomb;
411
412 // SAFETY: We have exclusive access because we cleared the INACTIVE state bit.
413 let result = unsafe { (meta.vtable.poll)(meta.into(), cx) };
414
415 std::mem::forget(bomb);
416
417 if has_active_guard {
418 meta.scope().release_cancel_guard();
419 }
420
421 if let Poll::Ready(()) = result {
422 // The future will have been dropped, so we just need to set the state.
423 //
424 // This needs to be Release ordering because we need to synchronize with another thread
425 // that takes or drops the result.
426 let old = meta.state.fetch_or(DONE, Release);
427
428 if old & WITH_ACTIVE_GUARD != 0 {
429 // Whilst we were polling the task, it was given an active guard. We must return it
430 // now.
431 meta.scope().release_cancel_guard();
432 }
433
434 if old & DETACHED != 0 {
435 // If the future is detached, we should eagerly drop the result. This can be
436 // Relaxed ordering because the result was written by this thread.
437
438 // SAFETY: The future has completed.
439 unsafe {
440 meta.drop_result(Relaxed);
441 }
442 }
443 // No one else will read `future` unless they see `INACTIVE`, which will never
444 // happen again.
445 AttemptPollResult::IFinished
446 } else if meta.state.fetch_or(INACTIVE, Release) & READY == 0 {
447 AttemptPollResult::Pending
448 } else {
449 // The future was marked ready whilst we were polling, so yield.
450 AttemptPollResult::Yield
451 }
452 }
453
454 /// Drops the future without checking its current state.
455 ///
456 /// # Panics
457 ///
458 /// This will panic if the future is already marked with `DONE`.
459 ///
460 /// # Safety
461 ///
462 /// This doesn't check the current state, so this must only be called if it is known that there
463 /// is no concurrent access. This also does *not* include any memory barriers before dropping
464 /// the future.
465 pub(crate) unsafe fn drop_future_unchecked(&self) {
466 // Set the state first in case we panic when we drop.
467 let meta = self.meta();
468 let old = meta.state.fetch_or(DONE | RESULT_TAKEN, Relaxed);
469 assert_eq!(old & DONE, 0);
470 if old & WITH_ACTIVE_GUARD != 0 {
471 meta.scope().release_cancel_guard();
472 }
473 unsafe { (meta.vtable.drop_future)(meta.into()) };
474 }
475
476 /// Drops the future if it is not currently being polled. Returns success if the future was
477 /// dropped or was already dropped.
478 pub(crate) fn try_drop(&self) -> Result<(), ()> {
479 let old = self.meta().state.fetch_and(!INACTIVE, Acquire);
480 if old & DONE != 0 {
481 Ok(())
482 } else if old & INACTIVE != 0 {
483 // SAFETY: We have exclusive access.
484 unsafe {
485 self.drop_future_unchecked();
486 }
487 Ok(())
488 } else {
489 Err(())
490 }
491 }
492
493 /// Aborts the task. Returns true if the task needs to be added to a run queue.
494 #[must_use]
495 pub(crate) fn abort(&self) -> bool {
496 self.meta().state.fetch_or(ABORTED | READY, Relaxed) & (INACTIVE | READY | DONE) == INACTIVE
497 }
498
499 /// Marks the task as detached.
500 pub(crate) fn detach(&self) {
501 let meta = self.meta();
502 let old = meta.state.fetch_or(DETACHED, Relaxed);
503
504 if old & (DONE | RESULT_TAKEN) == DONE {
505 // If the future is done, we should eagerly drop the result. This needs to be acquire
506 // ordering because another thread might have written the result.
507
508 // SAFETY: The future has completed.
509 unsafe {
510 meta.drop_result(Acquire);
511 }
512 }
513 }
514
515 /// Marks the task as aborted and detached (for when the caller isn't interested in waiting
516 /// for the cancellation to be finished). Returns true if the task should be added to a run
517 /// queue.
518 pub(crate) fn abort_and_detach(&self) -> AbortAndDetachResult {
519 let meta = self.meta();
520 let old_state = meta.state.fetch_or(ABORTED | DETACHED | READY, Relaxed);
521 if old_state & DONE != 0 {
522 // If the future is done, we should eagerly drop the result. This needs to be acquire
523 // ordering because another thread might have written the result.
524
525 // SAFETY: The future has completed.
526 unsafe {
527 meta.drop_result(Acquire);
528 }
529
530 AbortAndDetachResult::Done
531 } else if old_state & (INACTIVE | READY) == INACTIVE {
532 AbortAndDetachResult::AddToRunQueue
533 } else {
534 AbortAndDetachResult::Pending
535 }
536 }
537
538 /// Returns true if the task is detached.
539 pub(crate) fn is_detached(&self) -> bool {
540 self.meta().state.load(Relaxed) & DETACHED != 0
541 }
542
543 /// Returns true if the task is aborted.
544 pub(crate) fn is_aborted(&self) -> bool {
545 self.meta().state.load(Relaxed) & ABORTED != 0
546 }
547
548 /// Takes the result.
549 ///
550 /// # Safety
551 ///
552 /// The caller must guarantee that `R` is the correct type.
553 pub(crate) unsafe fn take_result<R>(&self) -> Option<R> {
554 // This needs to be Acquire ordering to synchronize with the polling thread.
555 let meta = self.meta();
556 if meta.state.load(Relaxed) & (DONE | RESULT_TAKEN) == DONE
557 && meta.state.fetch_or(RESULT_TAKEN, Acquire) & RESULT_TAKEN == 0
558 {
559 Some(unsafe { ((meta.vtable.get_result)(meta.into()) as *const R).read() })
560 } else {
561 None
562 }
563 }
564
565 /// Marks the task as low priority. Returns the old state.
566 pub(crate) fn set_low_priority(&self, v: bool) -> bool {
567 let prev = if v {
568 self.meta().state.fetch_or(LOW_PRIORITY, Relaxed)
569 } else {
570 self.meta().state.fetch_and(!LOW_PRIORITY, Relaxed)
571 };
572 prev & LOW_PRIORITY != 0
573 }
574
575 /// Returns true if this is a low priority task.
576 pub(crate) fn is_low_priority(&self) -> bool {
577 self.meta().state.load(Relaxed) & LOW_PRIORITY != 0
578 }
579}
580
581impl AtomicFutureHandle<'static> {
582 /// Returns a waker for the future.
583 pub(crate) fn waker(&self) -> BorrowedWaker<'_> {
584 static BORROWED_WAKER_VTABLE: RawWakerVTable =
585 RawWakerVTable::new(waker_clone, waker_wake_by_ref, waker_wake_by_ref, waker_noop);
586 static WAKER_VTABLE: RawWakerVTable =
587 RawWakerVTable::new(waker_clone, waker_wake, waker_wake_by_ref, waker_drop);
588
589 fn waker_clone(raw_meta: *const ()) -> RawWaker {
590 // SAFETY: We did the reverse cast below.
591 let meta = unsafe { &*(raw_meta as *const Meta) };
592 meta.retain();
593 RawWaker::new(raw_meta, &WAKER_VTABLE)
594 }
595
596 fn waker_wake(raw_meta: *const ()) {
597 // SAFETY: We did the reverse cast below.
598 let meta = unsafe { &*(raw_meta as *const Meta) };
599 if meta.state.fetch_or(READY, Relaxed) & (INACTIVE | READY | DONE) == INACTIVE {
600 // This consumes the reference count.
601 meta.scope().executor().task_is_ready(AtomicFutureHandle(
602 // SAFETY: We know raw_meta is not null.
603 unsafe { NonNull::new_unchecked(raw_meta as *mut Meta) },
604 PhantomData,
605 ));
606 } else {
607 meta.release();
608 }
609 }
610
611 fn waker_wake_by_ref(meta: *const ()) {
612 // SAFETY: We did the reverse cast below.
613 let meta = unsafe { &*(meta as *const Meta) };
614 // SAFETY: The lifetime on `AtomicFutureHandle` is 'static.
615 unsafe {
616 meta.wake();
617 }
618 }
619
620 fn waker_noop(_meta: *const ()) {}
621
622 fn waker_drop(meta: *const ()) {
623 // SAFETY: We did the reverse cast below.
624 let meta = unsafe { &*(meta as *const Meta) };
625 meta.release();
626 }
627
628 BorrowedWaker(
629 // SAFETY: We meet the contract for RawWaker/RawWakerVtable.
630 unsafe {
631 Waker::from_raw(RawWaker::new(self.0.as_ptr() as *const (), &BORROWED_WAKER_VTABLE))
632 },
633 PhantomData,
634 )
635 }
636
637 /// Wakes the future.
638 pub(crate) fn wake(&self) {
639 // SAFETY: The lifetime on `AtomicFutureHandle` is 'static.
640 unsafe {
641 self.meta().wake();
642 }
643 }
644
645 /// Wakes the future with an active guard. Returns true if successful i.e. a guard needs to be
646 /// acquired.
647 ///
648 /// NOTE: `Scope::release_cancel_guard` can be called *before* this function returns because the
649 /// task can be polled on another thread. For this reason, the caller either needs to hold a
650 /// lock, or it should preemptively take the guard.
651 pub(crate) fn wake_with_active_guard(&self) -> bool {
652 // SAFETY: The lifetime on `AtomicFutureHandle` is 'static.
653 unsafe { self.meta().wake_with_active_guard() }
654 }
655}
656
657impl<F: Future> Drop for AtomicFuture<F> {
658 fn drop(&mut self) {
659 let meta = &mut self.meta;
660 // This needs to be acquire ordering so that we see writes that might have just happened
661 // in another thread when the future was polled.
662 let state = meta.state.load(Acquire);
663 if state & DONE == 0 {
664 // SAFETY: The state isn't DONE so we must drop the future.
665 unsafe {
666 (meta.vtable.drop_future)(meta.into());
667 }
668 } else if state & RESULT_TAKEN == 0 {
669 // SAFETY: The result hasn't been taken so we must drop the result.
670 unsafe {
671 (meta.vtable.drop_result)(meta.into());
672 }
673 }
674 }
675}
676
677pub struct BorrowedWaker<'a>(std::task::Waker, PhantomData<&'a ()>);
678
679impl Deref for BorrowedWaker<'_> {
680 type Target = Waker;
681
682 fn deref(&self) -> &Self::Target {
683 &self.0
684 }
685}
686
687struct Bomb;
688impl Drop for Bomb {
689 fn drop(&mut self) {
690 std::process::abort();
691 }
692}