RT_Thread内核机制学习(五)邮箱

之所以引入线程间通信,是为了实现互斥,休眠-唤醒。
RT_Thread内核机制学习(五)邮箱_第1张图片
队列可以指定消息的大小、个数,存放消息,取出消息时都是由rt_memcpy()实现。

邮箱

保存数据的核心在于数组,只能存放unsigned long类型数据,数据存取、读出,直接赋值即可,使传递小数据时,效率更高。

核心是链表、定时器、环形Buffer

RT_Thread内核机制学习(五)邮箱_第2张图片
避免两个线程同时写:关中断。

定时器超时函数,设置线程的错误码为ETIMEOUT,并将自己重新放入就绪链表;

 thread->error = -RT_ETIMEOUT;
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 */
};

RT_Thread内核机制学习(五)邮箱_第3张图片

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)); //邮箱大小*(unsigned long=4)
    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;
}
RTM_EXPORT(rt_mb_create);

读数据

/* disable interrupt */
temp = rt_hw_interrupt_disable(); //关中断
 if (mb->entry == 0 && timeout == 0) //没有数据且不愿意等待
    {
        rt_hw_interrupt_enable(temp);

        return -RT_ETIMEOUT;
    }

//没有数据,且愿意等待
rt_ipc_list_suspend(&(mb->parent.suspend_thread),
                            thread,
                            mb->parent.parent.flag);//从ready链表移出,挂到parent.suspend_thread链表



*value = mb->msg_pool[mb->out_offset]; //有数据从out_offset读取

//将读数据索引加+1,如果达到了最大值,又从0开始。
++ mb->out_offset;
if (mb->out_offset >= mb->size)
mb->out_offset = 0;

mb->entry --;//数据数量减少

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;
    }

发送数据

temp = rt_hw_interrupt_disable();
if (mb->entry == mb->size && timeout == 0)//邮箱已满,不愿意等待
    {
        rt_hw_interrupt_enable(temp);

        return -RT_EFULL;
    }
//邮箱满了,愿意等待
while (mb->entry == mb->size)
{
	rt_ipc_list_suspend(&(mb->suspend_sender_thread),
                            thread,
                            mb->parent.parent.flag); //从就绪链表移除,将自己挂在发送线程链表上。
    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));
        }

	...
	rt_schedule();//让出CPU资源
}
//邮箱有空闲位置
mb->msg_pool[mb->in_offset] = value; //写数据

定时器检查

void rt_timer_check(void)
{
    struct rt_timer *t;
    rt_tick_t current_tick;
    register rt_base_t level;

    RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check enter\n"));

    current_tick = rt_tick_get();

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

    while (!rt_list_isempty(&rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))//取出定时器
    {
        t = rt_list_entry(rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next,
                          struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);

        /*
         * It supposes that the new tick shall less than the half duration of
         * tick max.
         */
        if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2) //判断时间是否到了
        {
            RT_OBJECT_HOOK_CALL(rt_timer_enter_hook, (t));

            /* remove timer from timer list firstly */
            _rt_timer_remove(t);

            /* call timeout function */
            t->timeout_func(t->parameter); //时间到了调用定时器函数

            /* re-get tick */
            current_tick = rt_tick_get();

            RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t));
            RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));

            if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
                (t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
            {
                /* start it */
                t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
                rt_timer_start(t);
            }
            else
            {
                /* stop timer */
                t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
            }
        }
        else
            break;
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(level);

    RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check leave\n"));
}

你可能感兴趣的:(RT-Thread,学习,windows,RT-Thread)