linux_2.6.35_wait和wakeup源碼閱讀

寫在這裏只當是爲了備份一下,只是匆匆的瀏覽了一下源碼,如果您想獲得些什麼深刻的東西,這個肯定是沒有了,就是流水帳一個微笑


正文:

在wait.h中,可以看到定義了許多wait_up相關的宏
#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)

#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這個函數定義在sched.c中,數字是1的話,就是隻喚醒一個?

/**
 * __wake_up - wake up threads blocked on a waitqueue.
 * @q: the waitqueue
 * @mode: which threads
 * @nr_exclusive: how many wake-one or wake-many threads to wake up
 * @key: is directly passed to the wakeup function
 *
 * It may be assumed that this function implies a write memory barrier before
 * changing the task state if and only if any tasks are woken 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);
    spin_unlock_irqrestore(&q->lock, flags);
}
EXPORT_SYMBOL(__wake_up);

/*
 * The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just
 * wake everything up. If it's an exclusive wakeup (nr_exclusive == small +ve
 * number) then we wake all the non-exclusive tasks and one exclusive task.
 *
 * There are circumstances in which we can try to wake a task which has already
 * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns
 * zero in this (rare) case, and we handle it by continuing to scan the queue.
 */
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;
    }
}

所以wake_up(wqt)的執行路徑是這樣的  wakeup(x)-->__wake_up-->__wake_up_common  在這個流程中,只喚醒一個進程;
可以看到curr->func是在初始化時的函數,貌似剛開始的時候是什麼default_wake_up_func?
其中DEFINE_WAIT宏的實現是這樣的

#define DEFINE_WAIT_FUNC(name, function)                \
    wait_queue_t name = {                        \
        .private    = current,                \
        .func        = function,                \
        .task_list    = LIST_HEAD_INIT((name).task_list),    \
    }

#define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, autoremove_wake_function)

也就是說DEFINE_WAIT聲明定義了一個名爲name的wait_queue_t,初始化時,該wait_queue_t的private是current,同時掛上一個初始化task_list,方法使用autoremove_wake_function

autoremove_wake_function定義在wait.c中
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;
}
EXPORT_SYMBOL(autoremove_wake_function);

default_wake_function定義在shced.c中,差不多直接調用了try_to_wake_up,但是wake_up的是在定義wait_queue_t時存放去的進程(當時的current)

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);
}
EXPORT_SYMBOL(default_wake_function);

綜上:
1.DEFINE_WAIT定義一個wait_queue_t並且設置好喚醒的方法,將進程號放在這個結構裏
2.wakeup(x)的時候,wake_up傳入頭指針,並且說只要wake_up一個進程,調用__wake_up獲得spin_lock(加上irqsave),然後交給__wake_up_common核心函數,__wake_up_common遍歷wait_queue_t鏈表,每次調用wait_queue_t定義時綁定的函數(DEFINE_WAIT定義的函數見上),遍歷次數在這裏爲1,值得注意的是DEFINE_WAIT定義時綁定的那個函數會自動將進程從鏈表中清楚


注意:try_to_wake_up這個函數似乎是最核心的函數,不管怎麼樣,wake_up都會調用這個函數?
比如
int wake_up_process(struct task_struct *p)
{
    return try_to_wake_up(p, TASK_ALL, 0);
}
EXPORT_SYMBOL(wake_up_process);

int wake_up_state(struct task_struct *p, unsigned int state)
{
    return try_to_wake_up(p, state, 0);
}
鑑於該函數如此重要,有必要在此寫出它的聲明來:

/***
 * try_to_wake_up - wake up a thread
 * @p: the to-be-woken-up thread
 * @state: the mask of task states that can be woken
 * @sync: do a synchronous wakeup?
 *
 * Put it on the run-queue if it's not already there. The "current"
 * thread is always on the run-queue (except when the actual
 * re-schedule is in progress), and as such you're allowed to do
 * the simpler "current->state = TASK_RUNNING" to mark yourself
 * runnable without the overhead of this.
 *
 * returns failure only if the task is already active.
 */
static int try_to_wake_up(struct task_struct *p, unsigned int state,
              int wake_flags)


================其他========================================

在wait.h中
#define __wait_event(wq, condition)                     \
do {                                    \
    DEFINE_WAIT(__wait);                        \
                                    \
    for (;;) {                            \
        prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);    \
        if (condition)                        \
            break;                        \
        schedule();                        \
    }                                \
    finish_wait(&wq, &__wait);                    \
} while (0)

/**
 * wait_event - 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_UNINTERRUPTIBLE) until the
 * @condition evaluates to true. 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.
 */
#define wait_event(wq, condition)                     \
do {                                    \
    if (condition)                             \
        break;                            \
    __wait_event(wq, condition);                    \
} while (0)
上面這個函數和實驗中所使用的函數很類似
===================================================================
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章