訊息佇列
在前一篇文章中【TencentOS tiny學習】原始碼分析(3)——佇列
我們描述了TencentOS tiny的佇列實作,同時也點出了TencentOS tiny的佇列是依賴于訊息佇列的,那么我們今天來看看訊息佇列的實作,
其實訊息佇列是TencentOS tiny的一個基礎組件,作為佇列的底層,
所以在tos_config.h中會用以下宏定義:
#if (TOS_CFG_QUEUE_EN > 0u)
#define TOS_CFG_MSG_EN 1u
#else
#define TOS_CFG_MSG_EN 0u
#endif
系統訊息池初始化
在系統初始化(tos_knl_init())的時候,系統就會將訊息池進行初始化,其中, msgpool_init()函式就是用來初始化訊息池的,該函式的定義位于 tos_msg.c檔案中,函式的實作主要是通過一個for回圈,將訊息池k_msg_pool[TOS_CFG_MSG_POOL_SIZE]的成員變數進行初始化,初始化對應的串列節點,并且將它掛載到空閑訊息串列上k_msg_freelist
初始化完成示意圖:(假設只有3個訊息)

__KERNEL__ void msgpool_init(void)
{
uint32_t i;
for (i = 0; i < TOS_CFG_MSG_POOL_SIZE; ++i) {
tos_list_init(&k_msg_pool[i].list);
tos_list_add(&k_msg_pool[i].list, &k_msg_freelist);
}
}
__API__ k_err_t tos_knl_init(void)
{
···
#if (TOS_CFG_MSG_EN) > 0
msgpool_init();
#endif
···
}
訊息佇列創建
這個函式在佇列創建中會被呼叫,當然他也可以自己作為用戶API介面提供給用戶使用,而非僅僅是內核API介面,
這個函式的本質上就是初始化訊息佇列中的訊息串列queue_head,
初始化完成示意圖:

__API__ k_err_t tos_msg_queue_create(k_msg_queue_t *msg_queue)
{
TOS_PTR_SANITY_CHECK(msg_queue);
#if TOS_CFG_OBJECT_VERIFY_EN > 0u
knl_object_init(&msg_queue->knl_obj, KNL_OBJ_TYPE_MSG_QUEUE);
#endif
tos_list_init(&msg_queue->queue_head);
return K_ERR_NONE;
}
訊息佇列銷毀
tos_msg_queue_destroy()函式用于銷毀一個訊息佇列,當訊息佇列不在使用是可以將其銷毀,銷毀的本質其實是將訊息佇列控制塊的內容進行清除,首先判斷一下訊息佇列控制塊的型別是KNL_OBJ_TYPE_MSG_QUEUE,這個函式只能銷毀佇列型別的控制塊,然后呼叫tos_msg_queue_flush()函式將佇列的訊息串列的訊息全部“清空”,“清空”的意思是將掛載到佇列上的訊息釋放回訊息池(如果訊息佇列的訊息串列存在訊息,使用msgpool_free()函式釋放訊息),并且通過tos_list_init()函式將訊息佇列的訊息串列進行初始化,knl_object_deinit()函式是為了確保訊息佇列已經被銷毀,此時訊息佇列控制塊的pend_obj成員變數中的type 屬性標識為KNL_OBJ_TYPE_NONE,
但是有一點要注意,因為佇列控制塊的RAM是由編譯器靜態分配的,所以即使是銷毀了佇列,這個記憶體也是沒辦法釋放的~
__API__ k_err_t tos_msg_queue_destroy(k_msg_queue_t *msg_queue)
{
TOS_PTR_SANITY_CHECK(msg_queue);
#if TOS_CFG_OBJECT_VERIFY_EN > 0u
if (!knl_object_verify(&msg_queue->knl_obj, KNL_OBJ_TYPE_MSG_QUEUE)) {
return K_ERR_OBJ_INVALID;
}
#endif
tos_msg_queue_flush(msg_queue);
tos_list_init(&msg_queue->queue_head);
#if TOS_CFG_OBJECT_VERIFY_EN > 0u
knl_object_deinit(&msg_queue->knl_obj);
#endif
return K_ERR_NONE;
}
__API__ void tos_msg_queue_flush(k_msg_queue_t *msg_queue)
{
TOS_CPU_CPSR_ALLOC();
k_list_t *curr, *next;
TOS_CPU_INT_DISABLE();
TOS_LIST_FOR_EACH_SAFE(curr, next, &msg_queue->queue_head) {
msgpool_free(TOS_LIST_ENTRY(curr, k_msg_t, list));
}
TOS_CPU_INT_ENABLE();
}
從訊息佇列獲取訊息
tos_msg_queue_get()函式用于從訊息佇列中獲取訊息,獲取到的訊息通過msg_addr引數回傳,獲取到訊息的大小通過msg_size引數回傳給用戶,當獲取成功是回傳K_ERR_NONE,否則回傳對應的錯誤代碼,
這個從訊息佇列中獲取訊息的函式是不會產生阻塞的,如果有訊息則獲取成功,否則就獲取失敗,它的實作程序如下:
TOS_CFG_OBJECT_VERIFY_EN 宏定義使能了,就呼叫knl_object_verify()函式確保是從訊息佇列中獲取訊息,然后通過TOS_LIST_FIRST_ENTRY_OR_NULL判斷一下是訊息佇列的訊息串列否存在訊息,如果不存在則回傳K_ERR_MSG_QUEUE_EMPTY表示訊息佇列是空的,反正將獲取成功,獲取成功后需要使用msgpool_free()函式將訊息釋放回訊息池,
__API__ k_err_t tos_msg_queue_get(k_msg_queue_t *msg_queue, void **msg_addr, size_t *msg_size)
{
TOS_CPU_CPSR_ALLOC();
k_msg_t *msg;
#if TOS_CFG_OBJECT_VERIFY_EN > 0u
if (!knl_object_verify(&msg_queue->knl_obj, KNL_OBJ_TYPE_MSG_QUEUE)) {
return K_ERR_OBJ_INVALID;
}
#endif
TOS_CPU_INT_DISABLE();
msg = TOS_LIST_FIRST_ENTRY_OR_NULL(&msg_queue->queue_head, k_msg_t, list);
if (!msg) {
TOS_CPU_INT_ENABLE();
return K_ERR_MSG_QUEUE_EMPTY;
}
*msg_addr = msg->msg_addr;
*msg_size = msg->msg_size;
msgpool_free(msg);
TOS_CPU_INT_ENABLE();
return K_ERR_NONE;
}
向訊息佇列寫入訊息
當發送訊息時,TencentOS tiny會從訊息池(空閑訊息串列)中取出一個空閑訊息,掛載到訊息佇列的訊息串列中,可以通過opt引數選擇掛載到訊息串列的末尾或者是頭部,因此訊息佇列的寫入是支持FIFO與LIFO方式的,msg_queue是要寫入訊息的訊息佇列控制塊,msg_addr、msg_size則是要寫入訊息的地址與大小,
寫入訊息的程序非常簡單,直接通過msgpool_alloc()函式從訊息池取出一個空閑訊息,如果系統不存在空閑的訊息,則直接回傳錯誤代碼K_ERR_MSG_QUEUE_FULL表示系統可用的訊息已經被使用完,如果取出空閑訊息成功則將要寫入的訊息地址與大小記錄到訊息池的msg_addr 與 msg_size 成員變數中,然后通過opt引數選擇將訊息掛載到訊息串列的位置(頭部或者是尾部),
__API__ k_err_t tos_msg_queue_put(k_msg_queue_t *msg_queue, void *msg_addr, size_t msg_size, k_opt_t opt)
{
TOS_CPU_CPSR_ALLOC();
k_msg_t *msg;
#if TOS_CFG_OBJECT_VERIFY_EN > 0u
if (!knl_object_verify(&msg_queue->knl_obj, KNL_OBJ_TYPE_MSG_QUEUE)) {
return K_ERR_OBJ_INVALID;
}
#endif
TOS_CPU_INT_DISABLE();
msg = msgpool_alloc();
if (!msg) {
TOS_CPU_INT_ENABLE();
return K_ERR_MSG_QUEUE_FULL;
}
msg->msg_addr = msg_addr;
msg->msg_size = msg_size;
if (opt & TOS_OPT_MSG_PUT_LIFO) {
tos_list_add(&msg->list, &msg_queue->queue_head);
} else {
tos_list_add_tail(&msg->list, &msg_queue->queue_head);
}
TOS_CPU_INT_ENABLE();
return K_ERR_NONE;
}
實驗測驗代碼
#include "stm32f10x.h"
#include "bsp_usart.h"
#include "tos.h"
k_msg_queue_t test_msg_queue_00;
k_task_t task1;
k_task_t task2;
k_stack_t task_stack1[1024];
k_stack_t task_stack2[1024];
void test_task1(void *Parameter)
{
k_err_t err;
int i = 0;
int msg_received;
size_t msg_size = 0;
while(1)
{
printf("queue pend\r\n");
for (i = 0; i < 3; ++i)
{
err = tos_msg_queue_get(&test_msg_queue_00, (void **)&msg_received, &msg_size);
if (err == K_ERR_NONE)
printf("msg queue get is %d \r\n",msg_received);
if (err == K_ERR_PEND_DESTROY)
{
printf("queue is destroy\r\n");
tos_task_delay(TOS_TIME_FOREVER - 1);
}
}
tos_task_delay(1000);
}
}
void test_task2(void *Parameter)
{
k_err_t err;
int i = 0;
uint32_t msgs[3] = { 1, 2, 3 };
printf("task2 running\r\n");
while(1)
{
for (i = 0; i < 3; ++i)
{
err = tos_msg_queue_put(&test_msg_queue_00, (void *)(msgs[i]), sizeof(uint32_t), TOS_OPT_MSG_PUT_FIFO);
if (err != K_ERR_NONE)
printf("msg queue put fail! code : %d \r\n",err);
}
tos_task_delay(1000);
}
}
/**
* @brief 主函式
* @param 無
* @retval 無
*/
int main(void)
{
k_err_t err;
/*初始化USART 配置模式為 115200 8-N-1,中斷接收*/
USART_Config();
printf("Welcome to TencentOS tiny\r\n");
tos_knl_init(); // TOS Tiny kernel initialize
tos_robin_config(TOS_ROBIN_STATE_ENABLED, (k_timeslice_t)500u);
printf("create test_queue_00\r\n");
err = tos_msg_queue_create(&test_msg_queue_00);
if(err != K_ERR_NONE)
printf("TencentOS Create test_msg_queue_00 fail! code : %d \r\n",err);
printf("create task1\r\n");
err = tos_task_create(&task1,
"task1",
test_task1,
NULL,
3,
task_stack1,
1024,
20);
if(err != K_ERR_NONE)
printf("TencentOS Create task1 fail! code : %d \r\n",err);
printf("create task2\r\n");
err = tos_task_create(&task2,
"task2",
test_task2,
NULL,
4,
task_stack2,
1024,
20);
if(err != K_ERR_NONE)
printf("TencentOS Create task2 fail! code : %d \r\n",err);
tos_knl_start(); // Start TOS Tiny
}
現象

喜歡就關注我吧!

相關代碼可以在公眾號后臺回復 “ 19 ” 獲取,
更多資料歡迎關注“物聯網IoT開發”公眾號!
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/30534.html
標籤:嵌入式
