linux进程管理-----等待队列函数

本文详细介绍了Linux内核中等待队列的实现,包括等待队列头的定义、等待队列元素的结构、初始化函数以及等待队列的操作,如添加、删除和唤醒进程等。这些函数在进程同步和调度中起着关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据结构

1、等待队列由双向链表实现

2、每个等待队列都有一个等待队列头,等待队列头是一个类型位wait_queue_head_t的数据结构

typedef struct __wait_queue_head wait_queue_head_t;

struct __wait_queue_head {
        spinlock_t              lock; //同步自旋锁
        struct list_head        task_list; //等待进程链表的头
};

3、等待队列中的元素是wait_queue_t

typedef struct __wait_queue wait_queue_t;

struct __wait_queue {
        unsigned int            flags; //一般是用来标记是否为互斥进程
        void                    *private; //一般用来保存等待的进程描述符
        wait_queue_func_t       func; //基本上作为唤醒函数地址
        struct list_head        task_list; //用于挂入链表头部的节点
};

操作函数

DECLARE_WAIT_QUEUE_HEAD 宏用于定义一个等待队列头

#define __WAIT_QUEUE_HEAD_INITIALIZER(name) {                           \
        .lock           = __SPIN_LOCK_UNLOCKED(name.lock),              \ //初始化自旋锁,这里不展开
        .task_list      = { &(name).task_list, &(name).task_list } } //将队列头的的next、prev分别指向本身

#define DECLARE_WAIT_QUEUE_HEAD(name) \
        wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)

init_waitqueue_head用来初始化动态分配的等待队列头

#define init_waitqueue_head(q)                          \
        do {                                            \
                static struct lock_class_key __key;     \ //定义个key
                                                        \
                __init_waitqueue_head((q), #q, &__key); \ 
        } while (0)

void __init_waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *key)
{
        spin_lock_init(&q->lock); //初始化自旋锁
        lockdep_set_class_and_name(&q->lock, key, name); //没有作用
        INIT_LIST_HEAD(&q->task_list); //初始化队列头
}

函数init_waitqueue_entry 初始化wait_queue_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; //唤醒函数
}

default_wake_function

int default_wake_function(wait_queue_t *curr, unsigned mode, int wake_flags,
                          void *key)
{
        return try_to_wake_up(curr->private, mode, wake_flags); //唤醒一个进程,此函数后面展开
}

autoremove_wake_function函数会自动调用default_wake_function函数并将此进程从等待队列上删除

int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
{
        int ret = default_wake_function(wait, mode, sync, key); //调用唤醒函数

        if (ret)
                list_del_init(&wait->task_list); //如果唤醒没有出错则将此进程从等待队列中删除
        return ret;
}

init_waitqueue_func_entry函数可以自定义唤醒函数

typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int flags, void *key);

static inline void
init_waitqueue_func_entry(wait_queue_t *q, wait_queue_func_t func)
{
        q->flags        = 0; //初始化为非互斥等待进程
        q->private      = NULL;
        q->func         = func; //设置指定的唤醒函数
}

定义了等待元素之后需要插入等待队列中

add_wait_queue将初始化好的非互斥等待进程对应的等待描述符插入到等待队列中

void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
{
        unsigned long flags;

        wait->flags &= ~WQ_FLAG_EXCLUSIVE;
        spin_lock_irqsave(&q->lock, flags);
        __add_wait_queue(q, wait);
        spin_unlock_irqrestore(&q->lock, flags);
}

static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)
{
        list_add(&new->task_list, &head->task_list);
}

add_wait_queue_exclusive函数将互斥进程对应的等待描述符插入到等待队列中

void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait)
{
        unsigned long flags;

        wait->flags |= WQ_FLAG_EXCLUSIVE; //WQ_FLAG_EXCLUSIVE == 0x1
        spin_lock_irqsave(&q->lock, flags);
        __add_wait_queue_tail(q, wait); //将等待元素加入到等待队列尾
        spin_unlock_irqrestore(&q->lock, flags);
}

remove_wait_queue 从指定的等待队列中删除等待元素

void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
{
        unsigned long flags;

        spin_lock_irqsave(&q->lock, flags);
        __remove_wait_queue(q, wait);
        spin_unlock_irqrestore(&q->lock, flags);
}

waitqueue_active函数用于判定等待队列是否为空,非空返回true

static inline int waitqueue_active(wait_queue_head_t *q)
{
        return !list_empty(&q->task_list);
}

finish_wait 函数是将进程设置为running,从等待队列中移除

void finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
{
        unsigned long flags;

        __set_current_state(TASK_RUNNING);
        /*
         * We can check for list emptiness outside the lock
         * IFF:
         *  - we use the "careful" check that verifies both
         *    the next and prev pointers, so that there cannot
         *    be any half-pending updates in progress on other
         *    CPU's that we haven't seen yet (and that might
         *    still change the stack area.
         * and
         *  - all other users take the lock (ie we can only
         *    have _one_ other CPU that looks at or modifies
         *    the list).
         */
        if (!list_empty_careful(&wait->task_list)) {
                spin_lock_irqsave(&q->lock, flags);
                list_del_init(&wait->task_list);
                spin_unlock_irqrestore(&q->lock, flags);
        }
}

prepare_to_wait 函数用于设置进程状态和将进程对应的等待描述符加入非互斥等待队列

void
prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
{
        unsigned long flags;

        wait->flags &= ~WQ_FLAG_EXCLUSIVE; //设置为非互斥体
        spin_lock_irqsave(&q->lock, flags);
        if (list_empty(&wait->task_list)) //注意这个判断条件如果等待队列非空则不会加入
                __add_wait_queue(q, wait); //将进程对应的等待描述符加入等待队列
        set_current_state(state);
        spin_unlock_irqrestore(&q->lock, flags);
}

prepare_to_wait_exclusive 函数用于设置进程状态和将进程对应的等待描述符加入互斥等待队列

void
prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
{
        unsigned long flags;

        wait->flags |= WQ_FLAG_EXCLUSIVE;
        spin_lock_irqsave(&q->lock, flags);
        if (list_empty(&wait->task_list))  //注意这个判断条件如果等待队列非空则不会加入
                __add_wait_queue_tail(q, wait);
        set_current_state(state);
        spin_unlock_irqrestore(&q->lock, flags);
}

唤醒函数:

#define wake_up(x)                      __wake_up(x, TASK_NORMAL, 1, NULL)
#define wake_up_nr(x, nr)               __wake_up(x, TASK_NORMAL, nr, NULL)
#define wake_up_all(x)                  __wake_up(x, TASK_NORMAL, 0, NULL)
#define wake_up_locked(x)               __wake_up_locked((x), TASK_NORMAL, 1)
#define wake_up_all_locked(x)           __wake_up_locked((x), TASK_NORMAL, 0)

#define wake_up_interruptible(x)        __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)
#define wake_up_interruptible_nr(x, nr) __wake_up(x, TASK_INTERRUPTIBLE, nr, NULL)
#define wake_up_interruptible_all(x)    __wake_up(x, TASK_INTERRUPTIBLE, 0, NULL)
#define wake_up_interruptible_sync(x)   __wake_up_sync((x), TASK_INTERRUPTIBLE, 1)

所有的唤醒函数都是__wake_up

void __wake_up(wait_queue_head_t *q, unsigned int mode,
                        int nr_exclusive, void *key)
{
        unsigned long flags;

        spin_lock_irqsave(&q->lock, flags);
        __wake_up_common(q, mode, nr_exclusive, 0, key); //传入了key
        spin_unlock_irqrestore(&q->lock, flags);
}

void __wake_up_locked(wait_queue_head_t *q, unsigned int mode, int nr)
{
        __wake_up_common(q, mode, nr, 0, NULL); //传入的key为空
}

__wake_up_common函数则是遍历等待队列上的等待元素然后调用对应元素的唤醒函数

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) //注意这里nr_exclusive是上层调用者传入的nr值,如果是传入的>=1则唤醒nr个, 如果nr_exclusive传入的是0则唤醒所有的。
                        break;
        }
}

void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode,
                        int nr_exclusive, void *key)
{
        unsigned long flags;
        int wake_flags = 1; /* XXX WF_SYNC */ //同步唤醒标志

        if (unlikely(!q))
                return;

        if (unlikely(nr_exclusive != 1))
                wake_flags = 0;

        spin_lock_irqsave(&q->lock, flags);
        __wake_up_common(q, mode, nr_exclusive, wake_flags, key); 
        spin_unlock_irqrestore(&q->lock, flags);
}

/*
 * __wake_up_sync - see __wake_up_sync_key()
 */
void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive)
{
        __wake_up_sync_key(q, mode, nr_exclusive, NULL); //直接调用__wake_up_sync_key函数
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值