逐字逐句解析ucos ii 原始碼-》OS_SEM.C
阿新 • • 發佈:2019-02-17
//BY 簡單的元清 //部分內容引用了其他博主的文章,對這些博主表示感謝,時間關係就不一一指出了。 //如有轉載,請說明,謝謝 /* ********************************************************************************************************* * uC/OS-II * The Real-Time Kernel * SEMAPHORE MANAGEMENT * * (c) Copyright 1992-1998, Jean J. Labrosse, Plantation, FL * All Rights Reserved * * V2.00 * * File : OS_SEM.C * By : Jean J. Labrosse ********************************************************************************************************* */ #ifndef OS_MASTER_FILE #include "software\includes.h" #endif #if OS_SEM_EN /* ********************************************************************************************************* * ACCEPT SEMAPHORE * * Description: This function checks the semaphore to see if a resource is available or, if an event * occurred. Unlike OSSemPend(), OSSemAccept() does not suspend the calling task if the * resource is not available or the event did not occur. * * Arguments : pevent is a pointer to the event control block * * Returns : > 0 if the resource is available or the event did not occur the semaphore is * decremented to obtain the resource. * == 0 if the resource is not available or the event did not occur or, * you didn't pass a pointer to a semaphore ********************************************************************************************************* */ #if OS_SEM_ACCEPT_EN > 0 //無等待地請求一個訊號量 INT16U OSSemAccept (OS_EVENT *pevent) reentrant { INT16U cnt; OS_ENTER_CRITICAL(); //進入臨界區 if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */ OS_EXIT_CRITICAL(); return (0); //如果型別不是訊號量,退出臨界區返回錯誤碼 } cnt = pevent->OSEventCnt; //讀取訊號量 if (cnt > 0) { /* See if resource is available */ pevent->OSEventCnt--; /* Yes, decrement semaphore and notify caller */ //如果訊號量不是0,計數器減一 } OS_EXIT_CRITICAL(); //退出臨界區 return (cnt); //返回訊號量 // /* Return semaphore count */ } #endif /*$PAGE*/ /* ********************************************************************************************************* * CREATE A SEMAPHORE * * Description: This function creates a semaphore. * * Arguments : cnt is the initial value for the semaphore. If the value is 0, no resource is * available (or no event has occurred). You initialize the semaphore to a * non-zero value to specify how many resources are available (e.g. if you have * 10 resources, you would initialize the semaphore to 10). * * Returns : != (void *)0 is a pointer to the event control clock (OS_EVENT) associated with the * created semaphore * == (void *)0 if no event control blocks were available ********************************************************************************************************* */ //建立一個訊號量 OS_EVENT *OSSemCreate (INT16U cnt) reentrant { OS_EVENT *pevent; 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; //判斷ECB塊是不是空 } OS_EXIT_CRITICAL(); //退出臨界區 if (pevent != (OS_EVENT *)0) { /* Get an event control block */ pevent->OSEventType = OS_EVENT_TYPE_SEM; pevent->OSEventCnt = cnt; //如果有事件發生,把型別設定為SEM,賦值 /* Set semaphore value */ OSEventWaitListInit(pevent); //新增進等待列表 } return (pevent); } /*$PAGE*/ /* ********************************************************************************************************* * 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). * * err is a pointer to where an error message will be deposited. Possible error * messages are: * * OS_NO_ERR The call was successful and your task owns the resource * or, the event you are waiting for occurred. * OS_TIMEOUT The semaphore was not received within the specified * timeout. * 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. * * Returns : none ********************************************************************************************************* */ //等待一個訊號量 void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) reentrant { OS_ENTER_CRITICAL(); //進入臨界區 if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */ OS_EXIT_CRITICAL(); *err = OS_ERR_EVENT_TYPE; //如果事件的型別不是訊號量,退出臨界區然後返回錯誤碼 } if (pevent->OSEventCnt > 0) { /* If sem. is positive, resource available ... */ //如果有訊號發生 pevent->OSEventCnt--; /* ... decrement semaphore only if positive. */ //數目減一 OS_EXIT_CRITICAL(); //退出臨界區 *err = OS_NO_ERR; //返回錯誤碼 } else if (OSIntNesting > 0) { /* See if called from ISR ... */ //如果有中斷髮生 OS_EXIT_CRITICAL(); /* ... can't PEND from an ISR */ //退出臨界區 *err = OS_ERR_PEND_ISR; //返回錯誤碼 } else { /* Otherwise, must wait until event occurs */ OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not available, pend on semaphore */ OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */ OSEventTaskWait(pevent); /* Suspend task until event or timeout occurs */ //賦值訊號量引數給給OSTCBCur並加入等待列表 OS_EXIT_CRITICAL(); //退出臨界區 OSSched(); /* Find next highest priority task ready */ //退出臨界區 OS_ENTER_CRITICAL(); //進入臨界區 if (OSTCBCur->OSTCBStat & OS_STAT_SEM) { /* Must have timed out if still waiting for event*/ //如果超時並存在等待任務 OSEventTO(pevent); //直接執行不再等待 OS_EXIT_CRITICAL(); //退出臨界區 *err = OS_TIMEOUT; /* Indicate that didn't get event within TO */ //返回錯誤碼 } else { OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; //OSTCBCur->OSTCBEventPtr指向空指標 OS_EXIT_CRITICAL(); *err = OS_NO_ERR; //退出臨界區然後返回錯誤碼 } } } /*$PAGE*/ /* ********************************************************************************************************* * 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_NO_ERR The call was successful and the semaphore was signaled. * OS_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 ********************************************************************************************************* */ //傳送訊號量 INT8U OSSemPost (OS_EVENT *pevent) reentrant { OS_ENTER_CRITICAL(); //進入臨界區 if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */ OS_EXIT_CRITICAL(); return (OS_ERR_EVENT_TYPE); //如果事件的型別不是訊號量,退出臨界區然後返回錯誤碼 } if (pevent->OSEventGrp) { /* See if any task waiting for semaphore */ //如果有事件發生 OSEventTaskRdy(pevent, (void *)0, OS_STAT_SEM); /* Ready highest prio task waiting on event */ //把任務就緒 OS_EXIT_CRITICAL(); //退出臨界區 OSSched(); /* Find highest priority task ready to run */ //進行排程 return (OS_NO_ERR); //返回錯誤碼 } else { if (pevent->OSEventCnt < 65535) { /* Make sure semaphore will not overflow */ pevent->OSEventCnt++; /* Increment semaphore count to register event */ //如果訊號量滿足小於65535,pevent->OSEventCnt加加 OS_EXIT_CRITICAL(); return (OS_NO_ERR); //退出臨界區然後返回錯誤碼 } else { /* Semaphore value has reached its maximum */ OS_EXIT_CRITICAL(); //退出臨界區 return (OS_SEM_OVF); } } } /* ********************************************************************************************************* * QUERY A SEMAPHORE * * Description: This function obtains information about a semaphore * * Arguments : pevent is a pointer to the event control block associated with the desired * semaphore * * pdata is a pointer to a structure that will contain information about the * semaphore. * * Returns : OS_NO_ERR The call was successful and the message was sent * OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non semaphore. ********************************************************************************************************* */ #if OS_SEM_QUERY_EN > 0 INT8U OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *ppdata) reentrant { INT8U i; INT8U *psrc; INT8U *pdest; OS_ENTER_CRITICAL(); //進入臨界區 if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */ OS_EXIT_CRITICAL(); return (OS_ERR_EVENT_TYPE); //如果事件的型別不是訊號量,退出臨界區然後返回錯誤碼 } ppdata->OSEventGrp = pevent->OSEventGrp; /* Copy message mailbox wait list */ psrc = &pevent->OSEventTbl[0]; pdest = &ppdata->OSEventTbl[0]; for (i = 0; i < OS_EVENT_TBL_SIZE; i++) { *pdest++ = *psrc++; } ppdata->OSCnt = pevent->OSEventCnt; /* Get semaphore count */ //複製訊號量的引數給ppdata OS_EXIT_CRITICAL(); //退出臨界區 return (OS_NO_ERR); //返回錯誤碼 } #endif //************************* #endif