1. 程式人生 > 其它 >【RTOS】RTOS原始碼基礎之佇列結構體

【RTOS】RTOS原始碼基礎之佇列結構體

目錄

前言

以下 RTOS 是基於 FreeRTOS 原始碼分析。
建議直接看原始碼去了解。

李柱明部落格:https://www.cnblogs.com/lizhuming/p/15487239.html

IPC

本人認為在學習 RTOS 任務間通訊時必須瞭解的一個結構體就是 struct QueueDefinition,其原始碼參考 附件-原始碼。
該結構體被運用到訊息佇列、二進位制訊號量、計數訊號量、互斥量和遞迴互斥量等等關於任務間通訊的控制元件。

這些控制元件在系統中都是由 控制塊 + 儲存區 組成,而該結構體就是控制塊的角色,管理其對應的儲存區。

成員剖析

在成員剖析時預設按訊息佇列的作用去剖析。

int8_t *pcHead;:

/* 該佇列儲存區的起始位置,對應第一個訊息空間。*/
int8_t *pcHead;

int8_t *pcTail;:

/* 訊息佇列儲存區的結尾位置。
 * 結合 pcHead 指標就是整個儲存區合法區域。*/
int8_t *pcHead;

int8_t *pcWriteTo;:

/* 寫指標,指向儲存區中下一個空閒的空間。
 * 佇列下次寫資料的位置,需要入隊時呼叫該指標寫入資料。*/
int8_t *pcWriteTo;

int8_t *pcReadFrom;:

/* 讀指標,指向儲存區中下一個有效資料的空間。
 * 佇列下次讀取資料的位置,需要出隊時呼叫該指標寫入資料。*/
int8_t *pcReadFrom;

UBaseType_t uxRecursiveCallCount;:

/* 遞迴次數。
 * 用於互斥量時使用,與 pcReadFrom 為聯合體。
 * 記錄遞迴互斥量被呼叫的次數。 */
UBaseType_t uxRecursiveCallCount;

List_t xTasksWaitingToSend;:

/* 等待發送的任務列表。
 * 當佇列儲存區滿時,需要傳送訊息的任務阻塞時記錄到該連結串列。
 * 按任務優先順序排序。 */
List_t xTasksWaitingToSend;

List_t xTasksWaitingToReceive;:

/* 等待接收的任務列表。
 * 當佇列儲存區為空時,需要獲取訊息的任務阻塞時記錄到該連結串列。
 * 按任務優先順序排序。 */
List_t xTasksWaitingToReceive;

volatile UBaseType_t uxMessagesWaiting;:

/* 當前訊息節點的個數。
 * 即是當前有效訊息數量。
 * 二值訊號量、互斥訊號量時:表示有無訊號量可用。
 * 計數訊號量時:有效訊號量個數。 */
volatile UBaseType_t uxMessagesWaiting;

UBaseType_t uxLength;:

/* 當前佇列最大節點總數。
 * 即是最多能存放多少個訊息。
 * 二值訊號量、互斥訊號量時:最大為1。
 * 計數訊號量時:最大的訊號量個數。 */
UBaseType_t uxLength;

UBaseType_t uxItemSize;:

/* 單個節點的大小。
 * 單個訊息的大小。
 * 二值訊號量、互斥訊號量時:0。
 * 計數訊號量時:0。 */
UBaseType_t uxItemSize;

volatile int8_t cRxLock;:

/* 記錄出隊的資料項個數。
 * 即是需要解除多少個阻塞在接收等待列表中的任務。 */
volatile int8_t cRxLock;

volatile int8_t cTxLock;:

/* 記錄入隊的資料項個數。
 * 即是需要解除多少個阻塞在傳送等待列表中的任務。 */
volatile int8_t cTxLock;

cRxLock 和 cTxLock

當中斷服務程式操作佇列並且導致阻塞的任務解除阻塞時。
首先判斷該佇列是否上鎖:

  • 如果沒有上鎖,則解除被阻塞的任務,還會根據需要設定上下文切換請求標誌;
  • 如果佇列已經上鎖,則不會解除被阻塞的任務,取而代之的是,將 xRxLock 或 xTxLock 加 1,表示佇列上鎖期間出隊或入隊的數目,也表示有任務可以解除阻塞了。

cRxLock 對應待出隊的個數。
cTxLock 對應待入隊的個數。

觸發解除阻塞

觸發解除阻塞的方式:

  • 收發訊息。

    • 即是資料項出入隊時,會觸發阻塞的任務解除阻塞。
  • 超時。

    • 超時也會觸發對應的阻塞任務解除阻塞。
  • 解鎖後處理上鎖時未處理的出入隊。

    • cRxLock 和 cTxLock。

附件-原始碼

/*
 * Definition of the queue used by the scheduler.
 * Items are queued by copy, not reference.  See the following link for the
 * rationale: http://www.freertos.org/Embedded-RTOS-Queues.html
 */
typedef struct QueueDefinition
{
	int8_t *pcHead;					/*< Points to the beginning of the queue storage area. */
	int8_t *pcTail;					/*< Points to the byte at the end of the queue storage area.  Once more byte is allocated than necessary to store the queue items, this is used as a marker. */
	int8_t *pcWriteTo;				/*< Points to the free next place in the storage area. */

	union							/* Use of a union is an exception to the coding standard to ensure two mutually exclusive structure members don't appear simultaneously (wasting RAM). */
	{
		int8_t *pcReadFrom;			/*< Points to the last place that a queued item was read from when the structure is used as a queue. */
		UBaseType_t uxRecursiveCallCount;/*< Maintains a count of the number of times a recursive mutex has been recursively 'taken' when the structure is used as a mutex. */
	} u;

	List_t xTasksWaitingToSend;		/*< List of tasks that are blocked waiting to post onto this queue.  Stored in priority order. */
	List_t xTasksWaitingToReceive;	/*< List of tasks that are blocked waiting to read from this queue.  Stored in priority order. */

	volatile UBaseType_t uxMessagesWaiting;/*< The number of items currently in the queue. */
	UBaseType_t uxLength;			/*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
	UBaseType_t uxItemSize;			/*< The size of each items that the queue will hold. */

	volatile int8_t cRxLock;		/*< Stores the number of items received from the queue (removed from the queue) while the queue was locked.  Set to queueUNLOCKED when the queue is not locked. */
	volatile int8_t cTxLock;		/*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked.  Set to queueUNLOCKED when the queue is not locked. */

	#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
		uint8_t ucStaticallyAllocated;	/*< Set to pdTRUE if the memory used by the queue was statically allocated to ensure no attempt is made to free the memory. */
	#endif

	#if ( configUSE_QUEUE_SETS == 1 )
		struct QueueDefinition *pxQueueSetContainer;
	#endif

	#if ( configUSE_TRACE_FACILITY == 1 )
		UBaseType_t uxQueueNumber;
		uint8_t ucQueueType;
	#endif

} xQUEUE;