一、发送一个信号量 OSSemPost ()
/*
*********************************************************************************************************
* POST TO A SEMAPHORE
*
* Description : This function signals a semaphore
*
* Arguments : pevent is a pointer to the event control block associated with the desired
* semaphore.
*
* Returns : OS_ERR_NONE The call was successful and the semaphore was signaled.
* OS_ERR_SEM_OVF If the semaphore count exceeded its limit. In other words, you have
* signalled the semaphore more often than you waited on it with either
* OSSemAccept() or OSSemPend().
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
*********************************************************************************************************
*/
INT8U OSSemPost (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' 确保指针合法 */
return (OS_ERR_PEVENT_NULL);
}
#endif
OS_ENTER_CRITICAL(); /* 关中断 */
if (pevent->OSEventGrp != 0) { /* See if any task waiting for semaphore
有任务正在等待本信号量? */
/* Ready HPT waiting on event */
(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK);
/* OS_EventTaskRdy()函数把优先级最高的任务Taskx从等待列表中删除,并使其进入就绪态 */
OS_EXIT_CRITICAL(); /* 开中断 */
OS_Sched(); /* Find HPT ready to run 检查Taskx是否是系统中的最高优先级的
就绪态任务,是,则立即进行任务切换,(若ISR调用OSSemPost() ,则不会立即切换,
要等到中断嵌套的最外层ISR调用OSIntExit()后才进行任务切换)准备执行Taskx。
因为OSSemPost() 函数使得更重要的任务进入了就绪态,故调用OSSemPost() 的任务
就不能继续运行了 */
return (OS_ERR_NONE);
}
/* 这时若没有任务在等待本信号量,则信号量的值只是简单地加1 */
if (pevent->OSEventCnt < 65535u) { /* Make sure semaphore will not overflow 确保不溢出 */
pevent->OSEventCnt++; /* Increment semaphore count to register event */
OS_EXIT_CRITICAL();
return (OS_ERR_NONE);
}
OS_EXIT_CRITICAL(); /* Semaphore value has reached its maximum 若溢出则返回出错代码 */
return (OS_ERR_SEM_OVF);
}
二、等待(请求)一个信号量 OSSemPend ()
/*
*********************************************************************************************************
* PEND ON SEMAPHORE
*
* Description: This function waits for a semaphore.
*
* Arguments : pevent is a pointer to the event control block associated with the desired
* semaphore.
*
* timeout is an optional timeout period (in clock ticks). If non-zero, your task will
* wait for the resource up to the amount of time specified by this argument.
* If you specify 0, however, your task will wait forever at the specified
* semaphore or, until the resource becomes available (or the event occurs).
*
* perr is a pointer to where an error message will be deposited. Possible error
* messages are:
*
* OS_ERR_NONE The call was successful and your task owns the resource
* or, the event you are waiting for occurred.
* OS_ERR_TIMEOUT The semaphore was not received within the specified
* 'timeout'.
* OS_ERR_PEND_ABORT The wait on the semaphore was aborted.
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore.
* OS_ERR_PEND_ISR If you called this function from an ISR and the result
* would lead to a suspension.
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
* OS_ERR_PEND_LOCKED If you called this function when the scheduler is locked
*
* Returns : none
*********************************************************************************************************
*/
void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
#if OS_ARG_CHK_EN > 0 /* 若OS_ARG_CHK_EN 被设置为1 */
if (perr == (INT8U *)0) { /* Validate 'perr' 错误代码指针perr是否为非空指针 */
return;
}
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' pevent 是否为非空指针 */
*perr = OS_ERR_PEVENT_NULL;
return;
}
#endif
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type
是否指向由OSSemCreate()函数建立的事件控制块ECB */
*perr = OS_ERR_EVENT_TYPE;
return;
}
if (OSIntNesting > 0) { /* See if called from ISR ... 是否是中断服务子程序调用了本函数 */
*perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR
因为ISR不能等待,故调用本函数没有意义,不过ISR可以调用OSSemAccept()
即无等待地请求一个信号量 */
return;
}
if (OSLockNesting > 0) { /* See if called with scheduler locked ... */
*perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked
若调度器被锁定,则等待一个信号量变得没有意义 */
return;
}
OS_ENTER_CRITICAL();
if (pevent->OSEventCnt > 0) { /* If sem. is positive, resource available ...
若信号量本来就有效,则信号量的计数值递减 */
pevent->OSEventCnt--; /* ... decrement semaphore only if positive. */
OS_EXIT_CRITICAL();
*perr = OS_ERR_NONE; /* 返回无错代码 */
return;
}
/* Otherwise, must wait until event occurs
否则等待另一个任务或ISR发出信号量 OSSemPost() */
OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not available, pend on semaphore
将任务控制块中的状态标志置位,使调用本函数的任务进入睡眠状态 */
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB
最长等待时限也被放到任务控制块中,该值在系统节拍中被递减 */
OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs
真正将调用本函数的任务切换到睡眠状态 */
OS_EXIT_CRITICAL();
OS_Sched(); /* Find next highest priority task ready
由于等不到信号量,调用本函数的任务就不能再处在就绪态了,故调用调度
函数,让下一个优先级最高的任务得到运行,调用本函数的任务就被挂起了
一直到信号量来到才继续运行 */
OS_ENTER_CRITICAL();
switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */
case OS_STAT_PEND_OK: /* 等到了信号量 */
*perr = OS_ERR_NONE;
break;
case OS_STAT_PEND_ABORT:
*perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted 主动放弃等待? */
break;
case OS_STAT_PEND_TO: /* 若等待超时? */
default:
OS_EventTaskRemove(OSTCBCur, pevent); /* 将任务从等待链表中删除 */
*perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO 返回超时错误代码 */
break;
}
/* 至此可以执行到本函数之后的代码了 */
OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers
将指向信号量ECB的指针从任务的任务控制块中删除 */
#if (OS_EVENT_MULTI_EN > 0)
OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
#endif
OS_EXIT_CRITICAL();
}
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type 指针指向ECB? */
return (OS_ERR_EVENT_TYPE);
}