📄 semsmlib.c
字号:
{ /* * Add the shared TCB that was pended on the semaphore * pend queue to the list of event to send to the * CPU where is located the pended task. */ eventList.head = (SM_DL_NODE *) htonl (LOC_TO_GLOB_ADRS (firstSmTcb)); eventList.tail = eventList.head; /* * Unlink the shared TCB from other shared TCBs of the semaphore * pend queue. */ firstSmTcb->qNode.next = NULL; /* notify remote CPU */ if (smObjEventSend (&eventList, ntohl (firstSmTcb->ownerCpu)) != OK) { windExit (); /* EXIT KERNEL */ return (ERROR); } } windExit (); /* EXIT KERNEL */ return (OK); }/********************************************************************************* semSmTake - take shared memory binary or counting semaphore** Takes a shared 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 local or remote task * doing a semGive() of it. ** For binary semaphores, 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.** For counting semaphores, if the semaphore count is already greater * than 0, this call will decrement the semaphore count, and this task * will continue running.** The smSemId passed to this routine must be the local semaphore address.* * This routine is usually called by semTake which first convert the * semaphore id to the shared semaphore local address.** WARNING* This routine may not be used from interrupt level.** RETURNS: OK or ERROR.** ERRNO: S_objLib_OBJ_UNAVAILABLE, S_intLib_NOT_ISR_CALLABLE,* S_objLib_OBJ_ID_ERROR, S_objLib_OBJ_TIMEOUT, S_smObjLib_LOCK_TIMEOUT,* S_smMemLib_NOT_ENOUGH_MEMORY** NOMANUAL** INTERNAL* When semSmTake is called for the first time or after a timeout or a * RESTART signal occuring while this task was blocked on a shared * semaphore, a shared TCB is created in shared memory. * This is done by allocating a shared TCB structure* from a shared partition dedicated to shared TCBs. A pointer to this* shared TCB is then initialized in the local Task Control Block.*/STATUS semSmTake ( SM_SEM_ID smSemId, /* global semaphore ID to take */ int timeout /* timeout in ticks */ ) { Q_FIFO_G_HEAD pendQ; /* global FIFO to pend on */ int level; /* processor specific inLock return value */ int status; /* returned status */ WIND_TCB * pTcb; /* current task tcb pointer */ if (INT_RESTRICT () != OK) /* not ISR callable */ return (ERROR);again: if (SM_OBJ_VERIFY (smSemId) != OK) /* check semaphore */ { return (ERROR); } /* * If it's the first call to semSmBTake, or if a timeout or a * RESTART signal has occured while this task was blocked on a shared * semaphore, the pSmObjTcb field of the TCB is NULL, we allocate * and initialize a shared TCB */ pTcb = (WIND_TCB *) taskIdCurrent; if (pTcb->pSmObjTcb == NULL) { if (smObjTcbInit () != OK) return (ERROR); } /* ENTER LOCKED SECTION */ if (SM_OBJ_LOCK_TAKE (&smSemId->lock, &level) != OK) { smObjTimeoutLogMsg ("semTake", (char *) &smSemId->lock); return (ERROR); /* can't take lock */ } if (ntohl (smSemId->objType) == SEM_TYPE_SM_BINARY) /* binary semaphore */ { if (ntohl (smSemId->state.flag) == SEM_FULL) { smSemId->state.flag = htonl (SEM_EMPTY); /* set sem unavailable */ SM_OBJ_LOCK_GIVE (&smSemId->lock, level); /* EXIT LOCKED SECTION */ return (OK); } } else /* counting samaphore */ { if (ntohl (smSemId->state.count) > 0) { /* decrement semaphore count */ smSemId->state.count = htonl (ntohl (smSemId->state.count) - 1); SM_OBJ_LOCK_GIVE(&smSemId->lock, level); /* EXIT LOCKED SECTION */ return (OK); } } kernelState = TRUE; /* ENTER KERNEL */ if (timeout == NO_WAIT) /* NO_WAIT = no block */ { SM_OBJ_LOCK_GIVE (&smSemId->lock, level); /* EXIT LOCKED SECTION */ errno = S_objLib_OBJ_UNAVAILABLE; /* resource gone */ windExit (); /* KERNEL EXIT */ return (ERROR); } /* * We get here if the semaphore is not available * The calling task must be added to the shared semaphore * queue using standard wind kernel functions. For that we * initialize a pseudo multi-way queue header that points to * the shared semaphore pend queue and which will be used * by the multiway queue manipulation macros. */ /* * We optimize interrupt latency by doing only the Q_PUT on the * shared semaphore pend Q while interrupts are locked. * The remaining part of blocking the task is done in * windReadyQRemove with interrupts unlocked. */ pendQ.pLock = NULL; /* we already have the lock */ pendQ.pFifoQ = &smSemId->smPendQ; /* address of actual queue */ pendQ.pQClass = qFifoGClassId; /* global fifo multi way Q */ Q_PUT (&pendQ, taskIdCurrent, taskIdCurrent->priority); SM_OBJ_LOCK_GIVE (&smSemId->lock, level); /* EXIT LOCKED SECTION */ pendQ.pLock = &smSemId->lock; /* now we don't have lock */ /* windview - level 2 event logging */ EVT_TASK_1 (EVENT_OBJ_SEMTAKE, smSemId); windReadyQRemove ((Q_HEAD *) &pendQ, timeout); /* block task */ if ((status = windExit ()) == RESTART) /* KERNEL EXIT */ { timeout = SIG_TIMEOUT_RECALC(timeout); goto again; } return (status); }/********************************************************************************* semSmFlush - flush shared binary or counting semaphore** Flush the shared semaphore. If one or mores task have already taken* the semaphore (so that it is now pended waiting for it), those tasks* will now become ready to run, if a local higher priority task was * pending on the semaphore it will preempt the task that does the semFlush(). * If the semaphore pend queue is empty this call is essentially a no-op.* The smSemId passed to this routine must be the local semaphore address.** This routine is usually called by semFlush which first convert the * semaphore id to the shared semaphore local address.** WARNING* This routine may not be used from interrupt level.** RETURNS: OK or ERROR.** ERRNO: S_intLib_NOT_ISR_CALLABLE, S_objLib_OBJ_ID_ERROR,* S_smObjLib_LOCK_TIMEOUT** NOMANUAL*/STATUS semSmFlush ( SM_SEM_ID smSemId /* global semaphore ID to flush */ ) { SM_OBJ_TCB * firstSmTcb; /* first pending shared memory TCB */ SM_OBJ_TCB * pSmObjTcb; /* useful shared TCB pointer */ SM_OBJ_TCB * pSmObjTcbTmp; /* useful shared TCB pointer */ int level; /* processor specific inLock return value */ int cpuNum; /* loop counter for remote flush */ SM_DL_LIST flushQ [SM_OBJ_MAX_CPU]; /* per CPU flush Q */ if (INT_RESTRICT () != OK) /* not ISR callable */ return (ERROR); if (SM_OBJ_VERIFY (smSemId) != OK) /* check semaphore */ { return (ERROR); } /* ENTER LOCKED SECTION */ if (SM_OBJ_LOCK_TAKE (&smSemId->lock, &level) != OK) { smObjTimeoutLogMsg ("semFlush", (char *) &smSemId->lock); return (ERROR); /* can't take lock */ } /* * In order to reduce interrupt latency we get the first * shared TCB from the shared semaphore pend queue, then * we empty the pend queue by clearing pend queue head. * All the previously pended shared TCBs are still linked * to the first pending TCB and we can give back lock access * to the shared semaphore. */ firstSmTcb = (SM_OBJ_TCB *) SM_DL_FIRST (&smSemId->smPendQ); if (firstSmTcb == (SM_OBJ_TCB *) LOC_NULL) /* pendQ is empty */ { SM_OBJ_LOCK_GIVE (&smSemId->lock, level);/* EXIT LOCKED SECTION */ return (OK); } smSemId->smPendQ.head = NULL; /* empty semaphore pend queue */ smSemId->smPendQ.tail = NULL; SM_OBJ_LOCK_GIVE (&smSemId->lock, level); /* EXIT LOCKED SECTION */ /* create a list of pending task per cpu */ bzero ((char *) flushQ, sizeof (flushQ)); /* clear flush Q table */ pSmObjTcb = firstSmTcb; do { /* get next shared TCB behind current shared TCB */ pSmObjTcbTmp = (SM_OBJ_TCB *) SM_DL_NEXT (pSmObjTcb); /* add the shared TCB to its CPU flush Queue */ smDllAdd (&flushQ [ntohl (pSmObjTcb->ownerCpu)], (SM_DL_NODE *) pSmObjTcb); /* make current shared TCB be next shared TCB */ pSmObjTcb = pSmObjTcbTmp; } while (pSmObjTcbTmp != LOC_NULL); /* notify remote flush */ for (cpuNum = 0; cpuNum < SM_OBJ_MAX_CPU; cpuNum ++) { if ((SM_DL_FIRST (&flushQ [cpuNum]) != (int) LOC_NULL) && (cpuNum != smObjProcNum)) { /* * There is one or more task running on cpuNum to unblock and * cpuNum is not the local CPU so notify cpuNum. */ if (smObjEventSend (&flushQ [cpuNum], cpuNum) != OK) return (ERROR); } } /* perform local flush if needed */ if (SM_DL_FIRST (&flushQ [smObjProcNum]) != (int) LOC_NULL) { kernelState = TRUE; /* ENTER KERNEL */ /* * Since all tasks have been removed from the shared * semaphore pend queue, unblocking them consist now * in putting all the tasks for which the shared TCBs * are in the flush Queue in the ready Queue. * This is exacly what smObjEventProcess does on the remote * side so we just call it. */ smObjEventProcess (&flushQ [smObjProcNum]); windExit (); /* EXIT KERNEL */ } return (OK); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -