现在的位置: 首页 > 综合 > 正文

uC/OS-II V2.86 发送和等待一个信号量的工作原理

2013年08月05日 ⁄ 综合 ⁄ 共 9093字 ⁄ 字号 评论关闭

一、发送一个信号量 OSSemPost ()

/*
*********************************************************************************************************
*                                         POST TO A SEMAPHORE
*
* Description  : This function signals a semaphore
*
* Arguments  : pevent        is a pointer to the event control block associated with the desired
*                            semaphore.
*
* Returns      : OS_ERR_NONE         The call was successful and the semaphore was signaled.
*                    OS_ERR_SEM_OVF      If the semaphore count exceeded its limit.  In other words, you have
*                                  signalled the semaphore more often than you waited on it with either
*                                  OSSemAccept() or OSSemPend().
*                    OS_ERR_EVENT_TYPE   If you didn't pass a pointer to a semaphore
*                    OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer.
*********************************************************************************************************
*/

INT8U  OSSemPost (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register      */
    OS_CPU_SR  cpu_sr = 0;
#endif

 

#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {                   /* Validate 'pevent'     确保指针合法                        */
        return (OS_ERR_PEVENT_NULL);
    }
#endif

 

    OS_ENTER_CRITICAL();             /* 关中断 */

    if (pevent->OSEventGrp != 0) {                    /* 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_EventTaskRdy()函数把优先级最高的任务Taskx从等待列表中删除,并使其进入就绪态 */

        OS_EXIT_CRITICAL();            /* 开中断 */

        OS_Sched();                                            /* Find HPT ready to run  检查Taskx是否是系统中的最高优先级的

                                                                          就绪态任务,是,则立即进行任务切换,(若ISR调用OSSemPost() ,则不会立即切换,

                                                                          要等到中断嵌套的最外层ISR调用OSIntExit()后才进行任务切换)准备执行Taskx

                                                                          因为OSSemPost() 函数使得更重要的任务进入了就绪态,故调用OSSemPost() 的任务

                                                                          就不能继续运行了 */
        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);
}

 

 

 

二、等待(请求)一个信号量 OSSemPend ()

/*
*********************************************************************************************************
*                                           PEND ON SEMAPHORE
*
* Description: This function waits for a semaphore.

*
* Arguments  : pevent        is a pointer to the event control block associated with the desired
*                            semaphore.
*
*                     timeout       is an optional timeout period (in clock ticks).  If non-zero, your task will
*                            wait for the resource up to the amount of time specified by this argument.
*                            If you specify 0, however, your task will wait forever at the specified
*                            semaphore or, until the resource becomes available (or the event occurs).
*
*                     perr          is a pointer to where an error message will be deposited.  Possible error
*                            messages are:
*
*                            OS_ERR_NONE         The call was successful and your task owns the resource
*                                                or, the event you are waiting for occurred.
*                            OS_ERR_TIMEOUT      The semaphore was not received within the specified
*                                                'timeout'.
*                            OS_ERR_PEND_ABORT   The wait on the semaphore was aborted.
*                            OS_ERR_EVENT_TYPE   If you didn't pass a pointer to a semaphore.
*                            OS_ERR_PEND_ISR     If you called this function from an ISR and the result
*                                                would lead to a suspension.
*                            OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer.
*                            OS_ERR_PEND_LOCKED  If you called this function when the scheduler is locked
*
* Returns    : none
*********************************************************************************************************
*/
void  OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)
{
#if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register                                   */
    OS_CPU_SR  cpu_sr = 0;
#endif

 

#if OS_ARG_CHK_EN > 0              /* 若OS_ARG_CHK_EN 被设置为1                                                  */  
    if (perr == (INT8U *)0) {                                  /* Validate 'perr'        错误代码指针perr是否为非空指针                       */
        return;
    }
    if (pevent == (OS_EVENT *)0) {                        /* Validate 'pevent'    pevent 是否为非空指针                                    */
        *perr = OS_ERR_PEVENT_NULL;
        return;
    }
#endif

    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* Validate event block type     

                                                                                        是否指向由OSSemCreate()函数建立的事件控制块ECB             */
        *perr = OS_ERR_EVENT_TYPE;
        return;
    }

    if (OSIntNesting > 0) {                            /* See if called from ISR ...   是否是中断服务子程序调用了本函数                    */
        *perr = OS_ERR_PEND_ISR;                /* ... can't PEND from an ISR   

                                                                     因为ISR不能等待,故调用本函数没有意义,不过ISR可以调用OSSemAccept()

                                                                     即无等待地请求一个信号量   */
        return;
    }

    if (OSLockNesting > 0) {                                   /* See if called with scheduler locked ...       */
        *perr = OS_ERR_PEND_LOCKED;                  /* ... can't PEND when locked         

                                                                              若调度器被锁定,则等待一个信号量变得没有意义           */
        return;
    }

    OS_ENTER_CRITICAL();
    if (pevent->OSEventCnt > 0) {                     /* 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   

                                                                         否则等待另一个任务或ISR发出信号量 OSSemPost()   */
    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     

                                                                                       将指向信号量ECB的指针从任务的任务控制块中删除              */

 

 


#if (OS_EVENT_MULTI_EN > 0)
    OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
#endif
    OS_EXIT_CRITICAL();
}

 

    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* Validate event block type     指针指向ECB?                */
        return (OS_ERR_EVENT_TYPE);
    }

抱歉!评论已关闭.