libuv
I want to read about libuv because it is an important library used in multiple programming languages. I learned about the existence of libuv when reading the Node.js documentation.
References
Related
- Asynchronous I/O
- In computer science, asynchronous I/O (also non-sequential I/O) is a form of input/output processing that permits other processing to continue before the I/O operation has finished. A name used for asynchronous I/O in the Windows API is overlapped I/O. I/O operations can be extremely slow compared to the processing of data. An I/O device can incorporate mechanical devices that must physically move; this is orders of magnitude slower than the switching of an electric current. A simple approach to I/O would be to start the access and then wait for it to complete. But such an approach, called synchronous I/O or blocking I/O, would block the progress of a program while the communication is in progress, leaving system resources idle. Alternatively, It is possible to start the communication and then perform processing that does not require that the I/O be completed. This approach is called asynchronous input/output. One of the main functions of all but the most rudimentary of operating systems is to perform at least some form of basic asynchronous I/O.
- Input/Output
- In computing, input/output (I/O, i/o, or informally IO) is the communication between an information processing system, such as a computer, and the outside world, such as another computer system, peripherals, or a human operator. Inputs are the signals or data received by the system and outputs are the signals or data sent from it. The term can also be used as part of an action; to
perform I/O
is to perform an input or output operation. - I/O devices are pieces of hardware used by a human (or other system) to communicate with a computer. For instance, a keyboard or computer mouse is an input device for a computer, while monitors and printers are output devices. Devices for communication between computers, such as modems and network cards, typically perform both input and output operations. Any interaction with the system by an interactor is an input and the reaction the system responds is called the output.
- In computing, input/output (I/O, i/o, or informally IO) is the communication between an information processing system, such as a computer, and the outside world, such as another computer system, peripherals, or a human operator. Inputs are the signals or data received by the system and outputs are the signals or data sent from it. The term can also be used as part of an action; to
- Processing
- In computing, a process is the instance of a computer program that is being executed by one of many threads. There are many different process models, some of which are light weight, but almost all processes (even entire virtual machines) are rooted in an operating system (OS) process which comprises the program code, assigned system resources, physical and logical access permissions, and data structures to initiate, control, and coordinate execution activity. Depending on the OS, a process may be made up of multiple threads that execute instructions concurrently.
- While a computer program is a passive collection of instructions typically stored in a file on disk, a process is the execution of those instructions after being loaded from the disk into memory. Multitasking is a method to allow multiple processes to share processors (CPUs) and other system resources.
- I/O Scheduling
- Input/output (I/O) scheduling is the method that computer operating systems use to decide in which order I/O operations will be submitted to storage volumes. I/O scheduling is sometimes called disk scheduling.
Notes
libuv is a multi-platform support library with a focus on asynchronous I/O. It was primarily developed for use by Node.js, but it's also used by Luvit, Julia, uvloop, and others.
Features
- Full-featured event loop backed by epoll, kqueue, IOCP, event ports
- Asynchronous TCP and UDP sockets
- Asynchronous DNS resolution
- Asynchronous file and file system operations
- File system events
- ANSI escape code controlled TTY
- IPC with socket sharing, using Unix domain sockets or names pipes (Windows)
- Child processes
- Thread pool
- Signal handling
- High resolution clock
- Threading and synchronization primitives
Design Overview
libuv is a cross-platform support library which was originally written for Node.js. It's designed around the event-driven asynchronous I/O model. The library provides much more than a simple abstraction over different I/O polling mechanisms: handles
and streams
provide a high level abstraction for sockets and other entities; cross-platform file I/O and threading functionality is also provided, amongst other things.
Handles and Requests
libuv
provides users with 2 abstractions to work with, in combination with the event loop: handles and requests.
- Handles represent long lived objects capable of performing certain operations while active. Some examples:
- A prepare handle gets its callback called once every loop iteration when active.
- A TCP server handle that gets its connection callback called every time there is a new connection.
- Requests typically represent short-lived operations. These operations can be performed over a handle: write requests are used to write data on a handle; or standalone:
getaddrinfo
request don't need a handle they run directly on the loop.
The I/O Loop
The I/O (or event) loop is the central part of libuv. It establishes the content for all I/O operations, and it's meant to be tied to a single thread. One can run multiple event loops as long as each runs in a different thread. One can run multiple event loops as long as each runs in a different thread. The libuv event loop (or any other API involving the loop or handles, for that matter) is not thread-safe except where stated otherwise.
The event loop follows the rather usual single threaded asynchronous I/O approach: all (network) I/O is performed on non-blocking sockets which are polled using the best mechanism available on the given platform. As part of a loop iteration, the loop will block waiting for I/O activity on sockets which have been added to the poller and callbacks will be fired indicating socket conditions (readable, writable hang-up) so handles can be read, write or perform the desired I/O operation.
- The loop concept of
now
is initially set. - Due timers are run if the loop was run with
UV_REUN_DEFAULT
. All active timers scheduled for a time before the loop's concept of now get their callbacks called. - If the loop is alive an iteration is started, otherwise the loop will exit immediately. When is a loop considered to be alive? If a loop has active and ref'd handles, active requests or closing handles it is considered to be alive.
- Pending callbacks are called right after polling for I/O.
- Idle handle callbacks are called. Idle handles are run on every loop iteration, if they are active.
- Prepare handle callbacks are called. Prepare handles get their callbacks called right before the loop will block for I/O.
- Poll timeout is calculated. Before blocking for I/O the loop calculates how long it should block.
- The loop blocks for I/O.
- Check handle callbacks are called.
- Close callbacks are called.
- The loop concept of
now
is updated. - Due timers are run.
- Iteration ends.
File I/O
Unlike network I/O, there are no platform-specific file I/O primitives libuv could rely on, so the current approach is to run blocking I/O operations in a thread pool.
libuv currently uses a global thread pool on which all loops can queue work. 3 types of operations on this pool:
- File system operations
- DNS functions (
getaddrinfo
andgetnameinfo
) - User specified code via
uv_queue_work()
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.
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:
while there are still events to process:
e = get the next event
if there is a callback associated with e:
call the callback
Examples of events:
- File is ready for writing
- A socket has data ready to be read
- A timer has timed out
The most common activity of systems programs is to deal with input and output, rather than number crunching. The problem with conventional I/O functions 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. For programs that require high performance, this blocking is a major roadblock.
A standard solution to this problem is to use threads. Each blocking I/O operation is started on a different thread. 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. 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 and grab the data. It is asynchronous because the application expressed interest at one point, then the data at another point. 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.
Comments
You have to be logged in to add a comment
User Comments
There are currently no comments for this article.