linux内核阻塞IO
阻塞操作是指在执行设备操作时,若不能获得资源,则挂起进程直到满足可操作的条件后再进行操作。被挂起的进程进入休眠状态,被从调度器的运行队列移走,知道等待的条件被满足。而非阻塞的进程在不能进行设备操作时,并不挂起,它或者放弃,或者不停地查询,直到可以操作为止。
在linux驱动程序中,可以使用等待队列(wait queue)来实现阻塞进程的唤醒。
1. 等待队列头
一个等待队列有一个“等待队列头”来管理,wait_queue_head_t定义在linux/wait.h,实现在kernel/wait.c中。
struct __wait_queue_head {
    spinlock_t      lock;
    struct list_head    task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
DECLARE_WAIT_QUEUE_HEAD(name); //静态
wait_queue_head_t my_queue;
init_waitqueue_head(&my_queue);
2. 定义等待队列
typedef struct __wait_queue wait_queue_t;
typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int flags, void *key);
int default_wake_function(wait_queue_t *wait, unsigned mode, int flags, void *key); struct __wait_queue {
unsigned int flags;
#define WQ_FLAG_EXCLUSIVE 0x01
void *private;
wait_queue_func_t func;
struct list_head task_list;
};
DECLARE_WAIT_QUEUE(name, tsk);
该宏用于定义并初始化一个名为name的等待队列。
#define __WAITQUEUE_INITIALIZER(name, tsk) {                \
    .private    = tsk,                      \
    .func       = default_wake_function,            \
    .task_list  = { NULL, NULL } }
#define DECLARE_WAITQUEUE(name, tsk)                    \
    wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)
3. 移除和添加等待队列
extern void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
extern void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait);
extern void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
4. 等待事件
#define wait_event(wq, condition)
#define wait_event_timeout(wq, condition, timeout)
#define wait_event_interruptible(wq, condition)
#define wait_event_interruptible_timeout(wq, condition, timeout)
/**
* wait_event_interruptible_timeout - sleep until a condition gets true or a timeout elapses
* @wq: the waitqueue to wait on
* @condition: a C expression for the event to wait for
* @timeout: timeout, in jiffies
*
* The process is put to sleep (TASK_INTERRUPTIBLE) until the
* @condition evaluates to true or a signal is received.
* The @condition is checked each time the waitqueue @wq is woken up.
*
* wake_up() has to be called after changing any variable that could
* change the result of the wait condition.
*
* Returns:
* 0 if the @timeout elapsed, -%ERESTARTSYS if it was interrupted by
* a signal, or the remaining jiffies (at least 1) if the @condition
* evaluated to %true before the @timeout elapsed.
*/
等待第一个参数wq作为等待队列头的等待队列被唤醒,而且第2个参数condition必须满足,否则继续阻塞。
timeout以jiffy为单位。
5. 唤醒队列
void wake_up(wait_queue_head_t *queue);
void wake_up_interruptible(wait_queue_head_t *queue);
6. 在等待队列上睡眠
extern void sleep_on(wait_queue_head_t *q);
extern long sleep_on_timeout(wait_queue_head_t *q, signed long timeout);
extern void interruptible_sleep_on(wait_queue_head_t *q);
extern long interruptible_sleep_on_timeout(wait_queue_head_t *q, signed long timeout);
将当前进程添加到等待队列中,从而在等待队列上睡眠。当超时发生时,进程被唤醒。
参考:
1. 等待队列
linux内核阻塞IO的更多相关文章
- Linux非阻塞IO(六)使用poll实现非阻塞的服务器端
		关于poll模型监听的事件以及返回事件,我们定义宏如下: #define kReadEvent (POLLIN | POLLPRI) #define kWriteEvent (POLLOUT | PO ... 
- Linux非阻塞IO(五)使用poll实现非阻塞的回射服务器客户端
		前面几节我们讨论了非阻塞IO的基本概念.Buffer的设计以及非阻塞connect的实现,现在我们使用它们来完成客户端的编写. 我们在http://www.cnblogs.com/inevermore ... 
- Linux非阻塞IO(四)非阻塞IO中connect的实现
		我们为客户端的编写再做一些工作. 这次我们使用非阻塞IO实现connect函数. int connect(int sockfd, const struct sockaddr *addr, sockle ... 
- Linux非阻塞IO(三)非阻塞IO中缓冲区Buffer的实现
		本文我们来实现回射服务器的Buffer. Buffer的实现 上节提到了非阻塞IO必须具备Buffer.再次将Buffer的设计描述一下: 这里必须补充一点,writeIndex指向空闲空间的 ... 
- Linux非阻塞IO(二)网络编程中非阻塞IO与IO复用模型结合
		上文描述了最简易的非阻塞IO,采用的是轮询的方式,这节我们使用IO复用模型. 阻塞IO 过去我们使用IO复用与阻塞IO结合的时候,IO复用模型起到的作用是并发监听多个fd. 以简单的回射服务器 ... 
- Linux非阻塞IO(八)使用epoll重新实现非阻塞的回射服务器
		本文无太多内容,主要是几个前面提到过的注意点: 一是epoll的fd需要重新装填.我们将tcp_connection_t的指针保存在数组中,所以我们以这个数组为依据,重新装填fd的监听事件. //重新 ... 
- Linux非阻塞IO(七)使用epoll重新实现客户端
		使用poll与epoll的区别主要在于: poll可以每次重新装填fd数组,但是epoll的fd是一开始就加入了,不可能每次都重新加入 于是采用这种策略: epoll除了listenfd一开始就监听r ... 
- Linux SCSI回调IO的分析
		本文转载自:http://blog.csdn.net/xushiyan/article/details/6941640,如需参考,请访问原始链接地址. 没找到如何转载的入口,只好全文copy了. -- ... 
- 20169211《Linux内核原理与分析》 第九周作业
		一.Linux内核虚拟文件系统学习总结 Linux支持各种文件系统,Linux内核通过虚拟文件系统了对各种文件系统共性的进行抽象,并对外提供统一接口,从面向对象编程的角度来看,称为抽象文件系统更为合适 ... 
随机推荐
- HDUOJ---2546 饭卡
			饭卡 Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submissi ... 
- html5中的FileReader对象
			表单中有图片选项,选中图片文件之后要求可以预览.这个功能很多控件都封装好了,但是它们的底层都是FileReader对象. FileReader对象提供了丰富的功能,包括以二进制.以文本方式读取文件内容 ... 
- github常见操作和常见错误及其解决办法
			一.常见操作 1. 使用git在本地创建一个项目的过程 $ makdir ~/hello-world //创建一个项目hello-world $ cd ~/hello-world //打开这个项目 $ ... 
- 分布式缓存技术memcached学习系列(三)——memcached内存管理机制
			几个重要概念 Slab memcached通过slab机制进行内存的分配和回收,slab是一个内存块,它是memcached一次申请内存的最小单位,.在启动memcached的时候一般会使用参数-m指 ... 
- Python学习笔记010——匿名函数lambda
			1 语法 my_lambda = lambda arg1, arg2 : arg1 + arg2 + 1 arg1.arg2:参数 arg1 + arg2 + 1 :表达式 2 描述 匿名函数不需要r ... 
- Linux内核同步 - RCU基础
			一.前言 关于RCU的文档包括两份,一份讲基本的原理(也就是本文了),一份讲linux kernel中的实现.第二章描述了为何有RCU这种同步机制,特别是在cpu core数目不断递增的今天,一个性能 ... 
- HR面 - 十大经典提问
			1.HR:你希望通过这份工作获得什么? 1).自杀式回答:我希望自己为之工作的企业能够重视质量,而且会给做得好的员工予以奖励.我希望通过这份工作锻炼自己,提升自己的能力,能让公司更加重视我. a.“我 ... 
- VirtualBOX 不能mount优盘,移动硬盘解决方案
			The Solution (basically nayasis' solution with the second driver installation added): Safely unplug ... 
- mysql服务器无法连接10055错误解决示例
			windows服务器下,mysql运行一段时间之后忽然无法连接,但是mysql服务启动正常,连接时报错: can't connect to mysql server on 'localhost ... 
- Java:Swing篇,实现JList、JTextArea的自动滚动,实时刷新功能
			1. 功能 作为swing的组件,JList与JTextArea是不可以单独实现滚动功能的,需要与JScrollPane结合才可以. 本代码中: JList实现从其它数据源获取数据,然后依次对这些数据 ... 
