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

📄 semsmlib.c

📁 vxworks源码源码解读是学习vxworks的最佳途径
💻 C
📖 第 1 页 / 共 3 页
字号:
	{ 	/* 	 * 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 + -