我们为什么要用等待队列?
假设我们在 kernel 里产生一个 buffer,user 可以经由 read,write 等 system call 来读取或写资料到这个 buffer 里。如果有一个 user 写资料到 buffer 时,此时 buffer 已经满了。那请问你要如何去处理这种情形呢 ?
第一种,传给 user 一个错误讯息,说 buffer 已经满了,不能再写入。
第二种,将 user 的要求 block 住,等有人将 buffer 内容读走,留出空位时,再让 user 写入资料。
但问题来了,你要怎么将 user 的要求 block 住。难道你要用
while ( is_full );
write_to_buffer;
这样的程序代码吗? 想想看,如果你这样做会发生什么事?
第一,kernel会一直在这个 while 里执行。
第二,如果 kernel 一直在这个 while 里执行,表示它没有办法去 maintain系统的运作。那此时系统就相当于当掉了。
在这里 is_full 是一个变量,当然,你可以让 is_full 是一个 function,在这个 function里会去做别的事让 kernel 可以运作,那系统就不会死。这是一个方式。还有,你说可以在while里面把buffer里的内容读走,再把is_full的值改了,但是我们会可能把重 要的数据在我们不想被读的时候被读走了,那是比较麻烦的,而且很不灵活.
如果我们使用 wait_queue 的话,那程序看起来会比较漂亮,而且也比较让人了解,如下所示:
struct wait_queue_head_t wq; /* global variable */
DECLARE_WAIT_QUEUE_HEAD (wq);
while ( is_full )
{
interruptible_sleep_on( &wq );
}
write_to_buffer();
interruptible_sleep_on( &wq ) 是用来将目前的 process,也就是要求写资料到buffer 的 process放到 wq 这个 wait_queue 里。在 interruptible_sleep_on 里,则是最后会呼叫 schedule() 来做 schedule 的动作,谁调用了schedule谁就趴下,让别人去运行,醒来就原地起来,执行schedule()后的代码。那那个调用了schedule的家伙什么 醒过来呢?这时候就需要用到另一个函数了wake_up_interruptible()了。
结构图:
task_struct task_struct |---------|<--+ |---------|<--+ | | | | | | | | | | | | | | | | | | |---------| | |---------| | | | wait_queue_t | wait_queue_t | |---------------| | |---------------| | wait_queue_head_t | flags | | | flags | | |---------------| | *task |---+ | *task |---+ | lock | | func | | func | |---------------| |---------------| |---------------| |list_head *next|------>|list_head *next|------>|list_head *next| |list_head *prev|<------|list_head *prev|<------|list_head *prev| |---------------| |---------------| |---------------|