Using asynchronous notifications in device drivers can make access to the device accessible to the application by the driver when it is accessible. Therefore, applications that use nonblocking I/O do not need to poll the device for access, and blocking access can be superseded by asynchronous notifications like "break". Asynchronous notifications are similar to the concept of "interrupts" on hardware, and the more accurate term is "signal-driven asynchronous I/O".
1. The concept and function of asynchronous notifications
Impact: Blocking-The application does not need to poll the device for access
Non-blocking--Interrupt for notification
That is: initiated by the driver, actively notify the application
2, Linux asynchronous notification programming
2.1 Linux Signal
Role: In Linux systems, asynchronous notifications use signals to implement
The function prototypes are:
void (*signal (int signum,void (*handler)) (int))) (int)
Prototypes are difficult to understand and can be broken down into
typedef void (*sighandler_t) (int); sighandler_t signal (int signum,sighandler_t handler);
The first parameter is the value of the specified signal, and the second parameter is the handler function that specifies the signal for the front
2.2 Signal processing function (capture signal on the application side)
Signal () function
Example:
Start signal mechanism void Sigterm_handler (int sigo) {char Data[max_len];int Len;len = Read (Stdin_fileno,&data,max_len);d ata[ Len] = 0;printf ("Input available:%s\n", data); exit (0);} int main (void) {int oflags;//start signal-driven mechanism signal (sigio,sigterm_handler); Fcntl (Stdin_fileno,f_setown,getpid ()); oflags = Fcntl (STDIN_FILENO,F_GETFL); FCTCL (Stdin_fileno,f_setfl,oflags | Fasync);//Build a dead loop to prevent the program from ending Whlie (1); return 0;}
2.3 Release of the signal (release signal on device drive side)
In order for the device to support the asynchronous notification mechanism, the following 3 tasks are involved in the driver
(1), Support F_setown command, can be set in this control command processing filp->f_owner for the corresponding process ID. However, this work has been done by the kernel and the device driver is not required to process.
(2), Support F_SETFL command processing, each time the FASYNC flag changes, the driver function of the Fasync () function is executed. Therefore, the Fasync () function should be implemented in the driver
(3), can be obtained in the device resource, call Kill_fasync () function to fire the corresponding signal
Asynchronous notification programming in device drivers:
(1), fasync_struct join the device structure template
(2), two functions
Two functions for handling the FASYNC flag: int fasync_helper (int fd,struct file *filp,int mode,struct fasync_struct **fa);
function to release the signal: void Kill_fasync (struct fasync_struct **fa,int sig,int band);
and other struct pointers are placed in the device structure, the template is as follows
struct xxx_dev{struct cdev cdev;...struct fasync_struct *async_queue;//asynchronous struct pointer};
2.4 In the Fasync () function of the device driver, simply pass the function's 3 arguments and the pointer of the fasync_struct struct pointer as the fourth parameter to the Fasync_helper () function, and the template is as follows
static int xxx_fasync (int fd,struct file *FILP, int mode) {struct Xxx_dev *dev = filp->private_data; Return Fasync_helper (FD, FILP, mode, &dev->async_queue);}
2.5 When the device resource is available, you should call the Kill_fasync () function to release the Sigio signal, the third parameter is poll_in when read, and the third parameter is poll_out when writable, the template is as follows
Static ssize_t xxx_write (struct file *filp,const char __user *buf,size_t count,loff_t *ppos) {struct Xxx_dev *dev = FILP-&G T;private_data;...if (Dev->async_queue) Kill_fasync (&dev->async_queue,gigio,poll_in);
2.6 Finally when the file is closed, to remove the file from the asynchronous notification list
int xxx_release (struct inode *inode,struct file *filp) {Xxx_fasync ( -1,filp,0);... return 0;}
3. linux2.6 Asynchronous I/O
The most common input-output (I/O) model in a synchronous i/o:linux system is synchronous I/O, in which the application is blocked when the request is made, knowing that the request satisfies
Asynchronous I/O:I/O requests may need to overlap with other processes
The most commonly used input/output (I/O) model in a Linux system is synchronous I/O. In this model, when a request is made, the application blocks until the request is satisfied. This is a good solution because the calling application does not need to use any central processing unit (CPU) when it waits for the I/O request to complete. But in some
In some cases, I/O requests may need to overlap with other processes. This functionality is provided by the Portable Operating System interface (POSIX) asynchronous I/O (AIO) application Interface (API)
4.1. AIO Series API:
aio_read--Asynchronous Read
The Aio_read function is prototyped as follows:
The Aio_read () function returns immediately after the request is queued. If the execution succeeds, the return value is 0, and if an error occurs, the return value is −1 and the value of errno is set.
aio_write--Asynchronous Write
The Aio_write () function is used to request an asynchronous write operation whose function prototype is as follows:
The Aio_write () function returns immediately, stating that the request has been queued (the return value is 0 on success, the return value is −1 on failure, and the errno is set accordingly.)
aio_error--determining the status of a request
The Aio_error function is used to determine the state of the request, which is prototyped as follows:
This function can return the following content.
Einprogress: The description request has not been completed.
Ecancelled: Description The request was canceled by the application.
-1: Indicates that an error has occurred and the specific error reason is logged by errno.
aio_return--getting the return value of an asynchronous operation
Another difference between asynchronous I/O and standard block I/O is that the return state of the function cannot be immediately accessed because it is not blocked on the read () call. In a standard read () call, the return state is provided when the function returns. But in asynchronous I/O, we're going to use the Aio_return () function. The prototype of this function is as follows:
This function is called only after the Aio_error () call determines that the request has completed, possibly successfully, or an error has occurred. The return value of Aio_return () is equivalent to the return value of the read or write system call in the synchronization condition (the number of bytes transferred, and the return value is −1 if an error occurs).
aio_suspend--suspend asynchronous operation, until asynchronous request is complete
The Aio_suspend () function suspends (or blocks) the calling process until the asynchronous request completes, generating a signal, or other time-out actions occur. The caller provides a list of AIOCB references, any one of which will cause aio_suspend () to return. The function prototypes for Aio_suspend are as follows:
aio_cancel--canceling an asynchronous request
The Aio_cancel () function allows the user to cancel one or all of the I/O requests performed on a file descriptor. The prototype is as follows:
If you want to cancel a request, the user needs to provide a file descriptor and a AIOCB reference. If the request is successfully canceled, the function returns aio_canceled. If the request is complete, the function returns aio_notcanceled. If you want to cancel all requests for a given file descriptor, the user needs to provide a descriptor for the file and a NULL reference to AIOCBP. If all requests are canceled, the function returns aio_canceled, and if at least one request is not canceled, the function returns aio_not_canceled, and if no request can be canceled, the function returns Aio_alldone. You can then use Aio_error () to validate each AIO request, and if a request has been canceled, Aio_error () returns −1 and errno is set to ecanceled.
lio_listio--simultaneously initiates multiple transmissions (one system call can initiate a large number of I/O operations)
The Lio_listio () function can be used to initiate multiple transmissions at the same time. This function is very important, which allows the user to initiate a large number of I/O operations in a system call (one kernel context switch). The Lio_listio API functions are prototyped as follows:
The mode parameter can be lio_wait or lio_nowait. LIO_WAIT will block this call until all I/O is complete. After the operation is queued, the lio_nowait will return. List is a AIOCB reference, and the maximum number of elements is defined by nent. If the element of list is Null,lio_listio () it is ignored.
3.2, the use of signals as AIO notice
Signals are still used in AIO as a mechanism for asynchronous notifications, and in order to use the signals, applications that use AIO also need to define a signal handler that invokes the handler when the specified signal is triggered, as part of the signal context, where a specific AIOCB request is provided to the signal processing function to differentiate the AIO Request. The following code listing shows an example of using a signal as an AIO asynchronous I/O notification mechanism.
1/* Set asynchronous I/O requests */2 void Setup_io (...) 3 {4 int fd; 5 struct sigaction sig_act; 6 struct AIOCB MY_AIOCB; 7 ... 8/* Set signal processing function */9 Sigemptyset (&sig_act.sa_mask); Ten sig_act.sa_flags = Sa_siginfo; One sig_act.sa_sigaction = Aio_completion_handler; 12 13/* Set AIO Request */bzero ((char*) &MY_AIOCB, sizeof (struct AIOCB)); My_aiocb.aio_fildes = FD; My_aiocb.aio_buf = malloc (buf_size + 1); My_aiocb.aio_nbytes = buf_size; My_aiocb.aio_offset = Next_offset; 19 20/* Connect AIO request and signal processing function */my_aiocb.aio_sigevent.sigev_notify = sigev_signal; My_aiocb.aio_sigevent.sigev_signo = SIGIO; My_aiocb.aio_sigevent.sigev_value.sival_ptr = &my_aiocb; 24 25/* Binds the signal to the signal processing function */-ret = Sigaction (SIGIO, &sig_act, NULL); 27 ... ret = Aio_read (&MY_AIOCB); /* Make an asynchronous read request */29} 30 31/* Signal processing function */* * void Aio_completion_handler (int signo, siginfo_t *info, void *context) 33 {34 struct AIOCB *req; 35 36/* Make sure it's the letter we need.#/PNS if (Info->si_signo = = SIGIO) [req] = (struct aiocb*) info->si_value.sival_ptr;/* Get aiocb*/40 41/* Did the requested operation be completed? * * * IF (aio_error (req) = = 0) 43 {44/* Requested operation completed, get return value */ret = Aio_return (req); 46} 47} 4 8 return; 49}
3.3 Using callback functions as a notification for AIO
The code listing provides an example of a notification mechanism that uses a callback function as an AIO asynchronous I/O request completion
1/* Set asynchronous I/O requests */2 void Setup_io (...) 3 {4 int fd; 5 struct AIOCB my_aiocb; 6 ... 7/* Set AIO Request */8 Bzero ((char*) &MY_AIOCB, sizeof (struct AIOCB)); 9 my_aiocb.aio_fildes = FD; Ten my_aiocb.aio_buf = malloc (buf_size + 1); One my_aiocb.aio_nbytes = buf_size; My_aiocb.aio_offset = Next_offset; 13 14/* Connect AIO request and thread callback function */my_aiocb.aio_sigevent.sigev_notify = Sigev_thread; My_aiocb.aio_sigevent.notify_function = Aio_completion_handler; 17/* Set callback function */my_aiocb.aio_sigevent.notify_attributes = NULL; My_aiocb.aio_sigevent.sigev_value.sival_ptr = &my_aiocb; ret = Aio_read (&MY_AIOCB); Initiate AIO request 21} 22 23/* Asynchronous I/O completion callback function */Aio_completion_handler (sigval_t sigval) (AIOCB *req 2) 7 req = (struct aiocb*) sigval.sival_ptr; */* AIO request completed? */if (aio_error (req) = = 0) 31 {32/* request completed, get return value */"ret = Aio_return (req); 37}
3.4 Aio and device driver
In the kernel, each I/O request corresponds to a KIOCB struct, and its KI_FILP member only wants the corresponding file pointer, IS_SYNC_KIOCB to determine whether a KIOCB is a synchronous I/O request, and if it is true, it is expressed as an asynchronous I/O request.
Block devices and network devices: they are asynchronous in nature
Character device: You must explicitly support AIO (very few asynchronous I/O operations)
The character device driver file_operations contains 3 AIO-related member functions, as follows:
over~
All rights reserved, reprint please specify reprint address: http://www.cnblogs.com/lihuidashen/p/4455393.html
In layman's ~linux device-driven asynchronous notifications and asynchronous I/O