The event loop is the main source of blocking in an application which drives
all other I/O events and notifications happening. Each event loop can have
multiple handles pointing to it, each of which can then be used to create
various I/O objects to interact with the event loop in interesting ways.

Runs a future until completion, driving the event loop while we're
otherwise waiting for the future to complete.

This function will begin executing the event loop and will finish once
the provided future is resolved. Note that the future argument here
crucially does not require the 'static nor Send bounds. As a result
the future will be "pinned" to not only this thread but also this stack
frame.

This function will return the value that the future resolves to once
the future has finished. If the future never resolves then this function
will never return.