最近在公司維護的項目中碰到一個解決了定位好久的 bug , bug 找到的時候發現犯了很低級的錯誤——在中斷處理函數中調用了 printf 函數,由於中斷處理函數的調用了不可重入函數,致使中斷丟失和系統位置錯誤,這裏直接致使嵌入式 linux 系統應用進程中的全部線程停掉,進而致使看門狗進程得不到喂狗,設備重啓。linux
就以上三個問題展開小短文:c++
可重入函數主要用於多任務環境中,一個可重入的函數簡單來講就是能夠被中斷的函數,也就是說,能夠在這個函數執行的任什麼時候刻中斷它,轉入 OS 調度下去執行另一段代碼,而返回控制時不會出現什麼錯誤;而不可重入的函數因爲使用了一些系統資源,好比全局變量區,中斷向量表等,因此它若是被中斷的話,可能會出現問題,這類函數是不能運行在多任務環境下的。segmentfault
知足下列條件的函數多數是不可重入的:數據結構
void strcpy(char *lpszDest, char *lpszSrc)
{
while(*lpszDest++=*lpszSrc++);///< 使用的局部變量
*dest=0;
}
char cTemp; ///< 全局變量
void SwapChar1(char *lpcX, char *lpcY)
{
cTemp=*lpcX;
*lpcX=*lpcY;
lpcY=cTemp; ///< 訪問了全局變量
}
void SwapChar2(char *lpcX,char *lpcY)
{
static char cTemp; ///< 靜態局部變量
cTemp=*lpcX;
*lpcX=*lpcY;
lpcY=cTemp; ///< 使用了靜態局部變量
}
在多任務系統下,中斷可能在任務執行的任什麼時候間發生;若是一個函數的執行期間被中斷後,到從新恢復到斷點進行執行的過程當中,函數所依賴的環境沒有發生改變,那麼這個函數就是可重入的,不然就不可重入。多線程
在中斷先後不都要保存和恢復上下文嗎,怎麼會出現函數所依賴的環境發生改變了呢?咱們知道中斷時確實保存一些上下文,可是僅限於返回地址,cpu 寄存器等之類的少許上下文,而函數內部使用的諸如全局或靜態變量,buffer 等並不在保護之列,因此若是這些值在函數被中斷期間發生了改變,那麼當函數回到斷點繼續執行時,其結果就不可預料了。併發
在中斷處理函數中調用有互斥鎖保護的全局變量,若是剛好該變量正在被另外一個線程調用,會致使中斷處理函數不能及時返回,致使中斷丟失等嚴重問題。ide
而且在多線程環境中使用,在沒有加鎖的狀況下,對同一段內存塊進行併發讀寫,就會形成 segmentfault/coredump 之類的問題。函數
總而言之,中斷處理函數作的事情越簡單越好。url