等待队列——休眠与唤醒

原创 2012年03月29日 20:58:29

内核中的休眠是通过等待队列来处理的。等待队列是一个由正在等待某个事件发生的进程组成的一个简单链表。在内核用wait_queue_head_t来表示。

定义:

DECLARE_WAITQUEUE()(静态定义)

init_waitqueue_head()(动态定义)

在内核中实现休眠的方法有点复杂,实现的模板如下:


/*qisthewaitqueuewewishtosleepon*/

DEFINE_WAIT(wait);

add_wait_queue(q,&wait);//这个函数调用是可选

while(!condition){/*conditionistheeventthatwearewaitingfor*/

prepare_to_wait(&q,&wait,TASK_INTERRUPTIBLE);

if(signal_pending(current))

/*handlesignal*/

schedule();

}

finish_wait(&q,&wait);

一个进程执行如下步骤将自己加入到一个等待队列中:

  • 通过宏DEFINE_WAIT()来创建一个等待队列项。

  • 通过函数add_wait_queue()将该项加入到一个等待队列中。当等待的事件(条件)为真时,等待队列会唤醒该进程项。当然,需要在其他地方调用wake_up()函数。

  • 调用prepare_to_wait()函数将进程的状态改为TASK_INTERRUPTIBLETASK_UNINTERRUPTIBLE。该函数也会在必要的时候将进程加回到等待队列中,在后续的迭代中会用到(提示:第二个步骤可选,因为该函数在任务列表为空的时候也会将当前任务项加入到等待队列中)。

  • 如果状态设置为TASK_INTERRUPTIBLE,,一个信号会唤醒该进程。这称为伪休眠。因此要检测和处理信号。

  • 当进程被唤醒,它再次检测条件是否为真。如果为真,它会退出循环。否则,再次调用schedule()然后重复上述过程。

  • 当条件为真,该进程会将其状态设为TASK_RUNNING并将自己通过finish_wait()从等待队列中删除。

一个例子:

staticssize_t inotify_read(struct file *file, char __user *buf,

size_t count, loff_t *pos)

{

structfsnotify_group *group;

structfsnotify_event *kevent;

char__user *start;

intret;

DEFINE_WAIT(wait);


start= buf;

group= file->private_data;


while(1) {

prepare_to_wait(&group->notification_waitq,&wait,TASK_INTERRUPTIBLE);


mutex_lock(&group->notification_mutex);

kevent= get_one_event(group, count);

mutex_unlock(&group->notification_mutex);


if(kevent) {

ret= PTR_ERR(kevent);

if(IS_ERR(kevent))

break;

ret= copy_event_to_user(group, kevent, buf);

fsnotify_put_event(kevent);

if(ret < 0)

break;

buf+= ret;

count-= ret;

continue;

}


ret= -EAGAIN;

if(file->f_flags & O_NONBLOCK)

break;

ret= -EINTR;

if(signal_pending(current))

break;


if(start != buf)

break;


schedule();

}


finish_wait(&group->notification_waitq,&wait);

if(start != buf && ret != -EFAULT)

ret= buf - start;

returnret;

}

另一种模板:

/*Helper thread */

staticint

my_thread(void*unused)

{

/**

  *                wait_queue_t wait;

  *                init_waitqueue_entry(&wait, current);

  */

DECLARE_WAITQUEUE(wait,current);


daemonize("my_thread");

add_wait_queue(&my_thread_wait,&wait);


while(1) {

/*Relinquish processor until event occurs */

set_current_state(TASK_INTERRUPTIBLE);

if(signal_pending(current))

/*##handlesingalevent##*/

schedule();

/*Control gets here when the thread is woken

upfrom the my_thread_wait wait queue */


/*Quit if let go */

if(pink_slip) {

break;

}

/*Do the real work */

/*... */


}


/*Bail out of the wait queue */

__set_current_state(TASK_RUNNING);

remove_wait_queue(&my_thread_wait,&wait);


/*Atomically signal completion and exit */

complete_and_exit(&my_thread_exit,0);

}

唤醒

通过函数wake_up()唤醒,它将唤醒所有在特定等待队列上等待的进程。一般情况下默认的唤醒函数为:default_wake_function()。它会调用try_to_wake_up(),将被唤醒的进程状态设置为TASK_RUNNING,然后调用enqueue_task()将该进程加入到红黑树中,如果被唤醒的进程的优先级大于当前进程的优先级,设置need_resched1。休眠与唤醒之间的关系如下:

\

伪唤醒是指进程是因为接收到某个信号而被唤醒,而不是等待事件发生而导致其被唤醒。


在最新的内核代码中,一般会使用更高层的接口:wait_eventwait_event_timeout接口。使用wake_up_all唤醒所有添加到某个等待队列链表中的等待队列。使用模板如下:


1. 初始化一个等待队列头:

 

  init_waitqueue_head(&ret->wait_queue);

 

  注: 判断队列是否为空: waitqueue_active(...), 返回false即表示队列为空.

 

2. 等待某个条件发生:

 

   wait_event(...) 或 wait_event_timeout(...)

 

3. 唤醒队列

 

   wake_up_all(...)

 



in-band和out-band的区别

在计算机网络领域,in-band和out-band两种不同的网络架构概念和区别

C语言的那些小秘密之链表(四)

大多数的读者在学习编程语言的时候都不喜欢那些枯燥的文字描述,包括我自己在开始学习编程的时候也是这样,对于代码的热情远远高于文字,所以我在我写东西的时候也不喜欢用枯燥的文字描述来向读者讲解,更喜欢用代码...

linux进程的休眠(等待队列)

当进程以阻塞的方式通信,在得到结果前进程会挂起休眠。 为了将进程以一种安全的方式进入休眠,我们需要牢记两条规则: 一、永远不要在原子上下文中进入休眠。 二、进程休眠后,对环境一无所知。唤醒后,必...

linux进程的休眠(等待队列)

(转载) bojan 收录于2010-10-09 阅读数:  公众公开     我也要收藏    当进程以阻塞的方式通信,在得到结果前进程会挂起休眠。 为了将进程以一种安全的方式进入休眠,我们需要牢记...

ldd3学习之十二(2):高级字符驱动程序操作--等待队列,阻塞I/O,休眠

在应用程序调用read,write时,若驱动程序无法立即满足要求,该如何响应?驱动程序应该(默认)阻塞该进程,将其置入休眠状态直到请求可继续。1.休眠进程被置为休眠,意味着它被标识为处于一个特殊的状态...

linux内核的等待队列使用方法,wait_queue_head_t,进程休眠

阅读vhost的时候,发现使用了大量的等待队列和poll,这里温故而知新一下。注:wait_queue_t是等待在wait_queue_head_t队列中的等待元素当你在用户空间需要读写一大片数据的时...

linux内核的 等待队列 使用方法,wait_queue_head_t,进程休眠

假设我们在 kernel 里产生一个 buffer,user 可以经由 read,write 等 system call 来读取或写资料到这个 buffer 里。如果有一个 user 写资料到 buf...

linux poll 和 等待队列休眠的关系

说明:linux版本2.6.37.1 结合相关资料的概括和总结,在此做个记录,有误之处请网友指正,谢谢! 1.poll机制和等待队列 应用层通过系统调用poll函数进入内核,内核执行...

linux poll 和 等待队列休眠的关系(基于kernel 3.10.0)

原理分析来自网上,代码由本人梳理分析阅读vhost的时候,发现使用了大量的等待队列和poll,这里温故而知新一下。注:wait_queue_t是等待在wait_queue_head_t队列中的等待元素...

linux内核的 等待队列 使用方法,wait_queue_head_t,进程休眠

以下来自:http://www.yuanma.org/data/2006/1207/article_1916.htm 假设我们在 kernel 里产生一个 buffer,user 可以经由read,...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:等待队列——休眠与唤醒
举报原因:
原因补充:

(最多只允许输入30个字)