大概記錄下這個函數的過程以便於繼續分析,類似於偽代碼
xQueue: 隊列句柄,指明要向哪個隊列發送數據,創建隊列成功以后會返回此隊列的 隊列句柄。
pvItemToQueue:指向要發送的消息,發送的過程中會將這個消息拷貝到隊列中。
xTicksToWait : 阻塞時間。
xCopyPosition: 入隊方式
有三種入隊方式:
queueSEND_TO_BACK: 后向入隊
queueSEND_TO_FRONT: 前向入隊
queueOVERWRITE: 覆寫入隊。
隊列結構體主要部分(省略了隊列集):
進入臨界段后:
uxMessagesWaiting<uxLength 判斷隊列是否滿,(或覆寫入隊不考慮這個,但是一般不用覆寫入隊)
1 若隊列滿,且沒有阻塞時間,直接退出臨界段返回隊列滿。
2 若隊列未滿,則寫memcpy入隊,分為前入隊 后入隊 覆寫入隊 (deemo用的back)
后:寫入位置:pcWriteTo //初始化為隊列起始pcHead。 隨后更新pcWriteTo
前:寫入位置:u.pcReadFrom //初始化為隊列末尾pcTail(-1)。隨后更新u.pcReadFrom
覆寫:寫入位置:u.pcReadFrom //初始化為隊列末尾 ,隨后更新u.pcReadFrom並uxMessagesWaiting-- 因為覆寫不會改變長度
最后更新uxMessagesWaiting。當前隊列中消息數
入隊之后,相當於更新了隊列,需要判斷等待消息阻塞列表 list中 ,有沒有在等消息的任務,
有的話,因為剛剛消息已經入隊了,可以將其移除並放到就緒任務列表中,判斷移除的任務與當前任務的優先級,是否進行任務切換。
(若需要,則立即進行任務切換pendSV,與xTaskIncrementTick不同,這個是執行完之后再切換)
假如此時調度器上鎖,則不判斷優先級並將其放到掛起就緒列表。//uxSchedulerSuspended判斷是否上鎖
以上涉及到的幾個list:
xTasksWaitingToReceive (xTimerQueue成員)//等待消息阻塞列表 ,或稱等待接受消息的任務列表
pxReadyTasksLists(全局)// 就緒列表,注意是加到對應優先級的就緒列表
xPendingReadyList(全局)//掛起就緒列表
從列表中移除任務的過程:先獲取TCB,( (&( ( xTasksWaitingToSend )->xListEnd ))->pxNext->pvOwner )
然后鏈表操作,刪除TCB中的事件列表項 xEventListItem(列表項知道自己在那個列表,調度過程中會判斷是否在等待某個事件,刪除為NULL)
(列表按照升值排列列表項)
在這里退出臨界段。
3 若隊列滿,且設置了阻塞時間,阻塞時間為最大值
任務掛起vTaskSuspendAll,隊列上鎖,將狀態列表項 pxCurrentTCB->xGenericListItem掛到掛起列表xSuspendedTaskList 隊列上鎖
4若隊列滿,且設置了阻塞時間,阻塞時間為某個值
任務掛起vTaskSuspendAll,隊列上鎖,將狀態列表項 pxCurrentTCB->xGenericListItem掛到延時列表pxDelayedTaskList, 隊列上鎖並開始等待
有關延時列表和溢出延時列表暫不展開
等待:檢測隊列是否滿,檢測是否到達預定阻塞時間
計時方式:
獲取當前xTickCount 以及xNumOfOverflows
判斷當前時間是否達到預計時間, 若達到解鎖隊列,恢復調度器xTaskResumeAll
預計時間xTicksToWait會在每次獲取xTickCount 后更新減少。因為后續會會在新的xTickCount 的基礎上計算xTimeToWake
xTickCount 是系統滴答定時器會在中斷服務里遞增。(xTaskIncrementTick)
若在等待的過程中,隊列有空閑,解鎖隊列,恢復調度器(每次進入 入隊函數會嘗試發送,try again)
以上涉及到的list
掛起列表xSuspendedTaskList
延時列表pxDelayedTaskList
溢出延時列表pxOverflowDelayedTaskList