定义
#define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
含义
"list_entry" 宏用于通过仅使用一个内部结构指针来检索父结构指针。
示例
struct __wait_queue { unsigned int flags; struct task_struct * task; struct list_head task_list; }; struct list_head { struct list_head *next, *prev; }; // and with type definition: typedef struct __wait_queue wait_queue_t; // we'll have wait_queue_t *out list_entry(tmp, wait_queue_t, task_list); // where tmp point to list_head
因此,在这种情况下,通过 *tmp 指针 [list_head],我们检索到 *out 指针 [wait_queue_t]。
____________ <---- *out [we calculate that] |flags | /|\ |task *--> | | |task_list |<---- list_entry | prev * -->| | | | next * -->| | | |____________| ----- *tmp [we have this]
文件
函数
被调用的函数
互调用分析
|sleep_on |init_waitqueue_entry -- |__add_wait_queue | enqueuing request to resource list |list_add | |__list_add -- |schedule --- waiting for request to be executed |__remove_wait_queue -- |list_del | dequeuing request from resource list |__list_del --
描述
在 Linux 中,每个资源(理想情况下是多个用户和多个进程之间共享的对象)都有一个队列来管理所有请求它的任务。
这个队列被称为 “等待队列”,它由许多项组成,我们称之为 “等待队列元素”。
*** wait queue structure [include/linux/wait.h] *** struct __wait_queue { unsigned int flags; struct task_struct * task; struct list_head task_list; } struct list_head { struct list_head *next, *prev; };
图形化工作原理
*** wait queue element *** /|\ | <--[prev *, flags, task *, next *]--> *** wait queue list *** /|\ /|\ /|\ /|\ | | | | --> <--[task1]--> <--[task2]--> <--[task3]--> .... <--[taskN]--> <-- | | |__________________________________________________________________| *** wait queue head *** task1 <--[prev *, lock, next *]--> taskN
“等待队列头” 指向 “等待队列列表” 的第一个(使用 next *)和最后一个(使用 prev *)元素。
当需要添加新元素时,会调用 "__add_wait_queue" [include/linux/wait.h],之后将执行通用例程 "list_add" [include/linux/wait.h]。
*** function list_add [include/linux/list.h] *** // classic double link list insert static __inline__ void __list_add (struct list_head * new, \ struct list_head * prev, \ struct list_head * next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; }
为了完整描述,我们还看到 "remove_wait_queue" [include/linux/wait.h] 内部的 "list_del" [include/linux/list.h] 调用了 "__list_del" [include/linux/list.h] 函数。
*** function list_del [include/linux/list.h] *** // classic double link list delete static __inline__ void __list_del (struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; }
典型的列表(或队列)通常通过将其分配到堆中来管理(有关堆和栈的定义以及变量的分配位置,请参见第 10 章)。 然而,在这里,我们将等待队列数据静态分配在局部变量(栈)中,然后函数被调度中断,最后,(从调度返回后)我们将擦除局部变量。
new task <----| task1 <------| task2 <------| | | | | | | |..........| | |..........| | |..........| | |wait.flags| | |wait.flags| | |wait.flags| | |wait.task_|____| |wait.task_|____| |wait.task_|____| |wait.prev |--> |wait.prev |--> |wait.prev |--> |wait.next |--> |wait.next |--> |wait.next |--> |.. | |.. | |.. | |schedule()| |schedule()| |schedule()| |..........| |..........| |..........| |__________| |__________| |__________| Stack Stack Stack