In layman's ~linux device-driven asynchronous notifications and asynchronous I/O

Source: Internet
Author: User
Tags signal handler

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

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.