x64下longjmp函數有詭異?
為了做極小內存下的多任務程序,我用setjmp, longjmp做了一個協作式多任務,
https://github.com/xhawk18/setjmp_tasks實現方法是這樣的,用一個函數,函數內有一個局部數組,遞歸調用這個函數時,主程序棧將被 「撐開」。 每個任務的棧空間,來自每次 「撐開」 局部數組。
每次遞歸調用撐開棧空間的之前,用setjmp記錄下當前的運行上下文,下次再longjmp到這個位置,就可以當作一個子任務的入口。通過遞歸撐開棧,主程序的棧,實際上最終被劃分出來給子任務用 ---- | --- 任務1的棧 --- | --- 任務2的棧 --- | --- 任務3的棧 --- | ...如此,只要在各個任務之間,用setjmp/longjmp跳來跳去,就可以達到協作式多任務的目的。
問題來了,目前這個實現,在幾個系統下(8位機stm8單片機,32位cortex m0/m3單片機,win32下)都運行正常。但是編譯成64位windows程序會崩潰。經查,x64下,longjmp從棧頂到棧底方向跳,是沒有問題的;反過來跳,貌似程序會崩潰。不知道64位下,longjmp是否確實有跳轉方向限制?=====================================
補充一下,在linux x64下面,測試也沒發現問題。
像這種疑問,翻翻文檔就可以搞得很清楚。
C99/C11 §7.13.2.1/2
If there has been no such invocation, or if the function containing the invocation of the setjmp macro has terminated execution (For example, by executing a return statement or because another longjmp call has caused a transfer to a setjmp invocation in a function earlier in the set of nested calls.) in the interim, or if the invocation of the setjmp macro was within the scope of an identifier with variably modified type and execution has left that scope in the interim, the behavior is undefined.
加粗部分大意為:對 longjmp 的調用,如果對應的調用 setjmp 的函數已經終止運行,則為未定義行為。
你的代碼里,就有依賴「longjmp 到已退出的函數」的情況,比如:
void allocate_stack()
{
align_data_t stack[STACK_SIZE / sizeof(align_data_t)];
if (setjmp(JMP_BUF(g_jbuf_next)) == 0) {
longjmp(JMP_BUF(g_jbuf), 1); //Jump to the entry of created task
} else
run_task(stack /* Not use, just avoid warning */);
}
可見,「8 位機 stm8 單片機,32 位cortex m0/m3 單片機,win32 下都運行正常」只是湊巧沒有崩潰而已。
雖然不是很懂這些jump的底層細節,但是我覺得你用局部數組來hack調用棧的方法不太靠譜,畢竟C語言標準沒規定數組一定要存在棧上,甚至都沒提到調用棧這種東西
unwinding只能往棧基方向。
我也做過一樣的事,當時是51單片機,用彙編做的任務切換。每個任務的堆棧都是全局的,然後每個任務都負責一部分運算,測試時結果都和預期一樣。後來有任務的功能複雜了,就開始不停重啟,調好久發現是其中一個任務爆棧了,污染了其它的任務的堆棧,看門狗複位了。所以我覺得在小內存上,並行的多任務不太實用。你這個代碼的問題在於你沒辦法給每個任務分配唯一的堆棧空間,一旦longjmp後,longjmp之前setjmp之後做的所有操作全部付諸東流,包括分配的堆棧空間。所以longjmp和setjmp一般只用於異常處理。我覺得你之前的測試不奔潰,僅僅是不奔潰而已,代碼是否運行正確就不一定了。試著在你認為沒問題的機器上,寫三四個任務,然後每個任務都循環做一些簡單的四則運算,看看運行一段時間後,每個任務的輸出是否還是預期的。
推薦閱讀:
※RTOS如何保證局部變數被編譯器分配到堆棧里?
※如何評價中航計算機所研製的天脈操作系統?
※FPGA在圖像處理中的哪一步起到重要作用?
※是否可以用fpga搭建一個可以用的gpu模型?
TAG:C編程語言 | 嵌入式系統 | 多任務 | X編程語言有什麼奇技淫巧 |