⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 semsmlib.c

📁 VXWORKS源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
    /* pending task is remote */    else	{ 	/* 	 * Add the shared TCB that was pended on the semaphore	 * pend queue to the list of events to send to the	 * CPU where the pended task is located.	 */	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 */        CACHE_PIPE_FLUSH ();                    /* CACHE FLUSH   [SPR 68334] */        temp = firstSmTcb->ownerCpu;            /* PCI bridge bug [SPR 68844]*/	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 or if the optional <timeout> value is not NO_WAIT,* in which case the task will pend for no more than <timeout> system clock* ticks.  If <timeout> is WAIT_FOREVER , the task may never return if a remote* task has the semaphore and crashes.** 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 converts 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 */    SM_SEM_ID volatile smSemIdv = (SM_SEM_ID volatile) smSemId;    int                temp;    /* temp storage */    if (INT_RESTRICT () != OK)		/* not ISR callable */        {	return (ERROR);        }again:    CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */    temp = smSemIdv->verify;                    /* PCI bridge bug [SPR 68844]*/    if (SM_OBJ_VERIFY (smSemIdv) != 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 */	}        CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */    temp = smSemIdv->objType;                   /* PCI bridge bug [SPR 68844]*/    if (ntohl (smSemIdv->objType) == SEM_TYPE_SM_BINARY) /* binary semaphore */	{    	if (ntohl (smSemIdv->state.flag) == SEM_FULL)	    {	    smSemIdv->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 and we must wait.     * 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 multi-way 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 more tasks 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 converts 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 volatile * firstSmTcb;   /* first pending shared memory TCB */    SM_OBJ_TCB volatile * pSmObjTcb;    /* useful shared TCB pointer */     SM_OBJ_TCB volatile * pSmObjTcbTmp; /* useful shared TCB pointer */       int                   level;        /* CPU specific inLock return value */    int                   cpuNum;       /* loop counter for remote flush */    SM_DL_LIST            flushQ [SM_OBJ_MAX_CPU];  /* per CPU flush Q */    SM_SEM_ID volatile    smSemIdv = (SM_SEM_ID volatile) smSemId;    int                   temp;         /* temp storage */        if (INT_RESTRICT () != OK)			/* not ISR callable */        {	return (ERROR);        }    CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */    temp = smSemIdv->verify;                    /* PCI bridge bug [SPR 68844]*/    if (SM_OBJ_VERIFY (smSemIdv) != 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 the 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 volatile *) SM_DL_FIRST (&smSemId->smPendQ);    if (firstSmTcb == (SM_OBJ_TCB volatile *) LOC_NULL)  /* pendQ is empty */	{	SM_OBJ_LOCK_GIVE (&smSemId->lock, level);/* EXIT LOCKED SECTION */	return (OK);	}    smSemIdv->smPendQ.head = NULL;	    /* empty semaphore pend queue */    smSemIdv->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 volatile *) 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 now consists	 * of 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 + -