您的位置:首页 > 理论基础 > 数据结构算法

关于linux内核中 等待队列 数据结构之思考

2010-12-02 10:51 260 查看
关于linux等待队列,大体有如下描述:

等待队列是一个双向循环链表,在这个链表中,有两种数据结构:等待队列头(wait_queue_head_t)和等待队列项(wait_queue_t)。

等待队列头和等待队列项中都包含一个list_head类型的域作为"连接件"。



等待对头wait_queue_head_t 和等待队列元素wait_queue_t的定义如下:

//队头结构

struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;

//队列元素结构

struct __wait_queue {
unsigned int flags;
#define WQ_FLAG_EXCLUSIVE 0x01
void *private;
wait_queue_func_t func;
struct list_head task_list;
};

typedef struct __wait_queue wait_queue_t;

从队头和队列元素的定义中,可以看出,都包含了list_head类型的结构,而这个结构中只保存了向前和向后的指针。定义如下。

struct list_head {
struct list_head *next, *prev;
};

看到这里就有些纳闷了,为什么这些方向指针和外面的结构体是分开的,也就是说,实际的指向关系只是这些方向指针之间的关系,而其他元素是附加在这些指针之上的。和我们传统的数据结构中的链表定义有很大的不同。

由此,又产生了一个疑问:那通过这些指针来获得具体的队列元素属性的时候,岂不是很不方便?(需要通过结构体某个成员的地址来计算该结构体的的地址?联想到之前学校的函数container_of或许可以完成此功能)

好奇心驱使下,最终了解了内核中队列的wakeup函数的实现,果不其然,在list_entry的定义中,找到了container_of的调用。

具体调用关系如下:

__wake_up_common--》list_for_each_entry_safe——》list_entry——》container_of

static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
int nr_exclusive, int wake_flags, void *key)
{
wait_queue_t *curr, *next;

list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
unsigned flags = curr->flags;

if (curr->func(curr, mode, wake_flags, key) &&
(flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
break;
}
}

#define list_for_each_entry_safe(pos, n, head, member) /
for (pos = list_entry((head)->next, typeof(*pos), member), /
n = list_entry(pos->member.next, typeof(*pos), member); /
&pos->member != (head); /
pos = n, n = list_entry(n->member.next, typeof(*n), member))

#define list_entry(ptr, type, member) /
container_of(ptr, type, member)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: