RTthread线程间通信(邮箱,消息队列,信号/软件中断)---02代码分析邮箱和消息队列

RT-Thread代码分析

这是源码分析, 实际使用看这个
信号看这个
看这一篇之前最好看一下我的RT-Thread对象管理以及线程管理, 时钟管理

邮箱

实际是实现是一个对环形缓存区的使用

RTthread线程间通信(邮箱,消息队列,信号/软件中断)---02代码分析邮箱和消息队列_第1张图片

struct rt_mailbox
{
    struct rt_ipc_object parent;                        /**< inherit from ipc_object */

    rt_ubase_t          *msg_pool;                      /**< start address of 
    												message buffer 缓存区地址*/

    rt_uint16_t          size;                          /**< size of message pool 大小*/

    rt_uint16_t          entry;                         /**< index of messages in msg_pool
    												记录一下数量*/
    rt_uint16_t          in_offset;                     /**< input offset of the message 																				buffer记录一下写的位置 */
    rt_uint16_t          out_offset;                    /**< output offset of the message 																				记录一下读的位置buffer */

    rt_list_t            suspend_sender_thread;         /**< sender thread suspended on
    												挂起的任务链表this mailbox */
};
typedef struct rt_mailbox *rt_mailbox_t;
struct rt_ipc_object
{
    struct rt_object parent;                            /**< inherit from rt_object */

    rt_list_t        suspend_thread;                    /**< threads pended on this resource 记录接收的任务的队列 */
};

创建

rt_mailbox_t rt_mb_create(const char *name, rt_size_t size, rt_uint8_t flag)
{
    rt_mailbox_t mb;

    RT_DEBUG_NOT_IN_INTERRUPT;

    /* allocate object 这一个在对象创建的那一篇里面分析过了*/
    mb = (rt_mailbox_t)rt_object_allocate(RT_Object_Class_MailBox, name);
    if (mb == RT_NULL)
        return mb;

    /* set parent */
    mb->parent.parent.flag = flag;

    /* initialize ipc object 实际上就是初始化一个用于记录接收任务挂起的链表 */
    rt_ipc_object_init(&(mb->parent));

    /* initialize mailbox 记录一些信息 */
    mb->size     = size;
    //获取一个缓存区
    mb->msg_pool = (rt_ubase_t *)RT_KERNEL_MALLOC(mb->size * sizeof(rt_ubase_t));
    if (mb->msg_pool == RT_NULL)
    {
        //获取失败
        /* delete mailbox object */
        rt_object_delete(&(mb->parent.parent));

        return RT_NULL;
    }
    mb->entry      = 0;
    mb->in_offset  = 0;
    mb->out_offset = 0;

    /* initialize an additional list of sender suspend thread 发送者的队列 */
    rt_list_init(&(mb->suspend_sender_thread));

    return mb;
}
//实际就是记录一下信息
rt_err_t rt_mb_init(rt_mailbox_t mb,
                    const char  *name,
                    void        *msgpool,
                    rt_size_t    size,
                    rt_uint8_t   flag)
{
    RT_ASSERT(mb != RT_NULL);

    /* initialize object 具体看对象的分析那一章*/
    rt_object_init(&(mb->parent.parent), RT_Object_Class_MailBox, name);

    /* set parent flag */
    mb->parent.parent.flag = flag;

    /* initialize ipc object */
    rt_ipc_object_init(&(mb->parent));

    /* initialize mailbox */
    mb->msg_pool   = (rt_ubase_t *)msgpool;
    mb->size       = size;
    mb->entry      = 0;
    mb->in_offset  = 0;
    mb->out_offset = 0;

    /* initialize an additional list of sender suspend thread */
    rt_list_init(&(mb->suspend_sender_thread));

    return RT_EOK;
}

删除

rt_err_t rt_mb_delete(rt_mailbox_t mb)
{
    RT_DEBUG_NOT_IN_INTERRUPT;

    /* resume all suspended thread 把所有的挂起的接收线程释放, 这个同步那一章里面有 */
    rt_ipc_list_resume_all(&(mb->parent.suspend_thread));

    /* also resume all mailbox private suspended thread 发送线程释放 */
    rt_ipc_list_resume_all(&(mb->suspend_sender_thread));

    /* free mailbox pool 释放缓存内存 */
    RT_KERNEL_FREE(mb->msg_pool);

    /* delete mailbox object 控制块会在空闲任务释放 */
    rt_object_delete(&(mb->parent.parent));

    return RT_EOK;
}

发送

rt_err_t rt_mb_send(rt_mailbox_t mb, rt_ubase_t value)
{
    return rt_mb_send_wait(mb, value, 0);
}
rt_err_t rt_mb_send_wait(rt_mailbox_t mb,
                         rt_ubase_t   value,
                         rt_int32_t   timeout)
{
    struct rt_thread *thread;
    register rt_ubase_t temp;
    rt_uint32_t tick_delta;

    /* initialize delta tick */
    tick_delta = 0;
    /* get current thread 获取当前线程 */
    thread = rt_thread_self();
	//回调函数
    RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mb->parent.parent)));

    /* disable interrupt 临界区 */
    temp = rt_hw_interrupt_disable();

    /* for non-blocking call 看一看有没有位置 */
    if (mb->entry == mb->size && timeout == 0)
    {
        //没有并且不等待
        rt_hw_interrupt_enable(temp);

        return -RT_EFULL;
    }

    /* mailbox is full */
    while (mb->entry == mb->size)
    {
        //邮箱满了
        /* reset error number in thread */
        thread->error = RT_EOK;

        /* no waiting, return timeout */
        if (timeout == 0)
        {
            /* enable interrupt 这一个线程等待时间到了 */
            rt_hw_interrupt_enable(temp);

            return -RT_EFULL;
        }
		//这个使用的时候需要已经开始调度了
        RT_DEBUG_IN_THREAD_CONTEXT;
        /* suspend current thread */
        //把这一个任务记录在挂起队列里面(具体分析看任务同步的那一篇)
        rt_ipc_list_suspend(&(mb->suspend_sender_thread),
                            thread,
                            mb->parent.parent.flag);

        /* has waiting time, start thread timer */
        if (timeout > 0)
        {
            //需要等待
            /* get the start tick of timer 获取现在的时间 */
            tick_delta = rt_tick_get();

            RT_DEBUG_LOG(RT_DEBUG_IPC, ("mb_send_wait: start timer of thread:%s\n",
                                        thread->name));

            /* reset the timeout of thread timer and start it 开启一个时钟用于超时时候的唤醒*/
            rt_timer_control(&(thread->thread_timer),
                             RT_TIMER_CTRL_SET_TIME,
                             &timeout);
            rt_timer_start(&(thread->thread_timer));
        }

        /* enable interrupt */
        rt_hw_interrupt_enable(temp);

        /* re-schedule 启动一次调度 */
        rt_schedule();
		//这里线程被唤醒, 看一看这这时候是不是超时了
        /* resume from suspend state */
        if (thread->error != RT_EOK)
        {
            /* return error */
            return thread->error;
        }

        /* disable interrupt 在这之前可能有一个高优先级把这一个位置又使用了, 需要再看看可不可以发送*/
        temp = rt_hw_interrupt_disable();

        /* if it's not waiting forever and then re-calculate timeout tick 跟新一下发送的时间, 再试着发送一次 */
        if (timeout > 0)
        {
            tick_delta = rt_tick_get() - tick_delta;
            timeout -= tick_delta;
            //时间已经到了
            if (timeout < 0)
                timeout = 0;
        }
    }
	//可以发送信息
    /* set ptr 记录一下信息*/
    mb->msg_pool[mb->in_offset] = value;
    /* increase input offset 更新一下记录的指针 */
    ++ mb->in_offset;
    if (mb->in_offset >= mb->size)
        mb->in_offset = 0;//大小大于这一个环形缓冲区, 回头部
    /* increase message entry */
    mb->entry ++;//大小加一

    /* resume suspended thread 看一看接收的有没有在等的 */
    if (!rt_list_isempty(&mb->parent.suspend_thread))
    {
        //唤醒一下第一个等待的线程以及把时钟关了(看线程同步)
        rt_ipc_list_resume(&(mb->parent.suspend_thread));

        /* enable interrupt */
        rt_hw_interrupt_enable(temp);
		//切换一下任务
        rt_schedule();

        return RT_EOK;
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    return RT_EOK;
}

接收

//基本和发送一样, 只是循环判断是为空, 以及标识符加减反过来了
rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout)
{
    struct rt_thread *thread;
    register rt_ubase_t temp;
    rt_uint32_t tick_delta;

    /* parameter check */
    RT_ASSERT(mb != RT_NULL);
    RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox);

    /* initialize delta tick */
    tick_delta = 0;
    /* get current thread */
    thread = rt_thread_self();

    RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(mb->parent.parent)));

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

    /* for non-blocking call */
    if (mb->entry == 0 && timeout == 0)
    {
        rt_hw_interrupt_enable(temp);

        return -RT_ETIMEOUT;
    }

    /* mailbox is empty 看看是不是空的 */
    while (mb->entry == 0)
    {
        //需要等待
        /* reset error number in thread */
        thread->error = RT_EOK;

        /* no waiting, return timeout */
        if (timeout == 0)
        {
            //等待的时间到了, 失败
            /* enable interrupt */
            rt_hw_interrupt_enable(temp);

            thread->error = -RT_ETIMEOUT;

            return -RT_ETIMEOUT;
        }
		//必须打开调度器了
        RT_DEBUG_IN_THREAD_CONTEXT;
        //一个典型的icp挂起处理
        /* suspend current thread */
        rt_ipc_list_suspend(&(mb->parent.suspend_thread),
                            thread,
                            mb->parent.parent.flag);

        /* has waiting time, start thread timer 还有时间, 挂起*/
        if (timeout > 0)
        {
            /* get the start tick of timer */
            tick_delta = rt_tick_get();

            RT_DEBUG_LOG(RT_DEBUG_IPC, ("mb_recv: start timer of thread:%s\n",
                                        thread->name));

            /* reset the timeout of thread timer and start it */
            rt_timer_control(&(thread->thread_timer),
                             RT_TIMER_CTRL_SET_TIME,
                             &timeout);
            rt_timer_start(&(thread->thread_timer));
        }

        /* enable interrupt */
        rt_hw_interrupt_enable(temp);

        /* re-schedule */
        rt_schedule();
		//切换, 看一看是不是出错了(超时等)
        /* resume from suspend state */
        if (thread->error != RT_EOK)
        {
            /* return error */
            return thread->error;
        }

        /* disable interrupt 最后检测一下有没有位置 */
        temp = rt_hw_interrupt_disable();

        /* if it's not waiting forever and then re-calculate timeout tick 更新时间 */
        if (timeout > 0)
        {
            tick_delta = rt_tick_get() - tick_delta;
            timeout -= tick_delta;
            if (timeout < 0)
                timeout = 0;
        }
    }

    /* fill ptr */
    *value = mb->msg_pool[mb->out_offset];

    /* increase output offset */
    ++ mb->out_offset;
    if (mb->out_offset >= mb->size)
        mb->out_offset = 0;
    /* decrease message entry */
    mb->entry --;

    /* resume suspended thread */
    if (!rt_list_isempty(&(mb->suspend_sender_thread)))
    {
        //释放第一个线程
        rt_ipc_list_resume(&(mb->suspend_sender_thread));

        /* enable interrupt */
        rt_hw_interrupt_enable(temp);

        RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mb->parent.parent)));

        rt_schedule();

        return RT_EOK;
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mb->parent.parent)));

    return RT_EOK;
}

消息队列

实际上这是一个对链表的使用

消息链表: 使用两个指针记录消息链表的头以及尾

空闲链表: 类似栈, 使用一个指针记录空闲任务尾部

struct rt_messagequeue
{
    struct rt_ipc_object parent;                        /**< inherit from ipc_object */

    void                *msg_pool;                      /**< start address of message
    												queue 存放消息的缓冲区 */

    rt_uint16_t          msg_size;                      /**< message size of each message
    												记录可以容纳的每一个消息的大小*/
    rt_uint16_t          max_msgs;                      /**< max number of messages 
    												记录消息的个数*/

    rt_uint16_t          entry;                         /**< index of messages in the 													 								queue 记录现在消息的个数 */

    void                *msg_queue_head;                /**< list head 链表头 */
    void                *msg_queue_tail;                /**< list tail 链表尾*/
    void                *msg_queue_free;                /**< pointer indicated the free 																			node of queue 记录缓冲区里下一个空闲消息的链表 */

    rt_list_t            suspend_sender_thread;         /**< sender thread suspended on 																				this message queue 发送线程的挂起的等待队列*/
};
struct rt_mq_message
{
    struct rt_mq_message *next;
};

一个管理信息的链表

创建

RTthread线程间通信(邮箱,消息队列,信号/软件中断)---02代码分析邮箱和消息队列_第2张图片

初始化以后的缓冲区

rt_mq_t rt_mq_create(const char *name,
                     rt_size_t   msg_size,
                     rt_size_t   max_msgs,
                     rt_uint8_t  flag)
{
    struct rt_messagequeue *mq;
    struct rt_mq_message *head;
    register rt_base_t temp;
	//这一个函数不应该在中断里面使用
    RT_DEBUG_NOT_IN_INTERRUPT;

    /* allocate object 获取一个邮箱的对象 */
    mq = (rt_mq_t)rt_object_allocate(RT_Object_Class_MessageQueue, name);
    if (mq == RT_NULL)
        return mq;

    /* set parent 记录一下标志 */
    mq->parent.parent.flag = flag;

    /* initialize ipc object 主要是初始化一个ipc的链表(这一部分在信号同步的的那一篇里面有) */
    rt_ipc_object_init(&(mq->parent));

    /* initialize message queue */

    /* get correct message size 把这一个按照四字节对齐 */
    mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE);
    mq->max_msgs = max_msgs;

    /* allocate message pool 获取一个存信息的内存, 实际的大小是(信息大小 + 管理结构体(一个链表)) * 数量 */
    mq->msg_pool = RT_KERNEL_MALLOC((mq->msg_size + sizeof(struct rt_mq_message)) * mq->max_msgs);
    if (mq->msg_pool == RT_NULL)
    {
        //获取失败的时候
        rt_object_delete(&(mq->parent.parent));

        return RT_NULL;
    }

    /* initialize message list */
    mq->msg_queue_head = RT_NULL;
    mq->msg_queue_tail = RT_NULL;

    /* initialize message empty list 初始化这一个缓存里面的信息 */
    mq->msg_queue_free = RT_NULL;
    for (temp = 0; temp < mq->max_msgs; temp ++)
    {
        head = (struct rt_mq_message *)((rt_uint8_t *)mq->msg_pool +
                                        temp * (mq->msg_size + sizeof(struct rt_mq_message)));//计算一下第n个信息的位置
        head->next = (struct rt_mq_message *)mq->msg_queue_free;//初始化链表指向数组前一个信息
        mq->msg_queue_free = head;//更新一下可以使用的下一个的位置
    }

    /* the initial entry is zero */
    mq->entry = 0;

    /* initialize an additional list of sender suspend thread */
    rt_list_init(&(mq->suspend_sender_thread));

    return mq;
}
//静态, 实际就是记录一下用到的值
rt_err_t rt_mq_init(rt_mq_t     mq,
                    const char *name,
                    void       *msgpool,
                    rt_size_t   msg_size,
                    rt_size_t   pool_size,
                    rt_uint8_t  flag)
{
    struct rt_mq_message *head;
    register rt_base_t temp;

    /* parameter check */
    RT_ASSERT(mq != RT_NULL);

    /* initialize object */
    rt_object_init(&(mq->parent.parent), RT_Object_Class_MessageQueue, name);

    /* set parent flag */
    mq->parent.parent.flag = flag;

    /* initialize ipc object */
    rt_ipc_object_init(&(mq->parent));

    /* set message pool */
    mq->msg_pool = msgpool;

    /* get correct message size 计算一下实际可以存储的信息的个数 */
    mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE);
    mq->max_msgs = pool_size / (mq->msg_size + sizeof(struct rt_mq_message));

    /* initialize message list */
    mq->msg_queue_head = RT_NULL;
    mq->msg_queue_tail = RT_NULL;

    /* initialize message empty list */
    mq->msg_queue_free = RT_NULL;
    for (temp = 0; temp < mq->max_msgs; temp ++)
    {
        head = (struct rt_mq_message *)((rt_uint8_t *)mq->msg_pool +
                                        temp * (mq->msg_size + sizeof(struct rt_mq_message)));
        head->next = (struct rt_mq_message *)mq->msg_queue_free;
        mq->msg_queue_free = head;
    }

    /* the initial entry is zero */
    mq->entry = 0;

    /* initialize an additional list of sender suspend thread */
    rt_list_init(&(mq->suspend_sender_thread));

    return RT_EOK;
}

发送消息

rt_err_t rt_mq_send_wait(rt_mq_t     mq,
                         const void *buffer,
                         rt_size_t   size,
                         rt_int32_t  timeout)
{
    register rt_ubase_t temp;
    struct rt_mq_message *msg;
    rt_uint32_t tick_delta;
    struct rt_thread *thread;

    /* greater than one message size */
    if (size > mq->msg_size)
        //发送的消息太大了, 不能发送
        return -RT_ERROR;

    /* initialize delta tick */
    tick_delta = 0;
    /* get current thread 获取当前线程 */
    thread = rt_thread_self();

    RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mq->parent.parent)));

    /* disable interrupt 临界区 */
    temp = rt_hw_interrupt_disable();

    /* get a free list, there must be an empty item */
    msg = (struct rt_mq_message *)mq->msg_queue_free;
    /* for non-blocking call */
    if (msg == RT_NULL && timeout == 0)
    {
        /* enable interrupt 没有位置, 并且不等待 */
        rt_hw_interrupt_enable(temp);

        return -RT_EFULL;
    }

    /* message queue is full 没有可以用于发送的空闲缓冲区 */
    while ((msg = mq->msg_queue_free) == RT_NULL)
    {
        /* reset error number in thread */
        thread->error = RT_EOK;

        /* no waiting, return timeout */
        if (timeout == 0)
        {
            /* enable interrupt 时间到了 */
            rt_hw_interrupt_enable(temp);

            return -RT_EFULL;
        }
		//一个典型的ipc挂起
        RT_DEBUG_IN_THREAD_CONTEXT;
        /* suspend current thread */
        rt_ipc_list_suspend(&(mq->suspend_sender_thread),
                            thread,
                            mq->parent.parent.flag);

        /* has waiting time, start thread timer */
        if (timeout > 0)
        {
            //还需要等待
            /* get the start tick of timer 记录现在的时间, 用于计算是不是超时 */
            tick_delta = rt_tick_get();

            RT_DEBUG_LOG(RT_DEBUG_IPC, ("mq_send_wait: start timer of thread:%s\n",
                                        thread->name));

            /* reset the timeout of thread timer and start it */
            rt_timer_control(&(thread->thread_timer),
                             RT_TIMER_CTRL_SET_TIME,
                             &timeout);
            rt_timer_start(&(thread->thread_timer));
        }

        /* enable interrupt */
        rt_hw_interrupt_enable(temp);

        /* re-schedule 任务切换*/
        rt_schedule();
		//回来了, 可能有位置或者出错(超时)
        /* resume from suspend state */
        if (thread->error != RT_EOK)
        {
            //是出错回来的
            /* return error */
            return thread->error;
        }

        /* disable interrupt */
        temp = rt_hw_interrupt_disable();
		//最后更新时间以及检测一下是不是真的有位置
        /* if it's not waiting forever and then re-calculate timeout tick */
        if (timeout > 0)
        {
            tick_delta = rt_tick_get() - tick_delta;
            timeout -= tick_delta;
            if (timeout < 0)
                timeout = 0;
        }
    }
	//有位置
    /* move free list pointer 获取一个位置, 这个msg是记录空闲位置的那一个指针 */
    mq->msg_queue_free = msg->next;

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    /* the msg is the new tailer of list, the next shall be NULL 这是一个新加入的信息, 没有下一个*/
    msg->next = RT_NULL;
    /* copy buffer 把信息拷贝到缓冲区 */
    rt_memcpy(msg + 1, buffer, size);

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();
    /* link msg to message queue  看一看链表里面有没有信息*/
    if (mq->msg_queue_tail != RT_NULL)
    {
        //这是不第一个信息, 更新上一条信息的下一条为这个新的消息
        /* if the tail exists, */
        ((struct rt_mq_message *)mq->msg_queue_tail)->next = msg;
    }

    /* set new tail 尾部记录为这一个信息 */
    mq->msg_queue_tail = msg;
    /* if the head is empty, set head 这时候没有信息的话记录一下这一条信息为第一条 */
    if (mq->msg_queue_head == RT_NULL)
        mq->msg_queue_head = msg;

    /* increase message entry 数量加一 */
    mq->entry ++;

    /* resume suspended thread 看一看有没有可以释放的任务*/
    if (!rt_list_isempty(&mq->parent.suspend_thread))
    {
        //释放第一个任务
        rt_ipc_list_resume(&(mq->parent.suspend_thread));

        /* enable interrupt */
        rt_hw_interrupt_enable(temp);

        rt_schedule();

        return RT_EOK;
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    return RT_EOK;
}

接收信息

//基本一样, 主要看链表操作
rt_err_t rt_mq_recv(rt_mq_t    mq,
                    void      *buffer,
                    rt_size_t  size,
                    rt_int32_t timeout)
{
    struct rt_thread *thread;
    register rt_ubase_t temp;
    struct rt_mq_message *msg;
    rt_uint32_t tick_delta;

    /* parameter check */
    RT_ASSERT(mq != RT_NULL);
    RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue);
    RT_ASSERT(buffer != RT_NULL);
    RT_ASSERT(size != 0);

    /* initialize delta tick */
    tick_delta = 0;
    /* get current thread */
    thread = rt_thread_self();
    RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(mq->parent.parent)));

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

    /* for non-blocking call */
    if (mq->entry == 0 && timeout == 0)
    {
        //没有可以获取的信息, 并且不等待
        rt_hw_interrupt_enable(temp);

        return -RT_ETIMEOUT;
    }

    /* message queue is empty 没有信息 */
    while (mq->entry == 0)
    {
        RT_DEBUG_IN_THREAD_CONTEXT;

        /* reset error number in thread */
        thread->error = RT_EOK;

        /* no waiting, return timeout 超时 */
        if (timeout == 0)
        {
            /* enable interrupt */
            rt_hw_interrupt_enable(temp);

            thread->error = -RT_ETIMEOUT;

            return -RT_ETIMEOUT;
        }
		//ipc挂起
        /* suspend current thread */
        rt_ipc_list_suspend(&(mq->parent.suspend_thread),
                            thread,
                            mq->parent.parent.flag);

        /* has waiting time, start thread timer */
        if (timeout > 0)
        {
            /* get the start tick of timer */
            tick_delta = rt_tick_get();

            RT_DEBUG_LOG(RT_DEBUG_IPC, ("set thread:%s to timer list\n",
                                        thread->name));

            /* reset the timeout of thread timer and start it */
            rt_timer_control(&(thread->thread_timer),
                             RT_TIMER_CTRL_SET_TIME,
                             &timeout);
            rt_timer_start(&(thread->thread_timer));
        }

        /* enable interrupt */
        rt_hw_interrupt_enable(temp);

        /* re-schedule */
        rt_schedule();

        /* recv message */
        if (thread->error != RT_EOK)
        {
            /* return error */
            return thread->error;
        }

        /* disable interrupt */
        temp = rt_hw_interrupt_disable();

        /* if it's not waiting forever and then re-calculate timeout tick */
        if (timeout > 0)
        {
            tick_delta = rt_tick_get() - tick_delta;
            timeout -= tick_delta;
            if (timeout < 0)
                timeout = 0;
        }
    }

    /* get message from queue 获取当前的第一个信息 */
    msg = (struct rt_mq_message *)mq->msg_queue_head;

    /* move message queue head 更新一下下一条消息的位置 */
    mq->msg_queue_head = msg->next;
    /* reach queue tail, set to NULL 这个里面没有消息了(头尾一样, 只有一条信息) */
    if (mq->msg_queue_tail == msg)
        mq->msg_queue_tail = RT_NULL;

    /* decrease message entry 数量更新 */
    mq->entry --;

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    /* copy message 拷贝一下信息 */
    rt_memcpy(buffer, msg + 1, size > mq->msg_size ? mq->msg_size : size);

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();
    /* put message to free list 把这个回归空闲队列 */
    msg->next = (struct rt_mq_message *)mq->msg_queue_free;
    mq->msg_queue_free = msg;

    /* resume suspended thread 释放等待线程*/
    if (!rt_list_isempty(&(mq->suspend_sender_thread)))
    {
        rt_ipc_list_resume(&(mq->suspend_sender_thread));

        /* enable interrupt */
        rt_hw_interrupt_enable(temp);

        RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mq->parent.parent)));

        rt_schedule();

        return RT_EOK;
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mq->parent.parent)));

    return RT_EOK;
}

你可能感兴趣的:(windows,单片机,mcu,stm32,经验分享,笔记)