热门关键字:  ubuntu  分区  Fedora  linux系统进程  函数

当前位置 :| 主页>Linux教程>内核研究>

内核的等待队列

来源: 作者: 时间:2008-11-27 Tag: 点击:
内核的等待队列
creator sz111@126.com
1.
    等待队列在内核中有着极其重要的作用,作为异步操作,他的实现简单而又强大。

   它通过一个双链表和把等待tast的头,和等待的进程列表链接起来。从上图可以清晰看到。所以我们知道,如果要实现一个等待队列,首先要有两个部分。队列头和队列项。下面看他们的数据结构。
struct list_head {
    struct list_head *next, *prev;
};
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;//2.6版本是采用void指针,而以前的版本是struct task_struct * task;
                  //实际在用的时候,仍然把private赋值为task
    wait_queue_func_t func;
    struct list_head task_list;
};
typedef struct __wait_queue wait_queue_t;
所以队列头和队列项是通过list_head联系到一起的,list_head是一个双向链表,在linux内核中有着广泛的应用。并且在list.h中对它有着很多的操作。

2.对列头和队列项的初始化:
/*
 * Macros for declaration and initialisaton of the datatypes
 */

#define __WAITQUEUE_INITIALIZER(name, tsk) {                \
    .private    = tsk,                        \
    .func        = default_wake_function,            \
    .task_list    = { NULL, NULL } }
//这个是初始化一个队列项,设定tast_list链表前后都是空,说明还没有加入到链表里面。
//私有数据private为任务的任务结构。
//这个宏说声明和初始化都同时做了。如果不愿意这样的话,可以先声明,然后通过
//init_waitqueue_entry进行完成。
#define DECLARE_WAITQUEUE(name, tsk)                    \
    wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)

#define __WAIT_QUEUE_HEAD_INITIALIZER(name) {                \
    .lock        = __SPIN_LOCK_UNLOCKED(name.lock),        \
    .task_list    = { &(name).task_list, &(name).task_list } }
//声明一个队列头,让他的链表前后都指向自己,这个时候还没有加入任何的链表项。
//这个宏说声明和初始化都同时做了。如果不愿意这样的话,可以先声明,然后通过
//init_waitqueue_head进行完成。
#define DECLARE_WAIT_QUEUE_HEAD(name) \
    wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)

#define __WAIT_BIT_KEY_INITIALIZER(word, bit)                \
    { .flags = word, .bit_nr = bit, }

extern void init_waitqueue_head(wait_queue_head_t *q);

static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p)
{
    q->flags = 0;
    q->private = p;
    q->func = default_wake_function;
}
//将指定的等待队列项new添加到等待队列头head所在的链表头部,该函数假设已经获得锁
static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)
{
    list_add(&new->task_list, &head->task_list);
}

/*
 * Used for wake-one threads:
 */
//将指定的等待队列项new添加到等待队列头head所在的链表尾部,该函数假设已经获得锁。
//其实因为队列是个环形队列,所以head是头,head的钱一个就可以认为是尾,当然,环形也无所//谓头尾了。
static inline void __add_wait_queue_tail(wait_queue_head_t *head,
                        wait_queue_t *new)
{
    list_add_tail(&new->task_list, &head->task_list);
}

static inline void __remove_wait_queue(wait_queue_head_t *head,
                            wait_queue_t *old)
{
    list_del(&old->task_list);
}


相关文章:
精通initramfs构建step by step
Linux利用kexec迅速切换内核
进程上下文VS中断上下文
内核通知链 学习笔记
linux spi子系统驱动分析
menuconfig 配置选项
《Linux操作系统内核实习》之练习一
udev详解
什么叫微内核,宏内核?
Linux 信号signal处理机制
开发简单的 Linux2.6 内核模块
删除内核的perl脚本
Linux2.6内核usb gadget驱动移植
GCC hacks in the Linux kernel
iomem
kernel学习的想法
让自己的驱动支持udev
linux内核编译步骤
内核的等待队列
Linux内核wait_queue深入分析
升级和删除内核
SD卡驱动分析2
Linux Kernel VDSO本地权限提升漏洞
内核中的TCP的追踪分析-15-TCP(IPV4)的客户端与
linux 2.6内核可加载模块的编译
内核模块HelloWorld
在环回接口上发送一个数据报
ARP初始化
1分钟编译FreeBSD内核
linux设备模型之uart驱动架构分析