支持异步通知的globalfifo驱动
来源:互联网 发布:软件质量控制方法 编辑:程序博客网 时间:2024/05/15 07:52
前言
驱动程序运行在内核空间中,应用程序运行在用户空间中,两者是不能直接通信的。但在实际应用中,在设备已经准备好的时候,我们希望通知用户程序设备已经ok,用户程序可以读取了,这样应用程序就不需要一直查询该设备的状态,从而节约了资源,这就是异步通知。好,那下一个问题就来了,这个过程如何实现呢?简单,两方面的工作。
一 驱动方面
- 在设备抽象的数据结构中增加一个struct fasync_struct的指针
- 实现设备操作中的fasync函数,这个函数很简单,其主体就是调用内核的fasync_helper函数。
- 在需要向用户空间通知的地方(例如中断中)调用内核的kill_fasync函数。
- 在驱动的release方法中调用前面定义的fasync函数
其中fasync_helper和kill_fasync都是内核函数,我们只需要调用就可以了。在1中定义的指针是一个重要参数,fasync_helper和kill_fasync会使用这个参数。
二 应用层方面
- 利用signal或者sigaction设置SIGIO信号的处理函数
- fcntl的F_SETOWN指令设置当前进程为设备文件owner
- fcntl的F_SETFL指令设置FASYNC标志
完成了以上的工作的话,当内核执行到kill_fasync函数,用户空间SIGIO函数的处理函数就会被调用了。
三代码方面
1.增加异步通知后的globalfifo设备结构体
struct globalfifo_dev { struct cdev cdev; //cdev结构体 unsigned int current_len; //fifo有效数据长度 unsigned char mem[GLOBALFIFO_SIZE]; //全局内存 struct mutex mutex; //互斥锁 //struct semaphore sem; //并发控制用的信号量 wait_queue_head_t r_wait; //阻塞读用的等待队列头 wait_queue_head_t w_wait; //阻塞写用的等待队列头 struct fasync_struct *async_queue; //异步结构体指针,用于读 };
2.支持异步通知的globalfifo设备驱动fasync()函数
static int globalfifo_fasync(int fd,struct file *filp,int mode){ struct globalfifo_dev *dev=filp->private_data; return fasync_helper(fd,filp,mode,&dev->async_queue);}
3支持异步通知的globalfifo设备驱动写函数
static ssize_t globalfifo_write(struct file *filp,const char _user *buf,size_t count,loff_t *ppos){ struct globalfifo_dev *dev=filp->private_data; //获得设备结构体指针 int ret; DECLARE_WAITQUEUE(wait,current); //定义等待队列 mutex_ lock(& dev-> mutex); //取得互斥锁 //down(&dev->sem); //取得信号量 add_wait_queue(&dev->w_wait,&wait); //进入写等待队列 //等待fifo未满 while(dev->current_len==GLOBALFIFO_SIZE){ if(filp->f_flags&O_NOBLOCK){ //如果是非阻塞访问 ret=-EAGAIN; goto out; } _set_current_state(TASK_INTERRUPTIBLE) //改变进程状态为睡眠 mutex_unlock(& dev-> mutex); //up(&dev->sem); schedule(); if(signal_pending(current){ ret=-ERESTARTSYS; goto out2; } mutex_lock(& dev-> mutex); //down(&dev->sem); } //从用户空间拷贝到内核空间 if(count >GLOBALFIFO_SIZE- dev->current_len) count=GLOBALFIFO_SIZE-dev->current_len; if(copy_form_user(dev->mem+dev->current_len,buf,count)) { ret=-EFAULT; goto out; }else{ dev->current_len+=count; printk( KERN_ INFO "written %d bytes( s), current_ len:% d\ n", count, 38 dev-> current_ len); wake_up_interruptible(&dev->r_wait); //唤醒读等待队列 //产生异步读信号 if(dev->async_queue){ kill_fasync(&dev->async_queue,SIGIO,POLL_IN); printk( KERN_ DEBUG "%s kill SIGIO\ n", __func__); } ret=count; } out:mutex_unlock(& dev-> mutex);//up(&dev->sem); out2:remove_wait_queue(&dev->w_wait,&wait); set_current_state(TASK_RUNNING); return ret;}
4用globalfifo_fasync()函数将文件从异步通知列表中删除
static int globalfifo_release(struct inode *inode,struct file *filp) { globalfifo_fasync(-1,filp,0); return 0; }
四验证结果
监控 globalfifo 异步 通知 信号 的 应用 程序
static void signalio_handler(int signum){ printf("receive a signal from globalfifo, signalnum:%d\n",signum);}void main( void) { int fd, oflags; fd = open("/ dev/ globalfifo", O_ RDWR, S_ IRUSR | S_ IWUSR); if (fd != -1){ //启动信号驱动机制,将SIGIO信号同input_handler函数关联起来,一旦产生SIGIO信号,就会执行input_handler signal(SIGIO, input_handler); //STDIN_FILENO是打开的设备文件描述符,F_SETOWN用来决定操作是干什么的,getpid()是个系统调用, //功能是返回当前进程的进程号,整个函数的功能是STDIN_FILENO设置这个设备文件的拥有者为当前进程。 fcntl(STDIN_FILENO, F_SETOWN, getpid()); //得到打开文件描述符的状态 oflags = fcntl(STDIN_FILENO, F_GETFL); //设置文件描述符的状态为oflags | FASYNC属性,一旦文件描述符被设置成具有FASYNC属性的状态, //也就是将设备文件切换到异步操作模式。这时系统就会自动调用驱动程序的fasync方法。 fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC); while (1){ sleep( 100); } else { printf(" device open failure\ n"); }}(注:上面有一行解释为:这时系统就会自动调用驱动程序的fasync方法,我的理解是:这个时候我们联系一下后面的驱动,我们会发现在驱动层,是在file_operation中对应的fasync的函数调用,这是,会首先调fasync对应的my_fasync函数,而后者会进行 将该设备登记到fasync_queue队列中去,为后续做准备)
以下是几点说明:
1 两个函数的原型
int fasync_helper(struct inode *inode, struct file *filp, int mode, struct fasync_struct **fa);
一个”帮忙者”, 来实现 fasync 设备方法. mode 参数是传递给方法的相同的值, 而 fa 指针指向一个设
备特定的 fasync_struct *
void kill_fasync(struct fasync_struct *fa, int sig, int band);
如果这个驱动支持异步通知, 这个函数可用来发送一个信号到登记在 fa 中的进程.
2.fasync_helper 用来向等待异步信号的设备链表中添加或者删除设备文件, kill_fasync被用来通知拥有相关设备的进程. 它的参数是被传递的信号(常常是 SIGIO)和 band, 这几乎都是 POLL_IN[25](但是这可用来发送”紧急”或者带外数据, 在网络代码里).
- 支持异步通知的globalfifo驱动
- 9--2支持异步通知的globalfifo驱动
- 8--2支持阻塞操作的globalfifo设备驱动
- 8--4支持轮询操作的globalfifo驱动
- 支持异步通知的设备驱动和应用
- 《linux设备驱动开发详解》中支持阻塞操作的globalfifo设备驱动
- 支持轮询操作的globalfifo
- 设备驱动的异步通知实现
- 按键驱动的恩恩怨怨之异步通知
- Linux的fasync驱动异步通知详解
- Linux的异步通知字符设备驱动
- linux驱动的异步同步通知机制
- 基于异步通知机制的按键驱动
- globalfifo(管道)驱动
- 驱动实现异步通知
- 红外驱动-异步通知
- 红外驱动-异步通知
- linux设备驱动--异步通知
- C语言中的fgets函数
- 我的收藏
- Linux 中的负载工具-ttyload
- 1003Emergency(25)
- 学习用maven开发springmvc
- 支持异步通知的globalfifo驱动
- opencv3.0-Mat类笔记
- JDBC
- 管理CDB
- Dijkstra
- Ubuntu 16.04+CUDA8.0+Caffe+OpenCV3.1
- idea打开提示Cannot resolve symbol xxx
- 文件操作
- 菜鸟学习历程【5】约瑟夫环