内核中的等待队列

我们首先来看看等待队列的组成。

等待队列由等待队列头和等待队列项组成。要看的等待队列先要去linux-2.6.35/include/wait.h 。

我们来看看等待队列的头的样子:

Wait_queue_head_t就是等待队列的头,他的原型是

Typedef __wait_queue_head wait_queue_head_t
        Struct __wait_queue_head{
        Spinlock_t lock;
        Struct list_head task_list;
        };

关键字:task_list
        Struct list_head{
        Struct list_head *next *prev
        };

由此可见这个结构体里面只有两个指针,两个指针都是指向struct list_head 的结构体指针。

关键字:lock

Lock是spinlock_t类型的变量,只是一种锁而已。

看完了等待队列头再来看看等待队列项。等待队列项是在内核中的Linux-2.6.35/include/linux/wait.h

wait_queue_t就是等待队列的类型,他的原型是
        Typedef struct __wait_queue wait_queue_t
        Struct __wait_queue{
                Unsigned int flags;
        #define WQ_FLAG_EXCLUSIVE 0x01
                Void *private;
                Wait_queue_fun_t func;
                Struct list_head task_list;
        };

在观察等待队列的项的结构体时就会发现有一项struct list_head跟等待队列头的时相同的,因此我们可以想象下,等待队列头跟等待队列项是通过这个结构体来连接的,等待队列项跟其他的等待队列项也是通过这个结构体来连接的。

那么其他成员代表什么意思呢??

先去看flags,看名字就知道是标识作用,该标志是判断进程是否是互斥进程。总是唤醒所有等待事件的进程并不一定是合适的。如果队列中的多个进程等待资源是要互斥访问的,一定时间内只允许一个进程去访问,这时候只需要唤醒一个。

我们再来看一个比较奇怪的成员void *private。

从表面上是看不出这个成员的作用。其实在2.6版本中采用的是void指针,而以前的版本是struct task_struct *task;在实际用的时候还是把private赋值给task。在本文件也就是linux-2.6.35/include/liunx/wait.h会有赋值的体现。

Static inline void(wait_queue_t *q,struct task_struct *p)
        {
                q->flags = 0;
                q->private = p;
                q->func = default_wake_function;
        }

在这个函数中又出现了等待队列项中的参数func成员的赋值。

那么task_struct这个结构体时什么呢,我觉得看着很眼熟,其实就是很眼熟,它就是进程控制块PCB,里面有进程的所有信息。每一个进程都会有唯一的结构体。它里面包含着进程状态的标志位就是结构体的第一个成员叫volatile long state;改变这个值可以改变进程的状态,包括可执行,可中断等待,不可中断等待等。

至于default_wake_function 就是唤醒函数。

说完了等待队列头跟等待队列项。那么他们是怎么连接在一起的,内核又提供了那些函数来实现的。

有一个函数叫add_wait_queue的函数在 linux-2.6.35/kernel/wait.c下实现的。

它的作用就是把等待队列头与等待队列项关联起来形成一个链表,如下图:

它的函数原型是 void add_wait_queue(wait_queue_head_t *q,Wait_queue_t *wait)
        {
                Unsigned long flags;
                Wait->flags &= ~WQ_FLAG_EXCLUSIVE;
                Sipn_lock_irqsave(&q->lock,flags);
                __add_wait_queue(q,wait);
                Spin_unlock_irqrestore(&q->lock,flags);
        }

看这个函数很容易就看到__add_wait_queue这函数才是整个函数实现的关键,其他函数都是来帮助这个函数的实现。

__add_wait_queue(wait_queue_head_t head,wait_queue_t new)
        调用 list_add(&new->task_list,&head->task_list)
        调用__list_add(new,head,head->next)

我们看一下__list_add的实现

Void __list_add(struct list_head *new, struct list_head *prevStruct list_head *next)
        {
                Next -> prev = new;
                New -> next = next;
                New -> prev = prev;
                Prev -> next = new;
        }

这个函数的实现是什么呢?

头插法,就是头插法实现了等待队列的添加。


转自:http://www.embedu.org/Column/Column570.htm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值