uC/OS-II源码解析(os_sem.c)

/*
** 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                                                                               
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七七云享

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值