User space and kernel space
Linux operating systems and drivers run in kernel space, and applications run in user space. When we want to achieve in user space to the operation of the kernel, such as the use of the open function open/dev/led the driver, because the user cannot directly on kernel operation space, so you must use a method called “system calls” to implement from user space into a kernel space, so as to achieve to the operation of the underlying drivers.
In Linux, the virtual address layout is as follows:
The user space of the process stores the code and data of the user program, and the kernel space stores the kernel code and data. Both kernel space and user space reside in virtual memory and are mappings to physical addresses.
Processes are kernel-mode when running in kernel space and user-mode when running in user-space.
Processes in kernel space can access the protected memory space as well as the underlying hardware devices. That is, you can execute any command, call all resources of the system. In user space, only simple operations can be performed, and system resources cannot be directly called. Only through system interface (also known as system call) can instructions be issued to the kernel. The purpose of this partition is to prevent user processes from directly operating the kernel and ensure kernel security.
Synchronous and asynchronous
Synchronous request, A calls B, B’s processing is synchronous, he will not notify A until the completion of processing, only after the completion of the explicit notification A.
In an asynchronous request, A calls B, and B’s processing is asynchronous. After receiving the request, B first tells A that I have received the request, and then asynchronously processes it. After processing, B notifies A through callback and other methods.
Therefore, the biggest difference between synchronous and asynchronous is the execution and return time of the called party. Synchronous means that the called party does something and then returns. Asynchronous means that the called party returns first, then does something, and then finds a way to notify the caller.
Blocking and non-blocking
Block the request, A calls B, A waits for B to return, and does nothing else.
Non-blocking request, A calls B, A doesn’t have to wait for B to return, so he can do something else.
So the biggest difference between blocking and non-blocking is whether the caller waits until the result is returned. Blocking is when the caller waits for something else to do nothing. Non-blocking means that the caller does something else first.
Blocking and non-blocking are different from synchronous and asynchronous. Blocking and non-blocking refer to the caller, while synchronous and asynchronous refer to the called.
IO
I/O is generally divided into disk I/O and network I/O. Here, network I/O is used as an example. A complete NETWORK I/O process is as follows:
When we fetch data, if the piece of data already exists in the page memory of the user process, we read the data directly from the memory. If the data does not exist, it is first loaded from disk/network into the kernel buffer, and then copied from the kernel buffer into the page memory of the user process.
As you can see from the figure above, data needs to go through the kernel both from nic to user space and from user space to nic.
Five IO models for Linux
First, there are three main IO models in Java: blocking IO (BIO), non-blocking IO (NIO), and asynchronous IO (AIO). It can be understood as the encapsulation of various IO models of the operating system by the Java language. Programmers who use these apis do not need to care about operating system knowledge, nor do they need to write different code for different operating systems, just use Java apis.
So this is OS level IO, not Java level IO, don’t get confused. There are five IO models in Linux:
- Blocking IO model
- Non-blocking IO model
- IO multiplexing model
- Signal driven IO model
- Asynchronous IO model
The following are explained separately.
Blocking IO model
Application processes make system callsrecvfrom
Receives data, but since the kernel is not ready for datagrams, the application will block until the kernel is ready for datagrams and copies the datagrams from the kernel to user space.recvfrom
The application process is not blocked until success is returned.
The blocking IO model has the advantage of being easy to program, but has the disadvantage of needing to work with a large number of threads/thread pools. Every time an application process receives a connection, it needs to create a thread for the connection to handle the read and write tasks for the connection.
Non-blocking IO model
The calling process does not block while waiting for data, but instead continually rounds to see if the data is ready. If a poll finds that the data is ready, copy the data from kernel space to user space.
The application process keeps interacting with the kernel through recvFROM calls until the kernel is ready for data. If not, the kernel returns an error, and the application process sends the recvFROM request some time after receiving an error. The process can do something else between requests, waiting for data is non-blocking, but copying data is still blocked.
The advantage of non-blocking IO is that you can use a single thread to process multiple connections at the same time, reducing the number of threads used. The downside is that you have to constantly poll to see if the data is ready, which can be CPU-intensive and potentially slow.
IO multiplexing model
In order to solve the problem of increasing CPU usage caused by non-blocking I/O continuous polling, the IO multiplexing model was developed. Linux supports select, poll, and epoll for I/O reuse.
Pipes interact with the kernel uniformly. The following figure uses the SELECT function as an example. Multiple I/OS can be registered with the same SELECT. When a user process calls the select, the SELECT process will listen to all the registered I/OS. When the data for any IO is ready, the select call returns, and the process copies the data into user space via recvFROM.
IO multiplexing only blocks on SELECT, poll, or epoll and can handle and manage multiple connections simultaneously. The disadvantage is that when the number of connections managed by SELECT, poll, or epoll is too small, this model will degenerate into a blocking IO model. There is also one more system call: a SELECT, poll or epoll, and a recvfrom.
Signal driven IO model
The application creates a signal driver SIGIO, registers a signal handler with the kernel, and the user process returns to continue running without being blocked. When the kernel data is ready, a signal is sent to the application process, after which the signal driver executes and the user process begins copying the data into user space in the signal handler.
The advantage of the signal-driven IO model is that it is non-blocking, but the disadvantage is that the signal driver is serialized. If a SIGIO is not currently processed, the latter signal cannot be processed either. When the signal volume is large, the following signal can not be sensed in time.
Asynchronous IO model
In contrast to synchronous I/OS, asynchronous I/OS are not executed sequentially. After the aiO_read system call, the application process passes the descriptor, buffer pointer, buffer size, and so on to the kernel, telling the kernel how to notify the process when the operation is complete. When the kernel receives aiO_read, it returns immediately, and the application process does other things.
The kernel then waits for the data to be ready. When the data is ready, the kernel copies the data directly to the user process. After the kernel completes the relevant operation, the kernel sends a signal to the application process to tell it that the I/O has completed.
In the asynchronous IO model, the application process calls AIO_read and the data is copied to user space, both of which are non-blocking. Is perfect.
conclusion
The first four models differ in the first part, the system call, but the second part is the same. The process of copying data from kernel space to user space blocks the redvfrom call. The last type, the asynchronous IO model, is non-blocking during system calls and data copies.