Step 3-Implementing a proper Reactor 199 3. Every time we loop, we create an inner while let Some(... ) loop that runs as long as there are tasks in ready_queue. 4. If there is a task in ready_queue, we take ownership of the Future object by removing it from the collection. We guard against false wakeups by just continuing if there is no future there anymore (meaning that we're done with it but still get a wakeup). This will, for example, happen on Windows since we get a READABLE event when the connection closes, but even though we could filter those events out, mio doesn't guarantee that false wakeups won't happen, so we have to handle that possibility anyway. 5. Next, we create a new Waker instance that we can pass into Future::poll(). Remember that this Waker instance now holds the id property that identifies this specific Future trait and a handle to the thread we're currently running on. 6. The next step is to call Future::poll. 7. If we get Not Ready in return, we insert the task back into our tasks collection. I want to emphasize that when a Future trait returns Not Ready, we know it will arrange it so that Waker::wake is called at a later point in time. It's not the executor's responsibility to track the readiness of this future. 8. If the Future trait returns Ready, we simply continue to the next item in the ready queue. Since we took ownership over the Future trait, this will drop the object before we enter the next iteration of the while let loop. 9. Now that we've polled all the tasks in our ready queue, the first thing we do is get a task count to see how many tasks we have left. 10. We also get the name of the current thread for future logging purposes (it has nothing to do with how our executor works). 11. If the task count is larger than 0, we print a message to the terminal and call thread::park(). Parking the thread will yield control to the OS scheduler, and our Executor does nothing until it's woken up again. 12. If the task count is 0, we're done with our asynchronous program and exit the main loop. That's pretty much all there is to it. By this point, we've covered all our goals for step 2, so we can continue to the last and final step and implement a Reactor for our runtime that will wake up our executor when something happens. Step 3-Implementing a proper Reactor The final part of our example is the Reactor. Our Reactor will: Efficiently wait and handle events that our runtime is interested in Store a collection of Waker types and make sure to wake the correct Waker when it gets a notification on a source it's tracking