rt-thread的IPC机制之信号量源码分析(三)
}
else//如果此信号量的计数器的值小于或等于0,说明此时还未有信号
{
/* no waiting, return with timeout */
if (time == 0)//如果等待时间参数为0,则立即返回超时错误
{
rt_hw_interrupt_enable(temp);//开中断
return -RT_ETIMEOUT;//返回超时错误
}
else//等待信号
{
/* current context checking */
RT_DEBUG_NOT_IN_INTERRUPT;//确保此时不在中断中使用
/* semaphore is unavailable, push to suspend list */
/* get current thread */
thread = rt_thread_self();//获取当前正在运行的线程
/* reset thread error number */
thread->error = RT_EOK;//设置当前线程的错误代码为RT_EOK,需要注意这里
RT_DEBUG_LOG(RT_DEBUG_IPC, ("sem take: suspend thread - %s\n",
thread->name));
/* suspend thread */
rt_ipc_list_suspend(&(sem->parent.suspend_thread),//挂起当前线程到信号量中的断起线程链表
thread,
sem->parent.parent.flag);
/* has waiting time, start thread timer */
if (time > 0)//如果时间参数大于0
{
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,
&time);
rt_timer_start(&(thread->thread_timer));//启动定时器开始计时
}
/* enable interrupt */
rt_hw_interrupt_enable(temp);//开中断
/* do schedule */
rt_schedule();//当前线程已挂起,需要重新调试线程
//rt_schedule之后再执行到这里,只有两种可能,一是当前线程被挂起后时间已到达,此时,定时器的超时回调处理函数会将此线程的err值设为-RT_ETIMEOU,见thread.c源文件中的rt_thread_timeout函数;另一种情况是,有信号量到来,当前线程被rt_sem_release函数唤醒,此时,此线程的err值将一直保持原样不变,因此可以下面可能通过判断线程的err值来判断当前线程是否已被接收到信号量
if (thread->error != RT_EOK)//如果当前线程的错误代码不为RT_EOK,则返回,否则一直阻塞到等待到有信号到达或超时
{
return thread->error;
}
}
}
RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(sem->parent.parent)));
return RT_EOK;
}
4.2 获取无等待信号量
[cpp]
/**
* This function will try to take a semaphore and immediately return
*
* @param sem the semaphore object
*
* @return the error code
*/
rt_err_t rt_sem_trytake(rt_sem_t sem)
{
return rt_sem_take(sem, 0);
}
由此可见,rt_sem_trytake只是rt_sem_take函数的一种特例,时间参数为0而已.
5 释放信号量
[cpp]
/**
* This function will release a semaphore, if there are threads suspended on
* semaphore, it will be waked up.
*
* @param sem the semaphore object
*
* @return the error code
*/
rt_err_t rt_sem_release(rt_sem_t sem)
{
register rt_base_t temp;
register rt_bool_t need_schedule;
RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(sem->parent.parent)));
need_schedule = RT_FALSE;//默认情况下设置不需要重新调度标记
/* disable interrupt */
temp = rt_hw_interrupt_disable();//关中断
RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s releases sem:%s, which value is: %d\n",
rt_thread_self()->name,
((struct rt_object *)sem)->name,
sem->value));