1 2.. _design: 3 4Design overview 5=============== 6 7libuv is cross-platform support library which was originally written for `Node.js`_. It's designed 8around the event-driven asynchronous I/O model. 9 10.. _Node.js: https://nodejs.org 11 12The library provides much more than a simple abstraction over different I/O polling mechanisms: 13'handles' and 'streams' provide a high level abstraction for sockets and other entities; 14cross-platform file I/O and threading functionality is also provided, amongst other things. 15 16Here is a diagram illustrating the different parts that compose libuv and what subsystem they 17relate to: 18 19.. image:: static/architecture.png 20 :scale: 75% 21 :align: center 22 23 24Handles and requests 25^^^^^^^^^^^^^^^^^^^^ 26 27libuv provides users with 2 abstractions to work with, in combination with the event loop: 28handles and requests. 29 30Handles represent long-lived objects capable of performing certain operations while active. Some examples: 31 32- A prepare handle gets its callback called once every loop iteration when active. 33- A TCP server handle that gets its connection callback called every time there is a new connection. 34 35Requests represent (typically) short-lived operations. These operations can be performed over a 36handle: write requests are used to write data on a handle; or standalone: getaddrinfo requests 37don't need a handle they run directly on the loop. 38 39 40The I/O loop 41^^^^^^^^^^^^ 42 43The I/O (or event) loop is the central part of libuv. It establishes the content for all I/O 44operations, and it's meant to be tied to a single thread. One can run multiple event loops 45as long as each runs in a different thread. The libuv event loop (or any other API involving 46the loop or handles, for that matter) **is not thread-safe** except where stated otherwise. 47 48The event loop follows the rather usual single threaded asynchronous I/O approach: all (network) 49I/O is performed on non-blocking sockets which are polled using the best mechanism available 50on the given platform: epoll on Linux, kqueue on OSX and other BSDs, event ports on SunOS and IOCP 51on Windows. As part of a loop iteration the loop will block waiting for I/O activity on sockets 52which have been added to the poller and callbacks will be fired indicating socket conditions 53(readable, writable hangup) so handles can read, write or perform the desired I/O operation. 54 55In order to better understand how the event loop operates, the following diagram illustrates all 56stages of a loop iteration: 57 58.. image:: static/loop_iteration.png 59 :scale: 75% 60 :align: center 61 62 63#. The loop concept of 'now' is initially set. 64 65#. Due timers are run if the loop was run with ``UV_RUN_DEFAULT``. All active timers scheduled 66 for a time before the loop's concept of *now* get their callbacks called. 67 68#. If the loop is *alive* an iteration is started, otherwise the loop will exit immediately. So, 69 when is a loop considered to be *alive*? If a loop has active and ref'd handles, active 70 requests or closing handles it's considered to be *alive*. 71 72#. Pending callbacks are called. All I/O callbacks are called right after polling for I/O, for the 73 most part. There are cases, however, in which calling such a callback is deferred for the next 74 loop iteration. If the previous iteration deferred any I/O callback it will be run at this point. 75 76#. Idle handle callbacks are called. Despite the unfortunate name, idle handles are run on every 77 loop iteration, if they are active. 78 79#. Prepare handle callbacks are called. Prepare handles get their callbacks called right before 80 the loop will block for I/O. 81 82#. Poll timeout is calculated. Before blocking for I/O the loop calculates for how long it should 83 block. These are the rules when calculating the timeout: 84 85 * If the loop was run with the ``UV_RUN_NOWAIT`` flag, the timeout is 0. 86 * If the loop is going to be stopped (:c:func:`uv_stop` was called), the timeout is 0. 87 * If there are no active handles or requests, the timeout is 0. 88 * If there are any idle handles active, the timeout is 0. 89 * If there are any handles pending to be closed, the timeout is 0. 90 * If none of the above cases matches, the timeout of the closest timer is taken, or 91 if there are no active timers, infinity. 92 93#. The loop blocks for I/O. At this point the loop will block for I/O for the duration calculated 94 in the previous step. All I/O related handles that were monitoring a given file descriptor 95 for a read or write operation get their callbacks called at this point. 96 97#. Check handle callbacks are called. Check handles get their callbacks called right after the 98 loop has blocked for I/O. Check handles are essentially the counterpart of prepare handles. 99 100#. Close callbacks are called. If a handle was closed by calling :c:func:`uv_close` it will 101 get the close callback called. 102 103#. The loop concept of 'now' is updated. 104 105#. Due timers are run. Note that 'now' is not updated again until the next loop iteration. 106 So if a timer became due while other timers were being processed, it won't be run until 107 the following event loop iteration. 108 109#. Iteration ends. If the loop was run with ``UV_RUN_NOWAIT`` or ``UV_RUN_ONCE`` modes the 110 iteration ends and :c:func:`uv_run` will return. If the loop was run with ``UV_RUN_DEFAULT`` 111 it will continue from the start if it's still *alive*, otherwise it will also end. 112 113 114.. important:: 115 libuv uses a thread pool to make asynchronous file I/O operations possible, but 116 network I/O is **always** performed in a single thread, each loop's thread. 117 118.. note:: 119 While the polling mechanism is different, libuv makes the execution model consistent 120 across Unix systems and Windows. 121 122 123File I/O 124^^^^^^^^ 125 126Unlike network I/O, there are no platform-specific file I/O primitives libuv could rely on, 127so the current approach is to run blocking file I/O operations in a thread pool. 128 129For a thorough explanation of the cross-platform file I/O landscape, check out 130`this post <https://blog.libtorrent.org/2012/10/asynchronous-disk-io/>`_. 131 132libuv currently uses a global thread pool on which all loops can queue work. 3 types of 133operations are currently run on this pool: 134 135 * File system operations 136 * DNS functions (getaddrinfo and getnameinfo) 137 * User specified code via :c:func:`uv_queue_work` 138 139.. warning:: 140 See the :c:ref:`threadpool` section for more details, but keep in mind the thread pool size 141 is quite limited. 142