• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            jake1036

            linux0.11進(jìn)程切換

            就緒態(tài)和運行態(tài)之間的切換

                當(dāng)前占用CPU的進(jìn)程,只有調(diào)用了schedule()函數(shù),才會由運行態(tài)轉(zhuǎn)變?yōu)榫途w態(tài),schedule()函數(shù)選擇狀態(tài)為TASK_RUNNING的進(jìn)程,
                然后調(diào)用switch函數(shù),將cpu切換到所選定的進(jìn)程。
               schedule()函數(shù)可能會在以下三種情況下調(diào)用:
               (1) 用戶態(tài)時發(fā)生時鐘中斷
                    
                   如果當(dāng)前進(jìn)程是用戶態(tài)進(jìn)程,并且當(dāng)前進(jìn)程的時間片用完,那么中斷處理函數(shù)do_timer()就會調(diào)用schedule()函數(shù),
                  這相當(dāng)于用戶態(tài)的進(jìn)程被搶斷了。
                  如果當(dāng)前的進(jìn)程屬于內(nèi)核態(tài)進(jìn)程,那么該進(jìn)程是不會被搶占的。schedule() 函數(shù)不是系統(tǒng)調(diào)用,用戶程序不能直接調(diào)用,
                 但是放在時間中斷函數(shù)中,就能夠調(diào)用。所以在時間中斷中調(diào)用schedule()是必要的,這樣就保證用戶進(jìn)程不會永久地占有CPU。
                
               (2)系統(tǒng)調(diào)用時,相應(yīng)的sys_xxxx()函數(shù)返回之后。
                     這種情況是為了處理運行在內(nèi)核態(tài)的進(jìn)程,應(yīng)用程序一般是通過系統(tǒng)調(diào)用進(jìn)入內(nèi)核態(tài),因此,linux系統(tǒng)調(diào)用處理函數(shù)在結(jié)束的時候,
                     int 0x80 中斷函數(shù)會檢查當(dāng)前進(jìn)程的時間片和狀態(tài),如果時間片用完或者進(jìn)程的狀態(tài)不為RUNNING ,就會調(diào)用schedule()函數(shù)。
                    由此可見,如果系統(tǒng)的某個系統(tǒng)調(diào)用處理函數(shù)或者中斷處理異常永遠(yuǎn)不退出,那么整個系統(tǒng)就會死鎖,任何進(jìn)程都無法運行。
               (3)在睡眠函數(shù)內(nèi)
                   當(dāng)進(jìn)程等待的資源還不可用的時候,它就進(jìn)入了睡眠狀態(tài),并且調(diào)用schedule()函數(shù)再次調(diào)用CPU。

               
            #define switch_to(n) {\
            // __tmp用來構(gòu)造ljmp的操作數(shù)。該操作數(shù)由4字節(jié)偏移和2字節(jié)選擇符組成。當(dāng)選擇符
            // 是TSS選擇符時,指令忽略4字節(jié)偏移。
            // __tmp.a存放的是偏移,__tmp.b的低2字節(jié)存放TSS選擇符。高兩字節(jié)為0。
            // ljmp跳轉(zhuǎn)到TSS段選擇符會造成任務(wù)切換到TSS選擇符對應(yīng)的進(jìn)程。
            // ljmp指令格式是 ljmp 16位段選擇符:32位偏移,但如果操作數(shù)在內(nèi)存中,順序正好相反。

            // %0    內(nèi)存地址    __tmp.a的地址,用來放偏移
            // %1    內(nèi)存地址    __tmp.b的地址,用來放TSS選擇符
            // %2    edx            任務(wù)號為n的TSS選擇符
            // %3    ecx            task[n]
            struct {long a,b;} __tmp; \
            __asm__(
            "cmpl %%ecx,current\n\t" \    // 如果要切換的任務(wù)是當(dāng)前任務(wù)
                "je 1f\n\t" \                    // 直接退出
                "movw %%dx,%1\n\t" \            // 把TSS選擇符放入__tmp.b中
                "xchgl %%ecx,current\n\t" \        // 讓current指向新進(jìn)程的task_struct
                "ljmp *%0\n\t" \                // 任務(wù)切換在這里發(fā)生,CPU會搞定一切
                "cmpl %%ecx,last_task_used_math\n\t" \    // 除進(jìn)程第一次被調(diào)度外,以后進(jìn)程從就緒
                                                    
            // 態(tài)返回運行態(tài)后,都從這里開始運行。因
                                                    
            // 而返回到的是內(nèi)核運行態(tài)。
                "jne 1f\n\t" \
                
            "clts\n" \
                
            "1:" \
                ::
            "m" (*&__tmp.a),"m" (*&__tmp.b), \
                
            "d" (_TSS(n)),"c" ((long) task[n])); \
            }


               進(jìn)程調(diào)度函數(shù)
               
            /****************************************************************************/
            /* 功能:進(jìn)程調(diào)度。                                                            */
            /*         先對alarm和信號進(jìn)行處理,如果某個進(jìn)程處于可中斷睡眠狀態(tài),并且收    */
            /*         到信號,則把進(jìn)程狀態(tài)改成可運行。之后在處可運行狀態(tài)的進(jìn)程中挑選一個    */
            /*         并用switch_to()切換到那個進(jìn)程                                        */
            /* 參數(shù):(無)                                                                */
            /* 返回:(無)                                                                */
            /****************************************************************************/
            void schedule(void)
            {
                
            int i,next,c;
                
            struct task_struct ** p;

            /* check alarm, wake up any interruptible tasks that have got a signal */
            // 首先處理alarm信號,喚醒所有收到信號的可中斷睡眠進(jìn)程
                for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
                    
            if (*p) {
                        
            // 如果進(jìn)程設(shè)置了alarm,并且alarm已經(jīng)到時間了
                        if ((*p)->alarm && (*p)->alarm < jiffies) {
                                
            // 向該進(jìn)程發(fā)送SIGALRM信號
                                (*p)->signal |= (1<<(SIGALRM-1));
                                (
            *p)->alarm = 0;    // 清除alarm
                            }

            //可屏蔽信號位圖BLOCKABLE定義在sched.c第24行,(~(_S(SIGKILL) | _S(SIGSTOP)))
            // 說明SIGKILL和SIGSTOP是不能被屏蔽的。
            // 可屏蔽信號位圖 & 當(dāng)前進(jìn)程屏蔽的信號位圖 = 當(dāng)前進(jìn)程實際屏蔽的信號位圖
            // 當(dāng)前進(jìn)程收到的信號位圖 & ~當(dāng)前進(jìn)程實際屏蔽的信號位圖 
            //                            = 當(dāng)前進(jìn)程收到的允許相應(yīng)的信號位圖
            // 如果當(dāng)前進(jìn)程收到允許相應(yīng)的信號,并且當(dāng)前進(jìn)程處于可中斷睡眠態(tài)
            // 則把狀態(tài)改成運行態(tài),參與下面的選擇過程
                        if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
                        (
            *p)->state==TASK_INTERRUPTIBLE)
                            (
            *p)->state=TASK_RUNNING;
                    }


            /* this is the scheduler proper: */
            // 下面是進(jìn)程調(diào)度的主要部分
                while (1{
                    c 
            = -1;
                    next 
            = 0;
                    i 
            = NR_TASKS;
                    p 
            = &task[NR_TASKS];
                    
            while (--i) {        // 遍歷整個task[]數(shù)組
                        if (!*--p)        // 跳過task[]中的空項
                            continue;
                        
            // 尋找剩余時間片最長的可運行進(jìn)程,
            //  c記錄目前找到的最長時間片
            // next記錄目前最長時間片進(jìn)程的任務(wù)號
                        if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
                            c 
            = (*p)->counter, next = i;
                    }

                
            // 如果有進(jìn)程時間片沒有用完c一定大于0。這時退出循環(huán),執(zhí)行 switch_to任務(wù)切換
                    if (c) break;
                
            // 到這里說明所有可運行進(jìn)程的時間片都用完了,則利用任務(wù)優(yōu)先級重新分配時間片。
                
            // 這里需要重新設(shè)置所有任務(wù)的時間片,而不光是可運行任務(wù)的時間片。
                
            // 利用公式:counter = counter/2 + priority
                    for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
                        
            if (*p)
                            (
            *p)->counter = ((*p)->counter >> 1+
                                    (
            *p)->priority;
                
            // 整個設(shè)置時間片過程結(jié)束后,重新進(jìn)入進(jìn)程選擇過程
                }

                
            // 當(dāng)?shù)纳厦娴难h(huán)退出時,說明找到了可以切換的任務(wù)
                switch_to(next);
            }


                 
                2   運行態(tài)和睡眠態(tài)之間的轉(zhuǎn)化
                      當(dāng)進(jìn)程等待資源或者事件的時候,就進(jìn)入了睡眠狀態(tài),有兩種不同的睡眠狀態(tài),   不可中斷睡眠狀態(tài)和可中斷睡眠狀態(tài)。
                      處于可中斷睡眠狀態(tài)的進(jìn)程,不光可以由wake_up 喚醒,還可以由信號喚醒,在schedule()函數(shù)中,會把處于可中斷睡眠狀態(tài)的并且接收到信號的
                    進(jìn)程變?yōu)檫\行狀態(tài)。linux0.11的可中斷睡眠狀態(tài)可以由以下三中函數(shù)進(jìn)入:
                   (1)調(diào)用interruptiable_sleep_on()函數(shù)、
                   (2)調(diào)用sys_pause()函數(shù)。
                   (3)調(diào)用sys_waitpid()函數(shù)。

                進(jìn)程要進(jìn)入不可中斷睡眠狀態(tài),必須調(diào)用sleep_on()函數(shù)。進(jìn)程調(diào)用wake_up()函數(shù),將處于不可中斷狀態(tài)的進(jìn)程喚醒。

               
             
            /****************************************************************************/
            /* 功能:當(dāng)前進(jìn)程進(jìn)入不可中斷睡眠態(tài),掛起在等待隊列上                        */
            /* 參數(shù):p 等待隊列頭                                                        */
            /* 返回:(無)                                                                */
            /****************************************************************************/
            void sleep_on(struct task_struct **p)
            {
                
            struct task_struct *tmp;        // tmp用來指向等待隊列上的下一個進(jìn)程

                
            if (!p)            // 無效指針,退出
                    return;
                
            if (current == &(init_task.task))    // 進(jìn)程0不能睡眠
                    panic("task[0] trying to sleep");
                tmp 
            = *p;            // 下面兩句把當(dāng)前進(jìn)程放到等待隊列頭,等待隊列是以堆棧方式
                *= current;        //    管理的。后到的進(jìn)程等在前面
                current->state = TASK_UNINTERRUPTIBLE;    // 進(jìn)程進(jìn)入不可中斷睡眠狀態(tài)
                schedule();        // 進(jìn)程放棄CPU使用權(quán),重新調(diào)度進(jìn)程
            // 當(dāng)前進(jìn)程被wake_up()喚醒后,從這里開始運行。
            // 既然等待的資源可以用了,就應(yīng)該喚醒等待隊列上的所有進(jìn)程,讓它們再次爭奪
            // 資源的使用權(quán)。這里讓隊列里的下一個進(jìn)程也進(jìn)入運行態(tài)。這樣當(dāng)這個進(jìn)程運行
            // 時,它又會喚醒下下個進(jìn)程。最終喚醒所有進(jìn)程。
                if (tmp)    
                    tmp
            ->state=0;
            }


             

            當(dāng)前進(jìn)程

            的地址空間

            tmp指針

            當(dāng)前進(jìn)程的task_struct

            進(jìn)程2

            的地址空間

            tmp指針

            進(jìn)程2task_struct

            進(jìn)程1

            的地址空間

            tmp指針

            進(jìn)程1task_struct

            *p

            current


              以下是喚醒函數(shù) 
              
            /****************************************************************************/
            /* 功能:喚醒等待隊列上的頭一個進(jìn)程                                            */
            /* 參數(shù):p 等待隊列頭                                                        */
            /* 返回:(無)                                                                */
            /****************************************************************************/
            void wake_up(struct task_struct **p)
            {
                
            if (p && *p) {
                    (
            **p).state=0;        // 把隊列上的第一個進(jìn)程設(shè)為運行態(tài)
                    *p=NULL;        // 把隊列頭指針清空,這樣失去了都其他等待進(jìn)程的跟蹤。
                                    
            //  一般情況下這些進(jìn)程遲早會得到運行。
                }

            }



               
              



            posted on 2010-11-14 15:17 kahn 閱讀(1576) 評論(0)  編輯 收藏 引用


            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            亚洲精品白浆高清久久久久久| 国产精品伊人久久伊人电影| 国产精品久久久久久搜索| 久久久精品国产亚洲成人满18免费网站 | 欧美精品丝袜久久久中文字幕 | 色噜噜狠狠先锋影音久久| 久久久久久精品成人免费图片| yellow中文字幕久久网| 午夜不卡久久精品无码免费| 伊人久久亚洲综合影院| 激情综合色综合久久综合| 久久精品嫩草影院| 久久九九兔免费精品6| 伊人伊成久久人综合网777| 精品一久久香蕉国产线看播放| 久久精品国产亚洲欧美| 国产精品岛国久久久久| 99久久精品国产免看国产一区| 久久99热只有频精品8| 色综合久久久久综合体桃花网 | 思思久久好好热精品国产| 久久涩综合| 秋霞久久国产精品电影院| 久久久精品免费国产四虎| 久久精品国产精品青草app| 97久久久久人妻精品专区 | 国内精品久久久久影院一蜜桃| 久久久久无码精品国产| 精品久久久久久亚洲精品 | 亚洲欧美成人久久综合中文网 | 久久一区二区三区99| 久久精品极品盛宴观看| 伊人久久大香线蕉综合热线| 久久99热这里只有精品66| 久久久久久久亚洲Av无码| 99999久久久久久亚洲| 精品久久777| 久久综合九色综合97_久久久 | 99久久国产综合精品五月天喷水 | 久久精品a亚洲国产v高清不卡| 国产精品视频久久久|