/*
** ver : 2.52
** file : os_sem.c
** brief : 信号量相关函数C文件
*/
#ifndef OS_MASTER_FILE
#include "includes.h" /* 包含头文件 */
#endif
#if OS_SEM_EN > 0
/*
***************************************************************************
* 无等待的请求信号量
*
* brief : 该函数用于无等待的请求信号量,信号量无效时也不会使任务挂起
*
* pevent : 指向事件控制块的指针
*
* Returns : > 0 信号量有效
* == 0 信号量无效
***************************************************************************
*/
#if OS_SEM_ACCEPT_EN > 0
INT16U OSSemAccept (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
INT16U cnt;
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 无效的事件控制块指针 */
return (0);
}
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {
return (0); /* 无效的事件类型 */
}
#endif
OS_ENTER_CRITICAL();
cnt = pevent->OSEventCnt; /* 记录当前信号量值 */
if (cnt > 0) { /* 信号量有效 */
pevent->OSEventCnt--; /* 信号量值减 1 */
}
OS_EXIT_CRITICAL();
return (cnt); /* 返回信号量值 */
}
#endif
/*$PAGE*/
/*
*******************************************************************************
* 创建信号量
*
* brief : 该函数用于创建信号量
*
* cnt : 信号量初始值.如果信号量是用来表示一个或多个事件发生的
* 那么该信号量的初始值通常赋为0,如果信号量用于对共享资
* 源的访问,那么该信号量的初始化赋为1(例如把它当做二值
* 信号量使用),如果信号量用来表示允许任务访问n个相同的
* 资源,那么该信号量的初始值应被赋为n
*
* returns : != (void *)0 事件控制块指针,创建信号量成功
* == (void *)0 创建失败
********************************************************************************
*/
OS_EVENT *OSSemCreate (INT16U cnt)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
OS_EVENT *pevent;
if (OSIntNesting > 0) { /* 中断中不允许创建信号量 */
return ((OS_EVENT *)0);
}
OS_ENTER_CRITICAL();
pevent = OSEventFreeList; /* 获取一个空事件控制块 */
if (OSEventFreeList != (OS_EVENT *)0) { /* 调整事件控制块链表 */
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
}
OS_EXIT_CRITICAL();
if (pevent != (OS_EVENT *)0) { /* 获得一个事件控制块 */
pevent->OSEventType = OS_EVENT_TYPE_SEM;
pevent->OSEventCnt = cnt; /* 设置信号量初始值 */
pevent->OSEventPtr = (void *)0; /* 不在属于空事件控制块链表 */
OS_EventWaitListInit(pevent); /* 初始化等待任务表 */
}
return (pevent);
}
/*$PAGE*/
/*
********************************************************************************
* 删除信号量
*
* brief : 该函数用于删除信号量
*
* pevent : 指向事件控制块的指针
*
* opt : 删除信号量的选项:
* opt == OS_DEL_NO_PEND 无任务等待时删除
* opt == OS_DEL_ALWAYS 有无任务等待都删除,如有等待则进入就绪态
*
* err : 指向错误代码的指针,可能取值:
* OS_NO_ERR 成功删除
* OS_ERR_DEL_ISR 不能再中断中删除信号量
* OS_ERR_INVALID_OPT 无效的删除选项
* OS_ERR_TASK_WAITING 有任务正在等待信号量
* OS_ERR_EVENT_TYPE 错误的事件类型
* OS_ERR_PEVENT_NULL 事件控制块指针为空
*
* returns : pevent 出错
* (OS_EVENT *)0 成功删除
*
* Note(s) : 1) 该函数必须谨慎的使用.任务可能会请求已经删除了的信号量
* 应该检查OSSemPend()的返回值.
* 2) 调用OSSemAccept()的函数不知道信号量已经被删除了
* 3) 该函数将中断关闭. 中断关闭的时间取决于正在等待信号量
* 的任务数
* 4) 因为所有等待的任务都将进入就绪态,所以必须小心的使用
* 该函数
*******************************************************************************
*/
#if OS_SEM_DEL_EN > 0
OS_EVENT *OSSemDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
BOOLEAN tasks_waiting;
if (OSIntNesting > 0) { /* 不允许在中断中删除信号量 */
*err = OS_ERR_DEL_ISR;
return (pevent);
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 无效的时间控制块指针 */
*err = OS_ERR_PEVENT_NULL;
return (pevent);
}
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {
*err = OS_ERR_EVENT_TYPE; /* 无效的事件类型 */
return (pevent);
}
#endif
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0x00) { /* 查询是否有任务正等待信号量 */
tasks_waiting = TRUE; /* 有 */
} else {
tasks_waiting = FALSE; /* 无 */
}
switch (opt) {
case OS_DEL_NO_PEND: /* 无任务等待删除 */
if (tasks_waiting == FALSE) {
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
pevent->OSEventPtr = OSEventFreeList; /* 事件类型 */
OSEventFreeList = pevent; /* 返还事件控制块 */
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return ((OS_EVENT *)0); /* 信号量已被删除 */
} else {
OS_EXIT_CRITICAL();
*err = OS_ERR_TASK_WAITING; /* 有任务正等待信号量 */
return (pevent);
}
case OS_DEL_ALWAYS: /* 有无任务等待都删除 */
while (pevent->OSEventGrp != 0x00) { /* 所有等待任务就绪 */
OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM);
}
pevent->OSEventType = OS_EVENT_TYPE_UNUSED; /* 事件类型 */
pevent->OSEventPtr = OSEventFreeList; /* 返还事件控制块 */
OSEventFreeList = pevent;
OS_EXIT_CRITICAL();
if (tasks_waiting == TRUE) {
OS_Sched(); /* 任务调度 */
}
*err = OS_NO_ERR;
return ((OS_EVENT *)0); /* 信号量已被删除 */
default:
OS_EXIT_CRITICAL();
*err = OS_ERR_INVALID_OPT; /* 无效的删除选项 */
return (pevent);
}
}
#endif
/*$PAGE*/
/*
******************************************************************************
* 请求一个信号量
*
* brief : 该函数用于请求信号量
*
* pevent : 指向信号量的指针
*
* timeout : 等待超时时限.
* 为0 : 无限的等待或者等待的事件发生
* 不为0 : 超时进入就绪或者等待的事件发生
*
* err : 指向出错代码的指针,可能取值:
*
* OS_NO_ERR 成功
* OS_TIMEOUT 等待超时
* OS_ERR_EVENT_TYPE 错误的事件类型
* OS_ERR_PEND_ISR 不能在中断中请求信号量
* OS_ERR_PEVENT_NULL 错误的事件控制块指针
*
*******************************************************************************
*/
void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
if (OSIntNesting > 0) { /* 中断中不能请求信号量 */
*err = OS_ERR_PEND_ISR;
return;
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 无效的事件控制块指针 */
*err = OS_ERR_PEVENT_NULL;
return;
}
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {
*err = OS_ERR_EVENT_TYPE; /* 无效的事件类型 */
return;
}
#endif
OS_ENTER_CRITICAL();
if (pevent->OSEventCnt > 0) { /* 信号量有效 */
pevent->OSEventCnt--; /* 信号量值减 1 */
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return;
}
/* 无有效的信号量 */
OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* 任务状态为等待信号量 */
OSTCBCur->OSTCBDly = timeout; /* 超时时限 */
OS_EventTaskWait(pevent); /* 任务进入等待状态 */
OS_EXIT_CRITICAL();
OS_Sched(); /* 任务调度 */
OS_ENTER_CRITICAL();
if (OSTCBCur->OSTCBStat & OS_STAT_SEM) {/* 超时而进入就绪态 */
OS_EventTO(pevent);
OS_EXIT_CRITICAL();
*err = OS_TIMEOUT; /* 等待超时 */
return;
}
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
}
/*$PAGE*/
/*
******************************************************************************
* 释放信号量
*
* brief : 该函数用于释放信号量
*
* pevent : 指向事件控制块的指针
*
* Returns : OS_NO_ERR 成功
* OS_SEM_OVF 信号量值超过最大值
* OS_ERR_EVENT_TYPE 无效的事件类型
* OS_ERR_PEVENT_NULL 无效的事件控制块指针
******************************************************************************
*/
INT8U OSSemPost (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 无效的事件控制块指针 */
return (OS_ERR_PEVENT_NULL);
}
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {
return (OS_ERR_EVENT_TYPE); /* 无效的事件类型 */
}
#endif
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0x00) { /* 是否有任务在等待信号量 */
OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM);/* 优先级最高的等待任务就绪 */
OS_EXIT_CRITICAL();
OS_Sched(); /* 任务调度 */
return (OS_NO_ERR);
}
if (pevent->OSEventCnt < 65535) { /* 确保信号量值正确 */
pevent->OSEventCnt++; /* 增加信号量值 */
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
OS_EXIT_CRITICAL(); /* 信号量值错误 */
return (OS_SEM_OVF);
}
/*$PAGE*/
/*
******************************************************************************
* 查询信号量
*
* brief : 该函数用于获取信号量的信息
*
* pevent : 指向事件控制块的指针
*
* pdata : 指向返回信号量信息数据结构的指针
*
* Returns : OS_NO_ERR 成功
* OS_ERR_EVENT_TYPE 无效的事件类型
* OS_ERR_PEVENT_NULL 无效的事件控制块指针
******************************************************************************
*/
#if OS_SEM_QUERY_EN > 0
INT8U OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *pdata)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
INT8U *psrc;
INT8U *pdest;
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 无效的事件控制块指针 */
return (OS_ERR_PEVENT_NULL);
}
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* 无效的事件类型 */
return (OS_ERR_EVENT_TYPE);
}
#endif
OS_ENTER_CRITICAL();
pdata->OSEventGrp = pevent->OSEventGrp; /* 复制等待任务表 */
psrc = &pevent->OSEventTbl[0];
pdest = &pdata->OSEventTbl[0];
#if OS_EVENT_TBL_SIZE > 0
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 1
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 2
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 3
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 4
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 5
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 6
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 7
*pdest = *psrc;
#endif
pdata->OSCnt = pevent->OSEventCnt; /* 复制信号量值 */
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
#endif
#endif
uC/OS-II源码解析(os_sem.c)
最新推荐文章于 2022-04-02 01:30:17 发布