uCO/OS-ii源码 信号量理解

UCOSII-Version : V2.92.07

信号量作用

用于从一个任务向另一个任务传递一个开关量的BOOL信号。

事件控制块

一个任务或者中断服务子程序可以通过事件控制块 ECB(Event Control Blocks)来向另外的任务发信号。这里,所有的信号都被看成是事件(Event)。把用于通讯的数据结构叫做事件控制块。
µC/OS-II通过uCOS_II.H 中定义的 OS_EVENT数据结构来维护一个事件控制块的所有信息,也就是这里讲到的事件控制块 ECB。该结构中除了包含了事件本身的定义,如用于信号量的计数器,用于指向邮箱的指针,以及指向消息队列的指针数组等,还定义了等待该事件的所有任务的列表。

typedef struct
{ 
    void   *OSEventPtr;                     /* 指向消息或者消息队列的指针 */
    INT8U   OSEventTbl[OS_EVENT_TBL_SIZE];  /* 等待任务列表      */
    INT16U  OSEventCnt;                     /* 计数器(当事件是信号量时) */
    INT8U   OSEventType;                    /* 时间类型  */
    INT8U   OSEventGrp;                     /* 等待任务所在的组  */
} OS_EVENT;

0S_EVENT *OSSemCreate (INT16U cnt)注解

OS_EVENT  *OSSemCreate (INT16U cnt)
{
    OS_EVENT  *pevent;
/*ucosii采用方法3来开关中断,os_cpu_sr是用来存cpu状态寄存器*/
#if OS_CRITICAL_METHOD == 3u                               /* Allocate storage for CPU status register */
    OS_CPU_SR  cpu_sr = 0u;
#endif


/*未定义宏*/
#ifdef OS_SAFETY_CRITICAL_IEC61508
    if (OSSafetyCriticalStartFlag == OS_TRUE) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return ((OS_EVENT *)0);
    }
#endif
    /*如果中断子程序调用,一般不会,防御性编程*/
    if (OSIntNesting > 0u) {                               /* See if called from ISR ...               */
        return ((OS_EVENT *)0);                            /* ... can't CREATE from an ISR             */
    }
    OS_ENTER_CRITICAL();
    /*从空闲任务控制块链表中得到一个事件控制块*/
    pevent = OSEventFreeList;                              /* Get next free event control block        */
    /*空闲事件控制块链表指针非空闲事件快,即指向下一个空闲事件控制块*/
    if (OSEventFreeList != (OS_EVENT *)0) {                /* See if pool of free ECB pool was empty   */
        OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
    }
    OS_EXIT_CRITICAL();
    /*如果该控制块可用*/
    if (pevent != (OS_EVENT *)0) {                         /* Get an event control block               */
        /*该任务控制块的事件类型设置成信号量,防止其他类型任务控制块操作,如邮箱*/
        pevent->OSEventType    = OS_EVENT_TYPE_SEM;
        /*信号量值初始化*/
        pevent->OSEventCnt     = cnt;                      /* Set semaphore value                      */
        /*不链接空闲任务控制块*/
        pevent->OSEventPtr     = (void *)0;                /* Unlink from ECB free list                */
#if OS_EVENT_NAME_EN > 0u
        pevent->OSEventName    = (INT8U *)(void *)"?";
#endif
        /*等待任务列表进行初始化*/
        OS_EventWaitListInit(pevent);                      /* Initialize to 'nobody waiting' on sem.   */
    }
    return (pevent);
}

INT8U OSSemPost (OS_EVENT *pevent)注解

INT8U  OSSemPost (OS_EVENT *pevent)
{
/*ucosii采用方法3来开关中断,os_cpu_sr是用来存cpu状态寄存器*/
#if OS_CRITICAL_METHOD == 3u                          /* Allocate storage for CPU status register      */
    OS_CPU_SR  cpu_sr = 0u;
#endif



#if OS_ARG_CHK_EN > 0u
    /*检测是否有信号量*/
    if (pevent == (OS_EVENT *)0) {                    /* Validate "pevent"                             */
        return (OS_ERR_PEVENT_NULL);
    }
#endif
    /*检查参数指针pevent指向的任务控制块是否是OSSemCreate()创建*/
    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* Validate event block type                     */
        return (OS_ERR_EVENT_TYPE);
    }
    OS_ENTER_CRITICAL();
    /*检查是否有任务在等待该信号量,非0值即有等待该信号量*/
    if (pevent->OSEventGrp != 0u) {                   /* 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_EXIT_CRITICAL();
        /*任务调度,如果就绪任务满足最高优先级,即任务切换*/
        OS_Sched();                                   /* Find HPT ready to run                         */
        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);
}

void OSSemPend(OS_EVENT *pevent,INT32U timeout,INT8U *perr)注解

void  OSSemPend (OS_EVENT *pevent,INT32U timeout,INT8U *perr)//timeout为0的时候表示无限等待
{
/*ucosii采用方法3来开关中断,os_cpu_sr是用来存cpu状态寄存器*/
#if OS_CRITICAL_METHOD == 3u                          /* Allocate storage for CPU status register      */
    OS_CPU_SR  cpu_sr = 0u;
#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) {                    /* Validate "pevent"                             */
        *perr = OS_ERR_PEVENT_NULL;
        return;
    }
#endif
    /*检查参数指针pevent指向的任务控制块是否是OSSemCreate()创建*/
    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* Validate event block type                     */
        *perr = OS_ERR_EVENT_TYPE;
        return;
    }
    /*如果中断子程序调用,即不能请求*/
    if (OSIntNesting > 0u) {                          /* See if called from ISR ...                    */
        *perr = OS_ERR_PEND_ISR;                      /* ... can"t PEND from an ISR                    */
        return;
    }
    /*如果调度器被锁,即不能请求*/
    if (OSLockNesting > 0u) {                         /* See if called with scheduler locked ...       */
        *perr = OS_ERR_PEND_LOCKED;                   /* ... can't PEND when locked                    */
        return;
    }
    OS_ENTER_CRITICAL();
    /*当前信号量大于0,将其计数值减1*/
    if (pevent->OSEventCnt > 0u) {                    /* 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       */
    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                          */
#if (OS_EVENT_MULTI_EN > 0u)
    OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
#endif
    OS_EXIT_CRITICAL();
}

Version2.92.07的OSSemPend()中挂起任务及任务切换的处理和ucos-ii中文书(邵贝贝)PDF版的处理差异目前借助英文注释理解,其理解还停留在表层,待深入理解后再跟进。

信号量像一把钥匙,任务要运行下去,需先拿到这把钥匙
消息邮箱是一个指针型变量。可以向一个任务或一个中断服务子程序发送一则消息(一个指针),同样,一个或多个任务通过内核服务,可以接收这则消息。消息邮箱也可以当作2值信号量来用。
消息队列实际上是邮箱阵列

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值