rt-thread的IPC机制之邮箱源码分析(四)

2014-11-24 07:52:27 · 作者: · 浏览: 4
ITING_FOREVER宏定义为-1.在if语句内记录当前的时间点,然后设置一定时器并开启,接着重新调度。在重新调度后, 系统可能切换到其它线程,假设一段时间内,系统再次切换回来,原因可能有多种,1 邮箱被脱离,此时当前线程thread->error=-RT_ERROR.2 定时器时间到达,但是邮件还未到达,此时thread->error=-RT_ETIMEOUT;3:邮件到达,本线程在发送邮件函数中被唤醒(注:发送邮件函数中只是唤醒第一条等待邮件的线程),此时,thread->error还是保持原值RT_EOK不变;4:其它原因假设一段时间后线程切换回来,此时error的值也一直保持原样RT_EOK不变.因此,在重新调度了线程之后,才会有一个if语句通过判断thread->error的值是否为RT_EOK来判断当前线程是否被发送邮件函数唤醒。如果不是,则直接返回错误。接下来,按原则上说,当前线程一定是被发送邮件函数唤醒,因此,当前一定会存在接收的邮件,但是接下来的几行代码却是再次判断时间参数大于0的情况下,计算还剩余多多时间,然后返回到while循环接着循环...等等,不是当前已经接收到了邮件么?那么为什么不直接取邮件,而是还要进行下一次循环?这不是浪费时间么?这里给出的答案是,第一,确实原则上这时应该是收到邮件才会执行到这,但是,如果真的来了邮件的话,判断的唯一标准是while循环的判断条件,即邮箱内的接收信件条数不能为空,或为空,则判断循环,或不为空,则自然不会进行到while循环中了。但如果这时发现原来邮箱还是为空,那么当前线程则应该继续等待了,此时就应该计算出下一次循环中需要等待的剩下时间,好让下一循环进行精确等待这段时间。
接下来就是取出接收到的邮件,并更新邮箱的进出口偏移位置及邮箱中的邮件数减1,这样操作过后,不要忘记邮箱内可能还保留着因之前邮箱空间不中而挂起的发送线程,这个时候由于读取邮件操作,那么肯定是至少有一个空出的位置,那么是时候唤醒可能挂起的发送线程了(如果存在的话)。最后重新调度一下。
2.6 发送邮件
[cpp]
/**
* This function will send a mail to mailbox object. If the mailbox is full,
* current thread will be suspended until timeout.
*
* @param mb the mailbox object
* @param value the mail
* @param timeout the waiting time
*
* @return the error code
*/
rt_err_t rt_mb_send_wait(rt_mailbox_t mb,
rt_uint32_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);
/* 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)//如果邮箱满且无等待时间参数为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_NOT_IN_INTERRUPT;//确保不是在ISR中使用本函数
/* 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)//等待时间大于0
{
/* get the start tick of timer */
tick_delta = rt_tick_get();//得到当前的tick
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);//开中断