StatusType WaitSemaphore( OsSemaphoreType *semPtr, TickType tmo ) { OsTaskVarType *pcbPtr; uint32_t flags; StatusType rv = E_OK; (void)tmo; Irq_Save(flags); --semPtr->val; pcbPtr = Os_SysTaskGetCurr(); assert(OS_SYS_PTR->intNestCnt == 0 ); if (pcbPtr->constPtr->proc_type != PROC_EXTENDED) { return E_OS_ACCESS; } if(semPtr->val < 0 ) { /* To WAITING state */ if( tmo == 0 ) { /* Failed to acquire the semaphore */ rv = E_NOT_OK; } else { /* Add this task to the semaphore */ STAILQ_INSERT_TAIL(&semPtr->taskHead,pcbPtr,semEntry); Os_Dispatch(OP_WAIT_SEMAPHORE); } } else { /* We got the semaphore */ if( tmo == 0 ) { rv = E_NOT_OK; } else { /* * Wait for the semaphore to be signaled or timeout */ if ( Os_SchedulerResourceIsFree() ) { /* Set the timeout */ if( tmo != TICK_MAX ) { TAILQ_INSERT_TAIL(&OS_SYS_PTR->timerHead,pcbPtr,timerEntry); pcbPtr->timerDec = tmo; } Os_Dispatch(OP_WAIT_SEMAPHORE); } else { /* We hold RES_SCHEDULER */ rv = E_NOT_OK; } } } Irq_Restore(flags); return rv; }
/** * Increase the semaphore value by 1. If * * @param semPtr */ void SignalSemaphore( OsSemaphoreType *semPtr ) { uint32_t flags; OsTaskVarType *taskPtr; Irq_Save(flags); assert( semPtr != NULL ); ++semPtr->val; /* Remove the first task that waits at the semaphore */ if( semPtr->val <= 0 ) { taskPtr = STAILQ_FIRST(&semPtr->taskHead); /* Make the first task ready */ Os_TaskMakeReady(taskPtr); /* Release the first task in queue */ STAILQ_REMOVE_HEAD(&semPtr->taskHead,semEntry); if( taskPtr->activePriority > Os_SysTaskGetCurr()->activePriority ) { Os_Dispatch(OP_SIGNAL_SEMAPHORE); } } Irq_Restore(flags); }
StatusType ReleaseResource( ResourceType ResID) { StatusType rv = E_OK; OsTaskVarType *pcbPtr = Os_SysTaskGetCurr(); OsResourceType *rPtr; uint32_t flags; Irq_Save(flags); if( ResID == RES_SCHEDULER ) { rPtr = &Os_Sys.resScheduler; } else { /* Check we can access it */ if( (pcbPtr->constPtr->resourceAccess & (1<< ResID)) == 0 ) { rv = E_OS_ID; goto err; } rPtr = Os_ResourceGet(ResID); } /* Check for invalid configuration */ if( rPtr->owner == NO_TASK_OWNER) { rv = E_OS_NOFUNC; Irq_Restore(flags); goto err; } if( (pcbPtr->activePriority < rPtr->ceiling_priority)) { rv = E_OS_ACCESS; Irq_Restore(flags); goto err; } Os_TaskResourceRemove(rPtr,pcbPtr); /* do a rescheduling (in some cases) (see OSEK OS 4.6.1) */ if ( (pcbPtr->constPtr->scheduling == FULL) && (Os_Sys.intNestCnt == 0) && (Os_SchedulerResourceIsFree()) ) { OsTaskVarType* top_pcb = Os_TaskGetTop(); /* only dispatch if some other ready task has higher prio */ if (top_pcb->activePriority > Os_SysTaskGetCurr()->activePriority) { Os_Dispatch(OP_RELEASE_RESOURCE); } } Irq_Restore(flags); OS_STD_END_1(OSServiceId_ReleaseResource,ResID); }
StatusType WaitEvent( EventMaskType Mask ) { OsTaskVarType *curr_pcb = Os_SysTaskGetCurr(); StatusType rv = E_OK; imask_t state; OS_DEBUG(D_EVENT,"# WaitEvent %s\n",Os_SysTaskGetCurr()->constPtr->name); OS_VALIDATE( OS_SYS_PTR->intNestCnt == 0, E_OS_CALLEVEL); OS_VALIDATE( curr_pcb->constPtr->proc_type == PROC_EXTENDED,E_OS_ACCESS); OS_VALIDATE( !Os_TaskOccupiesResources(curr_pcb),E_OS_RESOURCE); #if (OS_NUM_CORES > 1) OS_VALIDATE( !Os_TaskOccupiesSpinlocks(curr_pcb) != 0,E_OS_SPINLOCK); /* @req 4.1.2/SWS_Os_00622 */ #endif /* Remove from ready queue */ Irq_Save(state); // OSEK/VDX footnote 5. The call of WaitEvent does not lead to a waiting state if one of the events passed in the event mask to // WaitEvent is already set. In this case WaitEvent does not lead to a rescheduling. if( !(curr_pcb->ev_set & Mask) ) { curr_pcb->ev_wait = Mask; if ( Os_SchedulerResourceIsFree() ) { // Os_TaskMakeWaiting(currTaskPtr); Os_Dispatch(OP_WAIT_EVENT); assert( curr_pcb->state & ST_RUNNING ); } else { Os_TaskMakeWaiting(curr_pcb); } } Irq_Restore(state); // The following line disables the unused label warning. Remove when // proper error handling is implemented. if (0) goto err; OS_STD_END_1(OSServiceId_WaitEvent,Mask); }
StatusType SetEvent( TaskType TaskID, EventMaskType Mask ) { StatusType rv = E_OK; OsTaskVarType *destPcbPtr; OsTaskVarType *currPcbPtr; uint32_t flags; OS_DEBUG(D_EVENT,"# SetEvent %s\n",Os_SysTaskGetCurr()->constPtr->name); TASK_CHECK_ID(TaskID); destPcbPtr = Os_TaskGet(TaskID); currPcbPtr = Os_SysTaskGetCurr(); #if (OS_SC3==STD_ON) || (OS_SC4==STD_ON) if( destPcbPtr->constPtr->applOwnerId != OS_SYS_PTR->currApplId ) { ApplicationType appId; APPL_CHECK_STATE(destPcbPtr->constPtr->applOwnerId); /* Do we have access to the task we are activating */ if(OS_SYS_PTR->intNestCnt == 0 ) { appId = currPcbPtr->constPtr->applOwnerId; } else { appId = Os_SysIsrGetCurr()->constPtr->appOwner; } APPL_CHECK_ACCESS( appId , destPcbPtr->constPtr->accessingApplMask); #if (OS_NUM_CORES > 1) if (Os_ApplGetCore(destPcbPtr->constPtr->applOwnerId) != GetCoreID()) { StatusType status = Os_NotifyCore(Os_ApplGetCore(destPcbPtr->constPtr->applOwnerId), OSServiceId_SetEvent, TaskID, Mask, 0); return status; #endif } #endif OS_VALIDATE( destPcbPtr->constPtr->proc_type == PROC_EXTENDED, E_OS_ACCESS ); OS_VALIDATE( !(destPcbPtr->state & ST_SUSPENDED ), E_OS_STATE); Irq_Save(flags); /* Calling SetEvent causes the task <TaskID> to be transferred * to the ready state, if it was waiting for at least one of the * events specified in <Mask>. * * OSEK/VDX 4.6.1, rescheduling is performed in all of the following cases: * .. * Setting an event to a waiting task at task level (e.g. system service SetEvent, * see chapter 13.5.3.1, message notification mechanism, alarm expiration, if event setting * defined, see chapter 9.2) * ... */ destPcbPtr->ev_set |= Mask; if( (Mask & destPcbPtr->ev_wait) ) { /* We have an event match */ if( destPcbPtr->state & ST_WAITING) { Os_TaskMakeReady(destPcbPtr); currPcbPtr = Os_SysTaskGetCurr(); /* Checking "4.6.2 Non preemptive scheduling" it does not dispatch if NON */ if( (OS_SYS_PTR->intNestCnt == 0) && (currPcbPtr->constPtr->scheduling == FULL) && (destPcbPtr->activePriority > currPcbPtr->activePriority) && (Os_SchedulerResourceIsFree()) ) { Os_Dispatch(OP_SET_EVENT); } } else if(destPcbPtr->state & (ST_READY|ST_RUNNING|ST_SLEEPING) ) { /* Hmm, we do nothing */ } else { assert( 0 ); } } Irq_Restore(flags); OS_STD_END_2(OSServiceId_SetEvent,TaskID, Mask); } /** * This service returns the current state of all event bits of the task * <TaskID>, not the events that the task is waiting for. * The service may be called from interrupt service routines, task * level and some hook routines (see Figure 12-1). * The current status of the event mask of task <TaskID> is copied * to <Event>. * * @param TaskId Task whose event mask is to be returned. * @param Mask Reference to the memory of the return data. * @return */ StatusType GetEvent( TaskType TaskId, EventMaskRefType Mask) { OsTaskVarType *destPcbPtr; StatusType rv = E_OK; TASK_CHECK_ID(TaskId); destPcbPtr = Os_TaskGet(TaskId); OS_VALIDATE( (destPcbPtr->constPtr->proc_type == PROC_EXTENDED) ,E_OS_ACCESS); OS_VALIDATE( !(destPcbPtr->state & ST_SUSPENDED),E_OS_STATE); *Mask = destPcbPtr->ev_set; if (0) goto err; OS_STD_END_2(OSServiceId_GetEvent,TaskId, Mask); }