本文檔目的在于探究部分QT程序在嵌入式板子上出現(xiàn)Bus Error問題的調(diào)試及解決方法;
以數(shù)碼相框程序出現(xiàn)的Bus Error為例;
2.1 產(chǎn)生Bus Error的可能原因:
Bus Error即總線錯誤, Bus Error通常都是因為非對齊訪問造成的。CPU在設(shè)計上為了性能上的考慮,要求待訪問,操作的數(shù)據(jù)地址都要對齊。如果發(fā)現(xiàn)沒有對齊的訪問,就會向當(dāng)前進程發(fā)出SIGBUS信號,使程序崩潰。RISC包括MIPS都是這種類型的芯片。而X86架構(gòu)就沒有這種對齊要求。所以代碼在嵌入式環(huán)境下有總線錯誤而在X86下面可能就沒有問題,當(dāng)然這是有性能的代價。
Bus Error的產(chǎn)生除了上邊提到的訪問數(shù)據(jù)地址對齊問題之外,還可能是因為一下原因:
1 機器物理問題或者訪問無效物理地址,但這種情況非常少見。
2 Linux平臺上執(zhí)行malloc(),如果沒有足夠的RAM,Linux不是讓malloc()失敗返回,
而是向當(dāng)前進程分發(fā)SIGBUS信號。
3 某些架構(gòu)上訪問數(shù)據(jù)時有對齊的要求,比如只能從4字節(jié)邊界上讀取一個4字節(jié)的數(shù)據(jù)類型。IA-32架構(gòu)沒有硬性要求對齊,盡管未對齊的訪問降低執(zhí)行效率。另外一些架構(gòu),比如SPARC、m68k,要求對齊訪問,否則向當(dāng)前進程分發(fā)SIGBUS信號。
SIGBUS與SIGSEGV(產(chǎn)生段錯誤Segment fault)信號一樣,可以正常捕獲。SIGBUS的缺省行為是終止當(dāng)前進程并產(chǎn)生core dump。
SIGBUS與SIGSEGV信號的一般區(qū)別如下:
1 SIGBUS(Bus error)意味著指針?biāo)鶎?yīng)的地址是有效地址,但總線不能正常使用該
指針。通常是未對齊的數(shù)據(jù)訪問所致。
2 SIGSEGV(Segment fault)意味著指針?biāo)鶎?yīng)的地址是無效地址,沒有物理內(nèi)存對
應(yīng)該地址。
2.2 數(shù)碼相框產(chǎn)生Bus Error的調(diào)試:
經(jīng)過查找資料:嵌入式板子上如果程序初始化運行無任何調(diào)試數(shù)據(jù)輸出即馬上出現(xiàn)Bus Error,則很大原因是由于交叉編譯環(huán)境中的庫和文件系統(tǒng)里庫的不一致,或者編譯的參數(shù)有問題之類的原因?qū)е碌姆菍R訪問數(shù)據(jù)地址。重新配置好編譯參數(shù)及更新文件系統(tǒng)內(nèi)的庫一般都能解決問題;
而數(shù)碼相框出現(xiàn)的Bus Error問題并不是上邊提到的情況,而是當(dāng)板上數(shù)碼相框程序在運行后,自動播放圖片并有特效切換時不定時間出現(xiàn)Bus Error,經(jīng)過打印調(diào)試信息,并未定位到Bus Error出現(xiàn)的確定位置,但是分析調(diào)試信息,可定位到兩個位置,其一為在定時器QTimer或者動畫類QtimeLine觸發(fā)的特效實現(xiàn)槽函數(shù)運行結(jié)束時出現(xiàn),其運行結(jié)束后會調(diào)用系統(tǒng)的畫圖事件函數(shù),然后數(shù)碼相框在畫圖事件中實現(xiàn)圖片的顯示;另一個位置為在畫圖事件中實現(xiàn)填充區(qū)域的QPainter成員函數(shù)fillRect()時出現(xiàn)Bus Error。
QT中QTimer類提供了定時器信號和單觸發(fā)定時器。它在內(nèi)部使用定時器事件來提供更通用的定時器。QTimer很容易使用:創(chuàng)建一個QTimer,使用start()來開始并且把它的timeout()連接到適當(dāng)?shù)牟?。?dāng)這段時間過去了,它將會發(fā)射timeout()信號。而QtimeLine也有相同的機制。我們通過連接信號與槽函數(shù),實現(xiàn)了時間間隔改變圖片的顯示,從而實現(xiàn)圖片切換特效。
從實際出發(fā),分析數(shù)碼相框程序中代碼的執(zhí)行效率,可以發(fā)現(xiàn)數(shù)碼相框從圖片文件中加載數(shù)據(jù)到緩存,以及畫圖事件中圖片的顯示均需要占用系統(tǒng)大部分資源來實現(xiàn),由于數(shù)碼相框程序中為了實現(xiàn)比較流暢的特效,定時器及動畫的間隔均設(shè)置的很短,時間約10ms~30ms出發(fā)一次畫圖,這時候便要求系統(tǒng)在這個時間間隔內(nèi)能順利的實現(xiàn)圖片的顯示,若在這個時間間隔內(nèi)系統(tǒng)無法完全執(zhí)行完畫圖事件,則定時到時間系統(tǒng)又重新調(diào)用槽函數(shù)進入畫圖事件,可能會導(dǎo)致重入的問題。
由于當(dāng)系統(tǒng)試圖訪問一塊無文件內(nèi)容對應(yīng)的內(nèi)存區(qū)域,比如超過文件尾的內(nèi)存區(qū)域,或者以前有文件內(nèi)容對應(yīng),現(xiàn)在為另一進程截斷過的內(nèi)存區(qū)域則會發(fā)生Bus Error,那么可以猜測數(shù)碼相框可能是由于函數(shù)重入問題導(dǎo)致的Bus Error,調(diào)試一下,先在數(shù)碼相框中對定期器及動畫類觸發(fā)的槽函數(shù)做以下處理:定時器定時觸發(fā)槽函數(shù),進入槽函數(shù)關(guān)閉定時器,實現(xiàn)槽函數(shù)后再開啟定時器,同理,動畫類可以用暫停的方式;用此方法避免函數(shù)重入的問題,再交叉編譯到板子上進行測試,發(fā)現(xiàn)程序穩(wěn)定性有所提高,但是依然有Bus Error問題出現(xiàn),分析調(diào)試信息,此時發(fā)現(xiàn)第一種情況出現(xiàn)Bus Error的問題得到解決,現(xiàn)在程序的Bus Error集中到第二個位置,即在畫圖事件中實現(xiàn)填充區(qū)域的QPainter成員函數(shù)fillRect()時出現(xiàn)Bus Error。
分析QT源碼,fillRect實現(xiàn)方式如下:
fillRect(r, Qt::SolidPattern);
--->
setBrush(Qt::SolidPattern); drawRect(r);
--->
inline void QPainter::drawRect(const QRectF &rect)
{
drawRects(&rect, 1);
}
--->
void QPainter::drawRects(const QRect *rects, int rectCount)
{
…
}
QT源碼中對于類的包裝導(dǎo)致我們比較難分析出其如何具體操作硬件,而且并不是每一次執(zhí)行此行代碼都會導(dǎo)致Bus Error,故猜測可能程序某些客觀存在的指針導(dǎo)致其實現(xiàn)fillRect偶然性出現(xiàn)未對齊的數(shù)據(jù)訪問。故對于數(shù)碼相框項目而言,我們暫時采取用其他方式填充屏幕區(qū)域:設(shè)置黑色背景圖的方式,再經(jīng)過測試,數(shù)碼相框程序終于能比較穩(wěn)定的運行了。
由于并未聯(lián)系loongson1B開發(fā)板底層的實現(xiàn)來分析Bus Error,故并沒有真正探究到Bus Error出現(xiàn)的原因是硬件上、底層軟件上或者確實是程序本身的原因,所以此文檔有待補充。
聯(lián)系客服