# 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  uv_signal_t* sh;
     2
     3  /* Note: while the handle is in the UV_HANDLE_CLOSING state now, it's still
     4   * possible for it to be active in the sense that uv__is_active() returns
     5   * true.
     6   *
     7   * A good example is when the user calls uv_shutdown(), immediately followed
     8   * by uv_close(). The handle is considered active at this point because the
     9   * completion of the shutdown req is still pending.
    10   */
    11  assert(handle->flags & UV_HANDLE_CLOSING);
    12  assert(!(handle->flags & UV_HANDLE_CLOSED));
    13  handle->flags |= UV_HANDLE_CLOSED;
    14
    15  switch (handle->type) {
    16    case UV_PREPARE:
    17    case UV_CHECK:
    18    case UV_IDLE:
    19    case UV_ASYNC:
    20    case UV_TIMER:
    21    case UV_PROCESS:

`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#include <stdio.h>
     2#include <uv.h>
     3
     4int64_t counter = 0;
     5
     6void idle_cb(uv_idle_t *handle) {
     7    printf("Idle callback\n");
     8    counter++;
     9
    10    if (counter >= 5) {
    11        uv_stop(uv_default_loop());
    12        printf("uv_stop() called\n");
    13    }
    14}
    15
    16void prep_cb(uv_prepare_t *handle) {
    17    printf("Prep callback\n");
    18}
    19
    20int main() {
    21    uv_idle_t idler;
    22    uv_prepare_t prep;
    23
    24    uv_idle_init(uv_default_loop(), &idler);
    25    uv_idle_start(&idler, idle_cb);
    26
    27    uv_prepare_init(uv_default_loop(), &prep);
    28    uv_prepare_start(&prep, prep_cb);
    29
    30    uv_run(uv_default_loop(), UV_RUN_DEFAULT);
    31
    32    return 0;
    33}