We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Async From First Principles step 8 of 25
RawWaker and RawWakerVTable: building a Waker with unsafe
Complete the raw-waker implementation used by
refcount_trace(clones: usize, wakes: usize) -> (usize, usize).
Keep the supplied Counter and tracing sequence. Repair the vtable's
ownership handling and construct the Waker with a justified unsafe block.
The trace performs these steps:
- Create an Arc<Counter> named state and a Waker that owns another handle.
- Call wake_by_ref on the original waker
wakestimes. - Create
clonesadditional wakers. - Consume the clones in order: call wake on indices 0, 2, 4, and so on; drop those at indices 1, 3, 5, and so on.
- Read the wake counter and Arc strong count while state and the original waker are still alive.
Return (wakes + clones.div_ceil(2), 2) for the exercised counts.
For example, (clones = 5, wakes = 1) produces (4, 2):
one borrowed wake plus three consuming wakes. Dropping a clone does not
increment the wake counter.
The second result is a snapshot before the remaining handles are dropped, not a count after the function has finished cleaning up.
Data pointer and callbacks
RawWaker combines a data pointer with a static RawWakerVTable containing four callbacks: clone, wake, wake_by_ref and drop. Waker::from_raw lets safe Waker methods call those callbacks, so its caller must ensure that they interpret the pointer consistently and preserve its validity.
Here the pointer comes from Arc::into_raw. That transfers one owned strong reference into the raw representation without decrementing the count. Each live waker needs its own strong reference, even when several wakers store the same pointer address.
| Callback | Wake counter | Owned strong references |
|---|---|---|
| clone | unchanged | retain one additional reference for the new waker |
| wake | increment | release the consumed waker's reference |
| wake_by_ref | increment | preserve the current waker's reference |
| drop | unchanged | release this waker's reference |
Arc::increment_strong_count supplies the extra reference for clone. Arc::from_raw reconstructs an owning handle; it does not increment the count. For wake and drop, let that handle be dropped exactly once.
For wake_by_ref, wrap the reconstructed handle in ManuallyDrop so its destructor does not release the reference still owned by the waker. ManuallyDrop suppresses destruction; it does not create an ordinary borrow or check that the pointer is valid.
Two separate starter defects
The starter calls Waker::from_raw without an unsafe block, causing E0133. It also creates clones without retaining additional strong references. Fix both before running it. Adding the unsafe block alone can leave live wakers referring to an allocation whose last counted owner was released.
Inside an unsafe fn, Rust 2024 enables unsafe_op_in_unsafe_fn as a warning by default. Explicit unsafe blocks around operations such as Arc::from_raw separate the caller's obligations from the implementation's justification. This site's warnings-as-errors gate makes that warning a failing check.
Thread safety includes the stored state
Waker can move between threads and be used through shared references. Its callbacks must therefore support those uses. Here Arc manages ownership atomically, and Counter uses AtomicUsize for the wake counter. Arc alone would not make arbitrary unsynchronized mutation of its contents safe.
An Rc-based implementation is unsuitable for this Waker. The requirements apply to the Waker being constructed; do not generalize them to every other API that uses a raw-waker representation.
Scope of the exercise
The counter records callback invocations. A runtime waker normally notifies an executor that a task should be polled again; this exercise does not implement that scheduling behavior.
Waker operations are not universally free: cloning this one updates an atomic count, and constructing its initial state allocates an Arc. A different callback implementation can have different costs.
Prefer the safe Wake abstraction when Arc-backed state suits the design. RawWaker is useful when implementing a custom representation or working under constraints that Wake does not cover. Understanding its ownership contract helps you review either approach.
The tests observe wake counts and retained owners. They can expose some bookkeeping mistakes, but passing outputs do not prove memory safety or correct behavior under every thread interleaving. The submission must compile, match the outputs and pass Clippy with warnings denied.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.