[英]Thread stack overflow
在像我們創建任務的vxworks這樣的RTO中,指定了stacksize。 我們可以在C中編寫一個例程來檢查堆棧是否溢出或者沒有執行任務嗎?
看看你的編譯器,他們經常讓你添加prelude函數來做這個,或者他們甚至可以自己檢查它,除非你操作堆棧指針寄存器。
並檢查操作系統是否允許您安裝“guard-pages”。 將線程堆棧中的最后一頁標記為非讀取/非寫入並捕獲SIGSEGV信號並使用特定於OS / CPU的方式來確定它是否是失敗的保護頁面。 為此,您必須確保函數的堆棧幀(堆棧傳遞參數,局部變量和alloca分配的空間)始終小於頁面大小,否則您可以跳過“guard-page”這是最好的方法處理它,因為它在正常處理期間沒有運行時開銷。
你會看到這種高度的OS / CPU /編譯器依賴。 但我很確定谷歌會為所有系統找到可用的代碼和幫助程序,因為它是低級程序員(例如運行時或解釋器實現者)的一種非常常見的技術。
如果你知道堆棧有多大,如果你小心,那么是(但不是便攜)。 如果沒有其他方法可以獲得堆棧的基址,則需要在線程的main函數中記錄堆棧變量的地址; 這使您可以近似堆棧的頂部。 然后,在您的檢查功能中,您獲取局部變量的地址; 這給了你堆棧的底部。 如果頂部和底部之間的差異與您的堆棧大小有關,那么現在是時候擔心; 如果差異大於堆棧大小,則擔心已經太晚了 - 損壞已經完成(但現在你需要考慮如何清理)。
僅供參考,您可以使用checkStack()從VxWorks中的shell執行類似的操作。
您可以使用一些技術 - 通常您有一個低優先級的任務,每隔一秒左右嗅探所有其他任務的堆棧狀態。
a:在任務開始之前,確保堆棧空間已填充已知模式。 然后,您可以通過檢查模式找出剩余多少“未損壞的”堆棧。
b:你可以簡單地嗅探所有其他線程的堆棧指針。
我建議兩者結合使用。 因為你正在使用像VxWorks TaskInfoGet()函數這樣的低級東西,所以很難使它甚至可以遠程移植。
我不知道VxWorks,但我的回憶是Green Hill的Velosity / uVelosity內核提供了執行此操作的代碼。 即使他們沒有,因為它們提供了用戶可以修改的源,並且基礎設施就在那里,所以很容易添加。
編輯:為了披露,我和他們一起做了一個夏季實習,將uVelosity移植到一個新的架構。 這就是我對線程堆棧處理的親密關系。
如果您的特定應用程序靜態分配其線程,則可以將其堆棧放置在靜態定義的區域中,並使用鏈接器映射將符號放置在這些區域的末尾。 然后,您只需要獲取當前的堆棧指針(如其他答案中所述),並將“堆棧段結束”指針與該地址進行比較。 如果每個線程都有一些位置來存儲作為其堆棧末尾提供給它的地址,那么這也適用於動態分配。
堆棧大小默認為1MB,具體取決於編譯器。 根據這些信息,您可以嘗試使用以下內容捕獲剩余的堆棧:
unsigned long remaining_stack_size() {
char dummy;
return 0x000fffff & (unsigned long)&dummy;
// 0x000fffff is 1MB -1 (1048576 -1)
}
編輯:請注意,它實際上返回當前堆棧位置,這是相同的事情。
編輯(2):對於那些說我錯了的人,這里有一個概念證明:
#include <stdio.h>
#include <windows.h>
unsigned long remaining_stack_size() {
char dummy;
return 0x001fffff & (unsigned long)&dummy + 1; // okay, some minor adjusts
}
void recurse_to_death(unsigned long used, char *p) {
char buf[32*1024];
used += 32*1024;
printf("Used: 0x%08x Remaining: 0x%08x\n", used, remaining_stack_size());
recurse_to_death(used, buf);
}
DWORD WINAPI my_thread(void *p) {
printf("Total stack size of this Thread: 0x%08x bytes\n", remaining_stack_size() + 72);
recurse_to_death(0, NULL);
return 0;
}
int main(int argc, char *argv) {
DWORD tid;
// CreateThread's stack size actually defaults to 1MB+64KB and does not honor lower values
CreateThread(NULL, NULL, my_thread, NULL, NULL, NULL);
Sleep(30000);
return 0;
}
remaining_stack_size()
預測堆棧溢出完美。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.