高级字符驱动学习--阻塞型I/0
2012-11-29 10:41
204 查看
提出问题:若驱动程序无法立即满足请求,该如何响应? 比如:当数据不可用时调用read,或是在缓冲区已满时,调用write
解决问题:驱动程序应该(默认)该阻塞进程,将其置入休眠状态直到请求可继续。
休眠:
当一个进程被置入休眠时,它会被标记为一种特殊状态并从调度器运行队列中移走,直到某些情况下修改了这个状态,才能运行该进程。
安全进入休眠两原则:
1.永远不要在原子上下文中进入休眠。(原子上下文:在执行多个步骤时,不能有任何的并发访问。这意味着,驱动程序不能再拥有自旋锁,seqlock,或是RCU锁时,休眠)
2.对唤醒之后的状态不能做任何假定,因此必须检查以确保我们等待的条件真正为真
临界区 vs 原子上下文
原子上下本:一般说来,具体指在中断,软中断,或是拥有自旋锁的时候。
临界区:每次只允许一个进程进入临界区,进入后不允许其它进程访问。
other question:
要休眠进程,必须有一个前提:有人能唤醒进程,而起这个人必须知道在哪儿能唤醒进程,这里,就引入了“等待队列”这个概念。
等待队列:就是一个进程链表(我的理解:是一个休眠进程链表),其中包含了等待某个特定事件的所有进程。
等待队列头:wait_queue_head_t,定义在<linux/wait.h>
定义方法:静态 DECLARE_QUEUE_HEAD(name)
动态 wait_queue_head_t my_queue;
init_waitqueue_head(&my_queue);
简单休眠
linux最简单的休眠方式是wait_event(queue,condition)及其变种,在实现休眠的同时,它也检查进程等待的条件。四种wait_event形式如下:
wait_event(queue,condition);/*不可中断休眠,不推荐*/
wait_event_interruptible(queue,condition);/*推荐,返回非零值意味着休眠被中断,且驱动应返回-ERESTARTSYS*/
wait_event_timeout(queue,condition,timeout);
wait_event_interruptible_timeout(queue,conditon,timeout);/*有限的时间的休眠,若超时,则不管条件为何值返回0*/
唤醒休眠进程的函数:wake_up
void wake_up(wait_queue_head_t *queue);
void wake_up_interruptible(wait_queue_head *queue);
休眠与唤醒 实例分析:
本例实现效果为:任何从该设备上读取的进程均被置于休眠。只要某个进程向给设备写入,所有休眠的进程就会被唤醒。
解决问题:驱动程序应该(默认)该阻塞进程,将其置入休眠状态直到请求可继续。
休眠:
当一个进程被置入休眠时,它会被标记为一种特殊状态并从调度器运行队列中移走,直到某些情况下修改了这个状态,才能运行该进程。
安全进入休眠两原则:
1.永远不要在原子上下文中进入休眠。(原子上下文:在执行多个步骤时,不能有任何的并发访问。这意味着,驱动程序不能再拥有自旋锁,seqlock,或是RCU锁时,休眠)
2.对唤醒之后的状态不能做任何假定,因此必须检查以确保我们等待的条件真正为真
临界区 vs 原子上下文
原子上下本:一般说来,具体指在中断,软中断,或是拥有自旋锁的时候。
临界区:每次只允许一个进程进入临界区,进入后不允许其它进程访问。
other question:
要休眠进程,必须有一个前提:有人能唤醒进程,而起这个人必须知道在哪儿能唤醒进程,这里,就引入了“等待队列”这个概念。
等待队列:就是一个进程链表(我的理解:是一个休眠进程链表),其中包含了等待某个特定事件的所有进程。
等待队列头:wait_queue_head_t,定义在<linux/wait.h>
定义方法:静态 DECLARE_QUEUE_HEAD(name)
动态 wait_queue_head_t my_queue;
init_waitqueue_head(&my_queue);
struct __wait_queue_head { spinlock_t lock; struct list_head task_list; }; typedef struct __wait_queue_head wait_queue_head_t;
简单休眠
linux最简单的休眠方式是wait_event(queue,condition)及其变种,在实现休眠的同时,它也检查进程等待的条件。四种wait_event形式如下:
wait_event(queue,condition);/*不可中断休眠,不推荐*/
wait_event_interruptible(queue,condition);/*推荐,返回非零值意味着休眠被中断,且驱动应返回-ERESTARTSYS*/
wait_event_timeout(queue,condition,timeout);
wait_event_interruptible_timeout(queue,conditon,timeout);/*有限的时间的休眠,若超时,则不管条件为何值返回0*/
唤醒休眠进程的函数:wake_up
void wake_up(wait_queue_head_t *queue);
void wake_up_interruptible(wait_queue_head *queue);
惯例:用wake_up唤醒wait_event,用wake_up_interruptible唤醒wait_event_interruptible |
本例实现效果为:任何从该设备上读取的进程均被置于休眠。只要某个进程向给设备写入,所有休眠的进程就会被唤醒。
static DECLARE_WAIT_QUEUE_HEAD(wq); static int flag =0; ssize_t sleepy_read(struct file *filp,char __user *buf,size_t count,loff_t *pos) { pirntk(KERN_DEBUG "process %i (%s) going to sleep\n",current->pid,current->comm); wait_event_interruptible(wq,flag!=0); flag=0; printk(KERN_DEBUG "awoken %i (%s) \n",current->pid,current->comm); return 0; } ssize_t sleepy_write(struct file *filp,const char __user *buf,size_t count,loff_t *pos) { printk(KERN_DEBUG "process %i (%s) awakening the readers ...\n",current->pid,current->comm); flag=1; wake_up_interruptible(&wq); return count; /*成功并避免重试*/ } |
相关文章推荐
- Linux设备驱动程序学习笔记 高级字符驱动学习--阻塞型I/0
- 高级字符驱动学习--阻塞型I/0
- linux设备驱动学习(6) 高级字符驱动学习--阻塞型I/0
- Linux设备驱动程式学习(5)-高级字符驱动程式操作[(2)阻塞型I/O和休眠]
- Linux设备驱动程序学习(5)-高级字符驱动程序操作〔(2)阻塞型I/O和休眠〕
- Linux设备驱动程序学习 高级字符驱动程序操作[阻塞型I/O和非阻塞I/O]【转】
- Linux设备驱动程序学习(5)-高级字符驱动程序操作[(2)阻塞型I/O和休眠]
- Linux设备驱动程式学习(6)-高级字符驱动程式操作[(3)设备文档的访问控制]
- linux高级字符设备驱动之 三 阻塞型字符设备驱动
- Linux设备驱动程序学习(5) -高级字符驱动程序操作[(2)阻塞型I/O和休眠]
- [Linux驱动]字符设备驱动学习笔记(三)———高级
- Linux驱动学习(四)——高级字符设备驱动程序
- 【Linux 驱动】第六章 高级字符驱动程序操作 ----阻塞型I/O
- 高级字符设备驱动-阻塞型字符设备驱动笔记
- 高级字符驱动程式操作[(2)阻塞型I/O和休眠]
- Linux设备驱动程序学习 高级字符驱动程序操作[阻塞型I/O和非阻塞I/O]
- [Linux驱动]字符设备驱动学习笔记(三)———高级
- Linux设备驱动程序学习(5) -高级字符驱动程序操作[(2)阻塞型I/O和休眠]
- 《Linux设备驱动程序》学习2—高级字符设备驱动ioctl
- 国嵌视频学习——高级字符设备驱动