wait queue 1

wait queue 用来等待某一个事件的发生。
使用上一般分为下面三步
初始化:DEFINE_WAIT(wait);
等待事件,通过prepare_to_wait将自己加入到等待队列中,只后这个thread就处于sleep状态,随后会等待wakeup来触发.
完成等待,从等待队列删除.
cpu_hotplug_begin 这个函数就包含我们刚才说的三步.
void cpu_hotplug_begin(void)
{
    DEFINE_WAIT(wait);

    cpu_hotplug.active_writer = current;
    cpuhp_lock_acquire();

    for (;;) {
        mutex_lock(&cpu_hotplug.lock);
        prepare_to_wait(&cpu_hotplug.wq, &wait, TASK_UNINTERRUPTIBLE);
        if (likely(!atomic_read(&cpu_hotplug.refcount)))
                break;
        mutex_unlock(&cpu_hotplug.lock);
        schedule();
    }
    finish_wait(&cpu_hotplug.wq, &wait);
}
wakeup是通过put_online_cpus 中的wake_up 来完成的.
void put_online_cpus(void)
{
    int refcount;

    if (cpu_hotplug.active_writer == current)
        return;

    refcount = atomic_dec_return(&cpu_hotplug.refcount);
    if (WARN_ON(refcount < 0)) /* try to fix things up */
        atomic_inc(&cpu_hotplug.refcount);

    if (refcount <= 0 && waitqueue_active(&cpu_hotplug.wq))
        wake_up(&cpu_hotplug.wq);

    cpuhp_lock_release();

}

先来首先看看DEFINE_WAIT(wait);
#define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, autoremove_wake_function)
这个name是一个变量,不需要提前定义,DEFINE_WAIT_FUNC 会帮忙实现这个变量
#define DEFINE_WAIT_FUNC(name, function)                \
    wait_queue_t name = {                        \
        .private    = current,                \
        .func        = function,                \
        .task_list    = LIST_HEAD_INIT((name).task_list),    \
    }
name是一个wait_queue_t 对象,定义如下,可见除了flag外在DEFINE_WAIT_FUNC 这个宏中会对wait_queue_t 对象的其他三个成员赋值。

typedef struct __wait_queue wait_queue_t;

/* __wait_queue::flags */
#define WQ_FLAG_EXCLUSIVE    0x01
#define WQ_FLAG_WOKEN        0x02

struct __wait_queue {
    unsigned int        flags;
    void            *private;
    wait_queue_func_t    func;
    struct list_head    task_list;
};
这三个成员中的func 就是后面wakeup时候会call的function。
autoremove_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);
}
这个curr->private 就是DEFINE_WAIT_FUNC 中的current,因此try_to_wake_up 会唤醒之前current 这个task
prepare_to_wait 函数就是将当前的__wait_queue 降到wait_queue_head_t 中,并把当前的task状态设置为TASK_UNINTERRUPTIBLE。即不可中断状态,只能通过wakeup来调用default_wake_function来唤醒.
prepare_to_wait(&cpu_hotplug.wq, &wait, TASK_UNINTERRUPTIBLE);

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 首先清掉WQ_FLAG_EXCLUSIVE(独占),判断&wait->task_list 是否为NULL,如果不为NULL 就通过__add_wait_queue 加入到wait_queue_head_t中,正常情况下wait->task_list 应该也是不为NULL的.
static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)
{
    list_add(&new->task_list, &head->task_list);
}
最后调用set_current_state设置当前task的状态
#define set_current_state(state_value)            \
    smp_store_mb(current->state, (state_value))

#ifndef smp_store_mb
#define smp_store_mb(var, value)  do { WRITE_ONCE(var, value); barrier(); } while (0)
#endif
可见是用了内存屏障来保证顺序的.
最后调用finish_wait 完成和prepare_to_wait 相反的动作.
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);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值