新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 實(shí)時(shí)嵌入式系統(tǒng)軟件調(diào)試問(wèn)題分析

實(shí)時(shí)嵌入式系統(tǒng)軟件調(diào)試問(wèn)題分析

作者: 時(shí)間:2010-09-29 來(lái)源:網(wǎng)絡(luò) 收藏

 本文將討論常見的以及預(yù)防和檢查這些故障的一些方法。

本文引用地址:http://butianyuan.cn/article/151473.htm

  從歷史角度上來(lái)看,應(yīng)用代碼的流程可以分為兩類。第一類流程是回答 “我的代碼現(xiàn)在執(zhí)行到哪里?” 的。當(dāng)開發(fā)商依靠打印語(yǔ)句或者LED的閃爍來(lái)指示應(yīng)用程序執(zhí)行到某個(gè)節(jié)點(diǎn)的調(diào)試方法時(shí),往往就屬于這種情形。如果開發(fā)工具支持這種調(diào)試方法,可以沿著應(yīng)用應(yīng)當(dāng)程序應(yīng)當(dāng)執(zhí)行的路徑插入斷點(diǎn)。第二類調(diào)試流程是幫助回答“我看到的這一數(shù)值是從哪里來(lái)的?”這一問(wèn)題。在這種情況下,人們往往依靠寄存器顯示窗口觀察變量信息、處理器內(nèi)存的內(nèi)容。人們還可以嘗試單步執(zhí)行,并且觀察所有這些數(shù)據(jù)窗口以了解某個(gè)寄存器狀態(tài)何時(shí)出現(xiàn)錯(cuò)誤,內(nèi)存位置何時(shí)得到錯(cuò)誤的數(shù)據(jù),抑或指針何時(shí)出現(xiàn)了誤用。

  當(dāng)開發(fā)商寫完全部代碼后,如果無(wú)需了解網(wǎng)絡(luò)基礎(chǔ)設(shè)施,也沒有操作的任務(wù)調(diào)度需要考慮,那么就可以利用這些調(diào)試方法使一個(gè)應(yīng)用程序運(yùn)行起來(lái)。然而,現(xiàn)在的情況并非如此。處理器以超過(guò)600 MHz的速度運(yùn)行,并且擁有可支持Ethernet和USB等協(xié)議的外設(shè),它們支持功能齊備的操作,例如uClinux,而且這些操作所調(diào)度的各種應(yīng)用程序是由數(shù)千行代碼構(gòu)成。使用打印語(yǔ)句和利用LED來(lái)調(diào)試是不現(xiàn)實(shí)的,因?yàn)楝F(xiàn)在常常有如此之多的功能在執(zhí)行是不可能的,或者它們會(huì)影響標(biāo)準(zhǔn)I/O口,從而造成處理器性能大幅度下降。

  也可能發(fā)生這樣的情況:處理器的工作速度是如此之快,以至于LED的亮滅速度會(huì)快到人眼無(wú)法察覺。另外現(xiàn)代的嵌入式系統(tǒng)通常支持?jǐn)帱c(diǎn)的設(shè)定,但是伴隨這些處理器所運(yùn)行的代碼數(shù)量,使得這種類型的斷點(diǎn)調(diào)試難以駕馭。中斷和多線程系統(tǒng)在代碼的任何一點(diǎn)上設(shè)置一個(gè)斷點(diǎn),可能都無(wú)法指示系統(tǒng)的正確狀態(tài)。由于斷點(diǎn)設(shè)置在物理內(nèi)存的某個(gè)地址上,索引不必了解線程的狀態(tài)。如果使用寄存器顯示方法,那么局部變量窗口和內(nèi)存窗口都將有助于隔離出所載入的不恰當(dāng)?shù)牧恐?,但是,由于這些是靜態(tài)化的工具,不能給出有意義的運(yùn)行中的調(diào)試信息,其適用性也常常很有限。

  嵌入式系統(tǒng)最常見的調(diào)試問(wèn)題可以大致劃分為如下幾類:

  1. 同步問(wèn)題

  2. 內(nèi)存和寄存器訛誤(corruption)

  3. 與中斷相關(guān)的問(wèn)題

  4. 硬件配置問(wèn)題

  5. 異常情況

  同步問(wèn)題

  在任何系統(tǒng)中,只要有多串序線程或者進(jìn)程都在運(yùn)行,而且是異步共享數(shù)據(jù),則系統(tǒng)必然存在同步問(wèn)題。對(duì)于共享數(shù)據(jù)的全部操作必須是原子化的,也就是說(shuō),只有在一個(gè)線程或者進(jìn)程完成對(duì)數(shù)據(jù)的操作后,其它的線程才能對(duì)數(shù)據(jù)進(jìn)行操作。

  以圖1為例,線程A和線程B對(duì)共享變量“counter”進(jìn)行操作,A讓counter 增加,而B則讓counter減少。下方示出了線程A的counter++和線程B counter—的匯編代碼。假設(shè)線程B的優(yōu)先級(jí)要高于線程A,而線程A目前正在運(yùn)行,則線程B將被阻止。

  


  舉例來(lái)說(shuō),假設(shè)初始的計(jì)數(shù)值是2,而線程A是執(zhí)行線程。則線程A讀入計(jì)數(shù)值,并送入一個(gè)寄存器,在使其增加一個(gè)增量后,再將其寫回計(jì)數(shù)器變量上。

  在可搶先的多線程系統(tǒng)中,高優(yōu)先級(jí)的線程的執(zhí)行可以搶先于低優(yōu)先級(jí)的線程。例如,假定線程A執(zhí)行Reg1 = Reg1+1指令后,一個(gè)事件喚醒線程B。此時(shí),Reg1儲(chǔ)存量值3?,F(xiàn)在線程B被喚醒(正如藍(lán)線所標(biāo)示的那樣),并讀入計(jì)數(shù)器的量值2(它尚未被線程A刷新)并將其量值減小到1。正如棕色的線所顯示的那樣,經(jīng)過(guò)一段時(shí)間,線程A恢復(fù)運(yùn)行,將Reg1寫入計(jì)數(shù)器中,而該計(jì)數(shù)器的儲(chǔ)存量值為3。 在這個(gè)過(guò)程中,線程B的減量操作結(jié)果被丟棄。計(jì)數(shù)器存儲(chǔ)的量值變?yōu)?,即線程A進(jìn)行一次增量后,線程B又進(jìn)行了一次減量操作。被竄改的鏈接表則是另一個(gè)例子。如果數(shù)據(jù)被一個(gè)線程和中斷例程共享,則也會(huì)出現(xiàn)上面的問(wèn)題,因?yàn)橹袛嗟膱?zhí)行與線程的執(zhí)行之間是異步關(guān)系。

  同步化方面的問(wèn)題常常是很難進(jìn)行調(diào)試的,因?yàn)樗鼈內(nèi)Q于時(shí)序,是隨著對(duì)數(shù)據(jù)的操作而隨機(jī)出現(xiàn)的。幸運(yùn)的是,這些問(wèn)題可以通過(guò)恰當(dāng)?shù)乇Wo(hù)任何共享數(shù)據(jù)來(lái)避免。大多數(shù)的操作系統(tǒng)可以提供同步化原語(yǔ)。開發(fā)商 可以使用最適當(dāng)?shù)臋C(jī)制來(lái)保護(hù)共享數(shù)據(jù),而不至于影響系統(tǒng)的性能。如果數(shù)據(jù)在多個(gè)線程之間共享,則開發(fā)商將有如下的選擇:

  a. 關(guān)閉調(diào)度器以便當(dāng)前的線程永遠(yuǎn)不會(huì)被其它線程搶先。(無(wú)調(diào)度區(qū))

  b. 使用信號(hào)兩(Semaphore)或者互斥信號(hào)量(Mutex)來(lái)保護(hù)共享數(shù)據(jù)。

  c. 利用關(guān)鍵區(qū)域來(lái)進(jìn)行保護(hù),即屏蔽所有的中斷。

  

  開發(fā)商必須從性能出發(fā)來(lái)選擇恰當(dāng)?shù)募夹g(shù)選項(xiàng)。關(guān)閉調(diào)度器,將防止任何一種環(huán)境的切換,從而使得現(xiàn)在的線程能繼續(xù)執(zhí)行,直到調(diào)度器重新打開為止。這種方法有一個(gè)負(fù)面的影響:它將阻止任何準(zhǔn)備好運(yùn)行的高優(yōu)先級(jí)的線程。這一現(xiàn)象被稱為優(yōu)先級(jí)倒置。將中斷關(guān)閉是最安全的方法,對(duì)于執(zhí)行時(shí)間短的情形來(lái)說(shuō)是理想選擇。于是,最差情況的中斷延遲就是所有未發(fā)生中斷的持續(xù)時(shí)間的總和。在硬系統(tǒng)中,一般來(lái)說(shuō),一個(gè)中斷功能可以被關(guān)閉的時(shí)間存在上限。

  調(diào)試的一個(gè)小竅門就是,如果共享的數(shù)據(jù)被破壞,則編程者就應(yīng)當(dāng)首先檢查出任何一種多個(gè)線程或者中斷對(duì)共享數(shù)據(jù)同時(shí)進(jìn)行的操作。如果線程和中斷共享了數(shù)據(jù),那么在線程代碼中必須將中斷關(guān)閉。如果數(shù)據(jù)在多個(gè)中斷例程之間共享的話,則中斷也應(yīng)當(dāng)被關(guān)閉,因?yàn)楦邇?yōu)先級(jí)的中斷可以搶先于低優(yōu)先級(jí)的中斷。

  在多線程的系統(tǒng)中,高優(yōu)先級(jí)的線程可以搶在低優(yōu)先級(jí)的線程之前執(zhí)行。因此,如果數(shù)據(jù)在多個(gè)線程間共享的話,則必須采用某種恰當(dāng)?shù)臋C(jī)制來(lái)保護(hù)被共享的數(shù)據(jù)。

  另外一個(gè)同步化問(wèn)題則與線程優(yōu)先級(jí)的不恰當(dāng)?shù)姆峙溆嘘P(guān)。應(yīng)當(dāng)確保系統(tǒng)的初始化線程在引導(dǎo)時(shí)間內(nèi)就啟動(dòng),并在生成其它的優(yōu)先級(jí)更高的線程之前,完成整個(gè)系統(tǒng)的初始化。例如,如果一個(gè)用于配置一個(gè)器件的低優(yōu)先級(jí)現(xiàn)場(chǎng)被一個(gè)使用該設(shè)備的高優(yōu)先級(jí)的線程搶先后,配置可能會(huì)完成,并可能會(huì)造成設(shè)備的故障。為了避免這種情形,開發(fā)商應(yīng)當(dāng)使用操作系統(tǒng)所支持的信號(hào)量或者其它同步化的原語(yǔ)。

linux操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)

上一頁(yè) 1 2 3 下一頁(yè)

評(píng)論


相關(guān)推薦

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

關(guān)閉