字符设备驱动之笔记-异步通知(fasync)

来源:互联网 发布:java随机数生成10个 编辑:程序博客网 时间:2024/05/20 20:46
 发信号:
1. 谁发
2. 发给谁
3. 发什么
4. 怎么发
5. 收到信号后做什么


16th_signal_app
发信号:
1. 谁发    a
2. 发给谁  b
3. 发什么  SIGIO
4. 怎么发  int kill(pid_t pid, int sig);
5. 收到信号后做什么: sighandler_t signal(int signum, sighandler_t handler);


驱动和应用
发信号:
1. 谁发    按键中断服务程序
2. 发给谁  使用按键的应用程序
3. 发什么  SIGIO
4. 怎么发  kill_fasync(谁, SIGIO)
5. 收到信号后做什么: sighandler_t signal(int signum, sighandler_t handler);

怎么写驱动?
1. 定义一个fasync_struct指针:
struct fasync_struct *buttons_async;

2. 设置它:
static int buttons_fasync(int fd, struct file *filp, int on)
{
 int retval;

 retval = fasync_helper(fd, filp, on, &buttons_async);
 if (retval < 0)
  return retval;
 return 0;
}
static const struct file_operations buttons_fops = {
    ......
 .fasync  = buttons_fasync,
};

3. 使用它:
kill_fasync(&buttons_async, SIGIO, POLL_IN);

 

怎么写应用?
1. 注册信号处理函数
signal(SIGNO, signal_function);

2. 执行某些函数, 使得驱动里的fasync被调用
 flag = fcntl(fd, F_GETFL);
 flag |= FASYNC;
 fcntl(fd, F_SETFL, flag);
 
3. 把应用程序的PID告诉驱动:
 fcntl(fd, F_SETOWN, getpid());

应用调用到驱动里的fasync:
1.
app:    flag = fcntl(fd, F_GETFL);
--------------------------------------------------------
kernel:  sys_fcntl
             do_fcntl
                 err = filp->f_flags;
                 return err;

2.
app:    fcntl(fd, F_SETFL, flag);
--------------------------------------------------------
kernel:  sys_fcntl
             do_fcntl
    err = setfl(fd, filp, arg);
       // 要改变file->f_flasgs的FASYNC时
       // 调用驱动的fasync
       if ((arg ^ filp->f_flags) & FASYNC) {
        if (filp->f_op && filp->f_op->fasync) {
         error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);
         if (error < 0)
          goto out;
        }

3.
app:    fcntl(fd, F_SETOWN, getpid());
-----------------------------------------------------
kernel: sys_fcntl
   do_fcntl
    err = f_setown(filp, arg, 1);
        result = __f_setown(filp, pid, type, force);


4.
kill_fasync(&buttons_async, SIGIO, POLL_IN);
 __kill_fasync(*fp, sig, band);
    fown = &fa->fa_file->f_owner;
    send_sigio(fown, fa->fa_fd, band);