[TencentOS tiny] Углубленный анализ исходного кода (4) — очередь сообщений

Интернет вещей

очередь сообщений

в предыдущем посте[TencentOS крошечное обучение] Анализ исходного кода (3) — очередьМы описали реализацию очереди TencentOS tiny, а также указали, что очередь TencentOS tiny зависит от очереди сообщений, поэтому давайте сегодня рассмотрим реализацию очереди сообщений.

На самом деле очередь сообщений — одна из самых крошечных в TencentOS.основные компоненты, как нижний слой очереди. так в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цикл, пул сообщений `kmsgpool[TOSCFGMSGPOOLSIZE]的成员变量进行初始化,初始化对应的列表节点,并且将它挂载到空闲消息列表上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.

Но есть одно замечание, потому что оперативная память блока управления очередью статически выделяется компилятором, поэтому даже если очередь уничтожена, эта память не может быть освобождена~

__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»