1、INT16U OSSemAccept (OS_EVENT *pevent)
宏:OS_SEM_EN > 0u,OS_SEM_ACCEPT_EN > 0u
功能描述:尝试获取信号量。与OSSemPend()不同,如果信号量资源不可用,OSSemAccept()不会挂起调用任务。
参数 pevent:指向事件控制块
返回值:> 0 信号量资源数量(调用此函数之前信号量值)。
==0 信号量资源不可用
INT16U OSSemAccept (OS_EVENT *pevent)
{INT16U cnt;
#if OS_CRITICAL_METHOD == 3u /* 为CPU状态分配存储 */OS_CPU_SR cpu_sr = 0u; /* cpu_sr用于存储CPU状态 */
#endif#if OS_ARG_CHK_EN > 0u /* 使能参数检查 */if (pevent == (OS_EVENT *)0) { /* 'pevent'是否为空指针 */return (0u);}
#endifif (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* 'pevent'的事件类型是否为信号量事件*/return (0u);}OS_ENTER_CRITICAL(); /* 进入临界区 */cnt = pevent->OSEventCnt;if (cnt > 0u) { /* 信号量资源是否可用 */pevent->OSEventCnt--; /* 信号量计数减一 */}OS_EXIT_CRITICAL();/* 退出临界区 */return (cnt); /* 返回信号量计数 */
}
2、OS_EVENT *OSSemCreate (INT16U cnt)
宏:OS_SEM_EN > 0u
功能描述:创建信号量。
参数 cnt:信号量的初始值。将信号量初始化为非零值,以指定有多少资源可用(例如,如果有10个资源,则将信号量初始化为10)。如果值为0,则没有信号量资源可用。
返回值:!= (void *)0 指向创建的信号量相关联的事件控制块。
== (void *)0 没有可用的事件控制块
OS_EVENT *OSSemCreate (INT16U cnt)
{OS_EVENT *pevent;
#if OS_CRITICAL_METHOD == 3u /* 为CPU状态分配存储 */OS_CPU_SR cpu_sr = 0u; /* cpu_sr用于存储CPU状态 */
#endif#ifdef OS_SAFETY_CRITICAL_IEC61508 /* 用于IEC61508认证 */if (OSSafetyCriticalStartFlag == OS_TRUE) {OS_SAFETY_CRITICAL_EXCEPTION();return ((OS_EVENT *)0);}
#endifif (OSIntNesting > 0u) { /* 是否从ISR中调用 */return ((OS_EVENT *)0); /* 返回空指针 */}OS_ENTER_CRITICAL(); /* 进入临界区 */pevent = OSEventFreeList; /* 获取下一个可用的事件控制块 */if (OSEventFreeList != (OS_EVENT *)0) { /* OSEventFreeList是否为空指针 */OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; /* OSEventFreeList指向下一个事件控制块 */}OS_EXIT_CRITICAL(); /* 退出临界区 */if (pevent != (OS_EVENT *)0) { /* pevent是否为空指针 */pevent->OSEventType = OS_EVENT_TYPE_SEM; /* pevent的事件类型设置为信号量事件 */pevent->OSEventCnt = cnt; /* 设置信号量的值 */pevent->OSEventPtr = (void *)0; /*断开与可用事件控制块的链接 */
#if OS_EVENT_NAME_EN > 0u /* 使能事件命名功能 */pevent->OSEventName = (INT8U *)(void *)"?"; /* 将事件名初始化为‘?’ */
#endifOS_EventWaitListInit(pevent); /* 初始化事件控制块的OSEventGrp,OSEventTbl[]变量 */}return (pevent);
}
3、OS_EVENT *OSSemDel (OS_EVENT *pevent, INT8U opt,INT8U *perr)
宏:OS_SEM_EN > 0u,OS_SEM_DEL_EN> 0u
功能描述:该函数删除一个信号量并就绪该信号量上所有挂起的任务。
参数 pevent:指向与所需信号量关联的事件控制块的指针。
opt:删除选项
opt == OS_DEL_NO_PEND 只有在没有任务挂起时才删除信号量
opt == OS_DEL_ALWAYS 即使有任务正在等待,也会删除信号量。在这种情况下,所有未完成的任务都将就绪。
perr:是指向错误码的指针,该错误码可以包含以下值之一:
OS_ERR_NONE 调用成功,信号量被删除
OS_ERR_DEL_ISR 试图从ISR中删除信号量
OS_ERR_INVALID_OPT 无效的opt选项
OS_ERR_TASK_WAITING 一个或多个任务正在等待信号量
OS_ERR_EVENT_TYPE 未传递一个指向信号量的指针
OS_ERR_PEVENT_NULL 'pevent'是空指针.
返回值:pevent 若成功删除信号量,则返回(OS_EVENT *)0
注:1、此函数必须小心使用。通常期望信号量存在的任务必须检查OSSemPend()的返回值。
2、除非检查“pevent”是否为空指针,否则OSSemAccept()调用者将不知道预期的信号量已被删除。
3、该调用可能会在很长一段时间内禁用中断。中断禁用时间与等待信号量的任务数量成正比。
4、因为信号量上所有挂起的任务都将被就绪,所以在使用信号量进行互斥的应用程序中必须小心,因为信号量将不再保护资源。
5、如果OSSemDel()被OS_DEL_ALWAYS调用,那么等待信号量的所有任务都将被就绪并返回一个OS_ERR_PEND_ABORT
OS_EVENT *OSSemDel (OS_EVENT *pevent,INT8U opt,INT8U *perr)
{BOOLEAN tasks_waiting; /* 是否有任务在等待此信号量的标志 */OS_EVENT *pevent_return;
#if OS_CRITICAL_METHOD == 3u /* 为CPU状态分配存储 */OS_CPU_SR cpu_sr = 0u; /* cpu_sr用于存储CPU状态 */
#endif#ifdef OS_SAFETY_CRITICAL /* 用于认证 */if (perr == (INT8U *)0) {OS_SAFETY_CRITICAL_EXCEPTION();return ((OS_EVENT *)0);}
#endif#if OS_ARG_CHK_EN > 0u /* 使能参数检查 */if (pevent == (OS_EVENT *)0) { /* 'pevent'是否为空指针 */*perr = OS_ERR_PEVENT_NULL; /* 将perr赋值为OS_ERR_PEVENT_NULL */return (pevent);}
#endifif (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* 事件类型是否为信号量事件 */*perr = OS_ERR_EVENT_TYPE; /* 将perr赋值为OS_ERR_EVENT_TYPE */return (pevent);}if (OSIntNesting > 0u) { /* 是否从ISR中调用 */*perr = OS_ERR_DEL_ISR; /* 将perr赋值为OS_ERR_PEVENT_NULL */ return (pevent);}OS_ENTER_CRITICAL(); /* 进入临界区 */if (pevent->OSEventGrp != 0u) { /* 是否有任务在等待此信号量 */tasks_waiting = OS_TRUE; /* 是*/} else {tasks_waiting = OS_FALSE; /* 否 */}switch (opt) {case OS_DEL_NO_PEND: /* 只有在没有任务挂起时才删除信号量 */if (tasks_waiting == OS_FALSE) { /* 没有任务在等待此信号量 */
#if OS_EVENT_NAME_EN > 0u /* 使能事件命名功能 */pevent->OSEventName = (INT8U *)(void *)"?"; /* 将事件名设置为‘?’ */
#endifpevent->OSEventType = OS_EVENT_TYPE_UNUSED; /* 将事件类型设置为未使用 */pevent->OSEventPtr = OSEventFreeList; /* 将事件控制块链接到可用事件控制链表 */pevent->OSEventCnt = 0u; /* 将信号量数量设置为0 */OSEventFreeList = pevent; /* 获取下一个可用的事件控制块 */OS_EXIT_CRITICAL(); /* 退出临界区 */*perr = OS_ERR_NONE; /* 将perr赋值为OS_ERR_NONE*/ pevent_return = (OS_EVENT *)0; /* 信号量已被删除 */} else { /* 有任务在等待此信号量 */OS_EXIT_CRITICAL(); /* 退出临界区 */*perr = OS_ERR_TASK_WAITING; /* 将perr赋值为OS_ERR_TASK_WAITING */pevent_return = pevent; /* 信号量未删除 */}break;case OS_DEL_ALWAYS: /* 即使有任务正在等待,也会删除信号量 */while (pevent->OSEventGrp != 0u) {/* 就绪所有等待此信号量的任务 */(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_ABORT);/}
#if OS_EVENT_NAME_EN > 0u /* 使能事件命名功能 */pevent->OSEventName = (INT8U *)(void *)"?"; /* 将事件名设置为‘?’ */
#endifpevent->OSEventType = OS_EVENT_TYPE_UNUSED; /* 将事件类型设置为未使用 */pevent->OSEventPtr = OSEventFreeList; /* 将事件控制块链接到可用事件控制链表 */pevent->OSEventCnt = 0u; /* 信号量已被删除 */OSEventFreeList = pevent; /* 获取下一个可用的事件控制块 */OS_EXIT_CRITICAL(); /* 退出临界区 */if (tasks_waiting == OS_TRUE) { /* 如果有任务在等待信号量,需重新调度 */OS_Sched(); /* 查找运行就绪的最高优先级任务 */}*perr = OS_ERR_NONE; /* 将perr赋值为OS_ERR_NONE */pevent_return = (OS_EVENT *)0; /* 信号量已被删除 */break;default:OS_EXIT_CRITICAL(); /* 退出临界区 */*perr = OS_ERR_INVALID_OPT; /* 将perr赋值为OS_ERR_INVALID_OPT*/pevent_return = pevent; /* 信号量未删除 */break;}return (pevent_return);
}
4、void OSSemPend (OS_EVENT *pevent, INT32U timeout,INT8U *perr)
宏:OS_SEM_EN > 0u,OS_SEM_DEL_EN> 0u
功能描述:等待信号量。
参数 pevent:指向与所需信号量关联的事件控制块的指针。
timeout:一个可选的超时时间(单位以时钟滴答)。如果非零,则任务将等待信号量资源直到此参数指定的时间量为止。但是,如果为0,那么任务将永远在指定的信号量处等待,直到信号量资源变得可用。
perr:指向将存放错误消息的指针。可能的错误信息有:
OS_ERR_NONE 调用成功,任务拥有了信号量资源,或者,正在等待的事件发生了。
OS_ERR_TIMEOUT 在指定的“超时时间”内没有接收到信号量信号量。
OS_ERR_PEND_ABORT 对信号量的等待被终止。
OS_ERR_EVENT_TYPE 未传递一个指向信号量的指针。
OS_ERR_PEND_ISR 从ISR中调用.
OS_ERR_PEVENT_NULL 'pevent'是空指针.
OS_ERR_PEND_LOCKED 在锁定调度程序时调用此函数
void OSSemPend (OS_EVENT *pevent,INT32U timeout,INT8U *perr)
{
#if OS_CRITICAL_METHOD == 3u /* 为CPU状态分配存储 */OS_CPU_SR cpu_sr = 0u; /* cpu_sr用于存储CPU状态 */
#endif#ifdef OS_SAFETY_CRITICAL /* 用于认证 */if (perr == (INT8U *)0) {OS_SAFETY_CRITICAL_EXCEPTION();return;}
#endif#if OS_ARG_CHK_EN > 0u /* 使能了参数检查功能 */if (pevent == (OS_EVENT *)0) { /* 'pevent'为空指针 */*perr = OS_ERR_PEVENT_NULL; /* 将perr赋值为OS_ERR_PEVENT_NULL */return;}
#endifif (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* pevent事件类型是否为信号量事件 */*perr = OS_ERR_EVENT_TYPE; /* 将perr赋值为OS_ERR_EVENT_TYPE */return;}if (OSIntNesting > 0u) { /* 是否从ISR中调用 */*perr = OS_ERR_PEND_ISR; /* 将perr赋值为OS_ERR_PEND_ISR*/return;}if (OSLockNesting > 0u) { /* 是否在调度器锁定时调用 */*perr = OS_ERR_PEND_LOCKED; /* 将perr赋值为OS_ERR_EVENT_TYPE */return;}OS_ENTER_CRITICAL(); /* 进入临界区 */if (pevent->OSEventCnt > 0u) { /*如果信号量计数为正,说明有可用的信号量资源 */pevent->OSEventCnt--; /* 信号量减一 */OS_EXIT_CRITICAL(); /* 退出临界区 */*perr = OS_ERR_NONE; /* 将perr赋值为OS_ERR_NONE */return;}/* 否则,必须等到事件发生 */OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not available, pend on semaphore */OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;OSTCBCur->OSTCBDly = timeout; /* 在TCB中存储挂起超时时间 */OS_EventTaskWait(pevent); /* 挂起任务,直到事件或超时发生 */OS_EXIT_CRITICAL(); /* 退出临界区 */OS_Sched(); /* 任务调度 */OS_ENTER_CRITICAL(); /* 进入临界区 */switch (OSTCBCur->OSTCBStatPend) { /* 超时或终止 */ case OS_STAT_PEND_OK: /* 获取到信号量 */*perr = OS_ERR_NONE;/* 将perr赋值为OS_ERR_NONE*/break;case OS_STAT_PEND_ABORT: /* 终止 */*perr = OS_ERR_PEND_ABORT; /* 将perr赋值为OS_ERR_PEND_ABORT */break;case OS_STAT_PEND_TO: /* 超时 */default:OS_EventTaskRemove(OSTCBCur, pevent);*perr = OS_ERR_TIMEOUT; /* 将perr赋值为OS_ERR_TIMEOUT */break;}OSTCBCur->OSTCBStat = OS_STAT_RDY; /* 设置当前TCB的任务状态为就绪 */OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* 清除当前TCB的挂起状态 */ OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* 清除事件指针 */
#if (OS_EVENT_MULTI_EN > 0u)OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
#endifOS_EXIT_CRITICAL(); /* 退出临界区 */
}
5、INT8U OSSemPendAbort (OS_EVENT *pevent,INT8U opt,INT8U *perr)
宏:OS_SEM_EN > 0u,OS_SEM_PEND_ABORT_EN> 0u
功能描述:此函数将中止并就绪正在等待信号量的任意任务。该函数应用于故障中止对信号量的等待,而不是通常通过OSSemPost()来对信号量发出信号。
参数 pevent:指向与所需信号量关联的事件控制块的指针。
opt:决定执行终止的类型
OS_PEND_OPT_NONE 中止等待最高优先级任务对信号量的等待
OS_PEND_OPT_BROADCAST 中止等待正在等待信号量的所有任务
perr:指向将消息的指针。可能的错误信息有:
OS_ERR_NONE 信号量上没有任务等待.
OS_ERR_PEND_ABORT 至少有一个等待信号量的任务已经就绪,并被告知等待失败;检查对信号量的等待被中止的任务数量的返回值。
OS_ERR_EVENT_TYPE 未传递一个指向信号量的指针。
OS_ERR_PEVENT_NULL 'pevent'是空指针。
返回值:== 0 如果信号量上没有任务等待,或者出现错误。
> 0 如果等待信号量的一个或多个任务现在已经就绪并得到通知
INT8U OSSemPendAbort (OS_EVENT *pevent,INT8U opt,INT8U *perr)
{INT8U nbr_tasks; /* 终止的任务数量 */
#if OS_CRITICAL_METHOD == 3u /* 为CPU状态分配存储 */OS_CPU_SR cpu_sr = 0u; /* cpu_sr用于存储CPU状态 */
#endif#ifdef OS_SAFETY_CRITICAL /* 用于认证 */if (perr == (INT8U *)0) {OS_SAFETY_CRITICAL_EXCEPTION();return (0u);}
#endif#if OS_ARG_CHK_EN > 0u /* 是否使能参数检查 */if (pevent == (OS_EVENT *)0) { /* 'pevent'为空指针 */*perr = OS_ERR_PEVENT_NULL; /* 将perr赋值为OS_ERR_PEVENT_NULL */return (0u);}
#endifif (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* pevent事件是否为信号量事件 */*perr = OS_ERR_EVENT_TYPE; /* 将perr赋值为OS_ERR_EVENT_TYPE */return (0u);}OS_ENTER_CRITICAL(); /* 进入临界区 */if (pevent->OSEventGrp != 0u) { /* 是否有任务在等待信号量 */nbr_tasks = 0u;switch (opt) {case OS_PEND_OPT_BROADCAST: /* 终止所有等待的任务 */while (pevent->OSEventGrp != 0u) { /* 就绪等待信号量的所有任务 */(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_ABORT); /* 就绪等待信号量的最高优先级任务 */nbr_tasks++; /* 终止的任务数量加一 */}break;case OS_PEND_OPT_NONE:default: /* 就绪等待信号量的最高优先级任务 */(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_ABORT);nbr_tasks++;break;}OS_EXIT_CRITICAL(); /* 退出临界区 */OS_Sched(); /* 任务调度 */*perr = OS_ERR_PEND_ABORT; /* 将perr赋值为OS_ERR_PEND_ABORT */return (nbr_tasks); /* 返回终止的任务数量 */}OS_EXIT_CRITICAL(); /* 退出临界区 */*perr = OS_ERR_NONE; /* 将perr赋值为OS_ERR_NONE */return (0u); /* 没有任务在等待信号量 */
}
6、INT8U OSSemPost (OS_EVENT *pevent)
宏:OS_SEM_EN > 0u
功能描述:释放信号量。
参数 pevent:指向与所需信号量关联的事件控制块的指针。
返回值:
OS_ERR_NONE 调用成功,释放信号量
OS_ERR_SEM_OVF 如果信号量计数超过其限制。换句话说,与使用OSSemAccept()或OSSemPend()等待的信号量相比,发出信号的频率更高。
OS_ERR_EVENT_TYPE 未传递一个指向信号量的指针
OS_ERR_PEVENT_NULL 'pevent'是空指针.
INT8U OSSemPost (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3u /* 为CPU状态分配存储 */OS_CPU_SR cpu_sr = 0u; /* cpu_sr用于存储CPU状态 */
#endif#if OS_ARG_CHK_EN > 0u /* 是否使能了参数检查 */if (pevent == (OS_EVENT *)0) { /* 'pevent'是否为空指针 */return (OS_ERR_PEVENT_NULL);}
#endifif (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* pevent事件是否为信号量事件 */return (OS_ERR_EVENT_TYPE);}OS_ENTER_CRITICAL(); /* 进入临界区 */if (pevent->OSEventGrp != 0u) { /* 是否有任务在等待此信号量 *//* 就绪等待事件的最高优先级的任务 */(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK);OS_EXIT_CRITICAL(); /* 退出临界区 */OS_Sched(); /* 任务调度 */return (OS_ERR_NONE);}if (pevent->OSEventCnt < 65535u) { /* 确保信号量不会溢出 */pevent->OSEventCnt++; /* 注册事件的信号量计数器加一 */OS_EXIT_CRITICAL(); /* 退出临界区 */return (OS_ERR_NONE);}OS_EXIT_CRITICAL(); /* 退出临界区 */return (OS_ERR_SEM_OVF);
}
7、OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *p_sem_data)
宏:OS_SEM_EN > 0u,OS_SEM_QUERY_EN>0u
功能描述:获得关于信号量的信息。
参数 pevent:指向与所需信号量关联的事件控制块的指针。
p_sem_data:是指向包含有关信号量信息的指针。
返回值:
OS_ERR_NONE 调用成功,
OS_ERR_EVENT_TYPE 试图从获取非信号量的数据。
OS_ERR_PEVENT_NULL 'pevent' 是空指针。
OS_ERR_PDATA_NULL 'p_sem_data'是空指针。
INT8U OSSemQuery (OS_EVENT *pevent,OS_SEM_DATA *p_sem_data)
{INT8U i;OS_PRIO *psrc;OS_PRIO *pdest;
#if OS_CRITICAL_METHOD == 3u /* 为CPU状态分配存储 */OS_CPU_SR cpu_sr = 0u; /* cpu_sr用于存储CPU状态 */
#endif#if OS_ARG_CHK_EN > 0u /* 是否使能了参数检查功能 */if (pevent == (OS_EVENT *)0) { /* 'pevent'是否为空指针 */return (OS_ERR_PEVENT_NULL);}if (p_sem_data == (OS_SEM_DATA *)0) {/* 'p_sem_data'是否为空指针 */return (OS_ERR_PDATA_NULL);}
#endifif (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* pevent事件类型是否为信号量事件 */return (OS_ERR_EVENT_TYPE);}OS_ENTER_CRITICAL(); /* 进入临界区 *//* 拷贝信号量等待列表 */p_sem_data->OSEventGrp = pevent->OSEventGrp; psrc = &pevent->OSEventTbl[0];pdest = &p_sem_data->OSEventTbl[0];for (i = 0u; i < OS_EVENT_TBL_SIZE; i++) {*pdest++ = *psrc++;}p_sem_data->OSCnt = pevent->OSEventCnt; /* 获取信号量计数 */OS_EXIT_CRITICAL(); /* 退出临界区 */return (OS_ERR_NONE);
}
8、void OSSemSet (OS_EVENT *pevent,INT16U cnt,INT8U *perr)
宏:OS_SEM_EN > 0u,OS_SEM_SET_EN>0u
功能描述:此函数将信号量计数设置为作为参数指定的值。通常,这个值是0。当信号量用作信号机制并希望重置计数值时,通常会使用此函数。
参数 pevent:指向与所需信号量关联的事件控制块的指针。
cnt: 信号量计数的新值。可以传递0来重置信号量计数。
perr:函数返回的错误码的指针,如下所示:
OS_ERR_NONE 调用成功,并设置了信号量值。
OS_ERR_EVENT_TYPE 未传递一个指向信号量的指针。
OS_ERR_PEVENT_NULL 'pevent' 为空指针。
OS_ERR_TASK_WAITING 如果任务正在等待信号量。
void OSSemSet (OS_EVENT *pevent,INT16U cnt,INT8U *perr)
{
#if OS_CRITICAL_METHOD == 3u /* 为CPU状态分配存储 */OS_CPU_SR cpu_sr = 0u; /* cpu_sr用于存储CPU状态 */
#endif#ifdef OS_SAFETY_CRITICAL /* 用于认证 */if (perr == (INT8U *)0) {OS_SAFETY_CRITICAL_EXCEPTION();return;}
#endif#if OS_ARG_CHK_EN > 0u /* 是否使能参数检查 */if (pevent == (OS_EVENT *)0) { /* 'pevent'是否为空指针 */*perr = OS_ERR_PEVENT_NULL; /* 将perr赋值为OS_ERR_PEVENT_NULL */return;}
#endifif (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* pevent事件类型是否为信号量事件 */*perr = OS_ERR_EVENT_TYPE; /* 将perr赋值为OS_ERR_EVENT_TYPE */return;}OS_ENTER_CRITICAL(); /* 进入临界区 */*perr = OS_ERR_NONE;if (pevent->OSEventCnt > 0u) { /* 信号量值是否大于0 */pevent->OSEventCnt = cnt; /* 设置为指定的值 */} else { if (pevent->OSEventGrp == 0u) { /* 是否有任务在等待信号量 */pevent->OSEventCnt = cnt; /* 没有任务在等待信号量 ,设置为指定的值*/} else {*perr = OS_ERR_TASK_WAITING; /* 将perr赋值为OS_ERR_TASK_WAITING */}}OS_EXIT_CRITICAL(); /* 退出临界区 */
}