xref: /netbsd-src/external/mit/libuv/dist/docs/src/guide/basics.rst (revision 82d56013d7b633d116a93943de88e08335357a7c)
1Basics of libuv
2===============
3
4libuv enforces an **asynchronous**, **event-driven** style of programming.  Its
5core job is to provide an event loop and callback based notifications of I/O
6and other activities.  libuv offers core utilities like timers, non-blocking
7networking support, asynchronous file system access, child processes and more.
8
9Event loops
10-----------
11
12In event-driven programming, an application expresses interest in certain events
13and respond to them when they occur. The responsibility of gathering events
14from the operating system or monitoring other sources of events is handled by
15libuv, and the user can register callbacks to be invoked when an event occurs.
16The event-loop usually keeps running *forever*. In pseudocode:
17
18.. code-block:: python
19
20    while there are still events to process:
21        e = get the next event
22        if there is a callback associated with e:
23            call the callback
24
25Some examples of events are:
26
27* File is ready for writing
28* A socket has data ready to be read
29* A timer has timed out
30
31This event loop is encapsulated by ``uv_run()`` -- the end-all function when using
32libuv.
33
34The most common activity of systems programs is to deal with input and output,
35rather than a lot of number-crunching. The problem with using conventional
36input/output functions (``read``, ``fprintf``, etc.) is that they are
37**blocking**. The actual write to a hard disk or reading from a network, takes
38a disproportionately long time compared to the speed of the processor. The
39functions don't return until the task is done, so that your program is doing
40nothing. For programs which require high performance this is a major roadblock
41as other activities and other I/O operations are kept waiting.
42
43One of the standard solutions is to use threads. Each blocking I/O operation is
44started in a separate thread (or in a thread pool). When the blocking function
45gets invoked in the thread, the processor can schedule another thread to run,
46which actually needs the CPU.
47
48The approach followed by libuv uses another style, which is the **asynchronous,
49non-blocking** style. Most modern operating systems provide event notification
50subsystems. For example, a normal ``read`` call on a socket would block until
51the sender actually sent something. Instead, the application can request the
52operating system to watch the socket and put an event notification in the
53queue. The application can inspect the events at its convenience (perhaps doing
54some number crunching before to use the processor to the maximum) and grab the
55data. It is **asynchronous** because the application expressed interest at one
56point, then used the data at another point (in time and space). It is
57**non-blocking** because the application process was free to do other tasks.
58This fits in well with libuv's event-loop approach, since the operating system
59events can be treated as just another libuv event. The non-blocking ensures
60that other events can continue to be handled as fast as they come in [#]_.
61
62.. NOTE::
63
64    How the I/O is run in the background is not of our concern, but due to the
65    way our computer hardware works, with the thread as the basic unit of the
66    processor, libuv and OSes will usually run background/worker threads and/or
67    polling to perform tasks in a non-blocking manner.
68
69Bert Belder, one of the libuv core developers has a small video explaining the
70architecture of libuv and its background. If you have no prior experience with
71either libuv or libev, it is a quick, useful watch.
72
73libuv's event loop is explained in more detail in the `documentation
74<http://docs.libuv.org/en/v1.x/design.html#the-i-o-loop>`_.
75
76.. raw:: html
77
78    <iframe width="560" height="315"
79    src="https://www.youtube-nocookie.com/embed/nGn60vDSxQ4" frameborder="0"
80    allowfullscreen></iframe>
81
82Hello World
83-----------
84
85With the basics out of the way, let's write our first libuv program. It does
86nothing, except start a loop which will exit immediately.
87
88.. rubric:: helloworld/main.c
89.. literalinclude:: ../../code/helloworld/main.c
90    :linenos:
91
92This program quits immediately because it has no events to process. A libuv
93event loop has to be told to watch out for events using the various API
94functions.
95
96Starting with libuv v1.0, users should allocate the memory for the loops before
97initializing it with ``uv_loop_init(uv_loop_t *)``. This allows you to plug in
98custom memory management. Remember to de-initialize the loop using
99``uv_loop_close(uv_loop_t *)`` and then delete the storage. The examples never
100close loops since the program quits after the loop ends and the system will
101reclaim memory. Production grade projects, especially long running systems
102programs, should take care to release correctly.
103
104Default loop
105++++++++++++
106
107A default loop is provided by libuv and can be accessed using
108``uv_default_loop()``. You should use this loop if you only want a single
109loop.
110
111.. note::
112
113    node.js uses the default loop as its main loop. If you are writing bindings
114    you should be aware of this.
115
116.. _libuv-error-handling:
117
118Error handling
119--------------
120
121Initialization 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`_.
122
123.. _constants: http://docs.libuv.org/en/v1.x/errors.html#error-constants
124
125You can use the ``uv_strerror(int)`` and ``uv_err_name(int)`` functions
126to get a ``const char *`` describing the error or the error name respectively.
127
128I/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).
129
130Handles and Requests
131--------------------
132
133libuv works by the user expressing interest in particular events. This is
134usually done by creating a **handle** to an I/O device, timer or process.
135Handles are opaque structs named as ``uv_TYPE_t`` where type signifies what the
136handle is used for.
137
138.. rubric:: libuv watchers
139.. code-block:: c
140
141    /* Handle types. */
142    typedef struct uv_loop_s uv_loop_t;
143    typedef struct uv_handle_s uv_handle_t;
144    typedef struct uv_dir_s uv_dir_t;
145    typedef struct uv_stream_s uv_stream_t;
146    typedef struct uv_tcp_s uv_tcp_t;
147    typedef struct uv_udp_s uv_udp_t;
148    typedef struct uv_pipe_s uv_pipe_t;
149    typedef struct uv_tty_s uv_tty_t;
150    typedef struct uv_poll_s uv_poll_t;
151    typedef struct uv_timer_s uv_timer_t;
152    typedef struct uv_prepare_s uv_prepare_t;
153    typedef struct uv_check_s uv_check_t;
154    typedef struct uv_idle_s uv_idle_t;
155    typedef struct uv_async_s uv_async_t;
156    typedef struct uv_process_s uv_process_t;
157    typedef struct uv_fs_event_s uv_fs_event_t;
158    typedef struct uv_fs_poll_s uv_fs_poll_t;
159    typedef struct uv_signal_s uv_signal_t;
160
161    /* Request types. */
162    typedef struct uv_req_s uv_req_t;
163    typedef struct uv_getaddrinfo_s uv_getaddrinfo_t;
164    typedef struct uv_getnameinfo_s uv_getnameinfo_t;
165    typedef struct uv_shutdown_s uv_shutdown_t;
166    typedef struct uv_write_s uv_write_t;
167    typedef struct uv_connect_s uv_connect_t;
168    typedef struct uv_udp_send_s uv_udp_send_t;
169    typedef struct uv_fs_s uv_fs_t;
170    typedef struct uv_work_s uv_work_t;
171
172
173Handles represent long-lived objects. Async operations on such handles are
174identified using **requests**. A request is short-lived (usually used across
175only one callback) and usually indicates one I/O operation on a handle.
176Requests are used to preserve context between the initiation and the callback
177of individual actions. For example, an UDP socket is represented by
178a ``uv_udp_t``, while individual writes to the socket use a ``uv_udp_send_t``
179structure that is passed to the callback after the write is done.
180
181Handles are setup by a corresponding::
182
183    uv_TYPE_init(uv_loop_t *, uv_TYPE_t *)
184
185function.
186
187Callbacks are functions which are called by libuv whenever an event the watcher
188is interested in has taken place. Application specific logic will usually be
189implemented in the callback. For example, an IO watcher's callback will receive
190the data read from a file, a timer callback will be triggered on timeout and so
191on.
192
193Idling
194++++++
195
196Here is an example of using an idle handle. The callback is called once on
197every turn of the event loop. A use case for idle handles is discussed in
198:doc:`utilities`. Let us use an idle watcher to look at the watcher life cycle
199and see how ``uv_run()`` will now block because a watcher is present. The idle
200watcher is stopped when the count is reached and ``uv_run()`` exits since no
201event watchers are active.
202
203.. rubric:: idle-basic/main.c
204.. literalinclude:: ../../code/idle-basic/main.c
205    :emphasize-lines: 6,10,14-17
206
207Storing context
208+++++++++++++++
209
210In callback based programming style you'll often want to pass some 'context' --
211application specific information -- between the call site and the callback. All
212handles and requests have a ``void* data`` member which you can set to the
213context and cast back in the callback. This is a common pattern used throughout
214the C library ecosystem. In addition ``uv_loop_t`` also has a similar data
215member.
216
217----
218
219.. [#] Depending on the capacity of the hardware of course.
220