qFifoGLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:14k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* qFifoGLib.c - global FIFO queue library (VxMP Option) */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01g,06may02,mas  cache flush and volatile fix (SPR 68334); bridge flush fix
  7.  (SPR 68844)
  8. 01f,24oct01,mas  fixed diab warnings (SPR 71120); doc update (SPR 71149)
  9. 01e,29jan93,pme  added little endian support
  10. 01d,02oct92,pme  added SPARC support.
  11. 01c,29sep92 pme  added comments to qFifoGRemove.
  12. 01b,30jul92,pme  removed qFifoGLibInit, added qFifoGInit.
  13.                  cleanup.
  14. 01a,19jul92,pme  fixed shared semaphore race, made qFifoGRemove return STATUS.
  15.                  written.
  16. */
  17. /*
  18. DESCRIPTION
  19. This library contains routines to manage a first-in-first-out global queue
  20. stored in shared memory.
  21. There are no user callable routines.
  22. This queue complies with the multi-way queue data structures and thus may be
  23. utilized by any multi-way queue.  The FIFO multi-way queue class is accessed
  24. by the global ID qFifoGClassId.
  25. The pointer to a global fifo queue points to a structure which
  26. contains the effective queue and an integer used as a spin-lock for the queue.
  27. This mechanism allows use of standard kernel functions such as windPendPut()
  28. and windPendQGet() to operate on multi-processor shared queues.
  29. AVAILABILITY
  30. This module is distributed as a component of the unbundled shared memory
  31. objects support option, VxMP.
  32. INTERNAL
  33. The routine qFifoGPut() takes a key in addition to a node to queue.  This key
  34. determines whether the node is placed at the head or tail of the queue.
  35. INCLUDE FILE: qFifoGLib.h
  36. SEE ALSO: qLib, smObjLib,
  37. tb VxWorks Programmer's Guide: Shared Memory Objects
  38. NOROUTINES
  39. */
  40. #include "vxWorks.h"
  41. #include "intLib.h"
  42. #include "smLib.h"
  43. #include "qClass.h"
  44. #include "qFifoGLib.h"
  45. #include "stdlib.h"
  46. #include "taskLib.h"
  47. #include "cacheLib.h"
  48. #include "netinet/in.h"
  49. #include "private/smObjLibP.h"
  50. /* forward static functions */
  51. static STATUS qFifoGNullRtn (void);
  52. /* locals */
  53. LOCAL Q_CLASS qFifoGClass =
  54.     {
  55.     (FUNCPTR)qFifoGNullRtn,
  56.     (FUNCPTR)qFifoGInit,
  57.     (FUNCPTR)qFifoGNullRtn,
  58.     (FUNCPTR)qFifoGNullRtn,
  59.     (FUNCPTR)qFifoGPut,
  60.     (FUNCPTR)qFifoGGet,
  61.     (FUNCPTR)qFifoGRemove,
  62.     (FUNCPTR)qFifoGNullRtn,
  63.     (FUNCPTR)qFifoGNullRtn,
  64.     (FUNCPTR)qFifoGNullRtn,
  65.     (FUNCPTR)qFifoGNullRtn,
  66.     (FUNCPTR)qFifoGNullRtn,
  67.     (FUNCPTR)qFifoGInfo,
  68.     (FUNCPTR)qFifoGEach,
  69.     &qFifoGClass
  70.     };
  71. /* globals */
  72. Q_CLASS_ID qFifoGClassId = &qFifoGClass;
  73. /******************************************************************************
  74. *
  75. * qFifoGInit - initialize global FIFO queue 
  76. *
  77. * This routine initializes the specified global FIFO queue.
  78. *
  79. * RETURNS: OK, or ERROR if FIFO queue could not be initialized.
  80. *
  81. * NOMANUAL
  82. */
  83. STATUS qFifoGInit 
  84.     (
  85.     Q_FIFO_G_HEAD * pQFifoGHead /* global FIFO queue to initialize */
  86.     )
  87.     {
  88.     Q_FIFO_G_HEAD volatile * pQFifoGHeadv =
  89.                                         (Q_FIFO_G_HEAD volatile *) pQFifoGHead;
  90.     void *                   temp;
  91.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  92.     temp = (void *) pQFifoGHeadv->pFifoQ;       /* PCI bridge bug [SPR 68844]*/
  93.     smDllInit (pQFifoGHeadv->pFifoQ); /* initialize the real queue */
  94.     return (OK);
  95.     }
  96. /******************************************************************************
  97. *
  98. * qFifoGPut - add a node to a global FIFO queue
  99. *
  100. * This routine adds the specifed node to the global FIFO queue.
  101. * The insertion is either at the tail or head based on the specified <key>
  102. * FIFO_KEY_TAIL or FIFO_KEY_HEAD respectively.
  103. *
  104. * This routine is only called through Q_PUT in windPendQPut() to add a shared
  105. * task control block into a semaphore pend Queue.  Thus, what we always
  106. * have to do when this function is called is to insert the shared TCB
  107. * of the task that calls us in the semaphore queue specified by <pQFifoGHead>.
  108. *
  109. * RETURNS: N/A
  110. *
  111. * NOMANUAL
  112. */
  113. void qFifoGPut 
  114.     (
  115.     Q_FIFO_G_HEAD * pQFifoGHead, /* Q to where to put node */
  116.     SM_DL_NODE *    pQFifoGNode, /* not used */
  117.     ULONG           key 
  118.     )
  119.     {
  120.     Q_FIFO_G_HEAD volatile * pQFifoGHeadv =
  121.                                         (Q_FIFO_G_HEAD volatile *) pQFifoGHead;
  122.     void *                   temp;
  123.     /* appease the Diab gods (SPR 71120) */
  124.     if (pQFifoGNode == NULL)
  125.         ;
  126.     /* do the shared TCB queueing */
  127.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  128.     if (key == FIFO_KEY_HEAD)
  129.         {
  130.         temp = (void *) pQFifoGHeadv->pFifoQ;   /* PCI bridge bug [SPR 68844]*/
  131. smDllInsert (pQFifoGHeadv->pFifoQ, (SM_DL_NODE *) NULL, 
  132.      (SM_DL_NODE *) taskIdCurrent->pSmObjTcb);
  133.         }
  134.     else
  135.         {
  136.         temp = (void *) pQFifoGHeadv->pFifoQ;   /* PCI bridge bug [SPR 68844]*/
  137. smDllAdd (pQFifoGHeadv->pFifoQ, (SM_DL_NODE*)taskIdCurrent->pSmObjTcb);
  138.         }
  139.     }
  140. /******************************************************************************
  141. *
  142. * qFifoGGet - get the first node out of a global FIFO queue
  143. *
  144. * This routine dequeues and returns the first node of a global FIFO queue.
  145. * If the queue is empty, NULL will be returned.
  146. *
  147. * RETURNS: pointer the first node, or NULL if queue is empty.
  148. *
  149. * NOMANUAL
  150. */
  151. SM_DL_NODE * qFifoGGet 
  152.     (
  153.     Q_FIFO_G_HEAD * pQFifoGHead  /* Q to get node from */
  154.     )
  155.     {
  156.     SM_DL_NODE volatile *    node;
  157.     Q_FIFO_G_HEAD volatile * pQFifoGHeadv =
  158.                                         (Q_FIFO_G_HEAD volatile *) pQFifoGHead;
  159.     void *                   temp;
  160.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  161.     temp = (void *) pQFifoGHeadv->pFifoQ;       /* PCI bridge bug [SPR 68844]*/
  162.     if (SM_DL_EMPTY (pQFifoGHeadv->pFifoQ))
  163.         {
  164. return (NULL);
  165.         }
  166.     node = (SM_DL_NODE volatile *) smDllGet (pQFifoGHeadv->pFifoQ);
  167.     return ((SM_DL_NODE *) ntohl ((int) 
  168.                                 (((SM_OBJ_TCB volatile *) (node))->localTcb)));
  169.     }
  170. /******************************************************************************
  171. *
  172. * qFifoGRemove - remove the specified node from a global FIFO queue
  173. *
  174. * This routine removes the specified node from a global FIFO queue.
  175. *
  176. * RETURNS: OK, ALREADY_REMOVED if node was removed by a timeout, a task
  177. *          deletion or a siganl, or ERROR if lock cannot be taken.
  178. *
  179. * ERRNO:  S_smObjLib_LOCK_TIMEOUT
  180. *
  181. * NOMANUAL
  182. */
  183. STATUS qFifoGRemove 
  184.     (
  185.     Q_FIFO_G_HEAD * pQFifoGHead, /* Q head to remove from */
  186.     SM_DL_NODE *    pQFifoGNode  /* pointer to node to remove */
  187.     )
  188.     {
  189.     BOOL                     status; /* return status */
  190.     int                      level; /* inlock return value */
  191.     Q_FIFO_G_HEAD volatile * pQFifoGHeadv =
  192.                                         (Q_FIFO_G_HEAD volatile *) pQFifoGHead;
  193.     SM_DL_NODE volatile *    pQFifoGNodev = (SM_DL_NODE volatile *)pQFifoGNode;
  194.     void *                   temp;
  195.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  196.     temp = (void *) pQFifoGHeadv->pLock;        /* PCI bridge bug [SPR 68844]*/
  197.     if (pQFifoGHeadv->pLock != NULL)
  198. {
  199.         /* 
  200.          * qFifoGRemove can be called by windPendQRemove() to remove a task
  201.          * from a semaphore pend queue when a task is deleted or when a delay
  202.  * expires.  It can also be called by windRestart() when a signal is
  203.  * sent to the task.  In all cases this function is called with
  204.  * pQFifoGHead->pLock not NULL indicating that lock access must
  205.  * be obtained before manipulating the queue and a pointer to
  206.  * the task control block is passed as node to remove, but
  207.  * actually what we need to remove from the pendQ is the shared TCB
  208.  * not the TCB itself.
  209.          */
  210. /* ENTER LOCKED SECTION */
  211. if (SM_OBJ_LOCK_TAKE(pQFifoGHeadv->pLock, &level) == ERROR)
  212.     {
  213.     return (ERROR);
  214.     }
  215. /* 
  216.  * What can happen here is that because the notification time
  217.  * is not null, the shared TCB may have been removed by a semGive()
  218.  * on another CPU but this removal has not shown up on the take
  219.  * side.
  220.  */
  221.   
  222.         if (! ntohl (((WIND_TCB volatile *) (pQFifoGNodev))
  223.                                                    ->pSmObjTcb->removedByGive))
  224.     {
  225.     /*
  226.      * This is the normal case, a task deletion, a timeout or
  227.      * a signal when the shared TCB has not been already removed
  228.      * by semGive() on another CPU, so we remove it.
  229.      */
  230.      /*
  231.       * If this shared TCB has been previously removed from a shared
  232.       * semaphore pendQ, removedByGive has been reset to FALSE
  233.       * by smObjEventProcess().
  234.       */
  235.     smDllRemove (pQFifoGHeadv->pFifoQ, (SM_DL_NODE *)
  236.                           (((WIND_TCB volatile *) (pQFifoGNodev))->pSmObjTcb));
  237.     status = OK;
  238.     }
  239.         else
  240.     {
  241.     /*
  242.      * This is the bad case, the removedByGive field of the shared
  243.      * TCB has been set to TRUE.  In that case we set the local TCB
  244.      * pointer in the shared TCB to NULL indicating that the task
  245.      * has been deleted, got a timeout or has received a signal.
  246.      * This will be use by smObjEventProcess() when the shared TCB
  247.      * eventually shows up.
  248.      * We also set the pointer to the shared TCB stored in the local
  249.      * TCB to NULL to oblige the task to re-allocate a shared TCB if
  250.      * it is not deleted and goes back to a semTake() on the same or
  251.      * on another shared semaphore.
  252.      * Then we return a special status to the upper layers of
  253.      * the kernel.
  254.      */
  255.      /* 
  256.       * This cannot be done outside the LOCKED SECTION because
  257.       * we want to be sure that the notification interrupt
  258.       * does not occur between the test on removedByGive and here.
  259.       */
  260.      /*
  261.       * Note that we don't need to reset removedByGive to FALSE
  262.       * because this shared TCB will be dropped by smObjEventProcess.
  263.       */
  264.     ((WIND_TCB volatile *) (pQFifoGNodev))->pSmObjTcb->localTcb = NULL;
  265.     ((WIND_TCB volatile *) (pQFifoGNodev))->pSmObjTcb = NULL;
  266.     status = ALREADY_REMOVED;
  267.     }
  268.         /* EXIT LOCKED SECTION */
  269.         SM_OBJ_LOCK_GIVE (pQFifoGHeadv->pLock, level);
  270. }
  271.     else
  272. {
  273. /* 
  274.  * We are called by semGive() with lock already obtained,
  275.  * simply remove the node from the queue.  Actually,
  276.  * pQFifoGNode is a pointer to a shared TCB and pQFifoGHead->pFifoQ
  277.  * is a shared semaphore pendQ.
  278.  */
  279.      smDllRemove (pQFifoGHeadv->pFifoQ, pQFifoGNode);
  280. /* tell everybody that we are no longer on the semaphore pend Q */ 
  281. ((SM_OBJ_TCB volatile *) (pQFifoGNodev))->removedByGive = htonl (TRUE);
  282. status = OK;
  283. }
  284.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  285.     temp = (void *) pQFifoGHeadv->pLock;        /* BRIDGE FLUSH  [SPR 68334] */
  286.     return (status);
  287.     }
  288. /******************************************************************************
  289. *
  290. * qFifoGInfo - get information of a FIFO queue
  291. *
  292. * This routine returns information of a FIFO queue.  If the parameter
  293. * <nodeArray> is NULL, the number of queued nodes is returned.  Otherwise, the
  294. * specified <nodeArray> is filled with node pointers of the FIFO queue
  295. * starting from the head.  Node pointers are copied until the TAIL of the
  296. * queue is reached or until <maxNodes> has been entered in the <nodeArray>.
  297. *
  298. * RETURNS: Number of nodes entered in nodeArray, or nodes in FIFO queue.
  299. *
  300. * NOMANUAL
  301. */
  302. int qFifoGInfo 
  303.     (
  304.     Q_FIFO_G_HEAD * pQFifoGHead,/* FIFO queue to gather list for */
  305.     int             nodeArray[],/* array of node pointers to be filled in */
  306.     int             maxNodes    /* max node pointers nodeArray can accomodate*/
  307.     )
  308.     {
  309.     SM_DL_NODE volatile *    pNode;
  310.     int *                    pElement     = nodeArray;
  311.     Q_FIFO_G_HEAD volatile * pQFifoGHeadv = 
  312.                                         (Q_FIFO_G_HEAD volatile *) pQFifoGHead;
  313.     void *                   temp;
  314.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  315.     temp = (void *) pQFifoGHeadv->pFifoQ;       /* PCI bridge bug [SPR 68844]*/
  316.     pNode = (SM_DL_NODE volatile *) SM_DL_FIRST (pQFifoGHeadv->pFifoQ);
  317.     /* NULL node array means return count */
  318.     if (nodeArray == NULL)
  319.         {
  320. return (smDllCount (pQFifoGHeadv->pFifoQ));
  321.         }
  322.     while ((pNode != LOC_NULL) && (--maxNodes >= 0))
  323. {
  324. *(pElement++) = (int) pNode;                 /* fill in table */
  325. pNode = (SM_DL_NODE volatile *) SM_DL_NEXT (pNode); /* next node */
  326. }
  327.     return (pElement - nodeArray); /* return count of active tasks */
  328.     }
  329. /******************************************************************************
  330. *
  331. * qFifoGEach - call a routine for each node in a queue
  332. *
  333. * This routine calls a user-supplied <routine> once for each node in the
  334. * queue.  The routine should be declared as follows:
  335. * cs
  336. *  BOOL routine (pQNode, arg)
  337. *      SM_DL_NODE volatile * pQNode; /@ pointer to a queue node          @/
  338. *      int              arg; /@ arbitrary user-supplied argument @/
  339. * ce
  340. * The user-supplied <routine> should return TRUE if qFifoGEach() is to continue
  341. * calling it for each entry, or FALSE if it is done and qFifoGEach() can exit.
  342. *
  343. * RETURNS: NULL if traversed whole queue, or pointer to SM_DL_NODE that
  344. *          qFifoGEach() stopped on.
  345. *
  346. * NOMANUAL
  347. */
  348. SM_DL_NODE * qFifoGEach 
  349.     (
  350.     Q_FIFO_G_HEAD * pQHead,     /* queue head of queue to call routine for */
  351.     FUNCPTR         routine,    /* the routine to call for each table entry */
  352.     int             routineArg  /* arbitrary user-supplied argument */
  353.     )
  354.     {
  355.     SM_DL_NODE volatile *    pQNode;
  356.     Q_FIFO_G_HEAD volatile * pQHeadv = (Q_FIFO_G_HEAD volatile *) pQHead;
  357.     void *                   temp;
  358.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  359.     temp = (void *) pQHeadv->pFifoQ;            /* PCI bridge bug [SPR 68844]*/
  360.     pQNode = (SM_DL_NODE volatile *) SM_DL_FIRST (pQHeadv->pFifoQ);
  361.     while ((pQNode != NULL) && ((* routine) (pQNode, routineArg)))
  362.         {
  363. pQNode = (SM_DL_NODE volatile *) SM_DL_NEXT (pQNode);
  364.         }
  365.     return ((SM_DL_NODE *) pQNode); /* return node we ended with */
  366.     }
  367. /******************************************************************************
  368. *
  369. * qFifoGNullRtn - null routine for global queue class structure
  370. *
  371. * This routine does nothing and returns OK.
  372. *
  373. * RETURNS: OK
  374. *
  375. * NOMANUAL
  376. */
  377. LOCAL STATUS qFifoGNullRtn (void)
  378.     {
  379.     return (OK);
  380.     }