在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > Linux學(xué)習(xí)-等待隊(duì)列

            Linux學(xué)習(xí)-等待隊(duì)列

            作者: 時(shí)間:2016-12-01 來(lái)源:網(wǎng)絡(luò) 收藏
            由于學(xué)習(xí)linux驅(qū)動(dòng)編程,學(xué)習(xí)到了堵塞型IO讀寫,等待隊(duì)列的操作比較的有意思,拿來(lái)分析分析,其中的一些代碼還是蠻有意思的,感受到了linux的美,體會(huì)到了藝術(shù)家和一般程序員的差別。
            我就簡(jiǎn)要的分析分析等待隊(duì)列的一些問(wèn)題,就相當(dāng)于自己的總結(jié)吧。邊學(xué)驅(qū)動(dòng),邊學(xué)內(nèi)核,還是蠻有意思的。
            1、等待隊(duì)列的定義,包括兩個(gè),等待隊(duì)列頭,節(jié)點(diǎn)。
            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;
            #define WQ_FLAG_EXCLUSIVE 0x01
            void *private;
            wait_queue_func_t func;
            struct list_head task_list;
            };
            /*關(guān)于等待隊(duì)列的操作主要是初始化操作*/
            #define DECLARE_WAIT_QUEUE_HEAD(name)
            wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
            /*就是初始化兩個(gè)元素*/
            #define __WAIT_QUEUE_HEAD_INITIALIZER(name) {
            .lock = __SPIN_LOCK_UNLOCKED(name.lock),
            .task_list = { &(name).task_list, &(name).task_list } }
            #define init_waitqueue_head(q)
            do {
            static struct lock_class_key __key;
            __init_waitqueue_head((q), &__key);
            } while (0)
            void __init_waitqueue_head(wait_queue_head_t *q, struct lock_class_key *key)
            {
            spin_lock_init(&q->lock);
            lockdep_set_class(&q->lock, key);
            INIT_LIST_HEAD(&q->task_list);
            }
            從上面的定義可知,實(shí)質(zhì)上等待隊(duì)列頭很簡(jiǎn)單,只要就是一個(gè)鏈表頭,而等待隊(duì)列的節(jié)點(diǎn)主要包含了一個(gè)函數(shù)指針和對(duì)應(yīng)的參數(shù),以及鏈表。
            我們?cè)隍?qū)動(dòng)過(guò)程中主要使用的函數(shù)主要包括wait_event(),wait_event_interruptible(),wait_event_killable(),以及喚醒過(guò)程中的wait_up(),wait_up_interruptible().
            基本的流程就是:
            #define wait_event(wq, condition)
            do {
            if (condition)
            /*添加滿足,則直接跳出*/
            break;
            /*負(fù)責(zé)進(jìn)入等待隊(duì)列*/
            __wait_event(wq, condition);
            } while (0)
            #define __wait_event(wq, condition)
            do {
            /*定義新的等待隊(duì)列節(jié)點(diǎn)*/
            DEFINE_WAIT(__wait);
            for (;;) {/*一個(gè)循環(huán)的過(guò)程,可能導(dǎo)致堵塞*/
            /*將添加的節(jié)點(diǎn)添加到隊(duì)列中,并改變進(jìn)程的運(yùn)行狀態(tài)*/
            prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);
            if (condition)/*如果條件合適了,就跳出當(dāng)前的循環(huán),也就是等待條件獲得*/
            break;
            /*當(dāng)前進(jìn)程放棄CPU,進(jìn)行調(diào)度其他的進(jìn)程,這時(shí)的進(jìn)程進(jìn)入睡眠狀態(tài)
            也就是說(shuō)在schedule中函數(shù)就不在繼續(xù)執(zhí)行,只有調(diào)用wake_up函數(shù)喚
            醒當(dāng)前的進(jìn)程,才會(huì)退出schedule函數(shù),然后繼續(xù)執(zhí)行下面的函數(shù),也就是繼續(xù)循環(huán)
            真正的退出循環(huán),只有當(dāng)條件滿足時(shí),如果條件不滿足,調(diào)用wake_up函數(shù)
            仍然不會(huì)滿足條件,只會(huì)再次調(diào)度,再次失去CPU,
            根據(jù)上面的分析可知,只有上面的條件滿足了,并調(diào)用
            wake_up函數(shù)才能跳出當(dāng)前的for循環(huán)。
            */
            schedule();
            }
            /*完成等待*/
            finish_wait(&wq, &__wait);
            } while (0)
            #define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, autoremove_wake_function)
            #define DEFINE_WAIT_FUNC(name, function)
            wait_queue_t name = {
            .private = current,
            .func = function,
            .task_list = LIST_HEAD_INIT((name).task_list),
            }
            void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
            {
            unsigned long flags;
            /*改變狀態(tài)*/
            wait->flags &= ~WQ_FLAG_EXCLUSIVE;
            spin_lock_irqsave(&q->lock, flags);
            /*如果鏈表是空,則將當(dāng)前的這個(gè)節(jié)點(diǎn)添加進(jìn)來(lái),這樣能避免wait被反復(fù)的添加,造成大量的浪費(fèi)*/
            if (list_empty(&wait->task_list))
            __add_wait_queue(q, wait);
            /*修改當(dāng)前進(jìn)程的狀態(tài)*/
            set_current_state(state);
            spin_unlock_irqrestore(&q->lock, flags);
            }
            #define set_current_state(state_value)
            set_mb(current->state, (state_value))
            static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)
            {
            /*就是將鏈表添加進(jìn)來(lái)而已*/
            list_add(&new->task_list, &head->task_list);
            }
            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);
            }
            void finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
            {
            unsigned long flags;
            /*修改當(dāng)前進(jìn)程的狀態(tài)為TASK_RUNNING,因此可以被執(zhí)行*/
            __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
            * CPUs that we havent 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).
            */
            /*刪除鏈表,實(shí)質(zhì)上就是釋放*/
            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);
            }
            }
            asmlinkage void __sched schedule(void)
            {
            struct task_struct *prev, *next;
            unsigned long *switch_count;
            struct rq *rq;
            int cpu;
            need_resched:
            preempt_disable();
            cpu = smp_processor_id();
            rq = cpu_rq(cpu);
            rcu_note_context_switch(cpu);
            prev = rq->curr;
            release_kernel_lock(prev);
            need_resched_nonpreemptible:
            schedule_debug(prev);
            if (sched_feat(HRTICK))
            hrtick_clear(rq);
            raw_spin_lock_irq(&rq->lock);
            switch_count = &prev->nivcsw;
            if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
            if (unlikely(signal_pending_state(prev->state, prev))) {
            prev->state = TASK_RUNNING;
            } else {
            /*
            * If a worker is going to sleep, notify and
            * ask workqueue whether it wants to wake up a
            * task to maintain concurrency. If so, wake
            * up the task.
            */
            if (prev->flags & PF_WQ_WORKER) {
            struct task_struct *to_wakeup;
            to_wakeup = wq_worker_sleeping(prev, cpu);
            if (to_wakeup)
            try_to_wake_up_local(to_wakeup);
            }
            deactivate_task(rq, prev, DEQUEUE_SLEEP);
            }
            switch_count = &prev->nvcsw;
            }
            pre_schedule(rq, prev);
            if (unlikely(!rq->nr_running))
            idle_balance(cpu, rq);
            put_prev_task(rq, prev);
            next = pick_next_task(rq);
            clear_tsk_need_resched(prev);
            rq->skip_clock_update = 0;
            if (likely(prev != next)) {
            sched_info_switch(prev, next);
            perf_event_task_sched_out(prev, next);
            rq->nr_switches++;
            rq->curr = next;
            ++*switch_count;
            context_switch(rq, prev, next); /* unlocks the rq */
            /*
            * The context switch have flipped the stack from under us
            * and restored the local variables which were saved when
            * this task called schedule() in the past. prev == current
            * is still correct, but it can be moved to another cpu/rq.
            */
            cpu = smp_processor_id();
            rq = cpu_rq(cpu);
            } else
            raw_spin_unlock_irq(&rq->lock);
            post_schedule(rq);
            if (unlikely(reacquire_kernel_lock(prev)))
            goto need_resched_nonpreemptible;
            preempt_enable_no_resched();
            if (need_resched())
            goto need_resched;
            }
            根據(jù)上面的各個(gè)函數(shù),宏定義可知,在wait_event函數(shù)中完成了大部分的事情,其中包括等待隊(duì)列節(jié)點(diǎn)的定義,添加,當(dāng)前進(jìn)程運(yùn)行狀態(tài)的改變,等待條件的滿足,跳出等待,函數(shù)介紹之前需要完成的任務(wù)是修改當(dāng)前進(jìn)程的狀態(tài)為TASK_RUNNING,刪除鏈表,釋放一些空間。
            其他的函數(shù)wait_event_interruptible以及wait_event_killable具有相似的操作,只是對(duì)前期修改進(jìn)程狀態(tài)存在差別。wait_event_interruptible則不一定只能在條件滿足時(shí)喚醒,也可以被信號(hào)喚醒,而wait_event則在條件滿足時(shí)被喚醒。


            評(píng)論


            技術(shù)專區(qū)

            關(guān)閉