diff --git a/.travis.yml b/.travis.yml
index 3e67b0f..bd66105 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,9 @@
 language: rust
 
-os: linux
+os:
+  - linux
+  - osx
+  - windows
 
 rust: nightly
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 87edaac..12678b7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,30 @@
+# Version 1.3.1
+
+- Make `spawn_local` available only on unix and windows.
+
+# Version 1.3.0
+
+- Add `waker_fn`.
+
+# Version 1.2.1
+
+- Add the `no-std` category to the package.
+
+# Version 1.2.0
+
+- The crate is now marked with `#![no_std]`.
+- Add `Task::waker` and `JoinHandle::waker`.
+- Add `Task::into_raw` and `Task::from_raw`.
+
+# Version 1.1.1
+
+- Fix a use-after-free bug where the schedule function is dropped while running.
+
+# Version 1.1.0
+
+- If a task is dropped or cancelled outside the `run` method, it gets re-scheduled.
+- Add `spawn_local` constructor.
+
 # Version 1.0.0
 
 - Initial release
diff --git a/Cargo.toml b/Cargo.toml
index e3dd091..f9e8c5f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "async-task"
-version = "1.0.0"
+version = "1.3.1"
 authors = ["Stjepan Glavina <stjepang@gmail.com>"]
 edition = "2018"
 license = "Apache-2.0/MIT"
@@ -9,13 +9,18 @@ homepage = "https://github.com/async-rs/async-task"
 documentation = "https://docs.rs/async-task"
 description = "Task abstraction for building executors"
 keywords = ["futures", "task", "executor", "spawn"]
-categories = ["asynchronous", "concurrency"]
+categories = ["asynchronous", "concurrency", "no-std"]
 readme = "README.md"
 
-[dependencies]
-crossbeam-utils = "0.7.0"
+[target.'cfg(unix)'.dependencies]
+libc = "0.2.66"
+
+[target.'cfg(windows)'.dependencies]
+winapi = { version = "0.3.8", features = ["processthreadsapi"] }
 
 [dev-dependencies]
 crossbeam = "0.7.3"
+crossbeam-utils = "0.7.0"
 futures = "0.3.1"
 lazy_static = "1.4.0"
+pin-utils = "0.1.0-alpha.4"
diff --git a/README.md b/README.md
index 875b193..217ee18 100644
--- a/README.md
+++ b/README.md
@@ -55,10 +55,6 @@ $ cargo add async-task
 
 [cargo-add]: https://github.com/killercup/cargo-edit
 
-## Safety
-This crate makes use of carefully checked `unsafe` blocks to construct an
-efficient timer implementation.
-
 ## Contributing
 Want to join us? Check out our ["Contributing" guide][contributing] and take a
 look at some of these issues:
diff --git a/benches/bench.rs b/benches/spawn.rs
similarity index 100%
rename from benches/bench.rs
rename to benches/spawn.rs
diff --git a/benches/waker_fn.rs b/benches/waker_fn.rs
new file mode 100644
index 0000000..90d99f9
--- /dev/null
+++ b/benches/waker_fn.rs
@@ -0,0 +1,89 @@
+#![feature(test)]
+
+extern crate test;
+
+use std::cell::RefCell;
+use std::future::Future;
+use std::pin::Pin;
+use std::task::{Context, Poll, Waker};
+
+use crossbeam::sync::Parker;
+use test::Bencher;
+
+/// Runs a future to completion on the current thread.
+fn block_on<F: Future>(future: F) -> F::Output {
+    // Pin the future on the stack.
+    pin_utils::pin_mut!(future);
+
+    thread_local! {
+        // Parker and waker associated with the current thread.
+        static CACHE: RefCell<(Parker, Waker)> = {
+            let parker = Parker::new();
+            let unparker = parker.unparker().clone();
+            let waker = async_task::waker_fn(move || unparker.unpark());
+            RefCell::new((parker, waker))
+        };
+    }
+
+    CACHE.with(|cache| {
+        // Panic if `block_on()` is called recursively.
+        let (parker, waker) = &mut *cache.try_borrow_mut().ok().expect("recursive `block_on`");
+
+        // Create the task context.
+        let cx = &mut Context::from_waker(&waker);
+
+        // Keep polling the future until completion.
+        loop {
+            match future.as_mut().poll(cx) {
+                Poll::Ready(output) => return output,
+                Poll::Pending => parker.park(),
+            }
+        }
+    })
+}
+
+#[bench]
+fn custom_block_on_0_yields(b: &mut Bencher) {
+    b.iter(|| block_on(Yields(0)));
+}
+
+#[bench]
+fn custom_block_on_10_yields(b: &mut Bencher) {
+    b.iter(|| block_on(Yields(10)));
+}
+
+#[bench]
+fn custom_block_on_50_yields(b: &mut Bencher) {
+    b.iter(|| block_on(Yields(50)));
+}
+
+#[bench]
+fn futures_block_on_0_yields(b: &mut Bencher) {
+    b.iter(|| futures::executor::block_on(Yields(0)));
+}
+
+#[bench]
+fn futures_block_on_10_yields(b: &mut Bencher) {
+    b.iter(|| futures::executor::block_on(Yields(10)));
+}
+
+#[bench]
+fn futures_block_on_50_yields(b: &mut Bencher) {
+    b.iter(|| futures::executor::block_on(Yields(50)));
+}
+
+struct Yields(u32);
+
+impl Future for Yields {
+    type Output = ();
+
+    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        if self.0 == 0 {
+            Poll::Ready(())
+        } else {
+            self.0 -= 1;
+            cx.waker().wake_by_ref();
+            Poll::Pending
+        }
+    }
+}
diff --git a/examples/block.rs b/examples/block.rs
new file mode 100644
index 0000000..e4124b2
--- /dev/null
+++ b/examples/block.rs
@@ -0,0 +1,60 @@
+//! A simple implementation of `block_on`.
+
+use std::cell::RefCell;
+use std::future::Future;
+use std::task::{Context, Poll, Waker};
+use std::thread;
+use std::time::Duration;
+
+use crossbeam::sync::Parker;
+use futures::channel::oneshot;
+
+/// Runs a future to completion on the current thread.
+fn block_on<F: Future>(future: F) -> F::Output {
+    // Pin the future on the stack.
+    pin_utils::pin_mut!(future);
+
+    thread_local! {
+        // Parker and waker associated with the current thread.
+        static CACHE: RefCell<(Parker, Waker)> = {
+            let parker = Parker::new();
+            let unparker = parker.unparker().clone();
+            let waker = async_task::waker_fn(move || unparker.unpark());
+            RefCell::new((parker, waker))
+        };
+    }
+
+    CACHE.with(|cache| {
+        // Panic if `block_on()` is called recursively.
+        let (parker, waker) = &mut *cache.try_borrow_mut().ok().expect("recursive block_on()");
+
+        // Create the task context.
+        let cx = &mut Context::from_waker(&waker);
+
+        // Keep polling the future until completion.
+        loop {
+            match future.as_mut().poll(cx) {
+                Poll::Ready(output) => return output,
+                Poll::Pending => parker.park(),
+            }
+        }
+    })
+}
+
+fn main() {
+    let (s, r) = oneshot::channel();
+
+    // Spawn a thread that will send a message through the channel.
+    thread::spawn(move || {
+        thread::sleep(Duration::from_secs(1));
+        s.send("Hello, world!").unwrap();
+    });
+
+    // Block until the message is received.
+    let msg = block_on(async {
+        println!("Awaiting...");
+        r.await.unwrap()
+    });
+
+    println!("{}", msg);
+}
diff --git a/examples/panic-propagation.rs b/examples/panic-propagation.rs
index 8a5339f..05ec85a 100644
--- a/examples/panic-propagation.rs
+++ b/examples/panic-propagation.rs
@@ -11,6 +11,8 @@ use futures::executor;
 use futures::future::FutureExt;
 use lazy_static::lazy_static;
 
+type Task = async_task::Task<()>;
+
 /// Spawns a future on the executor.
 fn spawn<F, R>(future: F) -> JoinHandle<R>
 where
@@ -19,8 +21,8 @@ where
 {
     lazy_static! {
         // A channel that holds scheduled tasks.
-        static ref QUEUE: Sender<async_task::Task<()>> = {
-            let (sender, receiver) = unbounded::<async_task::Task<()>>();
+        static ref QUEUE: Sender<Task> = {
+            let (sender, receiver) = unbounded::<Task>();
 
             // Start the executor thread.
             thread::spawn(|| {
diff --git a/examples/panic-result.rs b/examples/panic-result.rs
index 7cf5a14..6308240 100644
--- a/examples/panic-result.rs
+++ b/examples/panic-result.rs
@@ -9,16 +9,19 @@ use futures::executor;
 use futures::future::FutureExt;
 use lazy_static::lazy_static;
 
+type Task = async_task::Task<()>;
+type JoinHandle<T> = async_task::JoinHandle<T, ()>;
+
 /// Spawns a future on the executor.
-fn spawn<F, R>(future: F) -> async_task::JoinHandle<thread::Result<R>, ()>
+fn spawn<F, R>(future: F) -> JoinHandle<thread::Result<R>>
 where
     F: Future<Output = R> + Send + 'static,
     R: Send + 'static,
 {
     lazy_static! {
         // A channel that holds scheduled tasks.
-        static ref QUEUE: Sender<async_task::Task<()>> = {
-            let (sender, receiver) = unbounded::<async_task::Task<()>>();
+        static ref QUEUE: Sender<Task> = {
+            let (sender, receiver) = unbounded::<Task>();
 
             // Start the executor thread.
             thread::spawn(|| {
diff --git a/examples/spawn-local.rs b/examples/spawn-local.rs
new file mode 100644
index 0000000..4e66c32
--- /dev/null
+++ b/examples/spawn-local.rs
@@ -0,0 +1,76 @@
+//! A simple single-threaded executor that can spawn non-`Send` futures.
+
+use std::cell::Cell;
+use std::future::Future;
+use std::rc::Rc;
+
+use crossbeam::channel::{unbounded, Receiver, Sender};
+
+type Task = async_task::Task<()>;
+type JoinHandle<T> = async_task::JoinHandle<T, ()>;
+
+thread_local! {
+    // A channel that holds scheduled tasks.
+    static QUEUE: (Sender<Task>, Receiver<Task>) = unbounded();
+}
+
+/// Spawns a future on the executor.
+fn spawn<F, R>(future: F) -> JoinHandle<R>
+where
+    F: Future<Output = R> + 'static,
+    R: 'static,
+{
+    // Create a task that is scheduled by sending itself into the channel.
+    let schedule = |t| QUEUE.with(|(s, _)| s.send(t).unwrap());
+    let (task, handle) = async_task::spawn_local(future, schedule, ());
+
+    // Schedule the task by sending it into the queue.
+    task.schedule();
+
+    handle
+}
+
+/// Runs a future to completion.
+fn run<F, R>(future: F) -> R
+where
+    F: Future<Output = R> + 'static,
+    R: 'static,
+{
+    // Spawn a task that sends its result through a channel.
+    let (s, r) = unbounded();
+    spawn(async move { s.send(future.await).unwrap() });
+
+    loop {
+        // If the original task has completed, return its result.
+        if let Ok(val) = r.try_recv() {
+            return val;
+        }
+
+        // Otherwise, take a task from the queue and run it.
+        QUEUE.with(|(_, r)| r.recv().unwrap().run());
+    }
+}
+
+fn main() {
+    let val = Rc::new(Cell::new(0));
+
+    // Run a future that increments a non-`Send` value.
+    run({
+        let val = val.clone();
+        async move {
+            // Spawn a future that increments the value.
+            let handle = spawn({
+                let val = val.clone();
+                async move {
+                    val.set(dbg!(val.get()) + 1);
+                }
+            });
+
+            val.set(dbg!(val.get()) + 1);
+            handle.await;
+        }
+    });
+
+    // The value should be 2 at the end of the program.
+    dbg!(val.get());
+}
diff --git a/examples/spawn-on-thread.rs b/examples/spawn-on-thread.rs
index 22da0c5..95214ed 100644
--- a/examples/spawn-on-thread.rs
+++ b/examples/spawn-on-thread.rs
@@ -7,10 +7,12 @@ use std::thread;
 use crossbeam::channel;
 use futures::executor;
 
+type JoinHandle<T> = async_task::JoinHandle<T, ()>;
+
 /// Spawns a future on a new dedicated thread.
 ///
 /// The returned handle can be used to await the output of the future.
-fn spawn_on_thread<F, R>(future: F) -> async_task::JoinHandle<R, ()>
+fn spawn_on_thread<F, R>(future: F) -> JoinHandle<R>
 where
     F: Future<Output = R> + Send + 'static,
     R: Send + 'static,
diff --git a/examples/spawn.rs b/examples/spawn.rs
index 4af5a02..9db7215 100644
--- a/examples/spawn.rs
+++ b/examples/spawn.rs
@@ -8,16 +8,19 @@ use crossbeam::channel::{unbounded, Sender};
 use futures::executor;
 use lazy_static::lazy_static;
 
+type Task = async_task::Task<()>;
+type JoinHandle<T> = async_task::JoinHandle<T, ()>;
+
 /// Spawns a future on the executor.
-fn spawn<F, R>(future: F) -> async_task::JoinHandle<R, ()>
+fn spawn<F, R>(future: F) -> JoinHandle<R>
 where
     F: Future<Output = R> + Send + 'static,
     R: Send + 'static,
 {
     lazy_static! {
         // A channel that holds scheduled tasks.
-        static ref QUEUE: Sender<async_task::Task<()>> = {
-            let (sender, receiver) = unbounded::<async_task::Task<()>>();
+        static ref QUEUE: Sender<Task> = {
+            let (sender, receiver) = unbounded::<Task>();
 
             // Start the executor thread.
             thread::spawn(|| {
diff --git a/examples/task-id.rs b/examples/task-id.rs
index 66b7aec..2a7bcf7 100644
--- a/examples/task-id.rs
+++ b/examples/task-id.rs
@@ -13,6 +13,9 @@ use lazy_static::lazy_static;
 #[derive(Clone, Copy, Debug)]
 struct TaskId(usize);
 
+type Task = async_task::Task<TaskId>;
+type JoinHandle<T> = async_task::JoinHandle<T, TaskId>;
+
 thread_local! {
     /// The ID of the current task.
     static TASK_ID: Cell<Option<TaskId>> = Cell::new(None);
@@ -26,15 +29,15 @@ fn task_id() -> Option<TaskId> {
 }
 
 /// Spawns a future on the executor.
-fn spawn<F, R>(future: F) -> async_task::JoinHandle<R, TaskId>
+fn spawn<F, R>(future: F) -> JoinHandle<R>
 where
     F: Future<Output = R> + Send + 'static,
     R: Send + 'static,
 {
     lazy_static! {
         // A channel that holds scheduled tasks.
-        static ref QUEUE: Sender<async_task::Task<TaskId>> = {
-            let (sender, receiver) = unbounded::<async_task::Task<TaskId>>();
+        static ref QUEUE: Sender<Task> = {
+            let (sender, receiver) = unbounded::<Task>();
 
             // Start the executor thread.
             thread::spawn(|| {
diff --git a/src/header.rs b/src/header.rs
index f9aff4f..e676bef 100644
--- a/src/header.rs
+++ b/src/header.rs
@@ -1,10 +1,8 @@
-use std::alloc::Layout;
-use std::cell::Cell;
-use std::fmt;
-use std::sync::atomic::{AtomicUsize, Ordering};
-use std::task::Waker;
-
-use crossbeam_utils::Backoff;
+use core::alloc::Layout;
+use core::cell::UnsafeCell;
+use core::fmt;
+use core::sync::atomic::{AtomicUsize, Ordering};
+use core::task::Waker;
 
 use crate::raw::TaskVTable;
 use crate::state::*;
@@ -22,7 +20,7 @@ pub(crate) struct Header {
     /// The task that is blocked on the `JoinHandle`.
     ///
     /// This waker needs to be woken up once the task completes or is closed.
-    pub(crate) awaiter: Cell<Option<Waker>>,
+    pub(crate) awaiter: UnsafeCell<Option<Waker>>,
 
     /// The virtual table.
     ///
@@ -55,7 +53,7 @@ impl Header {
                 Ok(_) => {
                     // Notify the awaiter that the task has been closed.
                     if state & AWAITER != 0 {
-                        self.notify();
+                        self.notify(None);
                     }
 
                     break;
@@ -67,68 +65,105 @@ impl Header {
 
     /// Notifies the awaiter blocked on this task.
     ///
-    /// If there is a registered waker, it will be removed from the header and woken up.
+    /// If the awaiter is the same as the current waker, it will not be notified.
     #[inline]
-    pub(crate) fn notify(&self) {
-        if let Some(waker) = self.swap_awaiter(None) {
-            // We need a safeguard against panics because waking can panic.
-            abort_on_panic(|| {
-                waker.wake();
-            });
-        }
-    }
+    pub(crate) fn notify(&self, current: Option<&Waker>) {
+        // Mark the awaiter as being notified.
+        let state = self.state.fetch_or(NOTIFYING, Ordering::AcqRel);
 
-    /// Notifies the awaiter blocked on this task, unless its waker matches `current`.
-    ///
-    /// If there is a registered waker, it will be removed from the header in any case.
-    #[inline]
-    pub(crate) fn notify_unless(&self, current: &Waker) {
-        if let Some(waker) = self.swap_awaiter(None) {
-            if !waker.will_wake(current) {
+        // If the awaiter was not being notified nor registered...
+        if state & (NOTIFYING | REGISTERING) == 0 {
+            // Take the waker out.
+            let waker = unsafe { (*self.awaiter.get()).take() };
+
+            // Mark the state as not being notified anymore nor containing an awaiter.
+            self.state
+                .fetch_and(!NOTIFYING & !AWAITER, Ordering::Release);
+
+            if let Some(w) = waker {
                 // We need a safeguard against panics because waking can panic.
-                abort_on_panic(|| {
-                    waker.wake();
+                abort_on_panic(|| match current {
+                    None => w.wake(),
+                    Some(c) if !w.will_wake(c) => w.wake(),
+                    Some(_) => {}
                 });
             }
         }
     }
 
-    /// Swaps the awaiter for a new waker and returns the previous value.
+    /// Registers a new awaiter blocked on this task.
+    ///
+    /// This method is called when `JoinHandle` is polled and the task has not completed.
     #[inline]
-    pub(crate) fn swap_awaiter(&self, new: Option<Waker>) -> Option<Waker> {
-        let new_is_none = new.is_none();
+    pub(crate) fn register(&self, waker: &Waker) {
+        // Load the state and synchronize with it.
+        let mut state = self.state.fetch_or(0, Ordering::Acquire);
 
-        // We're about to try acquiring the lock in a loop. If it's already being held by another
-        // thread, we'll have to spin for a while so it's best to employ a backoff strategy.
-        let backoff = Backoff::new();
         loop {
-            // Acquire the lock. If we're storing an awaiter, then also set the awaiter flag.
-            let state = if new_is_none {
-                self.state.fetch_or(LOCKED, Ordering::Acquire)
-            } else {
-                self.state.fetch_or(LOCKED | AWAITER, Ordering::Acquire)
-            };
+            // There can't be two concurrent registrations because `JoinHandle` can only be polled
+            // by a unique pinned reference.
+            debug_assert!(state & REGISTERING == 0);
+
+            // If we're in the notifying state at this moment, just wake and return without
+            // registering.
+            if state & NOTIFYING != 0 {
+                waker.wake_by_ref();
+                return;
+            }
 
-            // If the lock was acquired, break from the loop.
-            if state & LOCKED == 0 {
-                break;
+            // Mark the state to let other threads know we're registering a new awaiter.
+            match self.state.compare_exchange_weak(
+                state,
+                state | REGISTERING,
+                Ordering::AcqRel,
+                Ordering::Acquire,
+            ) {
+                Ok(_) => {
+                    state |= REGISTERING;
+                    break;
+                }
+                Err(s) => state = s,
             }
+        }
 
-            // Snooze for a little while because the lock is held by another thread.
-            backoff.snooze();
+        // Put the waker into the awaiter field.
+        unsafe {
+            abort_on_panic(|| (*self.awaiter.get()) = Some(waker.clone()));
         }
 
-        // Replace the awaiter.
-        let old = self.awaiter.replace(new);
+        // This variable will contain the newly registered waker if a notification comes in before
+        // we complete registration.
+        let mut waker = None;
+
+        loop {
+            // If there was a notification, take the waker out of the awaiter field.
+            if state & NOTIFYING != 0 {
+                if let Some(w) = unsafe { (*self.awaiter.get()).take() } {
+                    waker = Some(w);
+                }
+            }
+
+            // The new state is not being notified nor registered, but there might or might not be
+            // an awaiter depending on whether there was a concurrent notification.
+            let new = if waker.is_none() {
+                (state & !NOTIFYING & !REGISTERING) | AWAITER
+            } else {
+                state & !NOTIFYING & !REGISTERING & !AWAITER
+            };
 
-        // Release the lock. If we've cleared the awaiter, then also unset the awaiter flag.
-        if new_is_none {
-            self.state.fetch_and(!LOCKED & !AWAITER, Ordering::Release);
-        } else {
-            self.state.fetch_and(!LOCKED, Ordering::Release);
+            match self
+                .state
+                .compare_exchange_weak(state, new, Ordering::AcqRel, Ordering::Acquire)
+            {
+                Ok(_) => break,
+                Err(s) => state = s,
+            }
         }
 
-        old
+        // If there was a notification during registration, wake the awaiter now.
+        if let Some(w) = waker {
+            abort_on_panic(|| w.wake());
+        }
     }
 
     /// Returns the offset at which the tag of type `T` is stored.
diff --git a/src/join_handle.rs b/src/join_handle.rs
index bd9366f..f4710cc 100644
--- a/src/join_handle.rs
+++ b/src/join_handle.rs
@@ -1,10 +1,10 @@
-use std::fmt;
-use std::future::Future;
-use std::marker::{PhantomData, Unpin};
-use std::pin::Pin;
-use std::ptr::NonNull;
-use std::sync::atomic::Ordering;
-use std::task::{Context, Poll};
+use core::fmt;
+use core::future::Future;
+use core::marker::{PhantomData, Unpin};
+use core::pin::Pin;
+use core::ptr::NonNull;
+use core::sync::atomic::Ordering;
+use core::task::{Context, Poll, Waker};
 
 use crate::header::Header;
 use crate::state::*;
@@ -24,7 +24,7 @@ pub struct JoinHandle<R, T> {
     pub(crate) _marker: PhantomData<(R, T)>,
 }
 
-unsafe impl<R, T> Send for JoinHandle<R, T> {}
+unsafe impl<R: Send, T> Send for JoinHandle<R, T> {}
 unsafe impl<R, T> Sync for JoinHandle<R, T> {}
 
 impl<R, T> Unpin for JoinHandle<R, T> {}
@@ -71,7 +71,7 @@ impl<R, T> JoinHandle<R, T> {
 
                         // Notify the awaiter that the task has been closed.
                         if state & AWAITER != 0 {
-                            (*header).notify();
+                            (*header).notify(None);
                         }
 
                         break;
@@ -92,6 +92,17 @@ impl<R, T> JoinHandle<R, T> {
             &*raw
         }
     }
+
+    /// Returns a waker associated with the task.
+    pub fn waker(&self) -> Waker {
+        let ptr = self.raw_task.as_ptr();
+        let header = ptr as *const Header;
+
+        unsafe {
+            let raw_waker = ((*header).vtable.clone_waker)(ptr);
+            Waker::from_raw(raw_waker)
+        }
+    }
 }
 
 impl<R, T> Drop for JoinHandle<R, T> {
@@ -190,7 +201,7 @@ impl<R, T> Future for JoinHandle<R, T> {
                 if state & CLOSED != 0 {
                     // Even though the awaiter is most likely the current task, it could also be
                     // another task.
-                    (*header).notify_unless(cx.waker());
+                    (*header).notify(Some(cx.waker()));
                     return Poll::Ready(None);
                 }
 
@@ -199,18 +210,17 @@ impl<R, T> Future for JoinHandle<R, T> {
                     // Replace the waker with one associated with the current task. We need a
                     // safeguard against panics because dropping the previous waker can panic.
                     abort_on_panic(|| {
-                        (*header).swap_awaiter(Some(cx.waker().clone()));
+                        (*header).register(cx.waker());
                     });
 
                     // Reload the state after registering. It is possible that the task became
                     // completed or closed just before registration so we need to check for that.
                     state = (*header).state.load(Ordering::Acquire);
 
-                    // If the task has been closed, notify the awaiter and return `None`.
+                    // If the task has been closed, return `None`. We do not need to notify the
+                    // awaiter here, since we have replaced the waker above, and the executor can
+                    // only set it back to `None`.
                     if state & CLOSED != 0 {
-                        // Even though the awaiter is most likely the current task, it could also
-                        // be another task.
-                        (*header).notify_unless(cx.waker());
                         return Poll::Ready(None);
                     }
 
@@ -231,7 +241,7 @@ impl<R, T> Future for JoinHandle<R, T> {
                         // Notify the awaiter. Even though the awaiter is most likely the current
                         // task, it could also be another task.
                         if state & AWAITER != 0 {
-                            (*header).notify_unless(cx.waker());
+                            (*header).notify(Some(cx.waker()));
                         }
 
                         // Take the output from the task.
diff --git a/src/lib.rs b/src/lib.rs
index 3f61ea4..c1391a2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,13 +1,11 @@
 //! Task abstraction for building executors.
 //!
+//! # Spawning
+//!
 //! To spawn a future onto an executor, we first need to allocate it on the heap and keep some
 //! state alongside it. The state indicates whether the future is ready for polling, waiting to be
 //! woken up, or completed. Such a future is called a *task*.
 //!
-//! This crate helps with task allocation and polling its future to completion.
-//!
-//! # Spawning
-//!
 //! All executors have some kind of queue that holds runnable tasks:
 //!
 //! ```
@@ -23,7 +21,7 @@
 //! # let (task, handle) = async_task::spawn(future, schedule, ());
 //! ```
 //!
-//! A task is constructed using the [`spawn`] function:
+//! A task is constructed using either [`spawn`] or [`spawn_local`]:
 //!
 //! ```
 //! # let (sender, receiver) = crossbeam::channel::unbounded();
@@ -89,23 +87,50 @@
 //! Task construction incurs a single allocation that holds its state, the schedule function, and
 //! the future or the result of the future if completed.
 //!
-//! The layout of a task is equivalent to 4 words followed by the schedule function, and then by a
-//! union of the future and its output.
+//! The layout of a task is equivalent to 4 `usize`s followed by the schedule function, and then by
+//! a union of the future and its output.
+//!
+//! # Waking
+//!
+//! The handy [`waker_fn`] constructor converts any function into a [`Waker`]. Every time it is
+//! woken, the function gets called:
+//!
+//! ```
+//! let waker = async_task::waker_fn(|| println!("Wake!"));
+//!
+//! // Prints "Wake!" twice.
+//! waker.wake_by_ref();
+//! waker.wake_by_ref();
+//! ```
+//!
+//! This is useful for implementing single-future executors like [`block_on`].
 //!
 //! [`spawn`]: fn.spawn.html
+//! [`spawn_local`]: fn.spawn_local.html
+//! [`waker_fn`]: fn.waker_fn.html
 //! [`Task`]: struct.Task.html
 //! [`JoinHandle`]: struct.JoinHandle.html
+//! [`Waker`]: https://doc.rust-lang.org/std/task/struct.Waker.html
+//! [`block_on`]: https://github.com/async-rs/async-task/blob/master/examples/block.rs
 
+#![no_std]
 #![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
 #![doc(test(attr(deny(rust_2018_idioms, warnings))))]
 #![doc(test(attr(allow(unused_extern_crates, unused_variables))))]
 
+extern crate alloc;
+
 mod header;
 mod join_handle;
 mod raw;
 mod state;
 mod task;
 mod utils;
+mod waker_fn;
 
 pub use crate::join_handle::JoinHandle;
 pub use crate::task::{spawn, Task};
+pub use crate::waker_fn::waker_fn;
+
+#[cfg(any(unix, windows))]
+pub use crate::task::spawn_local;
diff --git a/src/raw.rs b/src/raw.rs
index 3b993a3..ed3ee97 100644
--- a/src/raw.rs
+++ b/src/raw.rs
@@ -1,23 +1,20 @@
-use std::alloc::{self, Layout};
-use std::cell::Cell;
-use std::future::Future;
-use std::marker::PhantomData;
-use std::mem::{self, ManuallyDrop};
-use std::pin::Pin;
-use std::ptr::NonNull;
-use std::sync::atomic::{AtomicUsize, Ordering};
-use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
+use alloc::alloc::Layout;
+use core::cell::UnsafeCell;
+use core::future::Future;
+use core::marker::PhantomData;
+use core::mem::{self, ManuallyDrop};
+use core::pin::Pin;
+use core::ptr::NonNull;
+use core::sync::atomic::{AtomicUsize, Ordering};
+use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
 
 use crate::header::Header;
 use crate::state::*;
-use crate::utils::{abort_on_panic, extend};
+use crate::utils::{abort, abort_on_panic, extend};
 use crate::Task;
 
 /// The vtable for a task.
 pub(crate) struct TaskVTable {
-    /// The raw waker vtable.
-    pub(crate) raw_waker: RawWakerVTable,
-
     /// Schedules the task.
     pub(crate) schedule: unsafe fn(*const ()),
 
@@ -35,6 +32,9 @@ pub(crate) struct TaskVTable {
 
     /// Runs the task.
     pub(crate) run: unsafe fn(*const ()),
+
+    /// Creates a new waker associated with the task.
+    pub(crate) clone_waker: unsafe fn(ptr: *const ()) -> RawWaker,
 }
 
 /// Memory layout of a task.
@@ -95,22 +95,27 @@ impl<F, R, S, T> Clone for RawTask<F, R, S, T> {
 
 impl<F, R, S, T> RawTask<F, R, S, T>
 where
-    F: Future<Output = R> + Send + 'static,
-    R: Send + 'static,
+    F: Future<Output = R> + 'static,
     S: Fn(Task<T>) + Send + Sync + 'static,
-    T: Send + 'static,
 {
+    const RAW_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
+        Self::clone_waker,
+        Self::wake,
+        Self::wake_by_ref,
+        Self::drop_waker,
+    );
+
     /// Allocates a task with the given `future` and `schedule` function.
     ///
     /// It is assumed that initially only the `Task` reference and the `JoinHandle` exist.
-    pub(crate) fn allocate(tag: T, future: F, schedule: S) -> NonNull<()> {
+    pub(crate) fn allocate(future: F, schedule: S, tag: T) -> NonNull<()> {
         // Compute the layout of the task for allocation. Abort if the computation fails.
         let task_layout = abort_on_panic(|| Self::task_layout());
 
         unsafe {
             // Allocate enough space for the entire task.
-            let raw_task = match NonNull::new(alloc::alloc(task_layout.layout) as *mut ()) {
-                None => std::process::abort(),
+            let raw_task = match NonNull::new(alloc::alloc::alloc(task_layout.layout) as *mut ()) {
+                None => abort(),
                 Some(p) => p,
             };
 
@@ -119,20 +124,15 @@ where
             // Write the header as the first field of the task.
             (raw.header as *mut Header).write(Header {
                 state: AtomicUsize::new(SCHEDULED | HANDLE | REFERENCE),
-                awaiter: Cell::new(None),
+                awaiter: UnsafeCell::new(None),
                 vtable: &TaskVTable {
-                    raw_waker: RawWakerVTable::new(
-                        Self::clone_waker,
-                        Self::wake,
-                        Self::wake_by_ref,
-                        Self::drop_waker,
-                    ),
                     schedule: Self::schedule,
                     drop_future: Self::drop_future,
                     get_output: Self::get_output,
                     drop_task: Self::drop_task,
                     destroy: Self::destroy,
                     run: Self::run,
+                    clone_waker: Self::clone_waker,
                 },
             });
 
@@ -200,6 +200,14 @@ where
 
     /// Wakes a waker.
     unsafe fn wake(ptr: *const ()) {
+        // This is just an optimization. If the schedule function has captured variables, then
+        // we'll do less reference counting if we wake the waker by reference and then drop it.
+        if mem::size_of::<S>() > 0 {
+            Self::wake_by_ref(ptr);
+            Self::drop_waker(ptr);
+            return;
+        }
+
         let raw = Self::from_ptr(ptr);
 
         let mut state = (*raw.header).state.load(Ordering::Acquire);
@@ -240,13 +248,9 @@ where
                     Ok(_) => {
                         // If the task is not yet scheduled and isn't currently running, now is the
                         // time to schedule it.
-                        if state & (SCHEDULED | RUNNING) == 0 {
+                        if state & RUNNING == 0 {
                             // Schedule the task.
-                            let task = Task {
-                                raw_task: NonNull::new_unchecked(ptr as *mut ()),
-                                _marker: PhantomData,
-                            };
-                            (*raw.schedule)(task);
+                            Self::schedule(ptr);
                         } else {
                             // Drop the waker.
                             Self::drop_waker(ptr);
@@ -286,8 +290,8 @@ where
                     Err(s) => state = s,
                 }
             } else {
-                // If the task is not scheduled nor running, we'll need to schedule after waking.
-                let new = if state & (SCHEDULED | RUNNING) == 0 {
+                // If the task is not running, we can schedule right away.
+                let new = if state & RUNNING == 0 {
                     (state | SCHEDULED) + REFERENCE
                 } else {
                     state | SCHEDULED
@@ -301,14 +305,16 @@ where
                     Ordering::Acquire,
                 ) {
                     Ok(_) => {
-                        // If the task is not scheduled nor running, now is the time to schedule.
-                        if state & (SCHEDULED | RUNNING) == 0 {
+                        // If the task is not running, now is the time to schedule.
+                        if state & RUNNING == 0 {
                             // If the reference count overflowed, abort.
                             if state > isize::max_value() as usize {
-                                std::process::abort();
+                                abort();
                             }
 
-                            // Schedule the task.
+                            // Schedule the task. There is no need to call `Self::schedule(ptr)`
+                            // because the schedule function cannot be destroyed while the waker is
+                            // still alive.
                             let task = Task {
                                 raw_task: NonNull::new_unchecked(ptr as *mut ()),
                                 _marker: PhantomData,
@@ -327,7 +333,6 @@ where
     /// Clones a waker.
     unsafe fn clone_waker(ptr: *const ()) -> RawWaker {
         let raw = Self::from_ptr(ptr);
-        let raw_waker = &(*raw.header).vtable.raw_waker;
 
         // Increment the reference count. With any kind of reference-counted data structure,
         // relaxed ordering is appropriate when incrementing the counter.
@@ -335,10 +340,10 @@ where
 
         // If the reference count overflowed, abort.
         if state > isize::max_value() as usize {
-            std::process::abort();
+            abort();
         }
 
-        RawWaker::new(ptr, raw_waker)
+        RawWaker::new(ptr, &Self::RAW_WAKER_VTABLE)
     }
 
     /// Drops a waker.
@@ -362,7 +367,7 @@ where
                 (*raw.header)
                     .state
                     .store(SCHEDULED | CLOSED | REFERENCE, Ordering::Release);
-                ((*raw.header).vtable.schedule)(ptr);
+                Self::schedule(ptr);
             } else {
                 // Otherwise, destroy the task right away.
                 Self::destroy(ptr);
@@ -395,10 +400,18 @@ where
     unsafe fn schedule(ptr: *const ()) {
         let raw = Self::from_ptr(ptr);
 
-        (*raw.schedule)(Task {
+        // If the schedule function has captured variables, create a temporary waker that prevents
+        // the task from getting deallocated while the function is being invoked.
+        let _waker;
+        if mem::size_of::<S>() > 0 {
+            _waker = Waker::from_raw(Self::clone_waker(ptr));
+        }
+
+        let task = Task {
             raw_task: NonNull::new_unchecked(ptr as *mut ()),
             _marker: PhantomData,
-        });
+        };
+        (*raw.schedule)(task);
     }
 
     /// Drops the future inside a task.
@@ -437,7 +450,7 @@ where
         });
 
         // Finally, deallocate the memory reserved by the task.
-        alloc::dealloc(ptr as *mut u8, task_layout.layout);
+        alloc::alloc::dealloc(ptr as *mut u8, task_layout.layout);
     }
 
     /// Runs a task.
@@ -448,10 +461,7 @@ where
         let raw = Self::from_ptr(ptr);
 
         // Create a context from the raw task pointer and the vtable inside the its header.
-        let waker = ManuallyDrop::new(Waker::from_raw(RawWaker::new(
-            ptr,
-            &(*raw.header).vtable.raw_waker,
-        )));
+        let waker = ManuallyDrop::new(Waker::from_raw(RawWaker::new(ptr, &Self::RAW_WAKER_VTABLE)));
         let cx = &mut Context::from_waker(&waker);
 
         let mut state = (*raw.header).state.load(Ordering::Acquire);
@@ -462,7 +472,7 @@ where
             if state & CLOSED != 0 {
                 // Notify the awaiter that the task has been closed.
                 if state & AWAITER != 0 {
-                    (*raw.header).notify();
+                    (*raw.header).notify(None);
                 }
 
                 // Drop the future.
@@ -530,7 +540,7 @@ where
 
                             // Notify the awaiter that the task has been completed.
                             if state & AWAITER != 0 {
-                                (*raw.header).notify();
+                                (*raw.header).notify(None);
                             }
 
                             // Drop the task reference.
@@ -592,17 +602,13 @@ where
         /// A guard that closes the task if polling its future panics.
         struct Guard<F, R, S, T>(RawTask<F, R, S, T>)
         where
-            F: Future<Output = R> + Send + 'static,
-            R: Send + 'static,
-            S: Fn(Task<T>) + Send + Sync + 'static,
-            T: Send + 'static;
+            F: Future<Output = R> + 'static,
+            S: Fn(Task<T>) + Send + Sync + 'static;
 
         impl<F, R, S, T> Drop for Guard<F, R, S, T>
         where
-            F: Future<Output = R> + Send + 'static,
-            R: Send + 'static,
+            F: Future<Output = R> + 'static,
             S: Fn(Task<T>) + Send + Sync + 'static,
-            T: Send + 'static,
         {
             fn drop(&mut self) {
                 let raw = self.0;
@@ -641,7 +647,7 @@ where
 
                                 // Notify the awaiter that the task has been closed.
                                 if state & AWAITER != 0 {
-                                    (*raw.header).notify();
+                                    (*raw.header).notify(None);
                                 }
 
                                 // Drop the task reference.
diff --git a/src/state.rs b/src/state.rs
index c03fea3..167a371 100644
--- a/src/state.rs
+++ b/src/state.rs
@@ -48,10 +48,16 @@ pub(crate) const HANDLE: usize = 1 << 4;
 /// check that tells us if we need to wake anyone without acquiring the lock inside the task.
 pub(crate) const AWAITER: usize = 1 << 5;
 
-/// Set if the awaiter is locked.
+/// Set if an awaiter is being registered.
 ///
-/// This lock is acquired before a new awaiter is registered or the existing one is woken up.
-pub(crate) const LOCKED: usize = 1 << 6;
+/// This flag is set when `JoinHandle` is polled and we are registering a new awaiter.
+pub(crate) const REGISTERING: usize = 1 << 6;
+
+/// Set if the awaiter is being notified.
+///
+/// This flag is set when notifying the awaiter. If an awaiter is concurrently registered and
+/// notified, whichever side came first will take over the reposibility of resolving the race.
+pub(crate) const NOTIFYING: usize = 1 << 7;
 
 /// A single reference.
 ///
@@ -61,4 +67,4 @@ pub(crate) const LOCKED: usize = 1 << 6;
 ///
 /// Note that the reference counter only tracks the `Task` and `Waker`s. The `JoinHandle` is
 /// tracked separately by the `HANDLE` flag.
-pub(crate) const REFERENCE: usize = 1 << 7;
+pub(crate) const REFERENCE: usize = 1 << 8;
diff --git a/src/task.rs b/src/task.rs
index 42a4024..8ef209c 100644
--- a/src/task.rs
+++ b/src/task.rs
@@ -1,8 +1,10 @@
-use std::fmt;
-use std::future::Future;
-use std::marker::PhantomData;
-use std::mem;
-use std::ptr::NonNull;
+use core::fmt;
+use core::future::Future;
+use core::marker::PhantomData;
+use core::mem::{self, ManuallyDrop};
+use core::pin::Pin;
+use core::ptr::NonNull;
+use core::task::{Context, Poll, Waker};
 
 use crate::header::Header;
 use crate::raw::RawTask;
@@ -16,8 +18,16 @@ use crate::JoinHandle;
 /// When run, the task polls `future`. When woken up, it gets scheduled for running by the
 /// `schedule` function. Argument `tag` is an arbitrary piece of data stored inside the task.
 ///
+/// The schedule function should not attempt to run the task nor to drop it. Instead, it should
+/// push the task into some kind of queue so that it can be processed later.
+///
+/// If you need to spawn a future that does not implement [`Send`], consider using the
+/// [`spawn_local`] function instead.
+///
 /// [`Task`]: struct.Task.html
 /// [`JoinHandle`]: struct.JoinHandle.html
+/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
+/// [`spawn_local`]: fn.spawn_local.html
 ///
 /// # Examples
 ///
@@ -43,7 +53,109 @@ where
     S: Fn(Task<T>) + Send + Sync + 'static,
     T: Send + Sync + 'static,
 {
-    let raw_task = RawTask::<F, R, S, T>::allocate(tag, future, schedule);
+    let raw_task = RawTask::<F, R, S, T>::allocate(future, schedule, tag);
+    let task = Task {
+        raw_task,
+        _marker: PhantomData,
+    };
+    let handle = JoinHandle {
+        raw_task,
+        _marker: PhantomData,
+    };
+    (task, handle)
+}
+
+/// Creates a new local task.
+///
+/// This constructor returns a [`Task`] reference that runs the future and a [`JoinHandle`] that
+/// awaits its result.
+///
+/// When run, the task polls `future`. When woken up, it gets scheduled for running by the
+/// `schedule` function. Argument `tag` is an arbitrary piece of data stored inside the task.
+///
+/// The schedule function should not attempt to run the task nor to drop it. Instead, it should
+/// push the task into some kind of queue so that it can be processed later.
+///
+/// Unlike [`spawn`], this function does not require the future to implement [`Send`]. If the
+/// [`Task`] reference is run or dropped on a thread it was not created on, a panic will occur.
+///
+/// [`Task`]: struct.Task.html
+/// [`JoinHandle`]: struct.JoinHandle.html
+/// [`spawn`]: fn.spawn.html
+/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
+///
+/// # Examples
+///
+/// ```
+/// use crossbeam::channel;
+///
+/// // The future inside the task.
+/// let future = async {
+///     println!("Hello, world!");
+/// };
+///
+/// // If the task gets woken up, it will be sent into this channel.
+/// let (s, r) = channel::unbounded();
+/// let schedule = move |task| s.send(task).unwrap();
+///
+/// // Create a task with the future and the schedule function.
+/// let (task, handle) = async_task::spawn_local(future, schedule, ());
+/// ```
+#[cfg(any(unix, windows))]
+pub fn spawn_local<F, R, S, T>(future: F, schedule: S, tag: T) -> (Task<T>, JoinHandle<R, T>)
+where
+    F: Future<Output = R> + 'static,
+    R: 'static,
+    S: Fn(Task<T>) + Send + Sync + 'static,
+    T: Send + Sync + 'static,
+{
+    #[cfg(unix)]
+    #[inline]
+    fn thread_id() -> usize {
+        unsafe { libc::pthread_self() as usize }
+    }
+
+    #[cfg(windows)]
+    #[inline]
+    fn thread_id() -> usize {
+        unsafe { winapi::um::processthreadsapi::GetCurrentThreadId() as usize }
+    }
+
+    struct Checked<F> {
+        id: usize,
+        inner: ManuallyDrop<F>,
+    }
+
+    impl<F> Drop for Checked<F> {
+        fn drop(&mut self) {
+            assert!(
+                self.id == thread_id(),
+                "local task dropped by a thread that didn't spawn it"
+            );
+            unsafe {
+                ManuallyDrop::drop(&mut self.inner);
+            }
+        }
+    }
+
+    impl<F: Future> Future for Checked<F> {
+        type Output = F::Output;
+
+        fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+            assert!(
+                self.id == thread_id(),
+                "local task polled by a thread that didn't spawn it"
+            );
+            unsafe { self.map_unchecked_mut(|c| &mut *c.inner).poll(cx) }
+        }
+    }
+
+    let future = Checked {
+        id: thread_id(),
+        inner: ManuallyDrop::new(future),
+    };
+
+    let raw_task = RawTask::<_, R, S, T>::allocate(future, schedule, tag);
     let task = Task {
         raw_task,
         _marker: PhantomData,
@@ -153,6 +265,41 @@ impl<T> Task<T> {
             &*raw
         }
     }
+
+    /// Converts this task into a raw pointer to the tag.
+    pub fn into_raw(self) -> *const T {
+        let offset = Header::offset_tag::<T>();
+        let ptr = self.raw_task.as_ptr();
+        mem::forget(self);
+
+        unsafe { (ptr as *mut u8).add(offset) as *const T }
+    }
+
+    /// Converts a raw pointer to the tag into a task.
+    ///
+    /// This method should only be used with raw pointers returned from [`into_raw`].
+    ///
+    /// [`into_raw`]: #method.into_raw
+    pub unsafe fn from_raw(raw: *const T) -> Task<T> {
+        let offset = Header::offset_tag::<T>();
+        let ptr = (raw as *mut u8).sub(offset) as *mut ();
+
+        Task {
+            raw_task: NonNull::new_unchecked(ptr),
+            _marker: PhantomData,
+        }
+    }
+
+    /// Returns a waker associated with this task.
+    pub fn waker(&self) -> Waker {
+        let ptr = self.raw_task.as_ptr();
+        let header = ptr as *const Header;
+
+        unsafe {
+            let raw_waker = ((*header).vtable.clone_waker)(ptr);
+            Waker::from_raw(raw_waker)
+        }
+    }
 }
 
 impl<T> Drop for Task<T> {
diff --git a/src/utils.rs b/src/utils.rs
index 441ead1..cb9b65e 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -1,5 +1,21 @@
-use std::alloc::Layout;
-use std::mem;
+use core::alloc::Layout;
+use core::mem;
+
+/// Aborts the process.
+///
+/// To abort, this function simply panics while panicking.
+pub(crate) fn abort() -> ! {
+    struct Panic;
+
+    impl Drop for Panic {
+        fn drop(&mut self) {
+            panic!("aborting the process");
+        }
+    }
+
+    let _panic = Panic;
+    panic!("aborting the process");
+}
 
 /// Calls a function and aborts if it panics.
 ///
@@ -10,7 +26,7 @@ pub(crate) fn abort_on_panic<T>(f: impl FnOnce() -> T) -> T {
 
     impl Drop for Bomb {
         fn drop(&mut self) {
-            std::process::abort();
+            abort();
         }
     }
 
diff --git a/src/waker_fn.rs b/src/waker_fn.rs
new file mode 100644
index 0000000..37105f1
--- /dev/null
+++ b/src/waker_fn.rs
@@ -0,0 +1,43 @@
+use alloc::sync::Arc;
+use core::mem::{self, ManuallyDrop};
+use core::task::{RawWaker, RawWakerVTable, Waker};
+
+/// Creates a waker from a wake function.
+///
+/// The function gets called every time the waker is woken.
+pub fn waker_fn<F: Fn() + Send + Sync + 'static>(f: F) -> Waker {
+    let raw = Arc::into_raw(Arc::new(f)) as *const ();
+    let vtable = &Helper::<F>::VTABLE;
+    unsafe { Waker::from_raw(RawWaker::new(raw, vtable)) }
+}
+
+struct Helper<F>(F);
+
+impl<F: Fn() + Send + Sync + 'static> Helper<F> {
+    const VTABLE: RawWakerVTable = RawWakerVTable::new(
+        Self::clone_waker,
+        Self::wake,
+        Self::wake_by_ref,
+        Self::drop_waker,
+    );
+
+    unsafe fn clone_waker(ptr: *const ()) -> RawWaker {
+        let arc = ManuallyDrop::new(Arc::from_raw(ptr as *const F));
+        mem::forget(arc.clone());
+        RawWaker::new(ptr, &Self::VTABLE)
+    }
+
+    unsafe fn wake(ptr: *const ()) {
+        let arc = Arc::from_raw(ptr as *const F);
+        (arc)();
+    }
+
+    unsafe fn wake_by_ref(ptr: *const ()) {
+        let arc = ManuallyDrop::new(Arc::from_raw(ptr as *const F));
+        (arc)();
+    }
+
+    unsafe fn drop_waker(ptr: *const ()) {
+        drop(Arc::from_raw(ptr as *const F));
+    }
+}
diff --git a/tests/basic.rs b/tests/basic.rs
index 8c8734c..432e14c 100644
--- a/tests/basic.rs
+++ b/tests/basic.rs
@@ -109,132 +109,132 @@ macro_rules! task {
 fn cancel_and_drop_handle() {
     future!(f, POLL, DROP_F);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     assert_eq!(POLL.load(), 0);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
 
     task.cancel();
     assert_eq!(POLL.load(), 0);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
 
     drop(handle);
     assert_eq!(POLL.load(), 0);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
 
     drop(task);
     assert_eq!(POLL.load(), 0);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
 }
 
 #[test]
 fn run_and_drop_handle() {
     future!(f, POLL, DROP_F);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     drop(handle);
     assert_eq!(POLL.load(), 0);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
 
     task.run();
     assert_eq!(POLL.load(), 1);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
 }
 
 #[test]
 fn drop_handle_and_run() {
     future!(f, POLL, DROP_F);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     drop(handle);
     assert_eq!(POLL.load(), 0);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
 
     task.run();
     assert_eq!(POLL.load(), 1);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
 }
 
 #[test]
 fn cancel_and_run() {
     future!(f, POLL, DROP_F);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     handle.cancel();
     assert_eq!(POLL.load(), 0);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
 
     drop(handle);
     assert_eq!(POLL.load(), 0);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
 
     task.run();
     assert_eq!(POLL.load(), 0);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
 }
 
 #[test]
 fn run_and_cancel() {
     future!(f, POLL, DROP_F);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     task.run();
     assert_eq!(POLL.load(), 1);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
 
     handle.cancel();
     assert_eq!(POLL.load(), 1);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
 
     drop(handle);
     assert_eq!(POLL.load(), 1);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
 }
 
 #[test]
@@ -310,3 +310,61 @@ fn schedule_counter() {
     assert_eq!(handle.tag().load(Ordering::SeqCst), 3);
     r.recv().unwrap();
 }
+
+#[test]
+fn drop_inside_schedule() {
+    struct DropGuard(AtomicUsize);
+    impl Drop for DropGuard {
+        fn drop(&mut self) {
+            self.0.fetch_add(1, Ordering::SeqCst);
+        }
+    }
+    let guard = DropGuard(AtomicUsize::new(0));
+
+    let (task, _) = async_task::spawn(
+        async {},
+        move |task| {
+            assert_eq!(guard.0.load(Ordering::SeqCst), 0);
+            drop(task);
+            assert_eq!(guard.0.load(Ordering::SeqCst), 0);
+        },
+        (),
+    );
+    task.schedule();
+}
+
+#[test]
+fn waker() {
+    let (s, r) = channel::unbounded();
+    let schedule = move |t| s.send(t).unwrap();
+    let (task, handle) = async_task::spawn(
+        future::poll_fn(|_| Poll::<()>::Pending),
+        schedule,
+        Box::new(0),
+    );
+
+    assert!(r.is_empty());
+    let w = task.waker();
+    task.run();
+    w.wake();
+
+    let task = r.recv().unwrap();
+    task.run();
+    handle.waker().wake();
+
+    r.recv().unwrap();
+}
+
+#[test]
+fn raw() {
+    let (task, _handle) = async_task::spawn(async {}, |_| panic!(), Box::new(AtomicUsize::new(7)));
+
+    let a = task.into_raw();
+    let task = unsafe {
+        (*a).fetch_add(1, Ordering::SeqCst);
+        Task::from_raw(a)
+    };
+
+    assert_eq!(task.tag().load(Ordering::SeqCst), 8);
+    task.run();
+}
diff --git a/tests/join.rs b/tests/join.rs
index 4bfa7fd..8e17b34 100644
--- a/tests/join.rs
+++ b/tests/join.rs
@@ -126,7 +126,7 @@ fn ms(ms: u64) -> Duration {
 fn cancel_and_join() {
     future!(f, POLL, DROP_F, DROP_O);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     assert_eq!(DROP_O.load(), 0);
 
@@ -139,7 +139,7 @@ fn cancel_and_join() {
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
     assert_eq!(DROP_O.load(), 0);
 }
 
@@ -147,7 +147,7 @@ fn cancel_and_join() {
 fn run_and_join() {
     future!(f, POLL, DROP_F, DROP_O);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     assert_eq!(DROP_O.load(), 0);
 
@@ -159,7 +159,7 @@ fn run_and_join() {
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
     assert_eq!(DROP_O.load(), 1);
 }
 
@@ -167,7 +167,7 @@ fn run_and_join() {
 fn drop_handle_and_run() {
     future!(f, POLL, DROP_F, DROP_O);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     assert_eq!(DROP_O.load(), 0);
 
@@ -179,7 +179,7 @@ fn drop_handle_and_run() {
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
     assert_eq!(DROP_O.load(), 1);
 }
 
@@ -187,7 +187,7 @@ fn drop_handle_and_run() {
 fn join_twice() {
     future!(f, POLL, DROP_F, DROP_O);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, mut handle, f, s, DROP_D);
+    task!(task, mut handle, f, s, DROP_T);
 
     assert_eq!(DROP_O.load(), 0);
 
@@ -199,7 +199,7 @@ fn join_twice() {
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(DROP_O.load(), 1);
 
     assert!(block_on(&mut handle).is_none());
@@ -207,45 +207,45 @@ fn join_twice() {
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(DROP_O.load(), 1);
 
     drop(handle);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
 }
 
 #[test]
 fn join_and_cancel() {
     future!(f, POLL, DROP_F, DROP_O);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     crossbeam::scope(|scope| {
         scope.spawn(|_| {
-            thread::sleep(ms(100));
+            thread::sleep(ms(200));
 
             task.cancel();
             drop(task);
 
-            thread::sleep(ms(200));
+            thread::sleep(ms(400));
             assert_eq!(POLL.load(), 0);
             assert_eq!(SCHEDULE.load(), 0);
             assert_eq!(DROP_F.load(), 1);
             assert_eq!(DROP_O.load(), 0);
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
         });
 
         assert!(block_on(handle).is_none());
         assert_eq!(POLL.load(), 0);
         assert_eq!(SCHEDULE.load(), 0);
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
         assert_eq!(DROP_F.load(), 1);
         assert_eq!(DROP_O.load(), 0);
         assert_eq!(DROP_S.load(), 1);
-        assert_eq!(DROP_D.load(), 1);
+        assert_eq!(DROP_T.load(), 1);
     })
     .unwrap();
 }
@@ -254,20 +254,20 @@ fn join_and_cancel() {
 fn join_and_run() {
     future!(f, POLL, DROP_F, DROP_O);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     crossbeam::scope(|scope| {
         scope.spawn(|_| {
-            thread::sleep(ms(200));
+            thread::sleep(ms(400));
 
             task.run();
             assert_eq!(POLL.load(), 1);
             assert_eq!(SCHEDULE.load(), 0);
             assert_eq!(DROP_F.load(), 1);
 
-            thread::sleep(ms(100));
+            thread::sleep(ms(200));
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
         });
 
         assert!(block_on(handle).is_some());
@@ -276,9 +276,9 @@ fn join_and_run() {
         assert_eq!(DROP_F.load(), 1);
         assert_eq!(DROP_O.load(), 1);
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
         assert_eq!(DROP_S.load(), 1);
-        assert_eq!(DROP_D.load(), 1);
+        assert_eq!(DROP_T.load(), 1);
     })
     .unwrap();
 }
@@ -287,20 +287,20 @@ fn join_and_run() {
 fn try_join_and_run_and_join() {
     future!(f, POLL, DROP_F, DROP_O);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, mut handle, f, s, DROP_D);
+    task!(task, mut handle, f, s, DROP_T);
 
     crossbeam::scope(|scope| {
         scope.spawn(|_| {
-            thread::sleep(ms(200));
+            thread::sleep(ms(400));
 
             task.run();
             assert_eq!(POLL.load(), 1);
             assert_eq!(SCHEDULE.load(), 0);
             assert_eq!(DROP_F.load(), 1);
 
-            thread::sleep(ms(100));
+            thread::sleep(ms(200));
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
         });
 
         block_on(future::select(&mut handle, future::ready(())));
@@ -308,7 +308,7 @@ fn try_join_and_run_and_join() {
         assert_eq!(SCHEDULE.load(), 0);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(DROP_O.load(), 0);
 
         assert!(block_on(handle).is_some());
@@ -317,9 +317,9 @@ fn try_join_and_run_and_join() {
         assert_eq!(DROP_F.load(), 1);
         assert_eq!(DROP_O.load(), 1);
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
         assert_eq!(DROP_S.load(), 1);
-        assert_eq!(DROP_D.load(), 1);
+        assert_eq!(DROP_T.load(), 1);
     })
     .unwrap();
 }
@@ -328,18 +328,18 @@ fn try_join_and_run_and_join() {
 fn try_join_and_cancel_and_run() {
     future!(f, POLL, DROP_F, DROP_O);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, mut handle, f, s, DROP_D);
+    task!(task, mut handle, f, s, DROP_T);
 
     crossbeam::scope(|scope| {
         scope.spawn(|_| {
-            thread::sleep(ms(200));
+            thread::sleep(ms(400));
 
             task.run();
             assert_eq!(POLL.load(), 0);
             assert_eq!(SCHEDULE.load(), 0);
             assert_eq!(DROP_F.load(), 1);
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
         });
 
         block_on(future::select(&mut handle, future::ready(())));
@@ -347,7 +347,7 @@ fn try_join_and_cancel_and_run() {
         assert_eq!(SCHEDULE.load(), 0);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(DROP_O.load(), 0);
 
         handle.cancel();
@@ -355,7 +355,7 @@ fn try_join_and_cancel_and_run() {
         assert_eq!(SCHEDULE.load(), 0);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(DROP_O.load(), 0);
 
         drop(handle);
@@ -363,7 +363,7 @@ fn try_join_and_cancel_and_run() {
         assert_eq!(SCHEDULE.load(), 0);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(DROP_O.load(), 0);
     })
     .unwrap();
@@ -373,7 +373,7 @@ fn try_join_and_cancel_and_run() {
 fn try_join_and_run_and_cancel() {
     future!(f, POLL, DROP_F, DROP_O);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, mut handle, f, s, DROP_D);
+    task!(task, mut handle, f, s, DROP_T);
 
     crossbeam::scope(|scope| {
         scope.spawn(|_| {
@@ -384,7 +384,7 @@ fn try_join_and_run_and_cancel() {
             assert_eq!(SCHEDULE.load(), 0);
             assert_eq!(DROP_F.load(), 1);
             assert_eq!(DROP_S.load(), 0);
-            assert_eq!(DROP_D.load(), 0);
+            assert_eq!(DROP_T.load(), 0);
         });
 
         block_on(future::select(&mut handle, future::ready(())));
@@ -392,7 +392,7 @@ fn try_join_and_run_and_cancel() {
         assert_eq!(SCHEDULE.load(), 0);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(DROP_O.load(), 0);
 
         thread::sleep(ms(400));
@@ -402,7 +402,7 @@ fn try_join_and_run_and_cancel() {
         assert_eq!(SCHEDULE.load(), 0);
         assert_eq!(DROP_F.load(), 1);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(DROP_O.load(), 0);
 
         drop(handle);
@@ -410,7 +410,7 @@ fn try_join_and_run_and_cancel() {
         assert_eq!(SCHEDULE.load(), 0);
         assert_eq!(DROP_F.load(), 1);
         assert_eq!(DROP_S.load(), 1);
-        assert_eq!(DROP_D.load(), 1);
+        assert_eq!(DROP_T.load(), 1);
         assert_eq!(DROP_O.load(), 1);
     })
     .unwrap();
diff --git a/tests/panic.rs b/tests/panic.rs
index ef917dc..80a8f1b 100644
--- a/tests/panic.rs
+++ b/tests/panic.rs
@@ -33,7 +33,7 @@ macro_rules! future {
 
                 fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
                     $poll.fetch_add(1);
-                    thread::sleep(ms(200));
+                    thread::sleep(ms(400));
                     panic!()
                 }
             }
@@ -116,7 +116,7 @@ fn ms(ms: u64) -> Duration {
 fn cancel_during_run() {
     future!(f, POLL, DROP_F);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     crossbeam::scope(|scope| {
         scope.spawn(|_| {
@@ -125,24 +125,24 @@ fn cancel_during_run() {
             assert_eq!(SCHEDULE.load(), 0);
             assert_eq!(DROP_F.load(), 1);
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
         });
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
 
         handle.cancel();
         assert_eq!(POLL.load(), 1);
         assert_eq!(SCHEDULE.load(), 0);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
 
         drop(handle);
         assert_eq!(POLL.load(), 1);
         assert_eq!(SCHEDULE.load(), 0);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
     })
     .unwrap();
 }
@@ -151,56 +151,56 @@ fn cancel_during_run() {
 fn run_and_join() {
     future!(f, POLL, DROP_F);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     assert!(catch_unwind(|| task.run()).is_err());
     assert_eq!(POLL.load(), 1);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
 
     assert!(block_on(handle).is_none());
     assert_eq!(POLL.load(), 1);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
 }
 
 #[test]
 fn try_join_and_run_and_join() {
     future!(f, POLL, DROP_F);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, mut handle, f, s, DROP_D);
+    task!(task, mut handle, f, s, DROP_T);
 
     block_on(future::select(&mut handle, future::ready(())));
     assert_eq!(POLL.load(), 0);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
 
     assert!(catch_unwind(|| task.run()).is_err());
     assert_eq!(POLL.load(), 1);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
 
     assert!(block_on(handle).is_none());
     assert_eq!(POLL.load(), 1);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
 }
 
 #[test]
 fn join_during_run() {
     future!(f, POLL, DROP_F);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     crossbeam::scope(|scope| {
         scope.spawn(|_| {
@@ -209,21 +209,21 @@ fn join_during_run() {
             assert_eq!(SCHEDULE.load(), 0);
             assert_eq!(DROP_F.load(), 1);
 
-            thread::sleep(ms(100));
+            thread::sleep(ms(200));
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
         });
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
 
         assert!(block_on(handle).is_none());
         assert_eq!(POLL.load(), 1);
         assert_eq!(SCHEDULE.load(), 0);
         assert_eq!(DROP_F.load(), 1);
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
         assert_eq!(DROP_S.load(), 1);
-        assert_eq!(DROP_D.load(), 1);
+        assert_eq!(DROP_T.load(), 1);
     })
     .unwrap();
 }
@@ -232,7 +232,7 @@ fn join_during_run() {
 fn try_join_during_run() {
     future!(f, POLL, DROP_F);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, mut handle, f, s, DROP_D);
+    task!(task, mut handle, f, s, DROP_T);
 
     crossbeam::scope(|scope| {
         scope.spawn(|_| {
@@ -241,17 +241,17 @@ fn try_join_during_run() {
             assert_eq!(SCHEDULE.load(), 0);
             assert_eq!(DROP_F.load(), 1);
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
         });
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
 
         block_on(future::select(&mut handle, future::ready(())));
         assert_eq!(POLL.load(), 1);
         assert_eq!(SCHEDULE.load(), 0);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         drop(handle);
     })
     .unwrap();
@@ -261,7 +261,7 @@ fn try_join_during_run() {
 fn drop_handle_during_run() {
     future!(f, POLL, DROP_F);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     crossbeam::scope(|scope| {
         scope.spawn(|_| {
@@ -270,17 +270,17 @@ fn drop_handle_during_run() {
             assert_eq!(SCHEDULE.load(), 0);
             assert_eq!(DROP_F.load(), 1);
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
         });
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
 
         drop(handle);
         assert_eq!(POLL.load(), 1);
         assert_eq!(SCHEDULE.load(), 0);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
     })
     .unwrap();
 }
diff --git a/tests/ready.rs b/tests/ready.rs
index abdeb90..a966760 100644
--- a/tests/ready.rs
+++ b/tests/ready.rs
@@ -34,7 +34,7 @@ macro_rules! future {
 
                 fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
                     $poll.fetch_add(1);
-                    thread::sleep(ms(200));
+                    thread::sleep(ms(400));
                     Poll::Ready(Out(Box::new(0)))
                 }
             }
@@ -125,7 +125,7 @@ fn ms(ms: u64) -> Duration {
 fn cancel_during_run() {
     future!(f, POLL, DROP_F, DROP_O);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     crossbeam::scope(|scope| {
         scope.spawn(|_| {
@@ -134,27 +134,27 @@ fn cancel_during_run() {
             assert_eq!(SCHEDULE.load(), 0);
             assert_eq!(DROP_F.load(), 1);
             assert_eq!(DROP_S.load(), 0);
-            assert_eq!(DROP_D.load(), 0);
+            assert_eq!(DROP_T.load(), 0);
             assert_eq!(DROP_O.load(), 1);
         });
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
 
         handle.cancel();
         assert_eq!(POLL.load(), 1);
         assert_eq!(SCHEDULE.load(), 0);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(DROP_O.load(), 0);
 
-        thread::sleep(ms(200));
+        thread::sleep(ms(400));
 
         assert_eq!(POLL.load(), 1);
         assert_eq!(SCHEDULE.load(), 0);
         assert_eq!(DROP_F.load(), 1);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(DROP_O.load(), 1);
 
         drop(handle);
@@ -162,7 +162,7 @@ fn cancel_during_run() {
         assert_eq!(SCHEDULE.load(), 0);
         assert_eq!(DROP_F.load(), 1);
         assert_eq!(DROP_S.load(), 1);
-        assert_eq!(DROP_D.load(), 1);
+        assert_eq!(DROP_T.load(), 1);
         assert_eq!(DROP_O.load(), 1);
     })
     .unwrap();
@@ -172,7 +172,7 @@ fn cancel_during_run() {
 fn join_during_run() {
     future!(f, POLL, DROP_F, DROP_O);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     crossbeam::scope(|scope| {
         scope.spawn(|_| {
@@ -181,12 +181,12 @@ fn join_during_run() {
             assert_eq!(SCHEDULE.load(), 0);
             assert_eq!(DROP_F.load(), 1);
 
-            thread::sleep(ms(100));
+            thread::sleep(ms(200));
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
         });
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
 
         assert!(block_on(handle).is_some());
         assert_eq!(POLL.load(), 1);
@@ -194,9 +194,9 @@ fn join_during_run() {
         assert_eq!(DROP_F.load(), 1);
         assert_eq!(DROP_O.load(), 1);
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
         assert_eq!(DROP_S.load(), 1);
-        assert_eq!(DROP_D.load(), 1);
+        assert_eq!(DROP_T.load(), 1);
     })
     .unwrap();
 }
@@ -205,7 +205,7 @@ fn join_during_run() {
 fn try_join_during_run() {
     future!(f, POLL, DROP_F, DROP_O);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, mut handle, f, s, DROP_D);
+    task!(task, mut handle, f, s, DROP_T);
 
     crossbeam::scope(|scope| {
         scope.spawn(|_| {
@@ -214,18 +214,18 @@ fn try_join_during_run() {
             assert_eq!(SCHEDULE.load(), 0);
             assert_eq!(DROP_F.load(), 1);
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
             assert_eq!(DROP_O.load(), 1);
         });
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
 
         block_on(future::select(&mut handle, future::ready(())));
         assert_eq!(POLL.load(), 1);
         assert_eq!(SCHEDULE.load(), 0);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(DROP_O.load(), 0);
         drop(handle);
     })
@@ -236,7 +236,7 @@ fn try_join_during_run() {
 fn drop_handle_during_run() {
     future!(f, POLL, DROP_F, DROP_O);
     schedule!(s, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     crossbeam::scope(|scope| {
         scope.spawn(|_| {
@@ -245,18 +245,18 @@ fn drop_handle_during_run() {
             assert_eq!(SCHEDULE.load(), 0);
             assert_eq!(DROP_F.load(), 1);
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
             assert_eq!(DROP_O.load(), 1);
         });
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
 
         drop(handle);
         assert_eq!(POLL.load(), 1);
         assert_eq!(SCHEDULE.load(), 0);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(DROP_O.load(), 0);
     })
     .unwrap();
diff --git a/tests/waker_fn.rs b/tests/waker_fn.rs
new file mode 100644
index 0000000..fdad34c
--- /dev/null
+++ b/tests/waker_fn.rs
@@ -0,0 +1,29 @@
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Arc;
+
+#[test]
+fn wake() {
+    let a = Arc::new(AtomicUsize::new(0));
+    let w = async_task::waker_fn({
+        let a = a.clone();
+        move || {
+            a.fetch_add(1, Ordering::SeqCst);
+        }
+    });
+
+    assert_eq!(a.load(Ordering::SeqCst), 0);
+    w.wake_by_ref();
+    assert_eq!(a.load(Ordering::SeqCst), 1);
+
+    let w2 = w.clone();
+    assert_eq!(a.load(Ordering::SeqCst), 1);
+    w2.wake_by_ref();
+    assert_eq!(a.load(Ordering::SeqCst), 2);
+    drop(w2);
+    assert_eq!(a.load(Ordering::SeqCst), 2);
+
+    let w3 = w.clone();
+    assert_eq!(a.load(Ordering::SeqCst), 2);
+    w3.wake();
+    assert_eq!(a.load(Ordering::SeqCst), 3);
+}
diff --git a/tests/waker_panic.rs b/tests/waker_panic.rs
index 3a8dfe8..eb77912 100644
--- a/tests/waker_panic.rs
+++ b/tests/waker_panic.rs
@@ -39,7 +39,7 @@ macro_rules! future {
                 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
                     WAKER.store(Some(cx.waker().clone()));
                     $poll.fetch_add(1);
-                    thread::sleep(ms(200));
+                    thread::sleep(ms(400));
 
                     if self.0.get() {
                         panic!()
@@ -137,7 +137,7 @@ fn ms(ms: u64) -> Duration {
 fn wake_during_run() {
     future!(f, waker, POLL, DROP_F);
     schedule!(s, chan, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     task.run();
     let w = waker();
@@ -152,11 +152,11 @@ fn wake_during_run() {
             assert_eq!(SCHEDULE.load(), 1);
             assert_eq!(DROP_F.load(), 1);
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
             assert_eq!(chan.len(), 0);
         });
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
 
         w.wake();
         drop(handle);
@@ -164,16 +164,16 @@ fn wake_during_run() {
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
-        thread::sleep(ms(200));
+        thread::sleep(ms(400));
 
         assert_eq!(POLL.load(), 2);
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 1);
         assert_eq!(DROP_S.load(), 1);
-        assert_eq!(DROP_D.load(), 1);
+        assert_eq!(DROP_T.load(), 1);
         assert_eq!(chan.len(), 0);
     })
     .unwrap();
@@ -183,7 +183,7 @@ fn wake_during_run() {
 fn cancel_during_run() {
     future!(f, waker, POLL, DROP_F);
     schedule!(s, chan, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     task.run();
     let w = waker();
@@ -198,18 +198,18 @@ fn cancel_during_run() {
             assert_eq!(SCHEDULE.load(), 1);
             assert_eq!(DROP_F.load(), 1);
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
             assert_eq!(chan.len(), 0);
         });
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
 
         handle.cancel();
         assert_eq!(POLL.load(), 2);
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
         drop(handle);
@@ -217,16 +217,16 @@ fn cancel_during_run() {
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
-        thread::sleep(ms(200));
+        thread::sleep(ms(400));
 
         assert_eq!(POLL.load(), 2);
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 1);
         assert_eq!(DROP_S.load(), 1);
-        assert_eq!(DROP_D.load(), 1);
+        assert_eq!(DROP_T.load(), 1);
         assert_eq!(chan.len(), 0);
     })
     .unwrap();
@@ -236,7 +236,7 @@ fn cancel_during_run() {
 fn wake_and_cancel_during_run() {
     future!(f, waker, POLL, DROP_F);
     schedule!(s, chan, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     task.run();
     let w = waker();
@@ -251,18 +251,18 @@ fn wake_and_cancel_during_run() {
             assert_eq!(SCHEDULE.load(), 1);
             assert_eq!(DROP_F.load(), 1);
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
             assert_eq!(chan.len(), 0);
         });
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
 
         w.wake();
         assert_eq!(POLL.load(), 2);
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
         handle.cancel();
@@ -270,7 +270,7 @@ fn wake_and_cancel_during_run() {
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
         drop(handle);
@@ -278,16 +278,16 @@ fn wake_and_cancel_during_run() {
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
-        thread::sleep(ms(200));
+        thread::sleep(ms(400));
 
         assert_eq!(POLL.load(), 2);
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 1);
         assert_eq!(DROP_S.load(), 1);
-        assert_eq!(DROP_D.load(), 1);
+        assert_eq!(DROP_T.load(), 1);
         assert_eq!(chan.len(), 0);
     })
     .unwrap();
@@ -297,7 +297,7 @@ fn wake_and_cancel_during_run() {
 fn cancel_and_wake_during_run() {
     future!(f, waker, POLL, DROP_F);
     schedule!(s, chan, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     task.run();
     let w = waker();
@@ -312,18 +312,18 @@ fn cancel_and_wake_during_run() {
             assert_eq!(SCHEDULE.load(), 1);
             assert_eq!(DROP_F.load(), 1);
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
             assert_eq!(chan.len(), 0);
         });
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
 
         handle.cancel();
         assert_eq!(POLL.load(), 2);
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
         drop(handle);
@@ -331,7 +331,7 @@ fn cancel_and_wake_during_run() {
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
         w.wake();
@@ -339,16 +339,16 @@ fn cancel_and_wake_during_run() {
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
-        thread::sleep(ms(200));
+        thread::sleep(ms(400));
 
         assert_eq!(POLL.load(), 2);
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 1);
         assert_eq!(DROP_S.load(), 1);
-        assert_eq!(DROP_D.load(), 1);
+        assert_eq!(DROP_T.load(), 1);
         assert_eq!(chan.len(), 0);
     })
     .unwrap();
diff --git a/tests/waker_pending.rs b/tests/waker_pending.rs
index 11c6bfa..1374c4a 100644
--- a/tests/waker_pending.rs
+++ b/tests/waker_pending.rs
@@ -37,7 +37,7 @@ macro_rules! future {
                 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
                     WAKER.store(Some(cx.waker().clone()));
                     $poll.fetch_add(1);
-                    thread::sleep(ms(200));
+                    thread::sleep(ms(400));
                     Poll::Pending
                 }
             }
@@ -127,7 +127,7 @@ fn ms(ms: u64) -> Duration {
 fn wake_during_run() {
     future!(f, waker, POLL, DROP_F);
     schedule!(s, chan, SCHEDULE, DROP_S);
-    task!(task, _handle, f, s, DROP_D);
+    task!(task, _handle, f, s, DROP_T);
 
     task.run();
     let w = waker();
@@ -141,27 +141,27 @@ fn wake_during_run() {
             assert_eq!(SCHEDULE.load(), 2);
             assert_eq!(DROP_F.load(), 0);
             assert_eq!(DROP_S.load(), 0);
-            assert_eq!(DROP_D.load(), 0);
+            assert_eq!(DROP_T.load(), 0);
             assert_eq!(chan.len(), 1);
         });
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
 
         w.wake_by_ref();
         assert_eq!(POLL.load(), 2);
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
-        thread::sleep(ms(200));
+        thread::sleep(ms(400));
 
         assert_eq!(POLL.load(), 2);
         assert_eq!(SCHEDULE.load(), 2);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 1);
     })
     .unwrap();
@@ -174,7 +174,7 @@ fn wake_during_run() {
 fn cancel_during_run() {
     future!(f, waker, POLL, DROP_F);
     schedule!(s, chan, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     task.run();
     let w = waker();
@@ -189,18 +189,18 @@ fn cancel_during_run() {
             assert_eq!(SCHEDULE.load(), 1);
             assert_eq!(DROP_F.load(), 1);
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
             assert_eq!(chan.len(), 0);
         });
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
 
         handle.cancel();
         assert_eq!(POLL.load(), 2);
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
         drop(handle);
@@ -208,16 +208,16 @@ fn cancel_during_run() {
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
-        thread::sleep(ms(200));
+        thread::sleep(ms(400));
 
         assert_eq!(POLL.load(), 2);
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 1);
         assert_eq!(DROP_S.load(), 1);
-        assert_eq!(DROP_D.load(), 1);
+        assert_eq!(DROP_T.load(), 1);
         assert_eq!(chan.len(), 0);
     })
     .unwrap();
@@ -227,7 +227,7 @@ fn cancel_during_run() {
 fn wake_and_cancel_during_run() {
     future!(f, waker, POLL, DROP_F);
     schedule!(s, chan, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     task.run();
     let w = waker();
@@ -242,18 +242,18 @@ fn wake_and_cancel_during_run() {
             assert_eq!(SCHEDULE.load(), 1);
             assert_eq!(DROP_F.load(), 1);
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
             assert_eq!(chan.len(), 0);
         });
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
 
         w.wake();
         assert_eq!(POLL.load(), 2);
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
         handle.cancel();
@@ -261,7 +261,7 @@ fn wake_and_cancel_during_run() {
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
         drop(handle);
@@ -269,16 +269,16 @@ fn wake_and_cancel_during_run() {
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
-        thread::sleep(ms(200));
+        thread::sleep(ms(400));
 
         assert_eq!(POLL.load(), 2);
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 1);
         assert_eq!(DROP_S.load(), 1);
-        assert_eq!(DROP_D.load(), 1);
+        assert_eq!(DROP_T.load(), 1);
         assert_eq!(chan.len(), 0);
     })
     .unwrap();
@@ -288,7 +288,7 @@ fn wake_and_cancel_during_run() {
 fn cancel_and_wake_during_run() {
     future!(f, waker, POLL, DROP_F);
     schedule!(s, chan, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     task.run();
     let w = waker();
@@ -303,18 +303,18 @@ fn cancel_and_wake_during_run() {
             assert_eq!(SCHEDULE.load(), 1);
             assert_eq!(DROP_F.load(), 1);
             assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_D.load(), 1);
+            assert_eq!(DROP_T.load(), 1);
             assert_eq!(chan.len(), 0);
         });
 
-        thread::sleep(ms(100));
+        thread::sleep(ms(200));
 
         handle.cancel();
         assert_eq!(POLL.load(), 2);
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
         drop(handle);
@@ -322,7 +322,7 @@ fn cancel_and_wake_during_run() {
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
         w.wake();
@@ -330,16 +330,16 @@ fn cancel_and_wake_during_run() {
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 0);
         assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_D.load(), 0);
+        assert_eq!(DROP_T.load(), 0);
         assert_eq!(chan.len(), 0);
 
-        thread::sleep(ms(200));
+        thread::sleep(ms(400));
 
         assert_eq!(POLL.load(), 2);
         assert_eq!(SCHEDULE.load(), 1);
         assert_eq!(DROP_F.load(), 1);
         assert_eq!(DROP_S.load(), 1);
-        assert_eq!(DROP_D.load(), 1);
+        assert_eq!(DROP_T.load(), 1);
         assert_eq!(chan.len(), 0);
     })
     .unwrap();
@@ -349,7 +349,7 @@ fn cancel_and_wake_during_run() {
 fn drop_last_waker() {
     future!(f, waker, POLL, DROP_F);
     schedule!(s, chan, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     task.run();
     let w = waker();
@@ -359,7 +359,7 @@ fn drop_last_waker() {
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 0);
 
     drop(w);
@@ -367,7 +367,7 @@ fn drop_last_waker() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 1);
 
     chan.recv().unwrap().run();
@@ -375,7 +375,7 @@ fn drop_last_waker() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
     assert_eq!(chan.len(), 0);
 }
 
@@ -383,7 +383,7 @@ fn drop_last_waker() {
 fn cancel_last_handle() {
     future!(f, waker, POLL, DROP_F);
     schedule!(s, chan, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     task.run();
     drop(waker());
@@ -391,7 +391,7 @@ fn cancel_last_handle() {
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 0);
 
     handle.cancel();
@@ -399,7 +399,7 @@ fn cancel_last_handle() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 1);
 
     chan.recv().unwrap().run();
@@ -407,7 +407,7 @@ fn cancel_last_handle() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 0);
 
     drop(handle);
@@ -415,7 +415,7 @@ fn cancel_last_handle() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
     assert_eq!(chan.len(), 0);
 }
 
@@ -423,7 +423,7 @@ fn cancel_last_handle() {
 fn drop_last_handle() {
     future!(f, waker, POLL, DROP_F);
     schedule!(s, chan, SCHEDULE, DROP_S);
-    task!(task, handle, f, s, DROP_D);
+    task!(task, handle, f, s, DROP_T);
 
     task.run();
     drop(waker());
@@ -431,7 +431,7 @@ fn drop_last_handle() {
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 0);
 
     drop(handle);
@@ -439,7 +439,7 @@ fn drop_last_handle() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 1);
 
     chan.recv().unwrap().run();
@@ -447,6 +447,6 @@ fn drop_last_handle() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
     assert_eq!(chan.len(), 0);
 }
diff --git a/tests/waker_ready.rs b/tests/waker_ready.rs
index 800d6ae..a2223c6 100644
--- a/tests/waker_ready.rs
+++ b/tests/waker_ready.rs
@@ -136,7 +136,7 @@ fn ms(ms: u64) -> Duration {
 fn wake() {
     future!(f, waker, POLL, DROP_F);
     schedule!(s, chan, SCHEDULE, DROP_S);
-    task!(mut task, _, f, s, DROP_D);
+    task!(mut task, _, f, s, DROP_T);
 
     assert!(chan.is_empty());
 
@@ -145,7 +145,7 @@ fn wake() {
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 0);
 
     waker().wake();
@@ -154,7 +154,7 @@ fn wake() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 0);
 
     task.run();
@@ -162,7 +162,7 @@ fn wake() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 0);
 
     waker().wake();
@@ -170,7 +170,7 @@ fn wake() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
     assert_eq!(chan.len(), 0);
 }
 
@@ -178,7 +178,7 @@ fn wake() {
 fn wake_by_ref() {
     future!(f, waker, POLL, DROP_F);
     schedule!(s, chan, SCHEDULE, DROP_S);
-    task!(mut task, _, f, s, DROP_D);
+    task!(mut task, _, f, s, DROP_T);
 
     assert!(chan.is_empty());
 
@@ -187,7 +187,7 @@ fn wake_by_ref() {
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 0);
 
     waker().wake_by_ref();
@@ -196,7 +196,7 @@ fn wake_by_ref() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 0);
 
     task.run();
@@ -204,7 +204,7 @@ fn wake_by_ref() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 0);
 
     waker().wake_by_ref();
@@ -212,7 +212,7 @@ fn wake_by_ref() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
     assert_eq!(chan.len(), 0);
 }
 
@@ -220,14 +220,14 @@ fn wake_by_ref() {
 fn clone() {
     future!(f, waker, POLL, DROP_F);
     schedule!(s, chan, SCHEDULE, DROP_S);
-    task!(mut task, _, f, s, DROP_D);
+    task!(mut task, _, f, s, DROP_T);
 
     task.run();
     assert_eq!(POLL.load(), 1);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 0);
 
     let w2 = waker().clone();
@@ -241,7 +241,7 @@ fn clone() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 0);
 
     w3.wake();
@@ -249,27 +249,27 @@ fn clone() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 0);
 
     drop(w2);
     drop(waker());
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
 }
 
 #[test]
 fn wake_cancelled() {
     future!(f, waker, POLL, DROP_F);
     schedule!(s, chan, SCHEDULE, DROP_S);
-    task!(task, _, f, s, DROP_D);
+    task!(task, _, f, s, DROP_T);
 
     task.run();
     assert_eq!(POLL.load(), 1);
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 0);
 
     let w = waker();
@@ -280,7 +280,7 @@ fn wake_cancelled() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 0);
 
     w.wake();
@@ -288,7 +288,7 @@ fn wake_cancelled() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
     assert_eq!(chan.len(), 0);
 }
 
@@ -296,7 +296,7 @@ fn wake_cancelled() {
 fn wake_completed() {
     future!(f, waker, POLL, DROP_F);
     schedule!(s, chan, SCHEDULE, DROP_S);
-    task!(task, _, f, s, DROP_D);
+    task!(task, _, f, s, DROP_T);
 
     task.run();
     let w = waker();
@@ -304,7 +304,7 @@ fn wake_completed() {
     assert_eq!(SCHEDULE.load(), 0);
     assert_eq!(DROP_F.load(), 0);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 0);
 
     w.wake();
@@ -313,7 +313,7 @@ fn wake_completed() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_D.load(), 0);
+    assert_eq!(DROP_T.load(), 0);
     assert_eq!(chan.len(), 0);
 
     waker().wake();
@@ -321,6 +321,6 @@ fn wake_completed() {
     assert_eq!(SCHEDULE.load(), 1);
     assert_eq!(DROP_F.load(), 1);
     assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_D.load(), 1);
+    assert_eq!(DROP_T.load(), 1);
     assert_eq!(chan.len(), 0);
 }
