《電子技術(shù)應(yīng)用》
您所在的位置:首頁 > 嵌入式技術(shù) > 設(shè)計應(yīng)用 > 嵌入式Linux下的實時性增強方案
嵌入式Linux下的實時性增強方案
來源:電子技術(shù)應(yīng)用2010年第7期
單承剛
棗莊學院 計算機科學系,, 山東 棗莊 277160
摘要: 分析了嵌入式Linux在實時性方面的不足,針對Linux2.6內(nèi)核的中斷運行機制,、內(nèi)核不可搶占性,、自旋鎖及大內(nèi)核鎖等問題進行研究,,提出相應(yīng)的實時性改進方法。測試表明,,改進后的嵌入式Linux實時性效果較好,。
中圖分類號: TP316.8
文獻標識碼: A
文章編號: 0258-7998(2010)07-0137-03
Methods of enhancing real-time performance of embedded Linux
SHAN Cheng Gang
Computer and Science Department, Zaozhuang University, Zaozhuang 277160, China
Abstract: This paper describes the limination of real-time performance of embedded Linux,and puts forward corresponding improved methods of Linux 2.6 kernel.These methods focus on interrupt running mechanism,kernel preemption, spinlock mechanism and big kernel lock..According to these tests, the real-time performance of improved embedded Linux is effective.
Key words : embeded Linux; real-time; interrupt; preemption; spinlock

    Linux以其功能強大、源代碼開放,、支持多種硬件平臺,、模塊化設(shè)計方案以及豐富的開發(fā)工具支持等特點廣泛應(yīng)用在嵌入式系統(tǒng)領(lǐng)域。作為嵌入式產(chǎn)品的操作系統(tǒng)平臺,,具有較好的實時性,、系統(tǒng)可靠性、任務(wù)處理隨機性是系統(tǒng)追求的目標,目前商業(yè)嵌入式操作系統(tǒng)實時性能可以滿足嵌入式領(lǐng)域的需求,,但由于其價格昂貴,,應(yīng)用受到了限制[1]。而嵌入式Linux以其非常低廉的價格,,可以大大地降低成本,,逐漸成為嵌入式操作系統(tǒng)的首選。但由于其在實時應(yīng)用領(lǐng)域的技術(shù)障礙,,要應(yīng)用在嵌入式領(lǐng)域,還必須對Linux內(nèi)核作必要的改進,。本文以S3C2410+Linux作為移動機器人操作平臺,為了提高機器人任務(wù)處理的實時性,針對影響Linux OS實時性能的若干方面進行研究,,并利用相應(yīng)的解決方法基于標準Linux2.6內(nèi)核加以實現(xiàn),,最后通過測試,驗證了此改進方法的效果,。
1 Linux內(nèi)核實時性分析
1.1 Linux內(nèi)核制約實時性的因素

    衡量操作系統(tǒng)實時性的指標主要有中斷延遲和搶占延遲,。嵌入式系統(tǒng)中很多實時任務(wù)是靠中斷驅(qū)動的,中斷事件必須在限定的時限內(nèi)處理,,否則將產(chǎn)生災(zāi)難性的后果,。大多數(shù)實時系統(tǒng)都是處理一些周期性的或非周期性的重復(fù)事件,事件產(chǎn)生的頻度就確定了任務(wù)的執(zhí)行時限,,因此每次事件發(fā)生時,,相應(yīng)的處理任務(wù)必須及時響應(yīng)處理,否則將無法滿足時限[2],。搶占延遲就反映了系統(tǒng)的響應(yīng)及時程度,。針對Linux內(nèi)核,中斷關(guān)閉及中斷優(yōu)先級執(zhí)行機制,、內(nèi)核不可搶占性,、自旋鎖(spinlock)及大內(nèi)核鎖及一些O(n)的任務(wù)調(diào)度算法影響了系統(tǒng)的實時性能。
1.2 現(xiàn)存增強Linux內(nèi)核實時性的技術(shù)
    多年來,Linux實時性改進技術(shù)的發(fā)展主要有兩種技術(shù)方案:(1)直接修改Linux內(nèi)核,。針對內(nèi)核數(shù)據(jù)結(jié)構(gòu),、調(diào)度函數(shù)、中斷方式進行改動,,重新設(shè)計一個由優(yōu)先級驅(qū)動的實時調(diào)度器,替換原有Linux內(nèi)核中的進程調(diào)度器sched.c,。這一方案主要是針對中斷機制、任務(wù)調(diào)度算法進行改進的,,較為成功的案例為Kansas大學開發(fā)的Kurt-Linux,。Kurt提高了Linux系統(tǒng)中的實時精度,,將時鐘芯片設(shè)置為單觸發(fā)狀態(tài),。對于實時任務(wù)的調(diào)度,Kurt-Linux采用基于時間的靜態(tài)實時CPU調(diào)度算法,。實時任務(wù)在設(shè)計階段就需要明確地說明其實時事件要發(fā)生的時間,。這種調(diào)度算法對于那些循環(huán)執(zhí)行的任務(wù)能夠取得較好的調(diào)度效果;(2)在Linux內(nèi)核之外進行實時性擴展,,添加一個實時內(nèi)核。實時內(nèi)核接管硬件所有中斷,,并依據(jù)是否為實時任務(wù)給予響應(yīng),。Fsm Labs公司開發(fā)的RTLinux就是依據(jù)這種策略開發(fā)設(shè)計的[3]。以上論述的兩種技術(shù)方案有其可借鑒之處,,但如果綜合考慮任務(wù)響應(yīng),、內(nèi)核可搶占性、實時調(diào)度策略等都將影響操作系統(tǒng)的實時性能,,因此,,這兩種技術(shù)還不能很好地滿足實時性要求。為了增強嵌入式Linux實時性能,,下面將介紹中斷機制,、內(nèi)核的搶占性以及大內(nèi)核鎖等相關(guān)問題。
2 Linux實時性改進方法
 Linux2.4及以前版本內(nèi)核是不可搶占的,在Linux2.6中,,內(nèi)核已經(jīng)可以搶占,,實時性有所增強。但是內(nèi)核中仍然有不可搶占的區(qū)域,,如自旋鎖spinlock保護的臨界區(qū)等,。另外,影響內(nèi)核實時性能的因素還有中斷運行機制,、大內(nèi)核鎖機制以及調(diào)度算法等,。
2.1 中斷運行機制改進
 在Linux標準內(nèi)核中,中斷是最高優(yōu)先級的執(zhí)行單元,硬件架構(gòu)決定了硬件中斷到來的時候在該中斷沒有被屏蔽的條件下必須處理,。不管內(nèi)核當時處理什么,,即便是Linux中最高優(yōu)先級的實時進程,只要有中斷發(fā)生,,系統(tǒng)將立即響應(yīng)該事件并執(zhí)行相應(yīng)的中斷處理程序,,這就大大削弱了Linux的實時性能。特別是系統(tǒng)有嚴重的網(wǎng)絡(luò)或I/O負載時,,中斷將非常頻繁,,實時任務(wù)將很難有機會運行,這對于Linux的實時應(yīng)用來說是不可接受的,。Linux采用的關(guān)中斷技術(shù)在關(guān)中斷區(qū)域使相應(yīng)實時任務(wù)得不到響應(yīng),,增加了實時任務(wù)的中斷延遲。Linux實時化后自旋鎖變?yōu)榛コ怄i的技術(shù),,但由于自旋鎖的中斷處理不能及時響應(yīng),,降低了系統(tǒng)的實時性能。因此,借鑒Ingo Molnar實時補丁的實時化方法,,采用中斷線程化技術(shù)改進中斷運行機制,,中斷將作為內(nèi)核線程運行而且賦予不同的實時優(yōu)先級,實時任務(wù)可以有比中斷線程更高的優(yōu)先級,,這樣,,實時任務(wù)就可以作為最高優(yōu)先級的執(zhí)行單元來運行了,即使在嚴重負載下仍有實時性保證,。另一方面,中斷處理線程也可以因為在內(nèi)核同步中得不到鎖而掛載到鎖的等待隊列中,很多關(guān)中斷就不必真正的禁止硬件中斷了,,而是禁止內(nèi)核進程搶占,從而減小了中斷延遲[4],。
 在初始化階段,,常規(guī)中斷初始化和中斷線程化的初始化在start_kernel( )函數(shù)中都調(diào)用trap_init( )和init_IRQ( )兩個函數(shù)來初始化irq_desc_t結(jié)構(gòu)體,區(qū)別主要體現(xiàn)在內(nèi)核初始化創(chuàng)建init線程時,,中斷線程化的中斷在init( )函數(shù)中還將調(diào)用init_hardirqs(kernel/irq/manage.c)來為每一個IRQ創(chuàng)建一個內(nèi)核線程,,最高實時優(yōu)先級為50,依次類推直到25,。因此,,任何IRQ線程的最低實時優(yōu)先級為25,具體實現(xiàn)是通過kthread_create函數(shù)創(chuàng)建的,。功能實現(xiàn)等同于如下代碼:
   void __init init_hardirqs(void)
   {   ……
        for (i = 0; i < NR_IRQS; i++) {  
                          //對于每一個中斷建立一個中斷線程
        irq_desc_t *desc = irq_desc + i;
            if(desc->action && !(desc->status & IRQ_NODELAY))
              //有IRQ_NODELAY標志的中斷不允許線程化
                desc->thread = kthread_create(do_irqd,
                    desc, "IRQ %d", irq);     //建立線程
            &hellip;&hellip;
        }
    }
    static int do_irqd(void * __desc)
                          //分配中斷線程優(yōu)先級50~25
    {  &hellip;&hellip;
        /*Scale irq thread priorities from prio 50 to prio 25 */
        param.sched_priority = curr_irq_prio;
        if (param.sched_priority > 25)
        curr_irq_prio = param.sched_priority - 1;
       &hellip;&hellip;
    }
 在中斷處理階段當中斷發(fā)生時,CPU調(diào)用do_IRQ( )函數(shù)來處理中斷,,do_IRQ( )在做了必要的相關(guān)處理之后調(diào)用_do_IRQ( )。_do_IRQ( )主要功能為判斷該中斷是否已經(jīng)被線程化(核對終端描述符的狀態(tài)字段是否包含IRQ_NODELAY標志),,對于沒有線程化的中斷,,將直接調(diào)用handle_IRQ_event( )函數(shù)來處理。功能實現(xiàn)等同于如下代碼:
   fastcall notrace unsigned int __do_IRQ(unsigned int irq,
        struct pt_regs *regs)
   {  &hellip;&hellip;
        if (redirect_hardirq(desc))
                //檢測是否為線程化中斷,,若是則喚醒中斷線程
                goto out_no_end;
    &hellip;&hellip;
    action_ret = handle_IRQ_event(irq, regs, action);
                                  //處理非線程化中斷
           &hellip;&hellip;
   }
   int redirect_hardirq(struct irq_desc *desc)
                 //檢測irq_desc結(jié)構(gòu)體,,判斷是否線程化
   {  &hellip;&hellip;
        if (!hardirq_preemption || (desc->status & IRQ_
                    NODELAY) || !desc->thread)
            return 0;
       &hellip;&hellip;
        if (desc->thread && desc->thread->state != TASK_
                RUNNING)
            wake_up_process(desc->thread);
        &hellip;&hellip;
   }
 針對已線程化的情況,調(diào)用wake_up_process( )函數(shù)喚醒中斷處理線程執(zhí)行,,內(nèi)核線程將調(diào)用do_hardirq( )來處理相應(yīng)的中斷,。具體實現(xiàn)是通過handle_IRQ_event( )函數(shù)直接調(diào)用相應(yīng)的中斷處理函數(shù)完成的。對于緊急的中斷(如時鐘中斷),內(nèi)核保持原來的中斷處理方式,,而不為其創(chuàng)建中斷線程,,這樣就保證了緊急中斷的快速響應(yīng)。
2.2 內(nèi)核可搶占性設(shè)計
 在Linux標準內(nèi)核中,,因不具有可搶占性和導(dǎo)致較大的延遲,,增加內(nèi)核的可搶占性能,可提高系統(tǒng)的實時任務(wù)處理能力,。當前修改Linux內(nèi)核提高實時性的方法主要有增加搶占點和改造成搶占式內(nèi)核兩種方法,。增加搶占點方法是在內(nèi)核中插入搶占點,,通過檢測搶占點調(diào)度標志來決定是否進行實時任務(wù)的調(diào)度。采用這種方法,,在檢測搶占點標志時大大增加了系統(tǒng)開銷,因此本方案采用直接改造Linux內(nèi)核的方法,,通過修改自旋鎖為互斥鎖來提高內(nèi)核的可搶占性[5],。即借鑒Ingo Molnar的實時補丁的實時化方法,使用mutex互斥鎖來替換spinlock自旋鎖,。使用mutex替換spinlock,,可以讓spinlock可搶占。起初spinlock不可搶占性設(shè)計目的是避免死鎖,,可搶占性設(shè)計可能導(dǎo)致競爭者與保持者的死鎖局面,。中斷處理函數(shù)中也可以使用spinlock,如果spinlock已經(jīng)被某一進程保持,,則中斷處理函數(shù)無法進行,,從而形成死鎖。中斷線程化以后,,中斷線程將掛在等待隊列上并放棄CPU讓別的線程或進程來運行,讓每個spinlock都有一個等待隊列,,該等待隊列按進程或線程優(yōu)先級排隊,如果一個進程或線程競爭的spinlock已經(jīng)被另一個線程保持,它將把自己掛在該spinlock的優(yōu)先級化的等待隊列上,然后發(fā)生調(diào)度把CPU讓給別的進程或線程,。mutex替換spinlock后,,spinlock結(jié)構(gòu)定義如下代碼:
    typedef struct {
        struct rt_mutex lock;            //新的實時互斥鎖
        unsigned int break_lock;
    } spinlock_t;
    其中struct rt_mutex結(jié)構(gòu)如下:
    struct rt_mutex {
        raw_spinlock_t wait_lock;
        struct plist wait_list;                  //優(yōu)先級等待隊列
        struct task_struct *owner;     //擁有該鎖進程的信息
        int owner_prio;
        &hellip; &hellip;
    };
  在如上代碼中,類型raw_spinlock_t就是原來的spinlock_t。即代碼中的spinlock_t就是新設(shè)計的自旋鎖,。rt_mutex結(jié)構(gòu)中,wait_list字段為優(yōu)先級等待隊列,。在mutex使用中,當遇到鎖住的臨界資源時,,任務(wù)被掛起到wait_list中,,臨界資源解鎖時等待任務(wù)被激活。臨界資源被保護的同時可以搶占,。
    由于Linux內(nèi)核底層的臨界資源是不可搶占的,,使用mutex替換spinlock的過程中,這部分可以保留,,仍由不可搶占的spinlock保護,,如:保護硬件寄存器的鎖、調(diào)度器的運行隊列鎖等,。不可搶占的spinlock被重新命名為raw_spinlock_t,。spin_lock被宏定義為:
 #define spin_lock(lock)  PICK_OP(raw_spinlock_t,spin,_lock,lock)
 函數(shù)PICK_OP支持兩種鎖共存機制,PICK_OP在編譯階段將鎖操作轉(zhuǎn)化為mutex或者spinlock:
   #define PICK_OP(type, optype, op, lock) \
          do { \
          if (TYPE_EQUAL((lock), type)) \
          _raw_##optype##op((type *)(lock)); \
          else if (TYPE_EQUAL(lock, spinlock_t)) \
          //調(diào)用gcc的內(nèi)嵌函數(shù)__builtin_types_compatible_p()
      _spin##op((spinlock_t *)(lock)); \
          else __bad_spinlock_type(); \
          } while (0)
         #define TYPE_EQUAL(lock, type) \
    __builtin_types_compatible_p(typeof(lock), type *)
  gcc的內(nèi)嵌函數(shù)__builtin_types_compatible_p用于判斷一個變量的類型是否為某指定的類型,,如果類型為spinlock_t,,將運行函數(shù)_spin_lock;類型為raw_spinlock_t,,將運行函數(shù)_raw_spin_lock。
   實時rt_mutex在具體應(yīng)用中,,一個高優(yōu)先級任務(wù)搶占該鎖的同時,,把先前的鎖擁有者添加到互斥鎖等待隊列中,并在當前擁有該鎖的任務(wù)task_struct中標記等待該鎖的所有任務(wù);反之,,不能得到該鎖就把當前任務(wù)添加到鎖的優(yōu)先級等待隊列中,,直到喚醒執(zhí)行。為了防止優(yōu)先級逆轉(zhuǎn),,可以改變鎖的當前擁有者的優(yōu)先級為鎖的等待隊列中任務(wù)的最高優(yōu)先級,。
 rt_mutex可以使高優(yōu)先級任務(wù)利用搶占鎖進入臨界區(qū),這樣內(nèi)核不可搶占區(qū)的數(shù)量和范圍大大縮小,,內(nèi)核可搶占性有了很大的提高,,且降低了實時高優(yōu)先級任務(wù)的搶占延遲,改善了系統(tǒng)的實時性能,。
2.3 可搶占大內(nèi)核鎖設(shè)計
 大內(nèi)核鎖BKL(Big Kernel Lock)實質(zhì)上也是spinlock,,它用于保護整個內(nèi)核,該鎖保持時間較長,,對系統(tǒng)的實時性能影響很大[6],。采用Ingo Molnar的實時化方法,BKL使用semaphore實現(xiàn),,結(jié)構(gòu)定義如下代碼:
         struct semaphore {
         atomic_t count;
         struct rt_mutex lock;              //實時互斥鎖的使用
        };
   由結(jié)構(gòu)體發(fā)現(xiàn),,在BKL實現(xiàn)中利用了實時互斥鎖rt_mutex,在改進后的spinlock結(jié)構(gòu)體spinlock_t中也利用了實時互斥鎖rt_mutex,因此可搶占大內(nèi)核鎖和新的spinlock共用了低層的處理代碼,。使用semaphore之后,,大內(nèi)核鎖就可搶占了。
3 內(nèi)核實時性測試
   針對Linux2.6內(nèi)核,,本文并沒有作出對內(nèi)核調(diào)度算法的修正,,只是探討了中斷運行機制、自旋鎖及大內(nèi)核鎖技術(shù)在系統(tǒng)實時性能上的局限性,,所以實驗測試主要測試中斷延遲時間和任務(wù)響應(yīng)時間,。實驗環(huán)境: Intel 2 GHz CPU,256 DDR內(nèi)存,,Kernel 2.6.22版本,。測試結(jié)果如表1所示。

    由表可知,,在中斷服務(wù)程序中寫入標記,,測試中斷觸發(fā)至中斷服務(wù)程序執(zhí)行平均響應(yīng)時間,標準Linux2.6內(nèi)核平均中斷響應(yīng)時間為182 &mu;s,改進后Linux2.6內(nèi)核為14 &mu;s,。采用開源軟件LMbench3.0 測試系統(tǒng)任務(wù)調(diào)度延遲時間,標準Linux2.6內(nèi)核平均任務(wù)響應(yīng)時間為1 260 &mu;s,,改進后Linux2.6內(nèi)核為162&mu;s,。由此可見,改進策略在一定程度上大大減小了中斷延遲和任務(wù)調(diào)度時間,有利于改善移動機器人任務(wù)處理的實時性能,。
 本文基于Linux2.6內(nèi)核的關(guān)中斷,、中斷優(yōu)先級、內(nèi)核的不可搶占性以及大內(nèi)核鎖保持時間過長等問題進行了實時性分析,,提出了相應(yīng)的改進方法,。利用中斷線程化、互斥鎖的應(yīng)用及大內(nèi)核鎖的改進等技術(shù)提高了系統(tǒng)的實時性能,,降低了內(nèi)核中斷延遲和調(diào)度延遲。改進后的內(nèi)核在移動機器人控制器平臺中有很好的應(yīng)用價值,,提高了機器人控制的實時性能,。
參考文獻
[1]  吳軍,周轉(zhuǎn)運. 嵌入式Linux系統(tǒng)應(yīng)用基礎(chǔ)與開發(fā)范例[M].北京:人民郵電出版社,2007.
[2]  LOV R.Linux kernel development[M].陳莉君,等譯.北京: 機械工業(yè)出版社,2005.
[3]  鄒勇,王青,李明樹.Linux內(nèi)核的實時支持的研究與實現(xiàn)[J].計算機研究與發(fā)展,2002,39(4):466-472.
[4]  張玉芳,熊忠陽,王銀輝,等.Linux實時化設(shè)計方法研究[J].小型微型計算機系統(tǒng),2009,,30(3):421-424.
[5]  吳嬌梅,李紅艷,吳保榮,等.改善嵌入式Linux 實時性能的方法研究[J].微計算機信息,2006(1-2):46-47.
[6]  厲海燕,李新明.Linux搶占式內(nèi)核的研究與實現(xiàn)[J].計算機工程與設(shè)計,2005,26(9):2395-2399.

此內(nèi)容為AET網(wǎng)站原創(chuàng),,未經(jīng)授權(quán)禁止轉(zhuǎn)載。