wait_queue的实现和使用

/*************************************************************/
引入的数据结构: wait_queue_head and wait_queue
/*************************************************************/
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;
    void            *private;
    wait_queue_func_t    func;
    struct list_head    task_list;
};

/*************************************************************/
wait_queue:解决的是个什么样的问题?
当前进程要等待一个事件的发生:如某个条件成立
把当前进程设置为: interruptible 或者uninterruptible
并通过wait_queue把当前进程 加入到和这个时间相关的wait_queue_head的链表中;

当事件发生时,或者说条件成立时:通过 wait_queue_head找到睡眠在该事件上的进程
并唤醒它;
/*************************************************************/
init_waitqueue_head(&epfile->wait);

wait_event_interruptible(epfile->wait, (ep = epfile->ep));

wake_up(&epfile->wait);

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

/*************************************************************/
以f_fs.c 中一个具体的wait_queue为例:看下使用的接口
操作函数的参数都是: wait_queue_head_t,而不是wait_queue
F_fs.c (drivers\usb\gadget\function):ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep));
F_fs.c (drivers\usb\gadget\function):init_waitqueue_head(&epfile->wait);
F_fs.c (drivers\usb\gadget\function):waitqueue_active(&epfile->wait));
F_fs.c (drivers\usb\gadget\function):wake_up(&epfile->wait);

/*************************************************************/
#define init_waitqueue_head(q)                \
    do {                        \
        static struct lock_class_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);
}


struct ffs_epfile {
    wait_queue_head_t        wait;
}

/*************************************************************/
怎样使当前进程睡眠的?
/*************************************************************/
/
wait_event_interruptible(epfile->wait, (ep = epfile->ep));
/**
 * wait_event_interruptible - sleep until a condition gets true
 * @wq: the waitqueue to wait on
 * @condition: a C expression for the event to wait for
 *
 * The process is put to sleep (TASK_INTERRUPTIBLE) until the
 * @condition evaluates to true or a signal is received.
 * The @condition is checked each time the waitqueue @wq is woken up.
 *
 * wake_up() has to be called after changing any variable that could
 * change the result of the wait condition.
 *
 * The function will return -ERESTARTSYS if it was interrupted by a
 * signal and 0 if @condition evaluated to true.
 */
#define wait_event_interruptible(wq, condition)                \
({                                    \
    int __ret = 0;                            \
    might_sleep();                            \
    if (!(condition))                        \
        __ret = __wait_event_interruptible(wq, condition);    \
    __ret;                                \
})

#define __wait_event_interruptible(wq, condition)            \
    ___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0,        \
              schedule())


#define ___wait_event(wq, condition, state, exclusive, ret, cmd)    \
({                                    \
    __label__ __out;                        \
    wait_queue_t __wait;[这才引入了wait_queue_t,用户看到的只是 wait_queue_head]\
    long __ret = ret;    /* explicit shadow */            \
                                    \
    INIT_LIST_HEAD(&__wait.task_list);                \
    if (exclusive)                            \
        __wait.flags = WQ_FLAG_EXCLUSIVE;            \
    else                                \
        __wait.flags = 0;                    \
                                    \
    for (;;) {                            \
        long __int = prepare_to_wait_event(&wq, &__wait, state);\
                                    \
        if (condition)                        \
            break;                        \
        cmd;                            \
    }                                \
    finish_wait(&wq, &__wait);                    \
__out:    __ret;                                \
})


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

    if (signal_pending_state(state, current))
        return -ERESTARTSYS;

    wait->private = current;
    wait->func = autoremove_wake_function;

    spin_lock_irqsave(&q->lock, flags);
    if (list_empty(&wait->task_list)) {//[说的是wait_queue的task_list是empty而不是说的 wait_queue_head]
        if (wait->flags & WQ_FLAG_EXCLUSIVE)
            __add_wait_queue_tail(q, wait);
        else
            __add_wait_queue(q, wait);
    }
    set_current_state(state);
    spin_unlock_irqrestore(&q->lock, flags);

    return 0;
}

F_fs.c (drivers\usb\gadget\function):wake_up(&epfile->wait);
/*************************************************************/
怎样唤醒睡眠进程?
F_fs.c (drivers\usb\gadget\function):wake_up(&epfile->wait);
/*************************************************************/
#define wake_up(x)            __wake_up(x, TASK_NORMAL, 1, NULL)
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);
    spin_unlock_irqrestore(&q->lock, flags);
}

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;
    }
}

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;
}

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);
}

try_to_wake_up->ttwu_do_activate->ttwu_do_wakeup:p->state = TASK_RUNNING;
static void ttwu_queue(struct task_struct *p, int cpu)
{
    struct rq *rq = cpu_rq(cpu);
    raw_spin_lock(&rq->lock);
    ttwu_do_activate(rq, p, 0);
    raw_spin_unlock(&rq->lock);
}
static void
ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags)
{
    check_preempt_curr(rq, p, wake_flags);
    trace_sched_wakeup(p, true);

    p->state = TASK_RUNNING;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值