Blame docs/src/design.rst

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