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

VxWorks

开发平台:

C/C++

  1. /* qJobLib.c - fifo queue with singly-linked lists with intLocks */
  2. /* Copyright 1990-2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01w,19oct01,bwa  Added MSG_Q_EVENTSEND_ERR_NOTIFY options support.
  8. 01v,06sep00,bwa  added extra argument to qJobGet() (msgQid)
  9.                  also added an OBJ_VERIFY() on that msgQId (SPR #20195)
  10. 01u,07sep01,bwa  Added VxWorks events support.
  11. 01t,24jun96,sbs  made windview instrumentation conditionally compiled
  12. 01s,14mar95,rdc  fixed MSG_OFFSET macro.
  13. 01r,02feb94,smb  corrected side effect of errno and OBJ_VERIFY SPR #2984
  14.  corrected modhist 01q
  15. 01q,24jan94,smb  added instrumentation macros
  16. 01p,18jan94,smb  instrumentation corrections for msgQDelete
  17. 01o,17jan94,smb  instrumentation corrections
  18. 01n,10dec93,smb  added instrumentation for windView
  19. 01m,23aug92,jcf  cleanup.
  20. 01l,30jul92,rrr  added restarting, put in msgQ fix.
  21. 01k,18jul92,smb  Changed errno.h to errnoLib.h.
  22. 01j,04jul92,jcf  scalable/ANSI/cleanup effort.
  23. 01i,26may92,rrr  the tree shuffle
  24. 01h,19nov91,rrr  shut up some ansi warnings.
  25. 01g,04oct91,rrr  passed through the ansification filter
  26.                   -changed functions to ansi style
  27.   -changed VOID to void
  28.   -changed copyright notice
  29. 01f,21aug91,wmd  Conditionalized define of PORTABLE flag for MIPS.
  30. 01e,10aug91,del  changed interface to qInit to pass all "optional" args.
  31. 01d,07jun91,wmd  Conditionalized define of PORTABLE flag for CPU!=SPARC.
  32. 01c,10aug90,dnw  changed qJobPut() to void.
  33. 01b,18jul90,dnw  added missing call of windPendQTerminate() to qJobTerminate()
  34. 01a,01may90,dnw  written by modifying qFifoLib.c
  35. */
  36. /*
  37. DESCRIPTION
  38. Deviations for standard queue defs:
  39.     qCreate/Init type
  40.     qGet timeout
  41.     size (bigger than Q_HEAD)
  42. .CS
  43. windview INSTRUMENTATION
  44. ------------------------
  45. This Library should not be used by anything other than message queues.
  46.         LEVEL 1 N/A
  47.         LEVEL 2
  48.                 qJobTerminate causes EVENT_OBJ_MSGDELETE
  49.                 qJobPut causes EVENT_OBJ_MSGSEND
  50.                 qJobGet causes EVENT_OBJ_MSGRECEIVE
  51.         LEVEL 3 N/A
  52. .CE
  53. */
  54. #include "vxWorks.h"
  55. #include "qJobLib.h"
  56. #include "objLib.h"
  57. #include "stdlib.h"
  58. #include "intLib.h"
  59. #include "errnoLib.h"
  60. #include "eventLib.h"
  61. #include "private/windLibP.h"
  62. #include "private/workQLibP.h"
  63. #include "private/sigLibP.h"
  64. #include "private/msgQLibP.h"
  65. #include "private/eventP.h"
  66. /* forward static functions */
  67. LOCAL STATUS qJobNullRtn (void);
  68. LOCAL void qJobPendQGet (MSG_Q_ID msgQId, Q_JOB_HEAD *pQHead);
  69. /* locals */
  70. LOCAL Q_CLASS qJobClass =
  71.     {
  72.     (FUNCPTR)qJobCreate,
  73.     (FUNCPTR)qJobInit,
  74.     (FUNCPTR)qJobDelete,
  75.     (FUNCPTR)qJobTerminate,
  76.     (FUNCPTR)qJobPut,
  77.     (FUNCPTR)qJobGet,
  78.     (FUNCPTR)qJobNullRtn, /* no remove routine */
  79.     (FUNCPTR)qJobNullRtn,
  80.     (FUNCPTR)qJobNullRtn,
  81.     (FUNCPTR)qJobNullRtn,
  82.     (FUNCPTR)qJobNullRtn,
  83.     (FUNCPTR)qJobNullRtn,
  84.     (FUNCPTR)qJobInfo,
  85.     (FUNCPTR)qJobEach,
  86.     &qJobClass
  87.     };
  88. /* globals */
  89. Q_CLASS_ID qJobClassId = &qJobClass;
  90. #ifdef WV_INSTRUMENTATION
  91. /* defines */
  92. /* windview - this is needed by event logging in qJobLib */
  93. #define MSGQ_VERIFY(objId)                                     
  94.     (                                                                    
  95.     ((((OBJ_ID)(objId))->pObjClass == msgQClassId) ||    
  96.      (((OBJ_ID)(objId))->pObjClass == (CLASS_ID)(msgQClassId->initRtn))  
  97.     )                                                                    
  98.         ?                                                                
  99.             OK                                                           
  100.         :                                                                
  101.             ERROR                          
  102.     )
  103. #define MSG_OFFSET   (OFFSET(MSG_Q, msgQ))
  104. #define FREE_OFFSET   (OFFSET(MSG_Q, freeQ))
  105. #endif
  106. /* local defines */
  107. /******************************************************************************
  108. *
  109. * qJobCreate - create a job queue
  110. */
  111. Q_JOB_HEAD *qJobCreate
  112.     (
  113.     Q_CLASS_ID pendQType        /* queue class for task pend queue */
  114.     )
  115.     {
  116.     FAST Q_JOB_HEAD *pQHead = (Q_JOB_HEAD *) malloc (sizeof (Q_JOB_HEAD));
  117.     if (pQHead == NULL)
  118. return (NULL);
  119.     if (qJobInit (pQHead, pendQType) != OK)
  120. {
  121. free ((char *) pQHead);
  122. return (NULL);
  123. }
  124.     return (pQHead);
  125.     }
  126. /******************************************************************************
  127. *
  128. * qJobInit -
  129. */
  130. STATUS qJobInit
  131.     (
  132.     FAST Q_JOB_HEAD *pQHead,    /* queue head to initialize */
  133.     Q_CLASS_ID pendQType        /* queue class for task pend queue */
  134.     )
  135.     {
  136.     pQHead->first = NULL;
  137.     pQHead->last = NULL;
  138.     pQHead->count = 0;
  139.     qInit (&pQHead->pendQ, pendQType, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  140.     return (OK);
  141.     }
  142. /*******************************************************************************
  143. *
  144. * qJobDelete -
  145. */
  146. STATUS qJobDelete
  147.     (
  148.     Q_JOB_HEAD *pQHead
  149.     )
  150.     {
  151.     qJobTerminate (pQHead);
  152.     free ((char *) pQHead);
  153.     return OK;
  154.     }
  155. /*******************************************************************************
  156. *
  157. * qJobTerminate -
  158. */
  159. STATUS qJobTerminate
  160.     (
  161.     Q_JOB_HEAD *pQHead          /* queue head to terminate */
  162.     )
  163.     {
  164.     windPendQTerminate (&pQHead->pendQ);
  165.     return (OK);
  166.     }
  167. /*******************************************************************************
  168. *
  169. * qJobPut -
  170. */
  171. STATUS qJobPut
  172.     (
  173.     MSG_Q_ID    msgQId,
  174.     Q_JOB_HEAD *pQHead,
  175.     Q_JOB_NODE *pNode,
  176.     int         key
  177.     )
  178.     {
  179.     FAST int level;
  180.     if (key == 0)
  181. {
  182. /* add node to tail of queue */
  183. pNode->next = NULL;
  184. level = intLock (); /* LOCK INTERRUPTS */
  185. if (pQHead->first == NULL)
  186.     pQHead->last = pQHead->first = pNode;
  187. else
  188.     {
  189.     pQHead->last->next = pNode;
  190.     pQHead->last = pNode;
  191.     }
  192. }
  193.     else
  194. {
  195. /* add node to head of queue */
  196. level = intLock (); /* LOCK INTERRUPTS */
  197. if ((pNode->next = pQHead->first) == NULL)
  198.     pQHead->last = pNode;
  199. pQHead->first = pNode;
  200. }
  201.     pQHead->count++;
  202.     /* interrupts are still locked out */
  203.     if (kernelState == TRUE) /* interrupted kernel? */
  204. {
  205. intUnlock (level); /* UNLOCK INTERRUPTS */
  206. workQAdd2 ((FUNCPTR)qJobPendQGet, (int)msgQId, (int)pQHead);
  207.         }
  208.     else 
  209. {
  210. if (Q_FIRST (&pQHead->pendQ) == NULL) /* anybody waiting for msg? */
  211.     {
  212.     /*
  213.      * look if we are putting back the node on the msg Q. If so, it
  214.      * means that we are putting a msg on the queue and since no task
  215.      * is waiting for it, we have to send events.
  216.      */
  217.     if (pQHead == &msgQId->msgQ)
  218. {
  219. if (msgQId->events.taskId != (int)NULL)
  220.     {
  221.     STATUS evStatus;
  222.     STATUS retStatus = OK;
  223.     int oldErrno = errno;
  224.     kernelState = TRUE; /* KERNEL ENTER */
  225.     intUnlock (level); /* UNLOCK INTERRUPTS */
  226.     evStatus = eventRsrcSend(msgQId->events.taskId,
  227.      msgQId->events.registered);
  228.     if (evStatus != OK)
  229.      {
  230. if ((msgQId->options & MSG_Q_EVENTSEND_ERR_NOTIFY) != 0)
  231.     {
  232.          oldErrno = S_eventLib_EVENTSEND_FAILED;
  233.     retStatus = ERROR;
  234.     }
  235. /*
  236.       * Error, so remove registration so that next time the
  237.        * queue becomes empty it doesn't try to send events.
  238.        */
  239.      msgQId->events.taskId = (int)NULL;
  240.      }
  241.     else if ((msgQId->events.options & EVENTS_SEND_ONCE) != 0x0)
  242.      msgQId->events.taskId = (int)NULL;
  243.     windExit (); /* KERNEL EXIT */
  244.     errnoSet (oldErrno);
  245.     return (retStatus);
  246.     }
  247. else
  248.     intUnlock (level); /* UNLOCK INTERRUPTS */
  249. }
  250.     else
  251. intUnlock (level); /* UNLOCK INTERRUPTS */
  252.     }
  253. else
  254.     {
  255.     kernelState = TRUE; /* KERNEL ENTER */
  256.     intUnlock (level); /* UNLOCK INTERRUPTS */
  257. #ifdef WV_INSTRUMENTATION
  258.              /* windview - level 2 instrumentation */
  259.      if (pQHead == &msgQId->msgQ)
  260.          EVT_TASK_1 (EVENT_OBJ_MSGSEND, msgQId);
  261.      else
  262.          EVT_TASK_1 (EVENT_OBJ_MSGRECEIVE, msgQId);
  263. #endif
  264.     windPendQGet (&pQHead->pendQ); /* unblock receiver */
  265.     windExit (); /* KERNEL EXIT */
  266.     }
  267. }
  268.     return (OK);
  269.     }
  270. /*******************************************************************************
  271. *
  272. * qJobPendQGet - work routine to unblock a receiver (if any)
  273. *
  274. * If a task is waiting then unblock first task in pendQ.  This routine must
  275. * be called with kernelState = TRUE.  It is called as deferred work from
  276. * qJobPut().
  277. *
  278. */
  279.  
  280. LOCAL void qJobPendQGet
  281.     (
  282.     MSG_Q_ID msgQId,
  283.     Q_JOB_HEAD *pQHead
  284.     )
  285.     {
  286.     /* this IS a msgQSend since msgQReceive can't be done from ISR */
  287.     if (Q_FIRST (&pQHead->pendQ) != NULL)       /* any receivers? */
  288. {
  289. #ifdef WV_INSTRUMENTATION
  290.       /* windview - level 2 instrumentation */
  291. EVT_TASK_1 (EVENT_OBJ_MSGSEND,msgQId);
  292. #endif
  293. windPendQGet (&pQHead->pendQ);          /* unblock receiver */
  294. }
  295.     else
  296. {
  297. if (msgQId->events.taskId != (int)NULL)
  298.     {
  299.     if (eventRsrcSend (msgQId->events.taskId,
  300.        msgQId->events.registered) != OK)
  301.      {
  302. /*
  303.       * Error, so remove registration so that next time the
  304.        * queue becomes empty it doesn't try to send events.
  305.        */
  306.      msgQId->events.taskId = (int)NULL;
  307. return;
  308.      }
  309.     else if ((msgQId->events.options & EVENTS_SEND_ONCE) != 0x0)
  310.    msgQId->events.taskId = (int)NULL;
  311.     }
  312. }
  313.     }
  314. /*******************************************************************************
  315. *
  316. * qJobGet -
  317. *
  318. * WORKS FROM INT LVL IF TIMEOUT == 0!
  319. *
  320. * RETURNS: pNode or NULL if empty list
  321. *
  322. * ERRNO: S_objLib_OBJ_UNAVAILABLE
  323. *
  324. */
  325. Q_JOB_NODE *qJobGet
  326.     (
  327.     MSG_Q_ID msgQId,
  328.     FAST Q_JOB_HEAD *pQHead,
  329.     FAST int timeout
  330.     )
  331.     {
  332.     int level;
  333.     int status;
  334.     Q_JOB_NODE *pNode;
  335.     level = intLock (); /* LOCK INTERRUPTS */
  336.     while ((pNode = pQHead->first) == NULL)
  337. {
  338. if (timeout == 0)
  339.     {
  340.     intUnlock (level); /* UNLOCK INTERRUPTS */
  341.     errnoSet (S_objLib_OBJ_UNAVAILABLE);
  342.     return (NULL);
  343.     }
  344. /* assume not at intlvl since timeout != 0 (?) */
  345. kernelState = TRUE; /* KERNEL ENTER */
  346. intUnlock (level); /* UNLOCK INTERRUPTS */
  347. #ifdef WV_INSTRUMENTATION
  348.         /* windview - level 2 instrumentation 
  349.          * EVENT_OBJ_MSGRECEIVE needs to return the msgQId so MSG_OFFSET is
  350.          * used to calulate the msgQId from the pQHead
  351.        * EVENT_OBJ_MSGSEND needs FREE_OFFSET to calulate the 
  352.  * msgQId from the pQHead
  353.  *
  354.  * msgQDelete() also call this routine but the msgQId will be 
  355.  * an invalid id. and thus no events will get logged.
  356.          */
  357.         if (MSGQ_VERIFY ((char *) pQHead - (MSG_OFFSET)) == OK)
  358.             EVT_TASK_1 (EVENT_OBJ_MSGRECEIVE, 
  359.                 ((char *)pQHead - (MSG_OFFSET)));
  360. else
  361.             if (MSGQ_VERIFY ((char *) pQHead - (FREE_OFFSET)) == OK)
  362.              EVT_TASK_1 (EVENT_OBJ_MSGSEND,
  363.     ((char *)pQHead - (FREE_OFFSET)));
  364. #endif
  365. windPendQPut (&pQHead->pendQ, timeout);
  366. if ((status = windExit ()) == RESTART) /* KERNEL EXIT */
  367.     return ((Q_JOB_NODE *) NONE); /* restart */
  368. if (status != OK)
  369.     return (NULL); /* timeout */
  370. if (OBJ_VERIFY (msgQId, msgQClassId) != OK)
  371.             {
  372.             errnoSet (S_objLib_OBJ_DELETED); /* queue got deleted */
  373.     return NULL;
  374.             }
  375. level = intLock (); /* LOCK INTERRUPTS */
  376. }
  377.     /* exit above loop with queue not empty (pNode != NULL) and
  378.      * interrupts locked out
  379.      */
  380.     pQHead->first = pNode->next;
  381.     pQHead->count--;
  382.     intUnlock (level); /* UNLOCK INTERRUPTS */
  383.     return (pNode);
  384.     }
  385. /*******************************************************************************
  386. *
  387. * qJobInfo -
  388. *
  389. * ARGSUSED
  390. */
  391. int qJobInfo
  392.     (
  393.     Q_JOB_HEAD *pQHead,         /* job queue to gather list for */
  394.     FAST int nodeArray[],       /* array of node pointers to be filled in */
  395.     FAST int maxNodes           /* max node pointers nodeArray can accomodate */
  396.     )
  397.     {
  398.     FAST Q_JOB_NODE *pNode;
  399.     FAST int *pElement;
  400.     FAST int level;
  401.     if (nodeArray == NULL)
  402. return (pQHead->count);
  403.     pElement = nodeArray;
  404.     level = intLock (); /* LOCK INTERRUPTS */
  405.     pNode = pQHead->first;
  406.     while ((pNode != NULL) && (--maxNodes >= 0))
  407. {
  408. *(pElement++) = (int)pNode; /* fill in table */
  409. pNode = pNode->next; /* next node */
  410. }
  411.     intUnlock (level); /* UNLOCK INTERRUPTS */
  412.     return (pElement - nodeArray); /* return count of nodes */
  413.     }
  414. /*******************************************************************************
  415. *
  416. * qJobEach - call a routine for each node in a queue
  417. *
  418. * This routine calls a user-supplied routine once for each node in the
  419. * queue.  The routine should be declared as follows:
  420. * .CS
  421. *  BOOL routine (pNode, arg)
  422. *      Q_JOB_NODE *pNode; /@ pointer to a queue node          @/
  423. *      int    arg; /@ arbitrary user-supplied argument @/
  424. * .CE
  425. * The user-supplied routine should return TRUE if qJobEach (2) is to
  426. * continue calling it for each entry, or FALSE if it is done and qJobEach
  427. * can exit.
  428. *
  429. * WARNING: calls user routine with interrupts locked out!
  430. *
  431. * RETURNS: NULL if traversed whole queue, or pointer to Q_JOB_NODE that
  432. *          qJobEach stopped on.
  433. */
  434. Q_JOB_NODE *qJobEach
  435.     (
  436.     Q_JOB_HEAD *pQHead,         /* queue head of queue to call routine for */
  437.     FUNCPTR     routine,        /* the routine to call for each table entry */
  438.     int         routineArg      /* arbitrary user-supplied argument */
  439.     )
  440.     {
  441.     FAST Q_JOB_NODE *pNode;
  442.     FAST int level;
  443.     level = intLock (); /* LOCK INTERRUPTS */
  444.     pNode = pQHead->first;
  445.     while ((pNode != NULL) && ((* routine) (pNode, routineArg)))
  446. pNode = pNode->next; /* next node */
  447.     intUnlock (level); /* UNLOCK INTERRUPTS */
  448.     return (pNode); /* return node we ended with */
  449.     }
  450. /*******************************************************************************
  451. *
  452. * qJobNullRtn -
  453. *
  454. * RETURNS: OK
  455. */
  456. LOCAL STATUS qJobNullRtn (void)
  457.     {
  458.     return (OK);
  459.     }