Advanced event loops¶
libuv provides considerable user control over event loops, and you can achieve interesting results by juggling multiple loops. You can also embed libuv’s event loop into another event loop based library – imagine a Qt based UI, and Qt’s event loop driving a libuv backend which does intensive system level tasks.
Stopping an event loop¶
uv_stop()
can be used to stop an event loop. The earliest the loop will
stop running is on the next iteration, possibly later. This means that events
that are ready to be processed in this iteration of the loop will still be
processed, so uv_stop()
can’t be used as a kill switch. When uv_stop()
is called, the loop won’t block for i/o on this iteration. The semantics of
these things can be a bit difficult to understand, so let’s look at
uv_run()
where all the control flow occurs.
src/unix/core.c - uv_run
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | int uv_run(uv_loop_t* loop, uv_run_mode mode) {
int timeout;
int r;
int ran_pending;
r = uv__loop_alive(loop);
if (!r)
uv__update_time(loop);
while (r != 0 && loop->stop_flag == 0) {
uv__update_time(loop);
uv__run_timers(loop);
ran_pending = uv__run_pending(loop);
uv__run_idle(loop);
uv__run_prepare(loop);
timeout = 0;
if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
timeout = uv_backend_timeout(loop);
uv__io_poll(loop, timeout);
|
stop_flag
is set by uv_stop()
. Now all libuv callbacks are invoked
within the event loop, which is why invoking uv_stop()
in them will still
lead to this iteration of the loop occurring. First libuv updates timers, then
runs pending timer, idle and prepare callbacks, and invokes any pending I/O
callbacks. If you were to call uv_stop()
in any of them, stop_flag
would be set. This causes uv_backend_timeout()
to return 0
, which is
why the loop does not block on I/O. If on the other hand, you called
uv_stop()
in one of the check handlers, I/O has already finished and is not
affected.
uv_stop()
is useful to shutdown a loop when a result has been computed or
there is an error, without having to ensure that all handlers are stopped one
by one.
Here is a simple example that stops the loop and demonstrates how the current iteration of the loop still takes places.
uvstop/main.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #include <stdio.h>
#include <uv.h>
int64_t counter = 0;
void idle_cb(uv_idle_t *handle) {
printf("Idle callback\n");
counter++;
if (counter >= 5) {
uv_stop(uv_default_loop());
printf("uv_stop() called\n");
}
}
void prep_cb(uv_prepare_t *handle) {
printf("Prep callback\n");
}
int main() {
uv_idle_t idler;
uv_prepare_t prep;
uv_idle_init(uv_default_loop(), &idler);
uv_idle_start(&idler, idle_cb);
uv_prepare_init(uv_default_loop(), &prep);
uv_prepare_start(&prep, prep_cb);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
return 0;
}
|