Asynchronous notification actively notifies the application after the device status changes.ProgramIn this way, the application does not need to block or query the device. The application processes asynchronous notifications of the kernel through signals. The last time poll select was used to query the readable status of the device, the following example is similar, the difference is that when the device has data, it actively notifies the application to read the data.
Application CCodeIt is very simple. It mainly sets the signal processing method. When the kernel has data, it will receive the sigio signal, and the application will automatically call the function set by signal to read the data.
Main. c
# Include <stdio. h> # include <fcntl. h> # include <signal. h> # include <stdlib. h> unsigned char rdbuf [1024]; int FD; void hand_signal (INT sign) {If (Sign = sigio) {If (read (FD, rdbuf, 1024)> 0) printf ("read data: % s \ n", rdbuf) ;}int main (int * argc, char ** argv) {int FD, flags; /* in the example of processing the sigio signal driver, the sigio signal */signal (sigio, hand_signal) is also sent to the application when receiving the data; FD = open ("/dev/moduledev60 ", o_rdwr); If (FD <0) {printf ("Open File error \ n"); Return-1 ;} /* tell the driver signal to whom the third parameter is passed the process Number */fcntl (FD, f_setown, getpid ()); /* set the fasync method to be driven after fasync execution. */flags = fcntl (FD, f_getfl); fcntl (FD, f_setfl, flags | fasync); While (1 );}
The main code of the driver. The read operation only returns the last written string. After the write operation, it sends a sigio signal to the set process.
Struct file_operations Ops = {. owner = this_module ,. read = fileops_read ,. write = fileops_write ,. fasync = fileops_fasync ,. close = fileops_release}; int fileops_release (struct inode * inode, struct file * filp) {printk (kern_alert "fileops_release \ n"); fileops_fasync (-1, filp, 0 ); // when the third parameter is 0, the first parameter is not used and is used to release the applied memory return 0;} ssize_t fileops_read (struct file * filp, char _ User * buff, size_t count, loff_t * OFFP) {unsigned int Len; If (rdflag = 0) return 0; Len = strlen (rdbuf); copy_to_user (buff, rdbuf, Len ); rdflag = 0; return Len;} ssize_t fileops_write (struct file * filp, const char _ User * buff, size_t count, loff_t * OFFP) {copy_from_user (rdbuf, buff, count); rdbuf [count] = 0; rdflag = 1; kill_fasync (& fasync_queue, sigio, poll_in ); // send the sigio signal printk (kern_alert "signal % d \ n", sigio); Return count;} int fileops_fasync (int fd, struct file * filp, int mode) {int res = fasync_helper (FD, filp, mode, & fasync_queue); // initialize fasync_queue printk (kern_alert "filp % x \ n ", (INT) filp); If (RES <0) return res; else return 0 ;}
Test Results
Compile and load the driver [root @ localhost ctest] # insmod moddev. ko runs the application [root @ localhost ctest] #. /main open another terminal to write data to the device [root @ localhost ctest] # echo 111>/dev/moduledev60 application output. After each data write, the driver notifies the application to read the device [root @ localhost ctest] #. /main read data: 111
Appendix fasync_helper source code/** fasync_helper () is used by some character device drivers (mainly mice) * to set up the fasync queue. it returns negative on error, 0 if it did * No changes and positive if it added/deleted the entry. */INT fasync_helper (int fd, struct file * filp, int on, struct fasync_struct ** Fapp) {/* This function maintains a linear table, used to create and release an asynchronous notification Structure linked list */struct fasync_struct * Fa, ** FP; struct fasync_struct * New = NULL; Int result = 0; If (on) {New = kmem_cache_alloc (fasync_cache, gfp_kernel); // request asynchronous notification Structure Variable if (! New) Return-enomem;} write_lock_irq (& fasync_lock); For (FP = Fapp; (FA = * FP )! = NULL; FP = & fa-> fa_next) {If (Fa-> fa_file = filp) {If (on) {// The filp node fa-> fa_fd = FD; kmem_cache_free (fasync_cache, new);} else {// release the found node * fp = fa-> fa_next; kmem_cache_free (fasync_cache, FA); Result = 1;} goto out;} If (on) {// Add the applied node to the linked list new-> magic = fasync_magic; new-> fa_file = filp; New-> fa_fd = FD; New-> fa_next = * Fapp; * Fapp = new; Result = 1;} Out: write_unlock_irq (& fasync_lock ); return result ;}