- Blocking IO model blocking IO
- Nonblocking IO model nonblocking IO
- IO multiplexing model IO multiplexing
- IO multiplexing select and Poll in detail
- Event driven — Epoll
- conclusion
There are two main stages when an operating system processes I/O:
- Wait for data to be transmitted to the I/O device
- IO devices copy data to the User space
We generally simplify the above process as:
- Wait until the data is sent to kernel space
- The kernel area copies data to the user space (understood as a buffer for processes or threads).
According to these two stages and different operation methods, a variety of IO models will be generated. This paper only discusses SELECT, poll and epoll, so only three IO models will be introduced.
Blocking IO model blocking IO
The most common is the blocking IO model. By default, all file operations are blocked. Using a socket interface as an example, a call to recvFROM in process space will not return until the packet arrives and is copied to the process buffer or an error occurs. During this time, the system call will block, so the process will block the entire time it calls recvfrom until it returns. Hence the blocking IO model.
Note: blocked programs do not waste CPU; the CPU simply stops performing IO operations and does something else.
The recvFROM method will be called when the data from the application layer is coming, but the data from the application layer has not been copied to the kernel. It takes time to copy the data from the application layer to the kerne stage, so the recvFROM method will block. When the data in the kernel is ready, the recvFROM method will not return. Instead, a system call is made to copy the kernel’s data into the process’s buffer, the user space, and when this is done, recvFROM returns and unblocks the program.
Therefore, we can conclude that the above two stages are the main ones
- Application layer data to the kernel
- Kernel is copied to the user space
The blocking IO model is to merge these two processes together and block together. Non-blocking models change the blocking of the first procedure to non-blocking, and the second stage is the system call, which must block, so non-blocking models are also synchronous, because they make system calls to copy the data into the process buffer after the kernel is ready.
Nonblocking IO model nonblocking IO
For the first phase, when the application layer data is sent to the kernel, recvFROM polls and returns an EWOULDBLOCK error if the kernel is not ready for return. Polling checks until the kernel is ready, returns, and then makes a system call to copy the data from the kernel into the process buffer. It’s kind of like busy-waiting.
IO multiplexing model IO multiplexing
-
Purpose: because the block model in the absence of received data can jam, if one needs to accept multiple socket fd, will cause must be processed in front of fd, to deal with the back of the fd, even may be behind the fd than previous fd ready first, so it can cause serious delay for the client. In order to handle multiple requests, we naturally thought of using multithreading to handle multiple socket fd, but this will start a large number of threads, resulting in a waste of resources, so this time IO multiplexing technology appeared. A process that handles multiple FD requests.
-
Application: Suitable for large number of I/O requests, especially when the server must simultaneously process a large number of I/O operations from clients
IO multiplexing select and Poll in detail
select
Select workflow: A single process can process I/O requests for multiple network connections at the same time (blocking multiple I/O operations at the same time). The basic principle is that the program calls SELECT, and the entire program blocks. At this point, the kernel polls all the FDS that the select is responsible for. When a client is found and data is ready, the select returns. Copy data from the kernel to the process buffer.
Select accepts data from multiple clients at the same time
Although the server process is blocked by SELECT, the select uses the kernel to constantly poll to listen for other clients to complete their I/O operations.
Poll is introduced
The principle of poll is very similar to select, the differences are as follows:
- The way the FD collection is described is different. Poll uses the pollFD structure instead of the SELECT fd_set structure, so poll is chained and there is no limit to the maximum number of connections
- One of the features of poll is the horizontal trigger, which means that if a poll is ready and the same FD is not processed this time, the next time the poll is ready, the same FD will be notified again.
Select faults
-
Fd_size is defined as 32 integer sizes (32*32 for 32-bit machines), one bit for each FD, so a maximum of 1024 FDS can be processed at the same time
-
Each time it is expensive to determine which events have occurred, because SELECT (which also polling) uses an active polling mechanism
1. Each call to select() requires a copy of FD_SET from user space to the kernel (approximately linear time cost). Why can’t select be replicated just once like epoll? The FD_SET may change before each call to SELECT (), and epoll provides a shared memory storage structure, so there is no need for data communication between the kernel and the user
2. The kernel also polls each FD in approximately linear time
- In reality, there are 1 million clients maintaining TCP connections with one server simultaneously, and only a few hundred or thousands of TCP connections are active at any one time. In this case, the select/poll mechanism is still used. The kernel must search 1 million FDS before it can find the active state. This is resource-intensive and inefficient.
For the above shortcomings of SELECT and poll, a new technology, epoll technology, was introduced
Event driven — Epoll
Epoll provides three functions:
-
int epoll_create(int size); Create an epoll object and return its ID
-
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); The event registration function gives the epoll object the events to listen for and the FDS to listen for
-
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); An event waiting for registration was triggered or a timeout occurred
Epoll solves:
-
Epoll does not have a limit on the number of FD’s. Epoll does not have this limit. We know that each epoll listens for one FD, so the maximum number is related to the number of FD’s that can be opened
-
Epoll does not need to copy the FD set from the user space to the kernel each time. Kernel Epoll already copies the FD to the kernel when registering the event with epoll_ctl, so it does not need to copy the FD again each time
-
Select and poll are both active polling mechanisms that need to visit every FD; Epoll_wait is a passive trigger. When an EVENT is registered for a FD, we specify a callback function for each FD. When the data is ready, the ready FD is added to a ready queue. Wake up the waiters on the ready queue and call the callback function.
-
Although the epoll. The poll. Epoll needs to check whether there are FDS ready, but epoll is triggered passively because it only needs to look for FDS in the ready queue. Ready FDS are actively added to the queue, and epoll does not need to be confirmed one by one. In other words, select and poll can only notify a ready FD, but do not know which FD is ready, so select and poll must actively poll to find the ready FD. Epoll can not only know the number of fd ready, but also know the number of FD ready, so it can be directly found without polling.
conclusion
- Select, poll is designed to solve the problem of a large number of IO at the same time (especially network servers), but the performance deteriorates as the number of connections increases
- Epoll is an improvement on Select and poll that can replace them on Linux and handle performance issues with large numbers of connections