异步通知的概念:

一旦设备就绪,主动通知应用程序。这样应用程序根本不需要查询设备状态。


阻塞,非阻塞和异步:

-阻塞IO是等待设备可访问后再访问

-非阻塞IO是查询设备是否可以访问

-异步通知是设备通知自身可以访问


为了使支持异步通知机制,驱动程序应该涉及以下3项工作。

支持F_SETOWN命令,能在这个控制命令处理。


处理FASYNC标志更变的函数

Int fasync_helper(int fd, struct file*filp, int mode, struct fasync_struct **fa);

释放信号用的函数

Void kill_fasync(struct fasync_struct **fa,int sig, int band);

void kill_fasync(struct fasync_struct **fp,int sig, int band)

{

      /*First a quick test without locking: usually

       * the list is empty.

       */

      if(*fp) {

             read_lock(&fasync_lock);

             /*reread *fp after obtaining the lock */

             __kill_fasync(*fp,sig, band);

             read_unlock(&fasync_lock);

      }

}


void __kill_fasync(struct fasync_struct*fa, int sig, int band)

{

      while(fa) {

             structfown_struct * fown;

             if(fa->magic != FASYNC_MAGIC) {

                    printk(KERN_ERR"kill_fasync: bad magic number in "

                           "fasync_struct!\n");

                    return;

             }

             fown= &fa->fa_file->f_owner;

             /*Don't send SIGURG to processes which have not set a

                queued signum: SIGURG has its own defaultsignalling

                mechanism. */

             if(!(sig == SIGURG && fown->signum == 0))

                    send_sigio(fown,fa->fa_fd, band);

             fa= fa->fa_next;

      }

}


void send_sigio(struct fown_struct *fown,int fd, int band)

{

      structtask_struct *p;

      enumpid_type type;

      structpid *pid;

      intgroup = 1;


      read_lock(&fown->lock);


      type= fown->pid_type;

      if(type == PIDTYPE_MAX) {

             group= 0;

             type= PIDTYPE_PID;

      }


      pid= fown->pid;

      if(!pid)

             gotoout_unlock_fown;


      read_lock(&tasklist_lock);

do_each_pid_task(pid, type, p) {

             send_sigio_to_task(p,fown, fd, band, group);

      } while_each_pid_task(pid, type, p);

      read_unlock(&tasklist_lock);

out_unlock_fown:

      read_unlock(&fown->lock);

}

通过内核,给所有的进程发送信号。


用户对应进程可以接受该信号,并作处理。

用户进程要做的是:

1.绑定信号和信号处理函数

Signal(SIGIO,input_handler)

2.设定本进程为某个标准输入文件的拥有者。这样内核就知道信号发送给那个进程。

Fcntl(STDIN_FILENO,F_SETNO,getpid());

3.对输入文件设定异步标志位。

Fcntl(STDIN_FILENO,F_SETFL,oflags | FASYNC)