📄 semsmlib.c
字号:
* This routine may be called to initialize such a semaphore. The semaphore* is initialized to the specified initial state of either SEM_FULL or * SEM_EMPTY.** Binary semaphore options include the queuing style for blocked tasks.* For now, the only available shared semaphore queueing style is * first-in-first-out, type SEM_Q_FIFO defined as 0 in semLib.h.** The semaphore address parameter is the local address of a shared semaphore * structure. ** RETURNS: OK, or ERROR if queue type or initial state is invalid.* * SEE ALSO: semBSmCreate** ERRNO: S_semLib_INVALID_QUEUE_TYPE, S_semLib_INVALID_STATE ** NOMANUAL*/STATUS semSmBInit ( SM_SEMAPHORE * pSem, /* pointer to semaphore to initialize */ int options, /* semaphore options */ SEM_B_STATE initialState /* initial semaphore state */ ) { Q_FIFO_G_HEAD pseudoPendQ; /* pseudo pendQ to initialize sem pend Q */ if (!semSmLibInstalled) semSmLibInit (); /* initialize package */ if (options != SEM_Q_FIFO) /* only FIFO queuing for now */ { errno = S_semLib_INVALID_QUEUE_TYPE; return (ERROR); } pSem->objType = htonl (SEM_TYPE_SM_BINARY); /* semaphore type is binary */ pSem->lock = 0; /* lock available */ /* initialize pseudo multi way queue */ pseudoPendQ.pLock = NULL; /* we already have the lock */ pseudoPendQ.pFifoQ = &pSem->smPendQ; /* address of actual queue */ pseudoPendQ.pQClass = qFifoGClassId; /* global fifo multi way Q */ qFifoGInit (&pseudoPendQ); /* initialize sem pend Q */ /* fill state flag according to initial state */ switch (initialState) { case SEM_EMPTY: case SEM_FULL: pSem->state.flag = htonl (initialState); break; default: errno = S_semLib_INVALID_STATE; return (ERROR); } /* verify field must contain the global address of semaphore */ pSem->verify = (UINT32) htonl (LOC_TO_GLOB_ADRS (pSem)); return (OK); }/********************************************************************************* semCSmCreate - create and initialize a shared memory counting semaphore (VxMP Option)** This routine allocates and initializes a shared memory counting* semaphore. The initial count value of the semaphore (the number of* times the semaphore should be taken before it can be given) is specified* by <initialCount>.** The semaphore ID returned by this routine can be used directly by the* generic semaphore-handling routines in semLib -- semGive(), semTake() and* semFlush() -- and the show routines, such as show() and semShow().** The queuing style for blocked tasks is set by <options>; the only* supported queuing style for shared memory semaphores is first-in-first-out,* selected by SEM_Q_FIFO.** Before this routine can be called, the shared memory objects facility must* be initialized (see semSmLib).** The maximum number of shared memory semaphores (binary plus counting) that* can be created is SM_OBJ_MAX_SEM.** AVAILABILITY* This routine is distributed as a component of the unbundled shared memory* support option, VxMP.* * RETURNS: The semaphore ID, or NULL if memory cannot be allocated* from the shared semaphore dedicated memory partition.** ERRNO: S_memLib_NOT_ENOUGH_MEMORY, S_semLib_INVALID_QUEUE_TYPE,* S_smObjLib_LOCK_TIMEOUT** SEE ALSO: semLib, semCLib, smObjLib, semShow** INTERNAL* The least significant bit of the semaphore ID is set to 1 in order to* differentiate shared and local semaphores.*/SEM_ID semCSmCreate ( int options, /* semaphore options */ int initialCount /* initial semaphore count */ ) { SM_SEM_ID smSemId; /* allocate semaphore structure from shared semaphore dedicated pool */ smSemId = (SM_SEM_ID) smMemPartAlloc (smSemPartId, sizeof(SM_SEMAPHORE)); if (smSemId == NULL) return (NULL); bzero ((char *) smSemId, sizeof(SM_SEMAPHORE)); /* initialize allocated semaphore */ if (semSmCInit ((SM_SEMAPHORE *) (smSemId), options, initialCount) != OK) { smMemPartFree (smSemPartId, (char *) smSemId); return (NULL); } /* update shared memory objects statistics */ pSmObjHdr->curNumSemC = htonl (ntohl (pSmObjHdr->curNumSemC) + 1); return ((SEM_ID) (SM_OBJ_ADRS_TO_ID (smSemId))); }/********************************************************************************* semSmCInit - initialize a declared shared counting semaphore** The initialization of a static counting semaphore, or a shared * counting semaphore embedded in some larger object need not deal * with allocation.* This routine may be called to initialize such a semaphore. The semaphore* is initialized to the specified initial count.** Counting semaphore options include the queuing style for blocked tasks.* The only available pending queue type is first-in-first-out, type* SEM_Q_FIFO defined as 0 in semLib.h.** The semaphore address parameter is the local address of a* shared semaphore data structure.** RETURNS: OK or ERROR if queue type invalid.** ERRNO: S_semLib_INVALID_QUEUE_TYPE** SEE ALSO: semCSmCreate()** NOMANUAL*/STATUS semSmCInit ( SM_SEMAPHORE * pSem, /* pointer to semaphore to initialize */ int options, /* semaphore options */ int initialCount /* initial semaphore count */ ) { Q_FIFO_G_HEAD pseudoPendQ; /* pseudo pendQ to initialize sem pend Q */ if (!semSmLibInstalled) semSmLibInit (); /* initialize package */ if (options != SEM_Q_FIFO) /* only FIFO queuing for now */ { errno = S_semLib_INVALID_QUEUE_TYPE; return (ERROR); } pSem->objType = htonl(SEM_TYPE_SM_COUNTING);/* fill semaphore type */ pSem->lock = 0; /* lock available */ /* initialize pseudo multi way queue */ pseudoPendQ.pLock = NULL; /* we already have the lock */ pseudoPendQ.pFifoQ = &pSem->smPendQ; /* address of actual queue */ pseudoPendQ.pQClass = qFifoGClassId; /* global fifo multi way Q */ qFifoGInit (&pseudoPendQ); /* initialize sem pend Q */ pSem->state.count = htonl (initialCount); /* set initial count */ /* verify field must contain the global address of semaphore */ pSem->verify = (UINT32) htonl (LOC_TO_GLOB_ADRS (pSem)); return (OK); }/********************************************************************************* semSmGive - give shared memory binary or counting 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, if that task is local to this CPU and is of* higher priority than the task that does the semGive, it will preempt this* task. If the first pended task is located on a remote processor the * availability of the semaphore is made known to the remote processor via* an internal notification mecanism.* * For shared binary semaphore, if the semaphore is already full (it has * been given but not taken) this call is essentially a no-op.** For shared counting semaphore, if the semaphore count is already * greater than 0 (semaphore was given but not taken) 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 semGive 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 semSmGive ( SM_SEM_ID smSemId /* global semaphore ID to give */ ) { Q_FIFO_G_HEAD pendQ; /* temporary pendQ to unpend task */ SM_OBJ_TCB * firstSmTcb; /* first pending shared memory tcb */ int level; /* processor specific inLock return value */ SM_DL_LIST eventList; /* list of events used to notify give */ if (INT_RESTRICT () != OK) /* not ISR callable */ return (ERROR); if (SM_OBJ_VERIFY (smSemId) != OK) /* check semaphore id */ { return (ERROR); } /* ENTER LOCKED SECTION */ if (SM_OBJ_LOCK_TAKE (&smSemId->lock, &level) != OK) { smObjTimeoutLogMsg ("semGive", (char *) &smSemId->lock); return (ERROR); /* can't take lock */ } /* get first pending shared TCB */ firstSmTcb = (SM_OBJ_TCB *) SM_DL_FIRST (&smSemId->smPendQ); if (firstSmTcb == (SM_OBJ_TCB *) LOC_NULL) /* pendQ is empty */ { if (ntohl (smSemId->objType) == SEM_TYPE_SM_BINARY) /* binary semaphore */ smSemId->state.flag = htonl (SEM_FULL); /* sem available */ else /* counting semaphore */ /* increment sem count */ smSemId->state.count = htonl (ntohl (smSemId->state.count) + 1); SM_OBJ_LOCK_GIVE (&smSemId->lock, level); /* EXIT LOCKED SECTION */ return (OK); } /* initialize pseudo multi way queue */ pendQ.pLock = NULL; /* we already have the lock */ pendQ.pFifoQ = &smSemId->smPendQ; /* address of actual queue */ pendQ.pQClass = qFifoGClassId; /* global fifo multi way Q */ /* * Do now the necessary manipulations in shared memory * in order to be able to release lock access ASAP * thus reducing interrupt latency. */ kernelState = TRUE; /* ENTER KERNEL */ Q_REMOVE (&pendQ, (SM_DL_NODE *) firstSmTcb); /* remove from pending list */ SM_OBJ_LOCK_GIVE (&smSemId->lock, level);/* EXIT LOCKED SECTION */ if (ntohl (firstSmTcb->ownerCpu) == smObjProcNum)/* pending task is local */ { /* * The shared TCB has been removed from the shared semaphore * pendQ by qFifoGRemove, during that call removedByGive is * set to TRUE to avoid non-null notification time race. * Then if the task that have taken the semaphore is remote, * a event notification is done and removedByGive is reset * by smObjEventProcess on the remote processor. * If the pended task is local removedByGive must be reset * here to avoid shared TCB to be screwed up. */ firstSmTcb->removedByGive = htonl (FALSE); /* windview - level 2 event logging */ EVT_TASK_1 (EVENT_OBJ_SEMGIVE, smSemId); windReadyQPut ((WIND_TCB *) ntohl ((int) firstSmTcb->localTcb)); } else /* pending task is remote */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -