📄 semmlib.c
字号:
#else objCoreInit (&pSemaphore->objCore, semClassId);#endif return (OK); }#ifdef semMLib_PORTABLE/********************************************************************************* semMGive - give a semaphore** Gives the semaphore. If a higher priority task has already taken* the semaphore (so that it is now pended waiting for it), that task* will now become ready to run, and preempt the task that does the semGive().* If the semaphore is already full (it has been given but not taken) this* call is essentially a no-op.** If deletion safe option is enabled, an implicit taskUnsafe() operation will* occur.** If priority inversion safe option is enabled, and this is the last priority* inversion safe semaphore to be released, the calling task will revert to* its normal priority.** WARNING* This routine may not be used from interrupt level.** ERRNO: S_semLib_INVALID_OPERATION** INTERNAL* The use of the variables kernWork and semMGiveKernWork looks pretty lame. It* is, in fact, necessary to facilitate the optimized version of this routine.* An optimized version would utilize a register for kernWork and stick the* value in semMGiveKernWork as a parameter to semMGiveKern(). This form of* parameter passing saves costly stack manipulation.** NOMANUAL*/STATUS semMGive ( FAST SEM_ID semId /* semaphore ID to give */ ) { FAST int level; FAST int kernWork = 0; if (INT_RESTRICT () != OK) /* restrict isr use */ return (ERROR); level = intLock (); /* LOCK INTERRUPTS */ if (OBJ_VERIFY (semId, semClassId) != OK) /* check validity */ { intUnlock (level); return (ERROR); } if (taskIdCurrent != semId->semOwner) /* check for ownership */ { intUnlock (level); errnoSet (S_semLib_INVALID_OPERATION); return (ERROR); } if (semId->recurse > 0) /* check recurse count */ { semId->recurse --; /* decrement recurse count */ intUnlock (level); return (OK); } if ((semId->options & SEM_INVERSION_SAFE) && (-- taskIdCurrent->priMutexCnt == 0)) { if (taskIdCurrent->priority != taskIdCurrent->priNormal) kernWork |= SEM_M_PRI_RESORT; } if ((semId->semOwner = (WIND_TCB *) Q_FIRST (&semId->qHead)) != NULL) kernWork |= SEM_M_Q_GET; else if (semId->events.taskId != (int)NULL) kernWork |= SEM_M_SEND_EVENTS; if ((semId->options & SEM_DELETE_SAFE) && (-- taskIdCurrent->safeCnt == 0) && (Q_FIRST (&taskIdCurrent->safetyQHead) != NULL)) kernWork |= SEM_M_SAFE_Q_FLUSH; if (kernWork == 0) { intUnlock (level); /* UNLOCK INTERRUPTS */ return (OK); } kernelState = TRUE; /* KERNEL ENTER */ intUnlock (level); /* UNLOCK INTERRUPTS */ semMGiveKernWork = kernWork; /* setup the work to do */ return (semMGiveKern (semId)); /* do the work */ }/********************************************************************************* semMTake - take a semaphore** Takes the semaphore. If the semaphore is empty, i.e., it has not been given* since the last semTake() or semInit(), this task will become pended until* the semaphore becomes available by some other task doing a semGive()* of it. If the semaphore is already available, this call will empty* the semaphore, so that no other task can take it until this task gives* it back, and this task will continue running.** If deletion safe option is enabled, an implicit taskSafe() operation will* occur.** If priority inversion safe option is enabled, and the calling task blocks,* and the priority of the calling task is greater than the semaphore owner,* the owner will inherit the caller's priority.** WARNING* This routine may not be used from interrupt level.** NOMANUAL*/STATUS semMTake ( FAST SEM_ID semId, /* semaphore ID to take */ int timeout /* timeout in ticks */ ) { int level; int status; if (INT_RESTRICT () != OK) return (ERROR);again: level = intLock (); /* LOCK INTERRUPTS */ if (OBJ_VERIFY (semId, semClassId) != OK) { intUnlock (level); /* UNLOCK INTERRUPTS */ return (ERROR); } if (semId->semOwner == NULL) { semId->semOwner = taskIdCurrent; /* update semaphore state */ if (semId->options & SEM_INVERSION_SAFE) taskIdCurrent->priMutexCnt ++; /* update inherit count */ if (semId->options & SEM_DELETE_SAFE) taskIdCurrent->safeCnt ++; /* update safety count */ intUnlock (level); /* UNLOCK INTERRUPTS */ return (OK); } if (semId->semOwner == taskIdCurrent) /* check for recursion */ { semId->recurse ++; /* keep recursion count */ intUnlock (level); /* UNLOCK INTERRUPTS */ return (OK); } kernelState = TRUE; /* KERNEL ENTER */ intUnlock (level); /* UNLOCK INTERRUPTS */ if (semMPendQPut (semId, timeout) != OK) { windExit (); /* windPendQPut failed */ return (ERROR); } if ((status = windExit ()) == RESTART) /* KERNEL EXIT */ { timeout = SIG_TIMEOUT_RECALC(timeout); goto again; /* we got signalled */ } return (status); }#endif /* semMLib_PORTABLE *//********************************************************************************* semMGiveForce - give a mutual-exclusion semaphore without restrictions** This routine gives a mutual-exclusion semaphore, regardless of semaphore* ownership. It is intended as a debugging aid only.** The routine is particularly useful when a task dies while holding some* mutual-exclusion semaphore, because the semaphore can be resurrected. The* routine will give the semaphore to the next task in the pend queue or make* the semaphore full if no tasks are pending. In effect, execution will* continue as if the task owning the semaphore had actually given the* semaphore.** CAVEATS* This routine should be used only as a debugging aid, when the condition of* the semaphore is known.** RETURNS: OK, or ERROR if the semaphore ID is invalid.** SEE ALSO: semGive()*/STATUS semMGiveForce ( FAST SEM_ID semId /* semaphore ID to give */ ) { STATUS status = OK; int oldErrno = errno; if (INT_RESTRICT () != OK) /* restrict isr use */ return (ERROR); if (OBJ_VERIFY (semId, semClassId) != OK) /* check validity */ return (ERROR);#ifdef WV_INSTRUMENTATION /* windview - level 1 event logging */ EVT_OBJ_3 (OBJ, semId, semClassId, EVENT_SEMMGIVEFORCE, semId, semId->options, semId->state);#endif /* if semaphore is not taken, nothing has to be done. */ if (semId->semOwner == NULL) return OK; /* first see if we are giving away one of calling task's semaphores */ if (semId->semOwner == taskIdCurrent) /* give semaphore until avail */ { while (semId->semOwner == taskIdCurrent)/* loop until recurse == 0 */ semGive (semId); /* give semaphore */ return (OK); /* done */ } /* give another task's semaphore away. Djkstra be damned... */ kernelState = TRUE; /* KERNEL ENTER */ semId->recurse = 0; /* initialize recurse count */ if ((semId->semOwner = (WIND_TCB *) Q_FIRST (&semId->qHead)) != NULL) {#ifdef WV_INSTRUMENTATION /* windview - level 2 event logging */ EVT_TASK_1 (EVENT_OBJ_SEMGIVE, semId);#endif windPendQGet (&semId->qHead); /* unblock receiver */ semId->semOwner->pPriMutex = NULL; /* receiver no longer pended */ if (semId->options & SEM_DELETE_SAFE) semId->semOwner->safeCnt ++; /* increment receiver safety */ if (semId->options & SEM_INVERSION_SAFE) semId->semOwner->priMutexCnt ++; /* update inherit count */ } else { if (semId->events.taskId != (int)NULL) /* sem is free, send events */ { if (eventRsrcSend (semId->events.taskId, semId->events.registered) != OK) { if ((semId->options & SEM_EVENTSEND_ERR_NOTIFY) != 0x0) { status = ERROR; } semId->events.taskId = (int)NULL; } else if ((semId->events.options & EVENTS_SEND_ONCE) != 0x0) semId->events.taskId = (int)NULL; } } if (status == ERROR) { windExit (); /* KERNEL EXIT */ errnoSet (S_eventLib_EVENTSEND_FAILED); } else { errnoSet (oldErrno); return (windExit ()); /* KERNEL EXIT */ } return (status); }/********************************************************************************* semMGiveKern - put current task on mutex semaphore pend queue** This routine is called if something of consequence occured in giving the* mutual exclusion semaphore that involved more lengthy processing. Things* of consequence are: task to be unblocked, priority to be uninherited, or* task safety queue of deleters to be flushed.** INTERNAL* The use of the variables kernWork and semMGiveKernWork looks pretty lame.* It is, in fact, necessary to facilitate the optimized version of this routine.* An optimized version would utilize a register for kernWork and stick the* value in semMGiveKernWork as a parameter to semMGiveKern(). This form of* parameter passing saves costly stack manipulation.** NOMANUAL*/STATUS semMGiveKern ( FAST SEM_ID semId /* semaphore ID to take */ ) { STATUS evStatus; STATUS retStatus = OK; int oldErrno = errno; if (semMGiveKernWork & SEM_M_Q_GET) {#ifdef WV_INSTRUMENTATION /* windview - level 2 event logging */ EVT_TASK_1 (EVENT_OBJ_SEMGIVE, semId);#endif windPendQGet (&semId->qHead); /* unblock receiver */ semId->semOwner->pPriMutex = NULL; /* receiver no longer pended */ if (semId->options & SEM_DELETE_SAFE) semId->semOwner->safeCnt ++; /* increment receiver safety */ if (semId->options & SEM_INVERSION_SAFE) semId->semOwner->priMutexCnt ++; /* update inherit count */ } if (semMGiveKernWork & SEM_M_PRI_RESORT) { windPrioritySet (taskIdCurrent, taskIdCurrent->priNormal); } if (semMGiveKernWork & SEM_M_SAFE_Q_FLUSH) {#ifdef WV_INSTRUMENTATION /* windview - level 2 event logging */ EVT_TASK_1 (EVENT_OBJ_SEMGIVE, semId);#endif windPendQFlush (&taskIdCurrent->safetyQHead); } if ((semMGiveKernWork & SEM_M_SEND_EVENTS) != 0x0) /* send events */ { evStatus = eventRsrcSend (semId->events.taskId, semId->events.registered); if (evStatus != OK) { if ((semId->options & SEM_EVENTSEND_ERR_NOTIFY) != 0x0) { oldErrno = S_eventLib_EVENTSEND_FAILED; retStatus = ERROR; } semId->events.taskId = (int)NULL; } else if ((semId->events.options & EVENTS_SEND_ONCE) != 0x0) semId->events.taskId = (int)NULL; } if (retStatus == ERROR) { windExit (); errnoSet (oldErrno); } else { errnoSet (oldErrno); retStatus = windExit (); /* KERNEL EXIT */ } return (retStatus); }/********************************************************************************* semMPendQPut - put current task on mutex semaphore pend queue** This routine is called if the mutex semaphore is empty and the caller must* pend. It is called inside the kernel with kernelState == TRUE! It is* pulled out of semMTake so optimized versions need not bother with the* following code.** RETURNS: OK, or ERROR if windPendQPut failed.* NOMANUAL*/STATUS semMPendQPut ( FAST SEM_ID semId, /* semaphore ID to take */ int timeout /* timeout in ticks */ ) {#ifdef WV_INSTRUMENTATION /* windview - level 2 event logging */ EVT_TASK_1 (EVENT_OBJ_SEMTAKE, semId);#endif if (windPendQPut (&semId->qHead, timeout) != OK) return (ERROR); /* if taskIdCurrent is of a higher priority than the task that owns * this semaphore, reprioritize the owner. */ if (semId->options & SEM_INVERSION_SAFE) { taskIdCurrent->pPriMutex = semId; /* track mutex we pend on */ if (taskIdCurrent->priority < semId->semOwner->priority) { windPrioritySet (semId->semOwner, taskIdCurrent->priority); } } return (OK); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -