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