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

📄 qfifoglib.c

📁 VXWORKS源代码
💻 C
字号:
/* qFifoGLib.c - global FIFO queue library (VxMP Option) *//* Copyright 1984-2002 Wind River Systems, Inc. *//*modification history--------------------01g,06may02,mas  cache flush and volatile fix (SPR 68334); bridge flush fix		 (SPR 68844)01f,24oct01,mas  fixed diab warnings (SPR 71120); doc update (SPR 71149)01e,29jan93,pme  added little endian support01d,02oct92,pme  added SPARC support.01c,29sep92 pme  added comments to qFifoGRemove.01b,30jul92,pme	 removed qFifoGLibInit, added qFifoGInit.                 cleanup.01a,19jul92,pme	 fixed shared semaphore race, made qFifoGRemove return STATUS.               	 written.*//*DESCRIPTIONThis library contains routines to manage a first-in-first-out global queuestored in shared memory.There are no user callable routines.This queue complies with the multi-way queue data structures and thus may beutilized by any multi-way queue.  The FIFO multi-way queue class is accessedby the global ID qFifoGClassId.The pointer to a global fifo queue points to a structure whichcontains the effective queue and an integer used as a spin-lock for the queue.This mechanism allows use of standard kernel functions such as windPendPut()and windPendQGet() to operate on multi-processor shared queues.AVAILABILITYThis module is distributed as a component of the unbundled shared memoryobjects support option, VxMP.INTERNALThe routine qFifoGPut() takes a key in addition to a node to queue.  This keydetermines whether the node is placed at the head or tail of the queue.INCLUDE FILE: qFifoGLib.hSEE ALSO: qLib, smObjLib,\tb VxWorks Programmer's Guide: Shared Memory ObjectsNOROUTINES*/#include "vxWorks.h"#include "intLib.h"#include "smLib.h"#include "qClass.h"#include "qFifoGLib.h"#include "stdlib.h"#include "taskLib.h"#include "cacheLib.h"#include "netinet/in.h"#include "private/smObjLibP.h"/* forward static functions */static STATUS qFifoGNullRtn (void);/* locals */LOCAL Q_CLASS qFifoGClass =    {    (FUNCPTR)qFifoGNullRtn,    (FUNCPTR)qFifoGInit,    (FUNCPTR)qFifoGNullRtn,    (FUNCPTR)qFifoGNullRtn,    (FUNCPTR)qFifoGPut,    (FUNCPTR)qFifoGGet,    (FUNCPTR)qFifoGRemove,    (FUNCPTR)qFifoGNullRtn,    (FUNCPTR)qFifoGNullRtn,    (FUNCPTR)qFifoGNullRtn,    (FUNCPTR)qFifoGNullRtn,    (FUNCPTR)qFifoGNullRtn,    (FUNCPTR)qFifoGInfo,    (FUNCPTR)qFifoGEach,    &qFifoGClass    };/* globals */Q_CLASS_ID qFifoGClassId = &qFifoGClass;/******************************************************************************** qFifoGInit - initialize global FIFO queue ** This routine initializes the specified global FIFO queue.** RETURNS: OK, or ERROR if FIFO queue could not be initialized.** NOMANUAL*/STATUS qFifoGInit     (    Q_FIFO_G_HEAD * pQFifoGHead		/* global FIFO queue to initialize */    )    {    Q_FIFO_G_HEAD volatile * pQFifoGHeadv =                                        (Q_FIFO_G_HEAD volatile *) pQFifoGHead;    void *                   temp;    CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */    temp = (void *) pQFifoGHeadv->pFifoQ;       /* PCI bridge bug [SPR 68844]*/    smDllInit (pQFifoGHeadv->pFifoQ);	/* initialize the real queue */    return (OK);    }/******************************************************************************** qFifoGPut - add a node to a global FIFO queue** This routine adds the specifed node to the global FIFO queue.* The insertion is either at the tail or head based on the specified <key>* FIFO_KEY_TAIL or FIFO_KEY_HEAD respectively.** This routine is only called through Q_PUT in windPendQPut() to add a shared* task control block into a semaphore pend Queue.  Thus, what we always* have to do when this function is called is to insert the shared TCB* of the task that calls us in the semaphore queue specified by <pQFifoGHead>.** RETURNS: N/A** NOMANUAL*/void qFifoGPut     (    Q_FIFO_G_HEAD * pQFifoGHead,	/* Q to where to put node */	    SM_DL_NODE *    pQFifoGNode,	/* not used */    ULONG           key     )    {    Q_FIFO_G_HEAD volatile * pQFifoGHeadv =                                        (Q_FIFO_G_HEAD volatile *) pQFifoGHead;    void *                   temp;    /* appease the Diab gods (SPR 71120) */    if (pQFifoGNode == NULL)        ;    /* do the shared TCB queueing */    CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */    if (key == FIFO_KEY_HEAD)        {        temp = (void *) pQFifoGHeadv->pFifoQ;   /* PCI bridge bug [SPR 68844]*/	smDllInsert (pQFifoGHeadv->pFifoQ, (SM_DL_NODE *) NULL, 		     (SM_DL_NODE *) taskIdCurrent->pSmObjTcb);        }    else        {        temp = (void *) pQFifoGHeadv->pFifoQ;   /* PCI bridge bug [SPR 68844]*/	smDllAdd (pQFifoGHeadv->pFifoQ, (SM_DL_NODE*)taskIdCurrent->pSmObjTcb);        }    }/******************************************************************************** qFifoGGet - get the first node out of a global FIFO queue** This routine dequeues and returns the first node of a global FIFO queue.* If the queue is empty, NULL will be returned.** RETURNS: pointer the first node, or NULL if queue is empty.** NOMANUAL*/SM_DL_NODE * qFifoGGet     (    Q_FIFO_G_HEAD * pQFifoGHead 	/* Q to get node from */    )    {    SM_DL_NODE volatile *    node;    Q_FIFO_G_HEAD volatile * pQFifoGHeadv =                                        (Q_FIFO_G_HEAD volatile *) pQFifoGHead;    void *                   temp;    CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */    temp = (void *) pQFifoGHeadv->pFifoQ;       /* PCI bridge bug [SPR 68844]*/    if (SM_DL_EMPTY (pQFifoGHeadv->pFifoQ))        {	return (NULL);        }    node = (SM_DL_NODE volatile *) smDllGet (pQFifoGHeadv->pFifoQ);    return ((SM_DL_NODE *) ntohl ((int) \                                (((SM_OBJ_TCB volatile *) (node))->localTcb)));    }/******************************************************************************** qFifoGRemove - remove the specified node from a global FIFO queue** This routine removes the specified node from a global FIFO queue.** RETURNS: OK, ALREADY_REMOVED if node was removed by a timeout, a task*          deletion or a siganl, or ERROR if lock cannot be taken.** ERRNO:  S_smObjLib_LOCK_TIMEOUT** NOMANUAL*/STATUS qFifoGRemove     (    Q_FIFO_G_HEAD * pQFifoGHead,	/* Q head to remove from */    SM_DL_NODE *    pQFifoGNode 	/* pointer to node to remove */    )    {    BOOL                     status;	/* return status */    int                      level;	/* inlock return value */    Q_FIFO_G_HEAD volatile * pQFifoGHeadv =                                        (Q_FIFO_G_HEAD volatile *) pQFifoGHead;    SM_DL_NODE volatile *    pQFifoGNodev = (SM_DL_NODE volatile *)pQFifoGNode;    void *                   temp;    CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */    temp = (void *) pQFifoGHeadv->pLock;        /* PCI bridge bug [SPR 68844]*/    if (pQFifoGHeadv->pLock != NULL)	{        /*          * qFifoGRemove can be called by windPendQRemove() to remove a task         * from a semaphore pend queue when a task is deleted or when a delay	 * expires.  It can also be called by windRestart() when a signal is	 * sent to the task.  In all cases this function is called with	 * pQFifoGHead->pLock not NULL indicating that lock access must	 * be obtained before manipulating the queue and a pointer to	 * the task control block is passed as node to remove, but	 * actually what we need to remove from the pendQ is the shared TCB	 * not the TCB itself.         */	/* ENTER LOCKED SECTION */	if (SM_OBJ_LOCK_TAKE(pQFifoGHeadv->pLock, &level) == ERROR)	    {	    return (ERROR);	    }	/* 	 * What can happen here is that because the notification time	 * is not null, the shared TCB may have been removed by a semGive()	 * on another CPU but this removal has not shown up on the take	 * side.	 */	          if (! ntohl (((WIND_TCB volatile *) (pQFifoGNodev))\                                                   ->pSmObjTcb->removedByGive))	    {	    /*	     * This is the normal case, a task deletion, a timeout or	     * a signal when the shared TCB has not been already removed	     * by semGive() on another CPU, so we remove it.	     */	     /*	      * If this shared TCB has been previously removed from a shared	      * semaphore pendQ, removedByGive has been reset to FALSE	      * by smObjEventProcess().	      */	    smDllRemove (pQFifoGHeadv->pFifoQ, (SM_DL_NODE *)\                          (((WIND_TCB volatile *) (pQFifoGNodev))->pSmObjTcb));	    status = OK;	    }        else	    {	    /*	     * This is the bad case, the removedByGive field of the shared	     * TCB has been set to TRUE.  In that case we set the local TCB	     * pointer in the shared TCB to NULL indicating that the task	     * has been deleted, got a timeout or has received a signal.	     * This will be use by smObjEventProcess() when the shared TCB	     * eventually shows up.	     * We also set the pointer to the shared TCB stored in the local	     * TCB to NULL to oblige the task to re-allocate a shared TCB if	     * it is not deleted and goes back to a semTake() on the same or	     * on another shared semaphore.	     * Then we return a special status to the upper layers of	     * the kernel.	     */	     /* 	      * This cannot be done outside the LOCKED SECTION because	      * we want to be sure that the notification interrupt	      * does not occur between the test on removedByGive and here.	      */	     /*	      * Note that we don't need to reset removedByGive to FALSE	      * because this shared TCB will be dropped by smObjEventProcess.	      */	    ((WIND_TCB volatile *) (pQFifoGNodev))->pSmObjTcb->localTcb = NULL;	    ((WIND_TCB volatile *) (pQFifoGNodev))->pSmObjTcb = NULL;	    status = ALREADY_REMOVED;	    }        /* EXIT LOCKED SECTION */        SM_OBJ_LOCK_GIVE (pQFifoGHeadv->pLock, level);	}    else	{	/* 	 * We are called by semGive() with lock already obtained,	 * simply remove the node from the queue.  Actually,	 * pQFifoGNode is a pointer to a shared TCB and pQFifoGHead->pFifoQ	 * is a shared semaphore pendQ.	 */    	smDllRemove (pQFifoGHeadv->pFifoQ, pQFifoGNode);	/* tell everybody that we are no longer on the semaphore pend Q */ 	((SM_OBJ_TCB volatile *) (pQFifoGNodev))->removedByGive = htonl (TRUE);					status = OK;	}    CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */    temp = (void *) pQFifoGHeadv->pLock;        /* BRIDGE FLUSH  [SPR 68334] */    return (status);    }/******************************************************************************** qFifoGInfo - get information of a FIFO queue** This routine returns information of a FIFO queue.  If the parameter* <nodeArray> is NULL, the number of queued nodes is returned.  Otherwise, the* specified <nodeArray> is filled with node pointers of the FIFO queue* starting from the head.  Node pointers are copied until the TAIL of the* queue is reached or until <maxNodes> has been entered in the <nodeArray>.** RETURNS: Number of nodes entered in nodeArray, or nodes in FIFO queue.** NOMANUAL*/int qFifoGInfo     (    Q_FIFO_G_HEAD * pQFifoGHead,/* FIFO queue to gather list for */    int             nodeArray[],/* array of node pointers to be filled in */    int             maxNodes    /* max node pointers nodeArray can accomodate*/    )    {    SM_DL_NODE volatile *    pNode;    int *                    pElement     = nodeArray;    Q_FIFO_G_HEAD volatile * pQFifoGHeadv = \                                        (Q_FIFO_G_HEAD volatile *) pQFifoGHead;    void *                   temp;    CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */    temp = (void *) pQFifoGHeadv->pFifoQ;       /* PCI bridge bug [SPR 68844]*/    pNode = (SM_DL_NODE volatile *) SM_DL_FIRST (pQFifoGHeadv->pFifoQ);    /* NULL node array means return count */    if (nodeArray == NULL)        {	return (smDllCount (pQFifoGHeadv->pFifoQ));        }    while ((pNode != LOC_NULL) && (--maxNodes >= 0))	{	*(pElement++) = (int) pNode;	                /* fill in table */	pNode = (SM_DL_NODE volatile *) SM_DL_NEXT (pNode); /* next node */	}    return (pElement - nodeArray);	/* return count of active tasks */    }/******************************************************************************** qFifoGEach - call a routine for each node in a queue** This routine calls a user-supplied <routine> once for each node in the* queue.  The routine should be declared as follows:* \cs*  BOOL routine (pQNode, arg)*      SM_DL_NODE volatile * pQNode;	/@ pointer to a queue node          @/*      int	             arg;	/@ arbitrary user-supplied argument @/* \ce* The user-supplied <routine> should return TRUE if qFifoGEach() is to continue* calling it for each entry, or FALSE if it is done and qFifoGEach() can exit.** RETURNS: NULL if traversed whole queue, or pointer to SM_DL_NODE that*          qFifoGEach() stopped on.** NOMANUAL*/SM_DL_NODE * qFifoGEach     (    Q_FIFO_G_HEAD * pQHead,     /* queue head of queue to call routine for */    FUNCPTR         routine,    /* the routine to call for each table entry */    int             routineArg  /* arbitrary user-supplied argument */    )    {    SM_DL_NODE volatile *    pQNode;    Q_FIFO_G_HEAD volatile * pQHeadv = (Q_FIFO_G_HEAD volatile *) pQHead;    void *                   temp;    CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */    temp = (void *) pQHeadv->pFifoQ;            /* PCI bridge bug [SPR 68844]*/    pQNode = (SM_DL_NODE volatile *) SM_DL_FIRST (pQHeadv->pFifoQ);    while ((pQNode != NULL) && ((* routine) (pQNode, routineArg)))        {	pQNode = (SM_DL_NODE volatile *) SM_DL_NEXT (pQNode);        }    return ((SM_DL_NODE *) pQNode);		/* return node we ended with */    }/******************************************************************************** qFifoGNullRtn - null routine for global queue class structure** This routine does nothing and returns OK.** RETURNS: OK** NOMANUAL*/LOCAL STATUS qFifoGNullRtn (void)    {    return (OK);    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -