亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 1419 | 回復(fù): 0
打印 上一主題 下一主題

linux內(nèi)核學(xué)習(xí)筆記-等待隊(duì)列 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2008-02-27 21:48 |只看該作者 |倒序?yàn)g覽

                等待隊(duì)列適用于通知其他相關(guān)任務(wù)某個(gè)事件的發(fā)生。這里的分析實(shí)例是等待物理頁面解鎖的函數(shù)
wait_on_page(),該函數(shù)判斷指定的物理頁面是否已經(jīng)加鎖。若已經(jīng)加鎖,則任務(wù)進(jìn)入等待狀態(tài),直到物理頁面被解鎖后才返回。
等待隊(duì)列相關(guān)的數(shù)據(jù)結(jié)構(gòu)。
等待隊(duì)列頭:
struct __wait_queue_head {
    wa_lock_t lock;                           // wa_lock_t實(shí)際上是一個(gè)“讀寫鎖”或“旋轉(zhuǎn)鎖”
    struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
等待隊(duì)列節(jié)點(diǎn):
struct __wait_queue {
    unsigned int flags;
    struct task_list * task;
    struct list_head task_list;
};
typedef struct __wait_queue wait_queue_t;
1. 等待解鎖:
wait_on_page()實(shí)際上只是檢查頁面是否已經(jīng)被鎖。假如沒有加鎖,立即返回;否則,調(diào)用__wait_on_page()函數(shù)將當(dāng)前任務(wù)加入等待隊(duì)列中:
extern inline void wait_on_page(struct page * page)
{
    if (PageLocked(page))
        __wait_on_page(page);
}
__wait_on_page()函數(shù):
void ___wait_on_page(struct page *page)
{
        struct task_struct *tsk = current;
        DECLARE_WAITQUEUE(wait, tsk);
        add_wait_queue(&page->wait, &wait);
        do {
                sync_page(page);
                set_task_state(tsk, TASK_UNINTERRUPTIBLE);
                if (!PageLocked(page))
                        break;
                run_task_queue(&tq_disk);
                schedule();
        } while (PageLocked(page));
        tsk->state = TASK_RUNNING;
        remove_wait_queue(&page->wait, &wait);
}
宏DECLARE_WAITQUEUE()的定義如下:
#define __WAITQUEUE_INITIALIZER(name,task) \
        { 0x0, task, { NULL, NULL } __WAITQUEUE_DEBUG_INIT(name)}
#define DECLARE_WAITQUEUE(name,task) \
        wait_queue_t name = __WAITQUEUE_INITIALIZER(name,task)
DECLARE_WAITQUEUE(name, task)宏定義了一個(gè)等待隊(duì)列節(jié)點(diǎn),并初始化wait_queue_t::task指向當(dāng)前任務(wù)的task結(jié)構(gòu)。以便在事件發(fā)生的時(shí)候能夠喚醒該task對應(yīng)的任務(wù)。
接下來便是將等待隊(duì)列節(jié)點(diǎn)wait加入page::wait等待隊(duì)列中:
void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
{
        unsigned long flags;
        wq_write_lock_irqsave(&q->lock, flags);
        wait->flags = 0;
        __add_wait_queue(q, wait);
        wq_write_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
()函數(shù)返回后,wait已經(jīng)加入到page::wait等待隊(duì)列中。接著調(diào)用了sync_page(),其功用在此不做討論。
再往下執(zhí)行,函數(shù)對任務(wù)標(biāo)
志做了設(shè)置:set_task_state(tsk,
TASK_UNINTERRUPTIBLE);意為通知調(diào)度器將任務(wù)轉(zhuǎn)入睡眠狀態(tài)。由于在以上的操作中,頁面可能已經(jīng)解鎖了,所以
__wait_on_page()函數(shù)在調(diào)用schedule()重新調(diào)度任務(wù)之前再做一次頁面加鎖檢查,以避免任務(wù)等待一個(gè)不加鎖的頁面而導(dǎo)致死鎖。本
次檢查中若頁面仍然處于加鎖狀態(tài),則調(diào)用schedule()將自己轉(zhuǎn)入睡眠,直到任務(wù)再次被喚醒。
2. 解鎖通知:
任務(wù)通過調(diào)用UnlockPage對指定的頁面解鎖。UnlockPage實(shí)際上是一個(gè)宏定義:
#define UnlockPage(page)        do { \
                                        smp_mb__before_clear_bit(); \
                                        if (!test_and_clear_bit(PG_locked, &(page)->flags)) BUG(); \
                                        smp_mb__after_clear_bit(); \
                                        if (waitqueue_active(&page->wait)) \
                                                wake_up(&page->wait); \
                                } while (0)
首先,調(diào)用test_and_clear_bit()清除加鎖標(biāo)志位。然后檢查是否有任務(wù)在等待頁面。若有,調(diào)用wake_up()喚醒等待任務(wù)。
static inline int waitqueue_active(wait_queue_head_t *q)
{
    return !list_empty(&q->task_list);
}
#define wake_up(x)                      __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE,WQ_FLAG_EXCLUSIVE)
void __wake_up(wait_queue_head_t *q, unsigned int mode, unsigned int wq_mode)
{
        __wake_up_common(q, mode, wq_mode, 0);
}
static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode,
                                     unsigned int wq_mode, const int sync)
{
        struct list_head *tmp, *head;
        struct task_struct *p, *best_exclusive;
        unsigned long flags;
        int best_cpu, irq;
        if (!q)
                goto out;
        best_cpu = smp_processor_id();
        irq = in_interrupt();
        best_exclusive = NULL;
        wq_write_lock_irqsave(&q->lock, flags);
        head = &q->task_list;
        tmp = head->next;
        while (tmp != head) {
                unsigned int state;
                wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list);
                tmp = tmp->next;
                p = curr->task;
                state = p->state;
                if (state & mode) {
                        /*
                         * If waking up from an interrupt context then
                         * prefer processes which are affine to this
                         * CPU.
                         */
                        if (irq && (curr->flags & wq_mode & WQ_FLAG_EXCLUSIVE)) {
                                if (!best_exclusive)
                                        best_exclusive = p;
                                if (p->processor == best_cpu) {
                                        best_exclusive = p;
                                        break;
                                }
                        } else {
                                if (sync)
                                        wake_up_process_synchronous(p);
                                else
                                        wake_up_process(p);
                                if (curr->flags & wq_mode & WQ_FLAG_EXCLUSIVE)
                                        break;
                        }
                }
        }
        if (best_exclusive) {
                if (sync)
                        wake_up_process_synchronous(best_exclusive);
                else
                        wake_up_process(best_exclusive);
        }
        wq_write_unlock_irqrestore(&q->lock, flags);
out:
        return;
}
__wake_up_common
()函數(shù)里面有個(gè)while循環(huán),該循環(huán)遍歷等待隊(duì)列里面的所有節(jié)點(diǎn)(具體情況仍然由任務(wù)的屬性、是否處于中斷處理等環(huán)境有關(guān))。由于__wake_up()調(diào)用__wake_up_common()函數(shù)的時(shí)候,
傳遞進(jìn)來的mode是(TASK_UNINTERRUPTIBLE|TASK_INTERRUPTIBLE),
wq_mode是WQ_FLAG_EXCLUSIVE,
sync是0,所以最終每個(gè)隊(duì)列節(jié)點(diǎn)的任務(wù)結(jié)構(gòu)指針都會被作為參數(shù)傳遞給wake_up_process(),顧名思義,這個(gè)函數(shù)的作用就是喚醒任務(wù)了。而此時(shí),調(diào)用schedule()函數(shù)的任務(wù)就可以從睡眠狀態(tài)轉(zhuǎn)到運(yùn)行狀態(tài),schedule()函數(shù)返回。
關(guān)于wake_up_process()函數(shù)所進(jìn)行的操所,主要就是將任務(wù)結(jié)構(gòu)放入運(yùn)行隊(duì)列中,讓調(diào)度器運(yùn)行該任務(wù)。
wake_up_process()函數(shù):
void wake_up_process(struct task_struct * p)
{
        unsigned long flags;
        /*
         * We want the common case fall through straight, thus the goto.
         */
        spin_lock_irqsave(&runqueue_lock, flags);
        p->state = TASK_RUNNING;
        if (task_on_runqueue(p))
                goto out;
        add_to_runqueue(p);
        reschedule_idle(p);
out:
        spin_unlock_irqrestore(&runqueue_lock, flags);
}
               
               
               
               
               

本文來自ChinaUnix博客,如果查看原文請點(diǎn):http://blog.chinaunix.net/u1/35101/showart_485204.html
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP