Blame docs/src/guide/basics.rst

Packit b5b901
Basics of libuv
Packit b5b901
===============
Packit b5b901
Packit b5b901
libuv enforces an **asynchronous**, **event-driven** style of programming.  Its
Packit b5b901
core job is to provide an event loop and callback based notifications of I/O
Packit b5b901
and other activities.  libuv offers core utilities like timers, non-blocking
Packit b5b901
networking support, asynchronous file system access, child processes and more.
Packit b5b901
Packit b5b901
Event loops
Packit b5b901
-----------
Packit b5b901
Packit b5b901
In event-driven programming, an application expresses interest in certain events
Packit b5b901
and respond to them when they occur. The responsibility of gathering events
Packit b5b901
from the operating system or monitoring other sources of events is handled by
Packit b5b901
libuv, and the user can register callbacks to be invoked when an event occurs.
Packit b5b901
The event-loop usually keeps running *forever*. In pseudocode:
Packit b5b901
Packit b5b901
.. code-block:: python
Packit b5b901
Packit b5b901
    while there are still events to process:
Packit b5b901
        e = get the next event
Packit b5b901
        if there is a callback associated with e:
Packit b5b901
            call the callback
Packit b5b901
Packit b5b901
Some examples of events are:
Packit b5b901
Packit b5b901
* File is ready for writing
Packit b5b901
* A socket has data ready to be read
Packit b5b901
* A timer has timed out
Packit b5b901
Packit b5b901
This event loop is encapsulated by ``uv_run()`` -- the end-all function when using
Packit b5b901
libuv.
Packit b5b901
Packit b5b901
The most common activity of systems programs is to deal with input and output,
Packit b5b901
rather than a lot of number-crunching. The problem with using conventional
Packit b5b901
input/output functions (``read``, ``fprintf``, etc.) is that they are
Packit b5b901
**blocking**. The actual write to a hard disk or reading from a network, takes
Packit b5b901
a disproportionately long time compared to the speed of the processor. The
Packit b5b901
functions don't return until the task is done, so that your program is doing
Packit b5b901
nothing. For programs which require high performance this is a major roadblock
Packit b5b901
as other activities and other I/O operations are kept waiting.
Packit b5b901
Packit b5b901
One of the standard solutions is to use threads. Each blocking I/O operation is
Packit b5b901
started in a separate thread (or in a thread pool). When the blocking function
Packit b5b901
gets invoked in the thread, the processor can schedule another thread to run,
Packit b5b901
which actually needs the CPU.
Packit b5b901
Packit b5b901
The approach followed by libuv uses another style, which is the **asynchronous,
Packit b5b901
non-blocking** style. Most modern operating systems provide event notification
Packit b5b901
subsystems. For example, a normal ``read`` call on a socket would block until
Packit b5b901
the sender actually sent something. Instead, the application can request the
Packit b5b901
operating system to watch the socket and put an event notification in the
Packit b5b901
queue. The application can inspect the events at its convenience (perhaps doing
Packit b5b901
some number crunching before to use the processor to the maximum) and grab the
Packit b5b901
data. It is **asynchronous** because the application expressed interest at one
Packit b5b901
point, then used the data at another point (in time and space). It is
Packit b5b901
**non-blocking** because the application process was free to do other tasks.
Packit b5b901
This fits in well with libuv's event-loop approach, since the operating system
Packit b5b901
events can be treated as just another libuv event. The non-blocking ensures
Packit b5b901
that other events can continue to be handled as fast as they come in [#]_.
Packit b5b901
Packit b5b901
.. NOTE::
Packit b5b901
Packit b5b901
    How the I/O is run in the background is not of our concern, but due to the
Packit b5b901
    way our computer hardware works, with the thread as the basic unit of the
Packit b5b901
    processor, libuv and OSes will usually run background/worker threads and/or
Packit b5b901
    polling to perform tasks in a non-blocking manner.
Packit b5b901
Packit b5b901
Bert Belder, one of the libuv core developers has a small video explaining the
Packit b5b901
architecture of libuv and its background. If you have no prior experience with
Packit b5b901
either libuv or libev, it is a quick, useful watch.
Packit b5b901
Packit b5b901
libuv's event loop is explained in more detail in the `documentation
Packit b5b901
<http://docs.libuv.org/en/v1.x/design.html#the-i-o-loop>`_.
Packit b5b901
Packit b5b901
.. raw:: html
Packit b5b901
Packit b5b901
    
Packit b5b901
    src="https://www.youtube-nocookie.com/embed/nGn60vDSxQ4" frameborder="0"
Packit b5b901
    allowfullscreen></iframe>
Packit b5b901
Packit b5b901
Hello World
Packit b5b901
-----------
Packit b5b901
Packit Service e08953
With the basics out of the way, let's write our first libuv program. It does
Packit b5b901
nothing, except start a loop which will exit immediately.
Packit b5b901
Packit b5b901
.. rubric:: helloworld/main.c
Packit b5b901
.. literalinclude:: ../../code/helloworld/main.c
Packit b5b901
    :linenos:
Packit b5b901
Packit b5b901
This program quits immediately because it has no events to process. A libuv
Packit b5b901
event loop has to be told to watch out for events using the various API
Packit b5b901
functions.
Packit b5b901
Packit b5b901
Starting with libuv v1.0, users should allocate the memory for the loops before
Packit b5b901
initializing it with ``uv_loop_init(uv_loop_t *)``. This allows you to plug in
Packit b5b901
custom memory management. Remember to de-initialize the loop using
Packit b5b901
``uv_loop_close(uv_loop_t *)`` and then delete the storage. The examples never
Packit b5b901
close loops since the program quits after the loop ends and the system will
Packit b5b901
reclaim memory. Production grade projects, especially long running systems
Packit b5b901
programs, should take care to release correctly.
Packit b5b901
Packit b5b901
Default loop
Packit b5b901
++++++++++++
Packit b5b901
Packit b5b901
A default loop is provided by libuv and can be accessed using
Packit b5b901
``uv_default_loop()``. You should use this loop if you only want a single
Packit b5b901
loop.
Packit b5b901
Packit b5b901
.. note::
Packit b5b901
Packit b5b901
    node.js uses the default loop as its main loop. If you are writing bindings
Packit b5b901
    you should be aware of this.
Packit b5b901
Packit b5b901
.. _libuv-error-handling:
Packit b5b901
Packit b5b901
Error handling
Packit b5b901
--------------
Packit b5b901
Packit b5b901
Initialization functions or synchronous functions which may fail return a negative number on error. Async functions that may fail will pass a status parameter to their callbacks. The error messages are defined as ``UV_E*`` `constants`_. 
Packit b5b901
Packit b5b901
.. _constants: http://docs.libuv.org/en/v1.x/errors.html#error-constants
Packit b5b901
Packit b5b901
You can use the ``uv_strerror(int)`` and ``uv_err_name(int)`` functions
Packit b5b901
to get a ``const char *`` describing the error or the error name respectively.
Packit b5b901
Packit b5b901
I/O read callbacks (such as for files and sockets) are passed a parameter ``nread``. If ``nread`` is less than 0, there was an error (UV_EOF is the end of file error, which you may want to handle differently).
Packit b5b901
Packit b5b901
Handles and Requests
Packit b5b901
--------------------
Packit b5b901
Packit b5b901
libuv works by the user expressing interest in particular events. This is
Packit b5b901
usually done by creating a **handle** to an I/O device, timer or process.
Packit b5b901
Handles are opaque structs named as ``uv_TYPE_t`` where type signifies what the
Packit b5b901
handle is used for. 
Packit b5b901
Packit b5b901
.. rubric:: libuv watchers
Packit Service e08953
.. code-block:: c
Packit Service e08953
Packit Service e08953
    /* Handle types. */
Packit Service e08953
    typedef struct uv_loop_s uv_loop_t;
Packit Service e08953
    typedef struct uv_handle_s uv_handle_t;
Packit Service e08953
    typedef struct uv_dir_s uv_dir_t;
Packit Service e08953
    typedef struct uv_stream_s uv_stream_t;
Packit Service e08953
    typedef struct uv_tcp_s uv_tcp_t;
Packit Service e08953
    typedef struct uv_udp_s uv_udp_t;
Packit Service e08953
    typedef struct uv_pipe_s uv_pipe_t;
Packit Service e08953
    typedef struct uv_tty_s uv_tty_t;
Packit Service e08953
    typedef struct uv_poll_s uv_poll_t;
Packit Service e08953
    typedef struct uv_timer_s uv_timer_t;
Packit Service e08953
    typedef struct uv_prepare_s uv_prepare_t;
Packit Service e08953
    typedef struct uv_check_s uv_check_t;
Packit Service e08953
    typedef struct uv_idle_s uv_idle_t;
Packit Service e08953
    typedef struct uv_async_s uv_async_t;
Packit Service e08953
    typedef struct uv_process_s uv_process_t;
Packit Service e08953
    typedef struct uv_fs_event_s uv_fs_event_t;
Packit Service e08953
    typedef struct uv_fs_poll_s uv_fs_poll_t;
Packit Service e08953
    typedef struct uv_signal_s uv_signal_t;
Packit Service e08953
Packit Service e08953
    /* Request types. */
Packit Service e08953
    typedef struct uv_req_s uv_req_t;
Packit Service e08953
    typedef struct uv_getaddrinfo_s uv_getaddrinfo_t;
Packit Service e08953
    typedef struct uv_getnameinfo_s uv_getnameinfo_t;
Packit Service e08953
    typedef struct uv_shutdown_s uv_shutdown_t;
Packit Service e08953
    typedef struct uv_write_s uv_write_t;
Packit Service e08953
    typedef struct uv_connect_s uv_connect_t;
Packit Service e08953
    typedef struct uv_udp_send_s uv_udp_send_t;
Packit Service e08953
    typedef struct uv_fs_s uv_fs_t;
Packit Service e08953
    typedef struct uv_work_s uv_work_t;
Packit Service e08953
Packit b5b901
Packit b5b901
Handles represent long-lived objects. Async operations on such handles are
Packit b5b901
identified using **requests**. A request is short-lived (usually used across
Packit b5b901
only one callback) and usually indicates one I/O operation on a handle.
Packit b5b901
Requests are used to preserve context between the initiation and the callback
Packit b5b901
of individual actions. For example, an UDP socket is represented by
Packit b5b901
a ``uv_udp_t``, while individual writes to the socket use a ``uv_udp_send_t``
Packit b5b901
structure that is passed to the callback after the write is done.
Packit b5b901
Packit b5b901
Handles are setup by a corresponding::
Packit b5b901
Packit b5b901
    uv_TYPE_init(uv_loop_t *, uv_TYPE_t *)
Packit b5b901
Packit b5b901
function.
Packit b5b901
Packit b5b901
Callbacks are functions which are called by libuv whenever an event the watcher
Packit b5b901
is interested in has taken place. Application specific logic will usually be
Packit b5b901
implemented in the callback. For example, an IO watcher's callback will receive
Packit b5b901
the data read from a file, a timer callback will be triggered on timeout and so
Packit b5b901
on.
Packit b5b901
Packit b5b901
Idling
Packit b5b901
++++++
Packit b5b901
Packit b5b901
Here is an example of using an idle handle. The callback is called once on
Packit b5b901
every turn of the event loop. A use case for idle handles is discussed in
Packit b5b901
:doc:`utilities`. Let us use an idle watcher to look at the watcher life cycle
Packit b5b901
and see how ``uv_run()`` will now block because a watcher is present. The idle
Packit b5b901
watcher is stopped when the count is reached and ``uv_run()`` exits since no
Packit b5b901
event watchers are active.
Packit b5b901
Packit b5b901
.. rubric:: idle-basic/main.c
Packit b5b901
.. literalinclude:: ../../code/idle-basic/main.c
Packit b5b901
    :emphasize-lines: 6,10,14-17
Packit b5b901
Packit b5b901
Storing context
Packit b5b901
+++++++++++++++
Packit b5b901
Packit b5b901
In callback based programming style you'll often want to pass some 'context' --
Packit b5b901
application specific information -- between the call site and the callback. All
Packit b5b901
handles and requests have a ``void* data`` member which you can set to the
Packit b5b901
context and cast back in the callback. This is a common pattern used throughout
Packit b5b901
the C library ecosystem. In addition ``uv_loop_t`` also has a similar data
Packit b5b901
member.
Packit b5b901
Packit b5b901
----
Packit b5b901
Packit b5b901
.. [#] Depending on the capacity of the hardware of course.