当前位置:嗨网首页>书籍在线阅读

08-在globalfifo驱动中增加异步通知

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

9.3.1 在globalfifo驱动中增加异步通知

首先,参照代码清单9.2,应该将异步结构体指针添加到globalfifo_dev设备结构体内,如代码清单9.7所示。

代码清单9.7 增加异步通知后的globalfifo设备结构体

1 struct globalfifo_dev {

2 struct cdev cdev; /cdev结构体/

3 unsigned int current_len; /fifo有效数据长度/

4 unsigned char mem[GLOBALFIFO_SIZE]; /全局内存/

5 struct semaphore sem; /并发控制用的信号量/

6 wait_queue_head_t r_wait; /阻塞读用的等待队列头/

7 wait_queue_head_t w_wait; /阻塞写用的等待队列头/

8 struct fasync_struct async_queue; / 异步结构体指针,用于读 */

9 };

参考代码清单9.3的fasync()函数模板,globalfifo的这个函数如代码清单9.8。

代码清单9.8 支持异步通知的globalfifo设备驱动fasync()函数

1 static int globalfifo_fasync(int fd, struct file *filp, int mode)

2 {

3 struct globalfifo_dev *dev = filp->private_data;

4 return fasync_helper(fd, filp, mode, &dev->async_queue);

5 }

在globalfifo设备被正确写入之后,它变得可读,这个时候驱动应释放SIGIO信号以便应用程序捕获,代码清单9.9给出了支持异步通知的globalfifo设备驱动的写函数。

代码清单9.9 支持异步通知的globalfifo设备驱动写函数

1 static ssize_t globalfifo_write(struct file filp, const char __user buf,

2 size_t count, loff_t *ppos)

3 {

4 struct globalfifo_dev dev = filp->private_data; / 获得设备结构体指针 */

5 int ret;

6 DECLARE_WAITQUEUE(wait, current); /定义等待队列/

7

8 down(&dev->sem); /获取信号量/

9 add_wait_queue(&dev->w_wait, &wait); /进入写等待队列头/

10

11 / 等待FIFO非满 /

12 if (dev->current_len == GLOBALFIFO_SIZE) {

13 if (filp->f_flags &O_NONBLOCK) { / 如果是非阻塞访问 /

14 ret = - EAGAIN;

15 goto out;

16 }

17 _ _set_current_state(TASK_INTERRUPTIBLE); /改变进程状态为睡眠/

18 up(&dev->sem);

19

20 schedule(); /调度其他进程执行/

21 if (signal_pending(current)) { / 如果是因为信号唤醒 /

22 ret = - ERESTARTSYS;

23 goto out2;

24 }

25

26 down(&dev->sem); /获得信号量/

27 }

28

29 /从用户空间拷贝到内核空间/

30 if (count > GLOBALFIFO_SIZE - dev->current_len)

31 count = GLOBALFIFO_SIZE - dev->current_len;

32

33 if (copy_from_user(dev->mem + dev->current_len, buf, count)) {

34 ret = - EFAULT;

35 goto out;

36 } else {

37 dev->current_len += count;

38 printk(KERN_INFO "written %d bytes(s),current_len:%d\n", count, dev

39 ->current_len);

40

41 wake_up_interruptible(&dev->r_wait); /唤醒读等待队列/

42 / 产生异步读信号 /

43 if (dev->async_queue)

44 kill_fasync(&dev->async_queue, SIGIO, POLL_IN);

45

46 ret = count;

47 }

48

49 out: up(&dev->sem); / 释放信号量 /

50 out2:remove_wait_queue(&dev->w_wait, &wait);

51 set_current_state(TASK_RUNNING);

52 return ret;

53 }

参考代码清单9.6,增加异步通知后的globalfifo设备驱动的release()函数中需调用globalfifo_fasync()函数将文件从异步通知列表中删除,代码清单9.10给出了支持异步通知的globalfifo_release()函数。

代码清单9.10 增加异步通知后的globalfifo设备驱动release()函数

1 int globalfifo_release(struct inode inode, struct file filp)

2 {

3 / 将文件从异步通知列表中删除 /

4 globalfifo_fasync( - 1, filp, 0);

5 return 0;

6 }