μC/OS-Ⅱ源码学习(4)---信号量

        快速回顾

μC/OS-Ⅱ中的多任务

μC/OS-Ⅱ源码学习(1)---多任务系统的实现

μC/OS-Ⅱ源码学习(2)---多任务系统的实现(下)

μC/OS-Ⅱ源码学习(3)---事件模型

        本文进一步解析事件模型中,信号量类型的函数源码。

         先回顾一下上一节的通用事件控制块类型OS_EVENT

//ucos_ii.h
typedef struct os_event {
    INT8U    OSEventType;      /* 事件类型,有六种(其中一种是UNUSED) */
    void    *OSEventPtr;       /* OSEventPtr是一个多用途的指针,当作为链表时,可以指向下一个控制块;当作为具体的事件控制块时,指向具体的事件结构,如OS_Q。信号量不使用该指针 */  
    INT16U   OSEventCnt;       /* 信号量计数器,其它事件类型不使用该成员 */
    OS_PRIO  OSEventGrp;       /* 等待信号的任务优先级组,和OSEventTbl共同组成”事件等待表“ */
    OS_PRIO  OSEventTbl[OS_EVENT_TBL_SIZE];  /* 等待信号的组内优先级 */

#if OS_EVENT_NAME_EN > 0u
    INT8U   *OSEventName;      //事件名称
#endif
} OS_EVENT;

信号量的创建

        信号量的创建函数为OSSemCreate(cnt),传入的cnt会作为初始值填入OSEventCnt成员,由于信号量没有自己的专属结构,因此OSEventPtr指向空。

//os_sem.c
OS_EVENT  *OSSemCreate (INT16U cnt)
{
    OS_EVENT  *pevent;
#if OS_CRITICAL_METHOD == 3u            /* 初始化临界区变量 */
    OS_CPU_SR  cpu_sr = 0u;
#endif



#ifdef OS_SAFETY_CRITICAL_IEC61508       //IEC标准,可以忽略
    if (OSSafetyCriticalStartFlag == OS_TRUE) {
        OS_SAFETY_CRITICAL_EXCEPTION();
    }
#endif

    if (OSIntNesting > 0u) {        /* 不能在中断中创建信号量         */
        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;       /* 内部指针指向空,断开和原链表的联系,信号量也没有自己的事件结构需要链接 */
#if OS_EVENT_NAME_EN > 0u
        pevent->OSEventName    = (INT8U *)(void *)"?";
#endif
        OS_EventWaitListInit(pevent);       /* 初始化等待任务表,就是把OSEventGrp和OSEventTbl清零 */
    }
    return (pevent);
}
 

信号量的操作

        信号量的操作有很多种,最常用的就是等待(Pend)和释放(Post)了,接下来依次探究各个信号量操作函数源码。

OSSemPend(OS_EVENT *pevent, INT32U timeout, INT8U *perr)

        先描述该函数的作用:

①任务使用该语句时,表明需要等待信号量pevent,当信号量计数器大于0时,直接减1并返回继续执行任务;当计数器等于0时,则要等待其它任务释放信号量。

②如果给定了timeout不为0,则若timeout减至0时都没有取得信号量,直接返回执行;若传入的timeout为0,则一直等待直到获得信号量。

//os_sem.c
void  OSSemPend (OS_EVENT  *pevent,
                 INT32U     timeout,
                 INT8U     *perr)
{
#if OS_CRITICAL_METHOD == 3u       /* 初始化临界区变量 */
    OS_CPU_SR  cpu_sr = 0u;
#endif



#ifdef OS_SAFETY_CRITICAL        //IEC标准,可以忽略
    if (perr == (INT8U *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
    }
#endif

#if OS_ARG_CHK_EN > 0u
    if (pevent == (OS_EVENT *)0) {
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值