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