??
字號:
關于中斷處理的系列問題
中斷的任務被調度后,再度獲得運行時是從任務被中斷處執行。
中斷的任務被調度后,再度獲得運行時是從任務被中斷處執行。
在中斷ISR中調用OSIntExit(), 在OSIntExit()中又調用OSIntCtxSW(),此時堆棧結構如下:
棧頂-->OSIntCtxSW()返回地址 2字節
OSIntExit()返回地址 2字節
SP-4-->保存寄存器PUSHALL
中斷斷點(任務返回地址)
。。。
可見SP-4就是寄存器信息和中斷返回地址,OSCtxSw()彈棧后就回到了任務斷點。
KEIL調用函數時壓入堆棧的就是2字節的返回地址。
中斷剩余部分沒有被跳過,準確的說是被OSCtxSw借用了。它的內容只有POPALL和RETI,此處沒有錯誤。
中斷完成后有可能使某些資源滿足,導致阻塞任務就緒,因此要進行任務調度,這樣中斷返回后的任務就不一定是這個被中斷的任務了。
***************************************************************************************************
在UCOS 中典型的中斷處理被建議成如下:
void OSTickISR(void)
{
保存處理器寄存器的值;
調用OSIntEnter()或是將OSIntNesting加1;
調用OSTimeTick();
調用OSIntExit();
恢復處理器寄存器的值;
執行中斷返回指令;
}
你的程序也是這么做的:
OSTickISR:
USING 0
PUSHALL
CLR TR0
MOV TH0,#70H ;定義Tick=50次/秒(即0.02秒/次)
MOV TL0,#00H ;OS_CPU_C.C 和 OS_TICKS_PER_SEC
SETB TR0
LCALL _?OSIntEnter
LCALL _?OSTimeTick
LCALL _?OSIntExit
POPALL
RETI
這樣好象有問題,我覺得“ 調用OSIntEnter()或是將OSIntNesting加1;”應放在中斷的第一條語句來執行,以保證在被更高級別中斷打斷之前將OSIntNesting加1,以避免在高級別中斷中發生任務切換。
如果在“保存處理器寄存器的值”時被打斷;發生任務切換,何時再返回到被打斷的中斷程序很難講了,從切換的原理,好象當被中斷打斷了的任務再次運行時,應是從被高級別中斷打斷的低級別中斷程序里面的斷點處繼續運行,即回到中斷程序把其余下的部分執行完,再返回任務。( 這樣理解請楊大師仔細批評指正一下), 這樣,中斷處理的時間太長了。中斷失去了意義。
對!“ 調用OSIntEnter()或是將OSIntNesting加1;”應放在中斷的第一條語句來執行。我當時沒有考慮清楚,這是又一個BUG。
你的理解正確。
中斷處理延遲在OS里是很常見的現象,最大中斷處理延遲是評價OS性能的重要指標。這說明CPU的負荷能力是有限的,工程上以最大中斷處理延遲為指標選擇CPU速度,只要延遲在允許的范圍內就可以接受。如果“中斷處理的時間太長了,中斷失去了意義”,那么說明所選CPU的能力不夠。
在理解OS工作原理的時候,不要想得太理想化,否則總是不得要領,你的思維定勢會誤導你的思考。注意計算機是個離散數字系統,它不能連續運行。有些觀念應該確立,例如:單CPU系統在微觀上串行,在宏觀上并發;實時指在一定時間范圍內完成任務;中斷處理必然有延遲等等。
不是你沒考慮清楚,而是UCOS 邵貝貝翻譯的UCOS 書里也是這么寫的,不知UCOS 源碼是依據此而產生一些BUGS?
而且您設計的調度方案,當程序任務再度運行時,是直接返回到任務。而不是返回到中斷里, 所以當任務再度運行時是回到任務去的,中斷剩余部分就被跳過去了。如果中斷剩余部分有重要的內容,那就有BUG了。
這樣理解對不對呢?
uC/OS-II一進入中斷,理論上應立即原語執行OSIntNesting+1,以便后續中斷了解中斷嵌套情況,不至于在中斷嵌套里切換任務。我認為原作此處是個BUG。有些CPU要求中斷后必須至少執行一條指令,這期間不會嵌套中斷,那么這條指令就可以是OSIntNesting+1原語操作或者關中斷(以便原語操作),這樣中斷嵌套就被嚴密監視了,不會漏掉導致判斷錯誤。
任務切換是通過模擬一次中斷實現的,它和硬件中斷產生的堆棧樣式相同。在中斷嵌套里不會執行任務切換,所有嵌套中斷都使用被中斷任務的堆棧空間,在最后一個中斷快要退出時進行任務調度。
此時中斷剩余部分只有兩個內容:POPALL和RETI,再沒有其他內容,更不用說重要內容了。如果不需調度,中斷正常完成,否則,保存現場到TCB,切換任務到高優先級。現場內容包括了斷點返回地址,中斷剩余部分沒有被跳過,它保存在此任務的TCB里,下次調度到此任務時,OSCtxSw借用這個中斷的剩余部分,直接返回到任務斷點繼續執行任務。因為OSCtxSw也是模擬一次中斷,棧與這個中斷的剩余部分一模一樣,可以直接借用。
中斷的重要工作均被完成后才會切換任務,最后一個中斷剩余的退出部分讓給OSCtxSw,假想成發生了一次切換中斷(切換中斷模擬的就是硬件中斷),而不是硬件中斷。
第一次任務切換時沒有中斷棧,就人工模擬一個。在硬件中斷里本身就有一個棧,那就直接拿過來用。
***************************************************************************************************
看了您的大作,對其中無任務切換中斷的處理好象有點想不通。你在串口中斷程序中不作任務切換,所以不調用OSIntEnter(),OSIntNesting沒增加;當有更高級別的中斷嵌套發生時,則有可能發生任務切換。這樣串口中斷的堆棧壓入和彈出分別在不同任務堆棧中,這樣是否會造成堆棧混亂?
是不是即使無任務切換中斷處理都應成對調用OSIntEnter()和 OSIntExit()?如果調用會有什么壞影響嗎?
SerialISR:
USING 0
PUSHALL
CLR EA
LCALL _?serial
SETB EA
POPALL
RETI
在以上串口中斷程序中,從SETB EA 之后到RETI之間,仍然可被高級別中斷打端,有可能發生任務切換。即使任務的堆棧不亂,那串口中斷程序何時能得以繼續運行也是問題,相當于中端程序中調了一個花費很長時間的子程序, 這樣理解對嗎?
同意你的觀點!
我主要是想節省一個任務號,同時提高效率,任務切換太費時間了,中斷的標準處理也比較煩瑣,所以當時采用了關閉中斷的臨界資源處理方式,現在看來這么做是有問題的,這是個BUG。你把它按標準中斷的處理方式做就可以解決這個問題。本來想偷機取巧來著,沒想到漏了破綻,呵呵。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -