110 likes | 349 Vues
Chapter7 Semaphore Management. Semaphores. Create a semaphore by calling OSSemCreate() The initial count of the semaphore can be 0 to 65535 Use to signal the occurrence of one ore more event, the init value is 0 (flag) Use to access a shared resource, the init value is set to 1 (binary) (key)
E N D
Semaphores • Create a semaphore by calling OSSemCreate() • The initial count of the semaphore can be 0 to 65535 • Use to signal the occurrence of one ore more event, the init value is 0 (flag) • Use to access a shared resource, the init value is set to 1 (binary) (key) • Five services will access semaphore: • OSSemCreate(), OSSemPend(), OSSemPost(), OSSemAccept(), OSSemQuery() Figure 7.1 Relationships between tasks, ISRs, and a semaphore
Creating a SemaphoreOSSemCreate() OS_EVENT *OSSemCreate (INT16U cnt) { OS_EVENT *pevent; OS_ENTER_CRITICAL(); pevent = OSEventFreeList; (1) if (OSEventFreeList != (OS_EVENT *)0) { (2) OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; } OS_EXIT_CRITICAL(); if (pevent != (OS_EVENT *)0) { (3) pevent->OSEventType = OS_EVENT_TYPE_SEM; (4) pevent->OSEventCnt = cnt; (5) OSEventWaitListInit(pevent); (6) } return (pevent); //semaphore address or say descriptor (7) }
Figure 7.2 ECB just before OSSemCreate() returns OS_EVENT pevent OSEventType OS_Evnet_Type_SEM OSEventCnt Cnt OSEventPtr (void *)0 OSEvnetGrp=0x00 OSEventGrp 7 6 5 4 3 2 1 0 All initialized to 0x00 63 62 61 60 59 58 57 56
Deleting a Semaphore, OSSemDel() #if OS_SEM_DEL_EN > 0 OS_EVENT *OSSemDel (OS_EVENT *pevent, INT8U opt, INT8U *err) { #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr; #endif BOOLEAN tasks_waiting; if (OSIntNesting > 0) { /* See if called from ISR ... */ *err = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */ return (pevent); } #if OS_ARG_CHK_EN > 0 if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ *err = OS_ERR_PEVENT_NULL; return (pevent); } if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */ *err = OS_ERR_EVENT_TYPE; return (pevent); } #endif
OS_ENTER_CRITICAL(); if (pevent->OSEventGrp != 0x00) { /* See if any tasks waiting on semaphore */ tasks_waiting = TRUE; /* Yes */ } else { tasks_waiting = FALSE; /* No */ } switch (opt) { case OS_DEL_NO_PEND: /* Delete semaphore only if no task waiting */ if (tasks_waiting == FALSE) { pevent->OSEventType = OS_EVENT_TYPE_UNUSED; pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */ OSEventFreeList = pevent; /* Get next free event control block */ OS_EXIT_CRITICAL(); *err = OS_NO_ERR; return ((OS_EVENT *)0); /* Semaphore has been deleted */ } else { OS_EXIT_CRITICAL(); *err = OS_ERR_TASK_WAITING; return (pevent); }
case OS_DEL_ALWAYS: /* Always delete the semaphore */ while (pevent->OSEventGrp != 0x00) { /* Ready ALL tasks waiting for semaphore */ OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM); } pevent->OSEventType = OS_EVENT_TYPE_UNUSED; pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */ OSEventFreeList = pevent; /* Get next free event control block */ OS_EXIT_CRITICAL(); if (tasks_waiting == TRUE) { /* Reschedule only if task(s) were waiting */ OS_Sched(); /* Find highest priority task ready to run */ } *err = OS_NO_ERR; return ((OS_EVENT *)0); /* Semaphore has been deleted */ default: OS_EXIT_CRITICAL(); *err = OS_ERR_INVALID_OPT; return (pevent); } } #endif
Waiting on a SemaphoreOSSemPend() void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) { OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { (1) OS_EXIT_CRITICAL(); *err = OS_ERR_EVENT_TYPE; } if (pevent->OSEventCnt > 0) { (2) pevent->OSEventCnt--; (3) OS_EXIT_CRITICAL(); *err = OS_NO_ERR; return; OSTCBCur->OSTCBStat |= OS_STAT_SEM; (5) OSTCBCur->OSTCBDly = timeout; (6) OSEventTaskWait(pevent); (7) OS_EXIT_CRITICAL(); OSSched(); (8) OS_ENTER_CRITICAL(); if (OSTCBCur->OSTCBStat & OS_STAT_SEM) { (9) OSEventTO(pevent); (10) OS_EXIT_CRITICAL(); *err = OS_TIMEOUT; return; } OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; (11) OS_EXIT_CRITICAL(); *err = OS_NO_ERR; }
Signaling a SemaphoreOSSemPost() INT8U OSSemPost (OS_EVENT *pevent) { OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { (1) OS_EXIT_CRITICAL(); return (OS_ERR_EVENT_TYPE); } if (pevent->OSEventGrp) { (2) OSEventTaskRdy(pevent, (void *)0, OS_STAT_SEM); (3) OS_EXIT_CRITICAL(); OSSched(); (4) return (OS_NO_ERR); } if (pevent->OSEventCnt < 65535) { pevent->OSEventCnt++; (5) OS_EXIT_CRITICAL(); return (OS_NO_ERR); } OS_EXIT_CRITICAL(); return (OS_SEM_OVF); }
Getting a Semaphore without WaitingOSSemAccept() • To obtain a semaphore without putting a task to sleep if the semaphore is not available INT16U OSSemAccept (OS_EVENT *pevent) { INT16U cnt; OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { (1) OS_EXIT_CRITICAL(); return (0); } cnt = pevent->OSEventCnt; (2) if (cnt > 0) { (3) pevent->OSEventCnt--; (4) } OS_EXIT_CRITICAL(); return (cnt); //original value (5) }
Obaining the status of a semaphoreOSSemQuery() • Allow APs to take a snapshot of an ECB • Two arguments are required • Pevent: pointer to the semaphore • Pdata pointer to a data structure which will receive the information about the desired semaphore INT8U OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *pdata) { INT8U i; INT8U *psrc; INT8U *pdest; OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { (1) OS_EXIT_CRITICAL(); return (OS_ERR_EVENT_TYPE); } pdata->OSEventGrp = pevent->OSEventGrp; (2) psrc = &pevent->OSEventTbl[0]; pdest = &pdata->OSEventTbl[0]; for (i = 0; i < OS_EVENT_TBL_SIZE; i++) { *pdest++ = *psrc++; } pdata->OSCnt = pevent->OSEventCnt; (3) OS_EXIT_CRITICAL(); return (OS_NO_ERR); }