2.6 发送邮件/**
* 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);//开中断
/* 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;
}
与接收函数类似,发送函数在邮箱满的时候会挂起发送线程。其它的参考接收函数,基本上差不多。
2.7 邮箱控制
/**
* This function can get or set some extra attributions of a mailbox object.
*
* @param mb the mailbox object
* @param cmd the execution command
* @param arg the execution argument
*
* @return the error code
*/
rt_err_t rt_mb_control(rt_mailbox_t mb, rt_uint8_t cmd, void *arg)
{
rt_ubase_t level;
RT_ASSERT(mb != RT_NULL);
if (cmd == RT_IPC_CMD_RESET)//重围邮箱
{
/* disable interrupt */
level = rt_hw_interrupt_disable();//关中断
/* resume all waiting 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));//唤醒所有的发送线程
/* re-init mailbox */
mb->entry = 0;
mb->in_offset = 0;
mb->out_offset = 0;
/* enable interrupt */
rt_hw_interrupt_enable(level);
rt_schedule();
return RT_EOK;
}
return -RT_ERROR;
}
邮箱控制控制函数目前只支持重围操作,此操作过程与初始化过程基本上类似.
4 小结邮箱相关源码主要是在发送与接收上。发送时,由于当前邮箱可能空间已满,放不下要发送的邮件,此时,不得不挂起当前发送线程(如果存在时间参数的话),只要在接收函数读取出一条邮件时才会唤醒它。同理,如果当前邮箱为空,则接收函数会挂起当前的接收线程,直到有新的邮件到达(在发送函数中唤醒接收线程)或等待超时。
另外需要注意地是,rt-thread操作系统支持多个发送线程和多个接收线程,多个发送线程倒还好,倒是多个接收线程就不太好控制了,一般这种情况也不会用的,如果真的需要这种情况,那么多个接收线程就得好好控制了,因为,到底是哪个接收线程接收到邮件还不好说。OK,到此完!
|