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 updated. The event loop caches the current time at the start of 64 the event loop tick in order to reduce the number of time-related system calls. 65 66#. If the loop is *alive* an iteration is started, otherwise the loop will exit immediately. So, 67 when is a loop considered to be *alive*? If a loop has active and ref'd handles, active 68 requests or closing handles it's considered to be *alive*. 69 70#. Due timers are run. All active timers scheduled for a time before the loop's concept of *now* 71 get their callbacks called. 72 73#. Pending callbacks are called. All I/O callbacks are called right after polling for I/O, for the 74 most part. There are cases, however, in which calling such a callback is deferred for the next 75 loop iteration. If the previous iteration deferred any I/O callback it will be run at this point. 76 77#. Idle handle callbacks are called. Despite the unfortunate name, idle handles are run on every 78 loop iteration, if they are active. 79 80#. Prepare handle callbacks are called. Prepare handles get their callbacks called right before 81 the loop will block for I/O. 82 83#. Poll timeout is calculated. Before blocking for I/O the loop calculates for how long it should 84 block. These are the rules when calculating the timeout: 85 86 * If the loop was run with the ``UV_RUN_NOWAIT`` flag, the timeout is 0. 87 * If the loop is going to be stopped (:c:func:`uv_stop` was called), the timeout is 0. 88 * If there are no active handles or requests, the timeout is 0. 89 * If there are any idle handles active, the timeout is 0. 90 * If there are any handles pending to be closed, the timeout is 0. 91 * If none of the above cases matches, the timeout of the closest timer is taken, or 92 if there are no active timers, infinity. 93 94#. The loop blocks for I/O. At this point the loop will block for I/O for the duration calculated 95 in the previous step. All I/O related handles that were monitoring a given file descriptor 96 for a read or write operation get their callbacks called at this point. 97 98#. Check handle callbacks are called. Check handles get their callbacks called right after the 99 loop has blocked for I/O. Check handles are essentially the counterpart of prepare handles. 100 101#. Close callbacks are called. If a handle was closed by calling :c:func:`uv_close` it will 102 get the close callback called. 103 104#. Special case in case the loop was run with ``UV_RUN_ONCE``, as it implies forward progress. 105 It's possible that no I/O callbacks were fired after blocking for I/O, but some time has passed 106 so there might be timers which are due, those timers get their callbacks called. 107 108#. Iteration ends. If the loop was run with ``UV_RUN_NOWAIT`` or ``UV_RUN_ONCE`` modes the 109 iteration ends and :c:func:`uv_run` will return. If the loop was run with ``UV_RUN_DEFAULT`` 110 it will continue from the start if it's still *alive*, otherwise it will also end. 111 112 113.. important:: 114 libuv uses a thread pool to make asynchronous file I/O operations possible, but 115 network I/O is **always** performed in a single thread, each loop's thread. 116 117.. note:: 118 While the polling mechanism is different, libuv makes the execution model consistent 119 across Unix systems and Windows. 120 121 122File I/O 123^^^^^^^^ 124 125Unlike network I/O, there are no platform-specific file I/O primitives libuv could rely on, 126so the current approach is to run blocking file I/O operations in a thread pool. 127 128For a thorough explanation of the cross-platform file I/O landscape, check out 129`this post <https://blog.libtorrent.org/2012/10/asynchronous-disk-io/>`_. 130 131libuv currently uses a global thread pool on which all loops can queue work. 3 types of 132operations are currently run on this pool: 133 134 * File system operations 135 * DNS functions (getaddrinfo and getnameinfo) 136 * User specified code via :c:func:`uv_queue_work` 137 138.. warning:: 139 See the :c:ref:`threadpool` section for more details, but keep in mind the thread pool size 140 is quite limited. 141