Blame docs/src/design.rst

Packit b5b901
Packit b5b901
.. _design:
Packit b5b901
Packit b5b901
Design overview
Packit b5b901
===============
Packit b5b901
Packit Service e08953
libuv is cross-platform support library which was originally written for `Node.js`_. It's designed
Packit b5b901
around the event-driven asynchronous I/O model.
Packit b5b901
Packit Service e08953
.. _Node.js: https://nodejs.org
Packit Service e08953
Packit b5b901
The library provides much more than a simple abstraction over different I/O polling mechanisms:
Packit b5b901
'handles' and 'streams' provide a high level abstraction for sockets and other entities;
Packit b5b901
cross-platform file I/O and threading functionality is also provided, amongst other things.
Packit b5b901
Packit b5b901
Here is a diagram illustrating the different parts that compose libuv and what subsystem they
Packit b5b901
relate to:
Packit b5b901
Packit b5b901
.. image:: static/architecture.png
Packit b5b901
    :scale: 75%
Packit b5b901
    :align: center
Packit b5b901
Packit b5b901
Packit b5b901
Handles and requests
Packit b5b901
^^^^^^^^^^^^^^^^^^^^
Packit b5b901
Packit b5b901
libuv provides users with 2 abstractions to work with, in combination with the event loop:
Packit b5b901
handles and requests.
Packit b5b901
Packit b5b901
Handles represent long-lived objects capable of performing certain operations while active. Some examples:
Packit b5b901
Packit b5b901
- A prepare handle gets its callback called once every loop iteration when active.
Packit b5b901
- A TCP server handle that gets its connection callback called every time there is a new connection.
Packit b5b901
Packit b5b901
Requests represent (typically) short-lived operations. These operations can be performed over a
Packit b5b901
handle: write requests are used to write data on a handle; or standalone: getaddrinfo requests
Packit b5b901
don't need a handle they run directly on the loop.
Packit b5b901
Packit b5b901
Packit b5b901
The I/O loop
Packit b5b901
^^^^^^^^^^^^
Packit b5b901
Packit b5b901
The I/O (or event) loop is the central part of libuv. It establishes the content for all I/O
Packit b5b901
operations, and it's meant to be tied to a single thread. One can run multiple event loops
Packit b5b901
as long as each runs in a different thread. The libuv event loop (or any other API involving
Packit b5b901
the loop or handles, for that matter) **is not thread-safe** except where stated otherwise.
Packit b5b901
Packit b5b901
The event loop follows the rather usual single threaded asynchronous I/O approach: all (network)
Packit b5b901
I/O is performed on non-blocking sockets which are polled using the best mechanism available
Packit b5b901
on the given platform: epoll on Linux, kqueue on OSX and other BSDs, event ports on SunOS and IOCP
Packit b5b901
on Windows. As part of a loop iteration the loop will block waiting for I/O activity on sockets
Packit b5b901
which have been added to the poller and callbacks will be fired indicating socket conditions
Packit b5b901
(readable, writable hangup) so handles can read, write or perform the desired I/O operation.
Packit b5b901
Packit b5b901
In order to better understand how the event loop operates, the following diagram illustrates all
Packit b5b901
stages of a loop iteration:
Packit b5b901
Packit b5b901
.. image:: static/loop_iteration.png
Packit b5b901
    :scale: 75%
Packit b5b901
    :align: center
Packit b5b901
Packit b5b901
Packit b5b901
#. The loop concept of 'now' is updated. The event loop caches the current time at the start of
Packit b5b901
   the event loop tick in order to reduce the number of time-related system calls.
Packit b5b901
Packit b5b901
#. If the loop is *alive*  an iteration is started, otherwise the loop will exit immediately. So,
Packit b5b901
   when is a loop considered to be *alive*? If a loop has active and ref'd handles, active
Packit b5b901
   requests or closing handles it's considered to be *alive*.
Packit b5b901
Packit b5b901
#. Due timers are run. All active timers scheduled for a time before the loop's concept of *now*
Packit b5b901
   get their callbacks called.
Packit b5b901
Packit b5b901
#. Pending callbacks are called. All I/O callbacks are called right after polling for I/O, for the
Packit b5b901
   most part. There are cases, however, in which calling such a callback is deferred for the next
Packit b5b901
   loop iteration. If the previous iteration deferred any I/O callback it will be run at this point.
Packit b5b901
Packit b5b901
#. Idle handle callbacks are called. Despite the unfortunate name, idle handles are run on every
Packit b5b901
   loop iteration, if they are active.
Packit b5b901
Packit b5b901
#. Prepare handle callbacks are called. Prepare handles get their callbacks called right before
Packit b5b901
   the loop will block for I/O.
Packit b5b901
Packit b5b901
#. Poll timeout is calculated. Before blocking for I/O the loop calculates for how long it should
Packit b5b901
   block. These are the rules when calculating the timeout:
Packit b5b901
Packit b5b901
        * If the loop was run with the ``UV_RUN_NOWAIT`` flag, the timeout is 0.
Packit b5b901
        * If the loop is going to be stopped (:c:func:`uv_stop` was called), the timeout is 0.
Packit b5b901
        * If there are no active handles or requests, the timeout is 0.
Packit b5b901
        * If there are any idle handles active, the timeout is 0.
Packit b5b901
        * If there are any handles pending to be closed, the timeout is 0.
Packit b5b901
        * If none of the above cases matches, the timeout of the closest timer is taken, or
Packit b5b901
          if there are no active timers, infinity.
Packit b5b901
Packit b5b901
#. The loop blocks for I/O. At this point the loop will block for I/O for the duration calculated
Packit b5b901
   in the previous step. All I/O related handles that were monitoring a given file descriptor
Packit b5b901
   for a read or write operation get their callbacks called at this point.
Packit b5b901
Packit b5b901
#. Check handle callbacks are called. Check handles get their callbacks called right after the
Packit b5b901
   loop has blocked for I/O. Check handles are essentially the counterpart of prepare handles.
Packit b5b901
Packit b5b901
#. Close callbacks are called. If a handle was closed by calling :c:func:`uv_close` it will
Packit b5b901
   get the close callback called.
Packit b5b901
Packit b5b901
#. Special case in case the loop was run with ``UV_RUN_ONCE``, as it implies forward progress.
Packit b5b901
   It's possible that no I/O callbacks were fired after blocking for I/O, but some time has passed
Packit b5b901
   so there might be timers which are due, those timers get their callbacks called.
Packit b5b901
Packit b5b901
#. Iteration ends. If the loop was run with ``UV_RUN_NOWAIT`` or ``UV_RUN_ONCE`` modes the
Packit b5b901
   iteration ends and :c:func:`uv_run` will return. If the loop was run with ``UV_RUN_DEFAULT``
Packit b5b901
   it will continue from the start if it's still *alive*, otherwise it will also end.
Packit b5b901
Packit b5b901
Packit b5b901
.. important::
Packit b5b901
    libuv uses a thread pool to make asynchronous file I/O operations possible, but
Packit b5b901
    network I/O is **always** performed in a single thread, each loop's thread.
Packit b5b901
Packit b5b901
.. note::
Packit b5b901
    While the polling mechanism is different, libuv makes the execution model consistent
Packit b5b901
    across Unix systems and Windows.
Packit b5b901
Packit b5b901
Packit b5b901
File I/O
Packit b5b901
^^^^^^^^
Packit b5b901
Packit b5b901
Unlike network I/O, there are no platform-specific file I/O primitives libuv could rely on,
Packit b5b901
so the current approach is to run blocking file I/O operations in a thread pool.
Packit b5b901
Packit b5b901
For a thorough explanation of the cross-platform file I/O landscape, checkout
Packit Service e08953
`this post <https://blog.libtorrent.org/2012/10/asynchronous-disk-io/>`_.
Packit b5b901
Packit Service e08953
libuv currently uses a global thread pool on which all loops can queue work. 3 types of
Packit b5b901
operations are currently run on this pool:
Packit b5b901
Packit b5b901
    * File system operations
Packit b5b901
    * DNS functions (getaddrinfo and getnameinfo)
Packit b5b901
    * User specified code via :c:func:`uv_queue_work`
Packit b5b901
Packit b5b901
.. warning::
Packit b5b901
    See the :c:ref:`threadpool` section for more details, but keep in mind the thread pool size
Packit b5b901
    is quite limited.