Master the fundamental concepts of rust for systems programming through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksasync fn in Rust desugars to a type implementing Future. tokio, hyper, and axum all boil down to executors calling poll until Poll::Ready. No magic threads: cooperative tasks yield at .await.
rustLoading…
Waker from cx and call it when I/O completesvrustLoading…
Real runtimes integrate epoll/kqueue and timer wheels; yours can spin for teaching.
For this exercise, you will implement a tiny executor that polls spawned futures until idle. This task asks you to wire a Waker that requeues tasks, because debugging tokio hangs without understanding poll/wake is guesswork.
Keep the relevant man page, ABI doc, or Rust reference chapter open while you work. When your output disagrees with the reference implementation on the same machine, the mismatch is usually an alignment rule, an off-by-one terminator, or a register slot you misread in GDB. Skim the official documentation for the tool or ABI named in the exercise; the prose changes, but register roles, syscall numbers, and ownership rules stay stable across releases.
An async runtime is a loop: pop a task from the ready queue and poll it until it returns Pending, then park it until a waker puts it back. Timers and channels are the wakers. Build a deterministic, single-threaded executor with a virtual clock, and trace what happens. You will see the two classic lessons: await only yields when the future is actually pending, and blocking code (compute) stalls every other task, making their timers fire late.
cLoading…
Steps (N is 0..1000000 ms, CH up to 15 characters, WORD up to 31 characters):
| Step | Meaning |
|---|---|
print WORD | print a line |
compute N | blocking work: the clock advances N ms immediately |
sleep N | sleep(N).await: register a timer at now+N and return Pending |
send CH V | unbounded channel send (never blocks); wakes the first task waiting on CH |
recv CH | recv().await: take the oldest value if there is one and continue, else register as a waiter and return Pending |
yield | yield_now().await: re-queue at the back and return Pending once |
run queues all tasks in declaration order.sleep continues after the sleep. A task woken by send retries its recv (and may go Pending again if another task took the value first).cLoading…
The last line is t=T all K tasks done after P polls (P counts every poll), or t=T deadlock: A (recv ch) B (recv x) listing the unfinished tasks in declaration order.
Errors: error: bad task (missing, long, duplicate or too many), error: bad step in task NAME (the task is not created), error: unknown command CMD.
Input:
cLoading…
Output:
cLoading…
poll resumes it and never re-runs completed steps.Hidden tests cover a ping-pong over two channels, several timers with equal deadlines, sleep 0, a waiter whose value is taken by another task, a deadlock, and malformed tasks.