comparison third_party/libuv/docs/src/guide/basics.rst @ 160:948de3f54cea

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