堆栈使用测量
文章目錄
- 1 堆棧使用測量
- 1.1 問題概述
- 1.2 設計原理
- 1.3 設計實現
1 堆棧使用測量
1.1 問題概述
我們知道在當前的設計中每個任務都配備一個有限的任務棧,用于保存各種關鍵性的數據。但是這個棧空間是有限的,實際有可能超出此空間。
可能出現如下錯誤:
1.2 設計原理
設計原理如下:
注意事項:
1.3 設計實現
清空堆棧空間:
統計堆棧使用情況:
需要修改task結構體:
// 任務結構:包含了一個任務的所有信息 typedef struct _tTask {// 任務所用堆棧的當前堆棧指針。每個任務都有他自己的堆棧,用于在運行過程中存儲臨時變量等一些環境參數// 在tinyOS運行該任務前,會從stack指向的位置處,會讀取堆棧中的環境參數恢復到CPU寄存器中,然后開始運行// 在切換至其它任務時,會將當前CPU寄存器值保存到堆棧中,等待下一次運行該任務時再恢復。// stack保存了最后保存環境參數的地址位置,用于后續恢復uint32_t * stack;// 堆棧的起即地址uint32_t * stackBase;// 堆棧的總容量uint32_t stackSize;// 連接結點tNode linkNode;// 任務延時計數器uint32_t delayTicks;// 延時結點:通過delayNode就可以將tTask放置到延時隊列中tNode delayNode;// 任務的優先級uint32_t prio;// 任務當前狀態uint32_t state;// 當前剩余的時間片uint32_t slice;// 被掛起的次數uint32_t suspendCount;// 任務被刪除時調用的清理函數void (*clean) (void * param);// 傳遞給清理函數的參數void * cleanParam;// 請求刪除標志,非0表示請求刪除uint8_t requestDeleteFlag;// 任務正在等待的事件類型struct _tEvent * waitEvent;// 等待事件的消息存儲位置void * eventMsg;// 等待事件的結果uint32_t waitEventResult;// 等待的事件方式uint32_t waitFlagsType;// 等待的事件標志uint32_t eventFlags; }tTask;// 任務相關信息結構 typedef struct _tTaskInfo {// 任務延時計數器uint32_t delayTicks;// 任務的優先級uint32_t prio;// 任務當前狀態uint32_t state;// 當前剩余的時間片uint32_t slice;// 被掛起的次數uint32_t suspendCount;// 堆棧的總容量uint32_t stackSize;// 堆棧空余量uint32_t stackFree; }tTaskInfo;任務初始化函數和任務查詢接口也需要修改如下:
/********************************************************************************************************** ** Function name : tTaskInit ** Descriptions : 初始化任務結構 ** parameters : task 要初始化的任務結構 ** parameters : entry 任務的入口函數 ** parameters : param 傳遞給任務的運行參數 ** Returned value : 無 ***********************************************************************************************************/ void tTaskInit (tTask * task, void (*entry)(void *), void *param, uint32_t prio, uint32_t * stack, uint32_t size) {uint32_t * stackTop;// 為了簡化代碼,tinyOS無論是在啟動時切換至第一個任務,還是在運行過程中在不同間任務切換// 所執行的操作都是先保存當前任務的運行環境參數(CPU寄存器值)的堆棧中(如果已經運行運行起來的話),然后再// 取出從下一個任務的堆棧中取出之前的運行環境參數,然后恢復到CPU寄存器// 對于切換至之前從沒有運行過的任務,我們為它配置一個“虛假的”保存現場,然后使用該現場恢復。task->stackBase = stack;task->stackSize = size;memset(stack, 0, size);// 注意以下兩點:// 1、不需要用到的寄存器,直接填了寄存器號,方便在IDE調試時查看效果;// 2、順序不能變,要結合PendSV_Handler以及CPU對異常的處理流程來理解stackTop = stack + size / sizeof(tTaskStack);*(--stackTop) = (unsigned long)(1<<24); // XPSR, 設置了Thumb模式,恢復到Thumb狀態而非ARM狀態運行*(--stackTop) = (unsigned long)entry; // 程序的入口地址*(--stackTop) = (unsigned long)0x14; // R14(LR), 任務不會通過return xxx結束自己,所以未用*(--stackTop) = (unsigned long)0x12; // R12, 未用*(--stackTop) = (unsigned long)0x3; // R3, 未用*(--stackTop) = (unsigned long)0x2; // R2, 未用*(--stackTop) = (unsigned long)0x1; // R1, 未用*(--stackTop) = (unsigned long)param; // R0 = param, 傳給任務的入口函數*(--stackTop) = (unsigned long)0x11; // R11, 未用*(--stackTop) = (unsigned long)0x10; // R10, 未用*(--stackTop) = (unsigned long)0x9; // R9, 未用*(--stackTop) = (unsigned long)0x8; // R8, 未用*(--stackTop) = (unsigned long)0x7; // R7, 未用*(--stackTop) = (unsigned long)0x6; // R6, 未用*(--stackTop) = (unsigned long)0x5; // R5, 未用*(--stackTop) = (unsigned long)0x4; // R4, 未用task->slice = TINYOS_SLICE_MAX; // 初始化任務的時間片計數task->stack = stackTop; // 保存最終的值task->prio = prio; // 設置任務的優先級task->state = TINYOS_TASK_STATE_RDY; // 設置任務為就緒狀態task->suspendCount = 0; // 初始掛起次數為0task->clean = (void(*)(void *))0; // 設置清理函數task->cleanParam = (void *)0; // 設置傳遞給清理函數的參數task->requestDeleteFlag = 0; // 請求刪除標記task->waitEvent = (tEvent *)0; // 沒有等待事件task->eventMsg = (void *)0; // 沒有等待事件task->waitEventResult = tErrorNoError; // 沒有等待事件錯誤tNodeInit(&(task->delayNode)); // 初始化延時結點tNodeInit(&(task->linkNode)); // 初始化鏈接結點tTaskSchedRdy(task); // 將任務插入就緒隊列 }/********************************************************************************************************** ** Function name : tTaskGetInfo ** Descriptions : 獲取任務相關信息 ** parameters : task 需要查詢的任務 ** parameters : info 任務信息存儲結構 ** Returned value : 無 ***********************************************************************************************************/ void tTaskGetInfo (tTask * task, tTaskInfo * info) {uint32_t * stackEnd;// 進入臨界區uint32_t status = tTaskEnterCritical();info->delayTicks = task->delayTicks; // 延時信息info->prio = task->prio; // 任務優先級info->state = task->state; // 任務狀態info->slice = task->slice; // 剩余時間片info->suspendCount = task->suspendCount; // 被掛起的次數info->stackSize = task->stackSize;// 計算堆棧使用量info->stackFree = 0;stackEnd = task->stackBase;while ((*stackEnd++ == 0) && (stackEnd <= task->stackBase + task->stackSize / sizeof(tTaskStack))){info->stackFree++;}// 轉換成字節數info->stackFree *= sizeof(tTaskStack);// 退出臨界區tTaskExitCritical(status); }參考資料:
總結
- 上一篇: 固定资产清理账务处理增值税税率怎么算(固
- 下一篇: 关于时间的名言大全六年级(关于时间的名言