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