阻塞型字符设备驱动
来源:互联网 发布:四会网络推广学校 编辑:程序博客网 时间:2024/04/29 21:15
阻塞型字符设备驱动
[概述]
首先明确一点,不管你是睡眠、休眠还是阻塞,还是挂起,本质上都是把进程放到等待队列上。
[休眠的实现]
休眠通过等待队列进行处理。等待队列是由等待某些事件发生的进程组成的简单链表。内核中用wake_queue_head_t来代表等待队列。等待队列可以通过DECLARE_WAITQUEUE()静态创建,也可以由Init_waitqueue_head()动态创建。进程把自己放入等待队列中并设置成不可执行状态。当与等待队列相关的事件发生的时候,队列上的进程会被唤醒。为了避免产生竞争条件,休眠和唤醒的实现不能有纰漏。
针对休眠,内核提供了一些简单的接口。但那些接口会带来竞争条件:有可能导致在判断条件为真后,进程却开始了休眠,那样就会使进程无限期地休眠下去,所以,在内核中进行休眠的推荐操作就想复杂了一些:
DEFINE_WAIT(wait); Add_wait_queue(q, &wait);While (!condition) { Prepare_to_wait(&q,&wait, TASK_INTERRUPTIBLE); If(signal_pending(current)) /*处理信号 */ Schedule();}Finish_wait(&q, &wait);
1) 调用宏DEFINE_WAIT()创建一个等待队列的项;
2) 调用add_wait_queue()把自己加入到队列中,该队列会在进程等待的条件满足时唤醒它,当然我们必须在其他地方编写相关代码,在事件发生时,对等待队列执行wake_up()操作;
3) 调用prepare_to_wait()方法将进程的状态变更为TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE。而且该函数如果有必要的话会将进程家回到等待队列,这是在接下来的循环遍历中所需要的;
4) 如果状态被设置为TASK_INTERRUPTIBLE,则信号唤醒进程。这就是所谓的伪唤醒,因此检查并处理信号;
5) 当进程被唤醒的时候,它会再次检查条件是否为真。如果是,它就退出循环;如果不是,它再次调用schedule()并一直重复这步操作;
6) 当条件满足后,进程将自己设置为TASK_RUNNING并调用finish_wait()方法把自己移出等待队列;
如果需要了解这些函数的实现,可以参考http://edsionte.com/techblog/archives/1854
[一个阻塞型FIFO实例]
对上面休眠实现理论有了一个了解,看下面的代码应该不难了。
[fifo结构体]
struct simple_chrdev_fifo { structcdev cdev; charfifo[MAX_SIZE]; intfifo_size; intcurrent_pos; /* read and writeposition in fifo */ structsemaphore sem; /* semaphore */ wait_queue_head_treadq, writeq; /* read queue andwrite queue */};
[阻塞型read方法]
static ssize_t simple_read(struct file*filp, char __user *buf, size_t count, loff_t*f_pos){ structsimple_chrdev_fifo *dev = filp->private_data; intret = 0; DEFINE_WAIT(wait); if(down_interruptible(&dev->sem)) return-ERESTARTSYS; add_wait_queue(&dev->readq,&wait); while(dev->current_pos == 0) { up(&dev->sem); if(filp->f_flags & O_NONBLOCK) return- EAGAIN; prepare_to_wait(&dev->readq,&wait, TASK_INTERRUPTIBLE); if(signal_pending(current)) { ret = - ERESTARTSYS; gotoout2; } schedule(); if(down_interruptible(&dev->sem)) { ret= -ERESTARTSYS; gotoout2; } } if(count > dev->current_pos) count= dev->current_pos; if(copy_to_user(buf, (void *)(dev->fifo), count)) { ret= -EFAULT; gotoout; } dev->current_pos-= count; ret= count; wake_up_interruptible(&dev->writeq);out: up(&dev->sem);out2: finish_wait(&dev->readq,&wait); returnret;}
[模块初始化函数]
static int __initsimple_chrdev_fifo_init(void){ …… /* * initialze wait queue */ init_waitqueue_head(&dev->readq); init_waitqueue_head(&dev->writeq); init_MUTEX(&dev->sem); ……}
使用init_waitqueue_head宏对等待读队列头和等待写队列头进行初始化;
这里只贴出了重要的代码,如果需要完整的代码,请发email给我。
- 阻塞型字符设备驱动
- 高级字符设备驱动-阻塞型字符设备驱动笔记
- 阻塞型字符设备驱动的编写
- 阻塞型字符设备驱动及例子
- Linux 设备驱动--- 阻塞型字符设备驱动 --- O_NONBLOCK --- 非阻塞标志
- linux高级字符设备驱动之 三 阻塞型字符设备驱动
- 阻塞型设备驱动
- 阻塞型字符设备
- 支持阻塞操作的字符设备驱动
- 字符设备驱动-同步互斥阻塞
- Linux 驱动程序笔记3--- 阻塞型字符设备驱动 --- O_NONBLOCK --- 非阻塞标志
- linux设备驱动学习(6) 高级字符驱动学习--阻塞型I/0
- Linux驱动编程 step-by-step (八) 阻塞型字符设备驱动
- 字符设备驱动同步之互斥阻塞
- 字符设备驱动第八课----file->flag判是否阻塞
- linux字符设备驱动-同步互斥阻塞笔记
- 字符设备驱动--异步通知、同步互斥阻塞
- Linux字符设备驱动之同步互斥阻塞
- C++程序设计语言--第七章:函数
- Bash - the shell (1)
- du2
- 面向对象的几个问题
- Session的介绍
- 阻塞型字符设备驱动
- PHP输出中文乱码的问题
- 【十大堕落的表现】如果堕落了,请收藏提醒自己,不能再这样了......
- 多线程控制方法
- Http的常见错误解析
- 在PHP中用Socket发送电子邮件
- 当被鄙视成为一种习惯,心里也多了一份坦然
- 线程优先级别
- perl模块之MIME::Lite发送有附件的邮件