阻塞操作是指在执行设备操作时,若不能获得资源,则挂起进程直到满足可操作的条件后再进行操作。被挂起的进程进入休眠状态,被从调度器的运行队列移走,知道等待的条件被满足。而非阻塞的进程在不能进行设备操作时,并不挂起,它或者放弃,或者不停地查询,直到可以操作为止。

在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的更多相关文章

  1. Linux非阻塞IO(六)使用poll实现非阻塞的服务器端

    关于poll模型监听的事件以及返回事件,我们定义宏如下: #define kReadEvent (POLLIN | POLLPRI) #define kWriteEvent (POLLOUT | PO ...

  2. Linux非阻塞IO(五)使用poll实现非阻塞的回射服务器客户端

    前面几节我们讨论了非阻塞IO的基本概念.Buffer的设计以及非阻塞connect的实现,现在我们使用它们来完成客户端的编写. 我们在http://www.cnblogs.com/inevermore ...

  3. Linux非阻塞IO(四)非阻塞IO中connect的实现

    我们为客户端的编写再做一些工作. 这次我们使用非阻塞IO实现connect函数. int connect(int sockfd, const struct sockaddr *addr, sockle ...

  4. Linux非阻塞IO(三)非阻塞IO中缓冲区Buffer的实现

    本文我们来实现回射服务器的Buffer.   Buffer的实现   上节提到了非阻塞IO必须具备Buffer.再次将Buffer的设计描述一下: 这里必须补充一点,writeIndex指向空闲空间的 ...

  5. Linux非阻塞IO(二)网络编程中非阻塞IO与IO复用模型结合

    上文描述了最简易的非阻塞IO,采用的是轮询的方式,这节我们使用IO复用模型.   阻塞IO   过去我们使用IO复用与阻塞IO结合的时候,IO复用模型起到的作用是并发监听多个fd. 以简单的回射服务器 ...

  6. Linux非阻塞IO(八)使用epoll重新实现非阻塞的回射服务器

    本文无太多内容,主要是几个前面提到过的注意点: 一是epoll的fd需要重新装填.我们将tcp_connection_t的指针保存在数组中,所以我们以这个数组为依据,重新装填fd的监听事件. //重新 ...

  7. Linux非阻塞IO(七)使用epoll重新实现客户端

    使用poll与epoll的区别主要在于: poll可以每次重新装填fd数组,但是epoll的fd是一开始就加入了,不可能每次都重新加入 于是采用这种策略: epoll除了listenfd一开始就监听r ...

  8. Linux SCSI回调IO的分析

    本文转载自:http://blog.csdn.net/xushiyan/article/details/6941640,如需参考,请访问原始链接地址. 没找到如何转载的入口,只好全文copy了. -- ...

  9. 20169211《Linux内核原理与分析》 第九周作业

    一.Linux内核虚拟文件系统学习总结 Linux支持各种文件系统,Linux内核通过虚拟文件系统了对各种文件系统共性的进行抽象,并对外提供统一接口,从面向对象编程的角度来看,称为抽象文件系统更为合适 ...

随机推荐

  1. C# 添加Windows服务,定时任务

    源码下载地址:http://files.cnblogs.com/files/lanyubaicl/20160830Windows%E6%9C%8D%E5%8A%A1.zip 步骤 一 . 创建服务项目 ...

  2. iOS开发 - 用AFNetworking实现https单向验证,双向验证

    https相关 自苹果宣布2017年1月1日开始强制使用https以来,htpps慢慢成为大家讨论的对象之一,不是说此前https没有出现,只是这一决策让得开发者始料未及,博主在15年的时候就做过ht ...

  3. libXext.so.6 libXp.so.6 libXt.so.6 is needed by openmotif21-2.1.30-11.el7.i686

    # rpm -ivh openmotif21--.el7.i686.rpm error: Failed dependencies: libXext.so. -.el7.i686 libXp.so. - ...

  4. PLSQL_统计信息系列08_统计信息生成和还原

    2015-02-01 Created By BaoXinjian

  5. Android oncreate onupgrade什么时候被调用

    在学习Android数据库SQLite之前,必须意识到这一点,目前在Android系统中集成的是SQLite3 版本,SQLite是一个开源的嵌入式数据库,他支持NULL.INTEGER.REAL.T ...

  6. Unix环境高级编程(四)数据系统文件和信息

    本章主要介绍了Unix系统的正常运行要使用的与系统有关的数据文件和信息.如:口令文件,阴影文件.组文件.附加组.系统标识.时间和日期历程. 口令文件,即Unix系统用户数据库,存储在/etc/pass ...

  7. Oracle免费版和付费版,各版本的说明

    Oracle免费版和付费版的区别:   首先这里给出一个答案,oracle确实是免费的给学习的人员使用.oracle的策略就是你可以随意下载我的产品,包括oracle,weblogic等产品用于学习, ...

  8. mysql开启skip-name-resolve 导致root@127.0.0.1(localhost)访问引发的ERROR 1045 (28000)错误解决方案

    为什么配置skip-name-resolve? 由于mysql -h${ip} 远程访问速度过慢, mysql -uroot -p123456 根据网友经验(https://www.cnblogs.c ...

  9. C++中虚基类在派生类中的内存布局

    今天重温C++的知识,当看到虚基类这点的时候,那时候也没有太过追究,就是知道虚基类是消除了类继承之间的二义性问题而已,可是很是好奇,它是怎么消除的,内存布局是怎么分配的呢?于是就深入研究了一下,具体的 ...

  10. android获取对话框文本注意事项

    1.View注意设置成final类型如final View layout=.. . 2.获取文本框对象时候格式EditText e = (EditText)layout.findViewById(R. ...