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

VxWorks

开发平台:

C/C++

  1. /* msgQLib.c - message queue library */
  2. /* Copyright 1990-2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02n,10dec01,bwa  Added comment about MSG_Q_EVENTSEND_ERR_NOTIFY msgQCreate
  8.                  option (SPR 72058).
  9. 02m,26oct01,bwa  Added msgQEvLib and eventLib to the list of 'SEE ALSO'
  10.                  modules.
  11. 02l,12oct01,cjj  Added documentation regarding S_eventLib_EVENTSEND_FAILED
  12.                  error
  13. 02k,09oct01,gls  merged in 02j, 02i, 02h, 02g below from AE.
  14. 02j,22feb01,ahm  ensured errno does'nt change if msgQDelete() is successful
  15.                  (SPR#34643)
  16. 02i,19sep00,bwa  passed extra argument (msgQid) to calls to qJobGet()
  17.                  added errnoSet after calls to qJobGet()(SPR #34057) 
  18. 02h,06sep00,aeg  doc: mentioned INCLUDE_MSG_Q component name.
  19. 02g,11aug00,aeg  fixed updating of timeout stats in msgQSend/Receive (SPR 33683)
  20. 02f,07sep01,bwa  Added VxWorks events support. Fixed SPR #31241 (corrected
  21.  msgQReceive comment for NO_WAIT).
  22. 02e,18dec00,pes  Correct compiler warnings
  23. 02d,19may98,drm  merged code from 3rd party to add distributed message queue 
  24.                  support.
  25.                  - merged code was originally based on version 02a 
  26. 02c,11may98,cjtc fix problem with problem fix!! Multiple calls to object
  27.                  instrumentation in msgQDestroy
  28. 02b,11may98,nps  fixed msgQDestroy instrumentation anomaly.
  29. 02c,17apr98,rlp  canceled msgQInit and msgQSend modifications for backward
  30.                  compatibility.
  31. 02b,04nov97,rlp  modified msgQInit and msgQSend for tracking messages sent.
  32. 02a,24jun96,sbs  made windview instrumentation conditionally compiled
  33. 01z,22oct95,jdi  doc: added bit values for options (SPR 4276).
  34. 02d,14apr94,smb  fixed class dereferencing for instrumentation macros
  35. 02c,15mar94,smb  modified instrumentation macros
  36. 02b,24jan94,smb  added instrumentation macros
  37. 02a,18jan94,smb  added instrumentation corrections for msgQDelete
  38. 01z,10dec93,smb  added instrumentation
  39. 01y,30jun93,jmm  changed msgQDestroy to look at msgQ as well as freeQ (spr 2070)
  40. 01x,02feb93,jdi  documentation cleanup for 5.1.
  41. 01w,13nov92,jcf  package init called with object creation.
  42. 01v,19oct92,pme  added reference to shared message queue documentation.
  43. 01u,23aug92,jcf  balanced taskSafe with taskUnsafe.
  44. 01t,11aug92,jcf  fixed msgQDestroy safety problem.
  45. 01s,30jul92,rrr  added restart and msgQ fix
  46. 01r,29jul92,pme  added NULL function pointer check for smObj routines.
  47. 01q,29jul92,jcf  package init called with object initialization.
  48. 01p,22jul92,pme  made msgQDestroy return S_smObjLib_NO_OBJECT_DESTROY when
  49.  trying to destroy a shared message queue.
  50. 01o,19jul92,pme  added shared message queue support.
  51. 01n,18jul92,smb  Changed errno.h to errnoLib.h.
  52. 01m,04jul92,jcf  show routine removed.
  53. 01l,26may92,rrr  the tree shuffle
  54. 01k,13dec91,gae  ANSI fixes.  
  55. 01j,19nov91,rrr  shut up some ansi warnings.
  56. 01i,04oct91,rrr  passed through the ansification filter
  57.                   -changed functions to ansi style
  58.   -changed includes to have absolute path from h/
  59.   -changed VOID to void
  60.   -changed copyright notice
  61. 01h,10aug91,del  changed interface to qInit to pass all "optional" args.
  62. 01g,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  63.  doc review by dnw.
  64. 01f,22jan91,jaa  documentation.
  65. 01e,08oct90,dnw  lint
  66. 01d,01oct90,dnw  fixed bug of msgQSend() not returning ERROR on timeout.
  67.  removed msgQSendArgs()/ReceiveArgs().
  68.  reordered parameters of msgQ{Send,Receive}().
  69.  simplified msgQInfoGet() interface.
  70.  added msgQNumMsgs().
  71.  made msgQDestroy() LOCAL.
  72.  made msgQ{LibInit,Init,Terminate}() be NOMANUAL.
  73.  finished documentation.
  74. 01c,19jul90,dnw  added VARARGS to msgQ{Send,Receive}Args()
  75. 01b,19jul90,dnw  changed call to objAlloc() to objAllocExtra()
  76.  made msgQShow() prettier
  77.  lint
  78. 01a,10may90,dnw  written
  79. */
  80. /*
  81. DESCRIPTION
  82. This library contains routines  for creating and using message queues, the 
  83. primary intertask communication mechanism within a single CPU.  Message
  84. queues allow a variable number of messages (varying in length) to be
  85. queued in first-in-first-out (FIFO) order.  Any task or interrupt service
  86. routine can send messages to a message queue.  Any task can receive
  87. messages from a message queue.  Multiple tasks can send to and receive
  88. from the same message queue.  Full-duplex communication between two tasks
  89. generally requires two message queues, one for each direction.
  90. To provide message queue support for a system, VxWorks must be configured
  91. with the INCLUDE_MSG_Q component.
  92. CREATING AND USING MESSAGE QUEUES
  93. A message queue is created with msgQCreate().  Its parameters specify the
  94. maximum number of messages that can be queued to that message queue and 
  95. the maximum length in bytes of each message.  Enough buffer space will 
  96. be pre-allocated to accommodate the specified number of messages of 
  97. specified length.
  98. A task or interrupt service routine sends a message to a message queue
  99. with msgQSend().  If no tasks are waiting for messages on the message queue,
  100. the message is simply added to the buffer of messages for that queue.
  101. If any tasks are already waiting to receive a message from the message
  102. queue, the message is immediately delivered to the first waiting task.
  103. A task receives a message from a message queue with msgQReceive().
  104. If any messages are already available in the message queue's buffer,
  105. the first message is immediately dequeued and returned to the caller.
  106. If no messages are available, the calling task will block and be added to
  107. a queue of tasks waiting for messages.  This queue of waiting tasks can
  108. be ordered either by task priority or FIFO, as specified in an option
  109. parameter when the queue is created.
  110. TIMEOUTS
  111. Both msgQSend() and msgQReceive() take timeout parameters.  When sending a
  112. message, if no buffer space is available to queue the message, the timeout
  113. specifies how many ticks to wait for space to become available.  When
  114. receiving a message, the timeout specifies how many ticks to wait if no
  115. message is immediately available.  The <timeout> parameter can
  116. have the special values NO_WAIT (0) or WAIT_FOREVER (-1).  NO_WAIT 
  117. means the routine should return immediately; WAIT_FOREVER means the routine
  118. should never time out.
  119. URGENT MESSAGES
  120. The msgQSend() routine allows the priority of a message to be specified
  121. as either normal or urgent, MSG_PRI_NORMAL (0) and MSG_PRI_URGENT (1),
  122. respectively.  Normal priority messages are added to the tail of the list
  123. of queued messages, while urgent priority messages are added to the head
  124. of the list.
  125. VXWORKS EVENTS
  126. If a task has registered with a message queue via msgQEvStart(), events will
  127. be sent to that task when a message arrives on that message queue, on the
  128. condition that no other task is pending on the queue.
  129. INTERNAL:
  130. WINDVIEW INSTRUMENTATION
  131. Level 1:
  132. msgQCreate() causes EVENT_MSGQCREATE
  133. msgQDestroy() causes EVENT_MSGQDELETE
  134. msgQSend() causes EVENT_MSGQSEND
  135. msgQReceive() causes EVENT_MSGQRECEIVE
  136. Level 2:
  137. N/A
  138. Level 3:
  139. N/A
  140. INCLUDE FILES: msgQLib.h
  141. SEE ALSO: pipeDrv, msgQSmLib, msgQEvLib, eventLib,
  142. .pG "Basic OS"
  143. */
  144. #include "vxWorks.h"
  145. #include "stdlib.h"
  146. #include "string.h"
  147. #include "taskLib.h"
  148. #include "intLib.h"
  149. #include "smObjLib.h"
  150. #include "errnoLib.h"
  151. #include "private/eventLibP.h"
  152. #include "private/classLibP.h"
  153. #include "private/objLibP.h"
  154. #include "private/msgQLibP.h"
  155. #include "private/msgQSmLibP.h"
  156. #include "private/distObjTypeP.h"
  157. #include "private/sigLibP.h"
  158. #include "private/eventP.h"
  159. #include "private/windLibP.h"
  160. #include "private/kernelLibP.h"
  161. /* locals */
  162. LOCAL OBJ_CLASS msgQClass;
  163. /* globals */
  164. CLASS_ID msgQClassId = &msgQClass;
  165. /* Instrumentation locals and globals */
  166. #ifdef WV_INSTRUMENTATION
  167. LOCAL OBJ_CLASS msgQInstClass;
  168. CLASS_ID msgQInstClassId = &msgQInstClass;
  169. #endif
  170. /* shared memory objects function pointers */
  171. FUNCPTR  msgQSmSendRtn;
  172. FUNCPTR  msgQSmReceiveRtn;
  173. FUNCPTR  msgQSmNumMsgsRtn;
  174. /* distributed objects function pointers */
  175. FUNCPTR  msgQDistSendRtn;
  176. FUNCPTR  msgQDistReceiveRtn;
  177. FUNCPTR  msgQDistNumMsgsRtn;
  178. /* forward declarations */
  179. LOCAL STATUS msgQDestroy (MSG_Q_ID msgQId, BOOL dealloc);
  180. /* locals */
  181. LOCAL BOOL msgQLibInstalled; /* protect from muliple inits */
  182. /*******************************************************************************
  183. *
  184. * msgQLibInit - initialize message queue library
  185. *
  186. * This routine initializes message queue facility.
  187. * It is called once in kernelInit().
  188. *
  189. * RETURNS: OK or ERROR
  190. *
  191. * NOMANUAL
  192. */
  193. STATUS msgQLibInit (void)
  194.     {
  195.     /* initialize shared memory objects function pointers */
  196.     if (!msgQLibInstalled)
  197. {
  198. if (classInit (msgQClassId, sizeof (MSG_Q), OFFSET (MSG_Q, objCore),
  199.        (FUNCPTR)msgQCreate, (FUNCPTR)msgQInit,
  200.        (FUNCPTR)msgQDestroy) == OK)
  201.     {
  202. #ifdef WV_INSTRUMENTATION
  203.     /* Instrumented class for windview */
  204.     msgQClassId->initRtn = msgQInstClassId;
  205.             classInstrument (msgQClassId,msgQInstClassId);
  206. #endif
  207.     msgQEvLibInit (); /* pull msgQLib in kernel */
  208.     msgQLibInstalled = TRUE;
  209.     }
  210. }
  211.     return ((msgQLibInstalled) ? OK : ERROR);
  212.     }
  213. /*******************************************************************************
  214. *
  215. * msgQCreate - create and initialize a message queue
  216. *
  217. * This routine creates a message queue capable of holding up to <maxMsgs>
  218. * messages, each up to <maxMsgLength> bytes long.  The routine returns 
  219. * a message queue ID used to identify the created message queue in all 
  220. * subsequent calls to routines in this library.  The queue can be created 
  221. * with the following options:
  222. * .iP "MSG_Q_FIFO  (0x00)" 8
  223. * queue pended tasks in FIFO order.
  224. * .iP "MSG_Q_PRIORITY  (0x01)"
  225. * queue pended tasks in priority order.
  226. * .iP "MSG_Q_EVENTSEND_ERR_NOTIFY (0x02)"
  227. * When a message is sent, if a task is registered for events and the
  228. * actual sending of events fails, a value of ERROR is returned and the errno
  229. * is set accordingly. This option is off by default.
  230. * .LP
  231. *
  232. * RETURNS:
  233. * MSG_Q_ID, or NULL if error.
  234. *
  235. * ERRNO: S_memLib_NOT_ENOUGH_MEMORY, S_intLib_NOT_ISR_CALLABLE
  236. *
  237. * SEE ALSO: msgQSmLib
  238. */
  239. MSG_Q_ID msgQCreate
  240.     (
  241.     int         maxMsgs,        /* max messages that can be queued */
  242.     int         maxMsgLength,   /* max bytes in a message */
  243.     int         options         /* message queue options */
  244.     )
  245.     {
  246.     MSG_Q_ID msgQId;
  247.     void * pPool; /* pointer to memory for messages */
  248.     UINT size = (UINT) maxMsgs * MSG_NODE_SIZE (maxMsgLength);
  249.     if (INT_RESTRICT () != OK) /* restrict ISR from calling */
  250. return (NULL);
  251.     if ((!msgQLibInstalled) && (msgQLibInit () != OK))
  252. return (NULL); /* package init problem */
  253.     if ((msgQId = (MSG_Q_ID)objAllocExtra (msgQClassId, size, &pPool)) == NULL)
  254. return (NULL);
  255.     if (msgQInit (msgQId, maxMsgs, maxMsgLength, options, pPool) != OK)
  256. {
  257. objFree (msgQClassId, (char *) msgQId);
  258. return (NULL);
  259. }
  260. #ifdef WV_INSTRUMENTATION
  261.     /* windview - level 1 event logging routine */
  262.     EVT_OBJ_4 (OBJ, msgQId, msgQClassId, EVENT_MSGQCREATE, 
  263. msgQId, maxMsgs, maxMsgLength, options);
  264. #endif
  265.     return ((MSG_Q_ID) msgQId);
  266.     }
  267. /*******************************************************************************
  268. *
  269. * msgQInit - initialize a message queue
  270. *
  271. * This routine initializes a message queue data structure.  Like msgQCreate()
  272. * the resulting message queue is capable of holding up to <maxMsgs> messages,
  273. * each of up to <maxMsgLength> bytes long.
  274. * However, instead of dynamically allocating the MSG_Q data structure,
  275. * this routine takes a pointer <pMsgQ> to the MSG_Q data structure to be
  276. * initialized, and a pointer <pMsgPool> to the buffer to be use to hold
  277. * queued messages.  <pMsgPool> must point to a 4 byte aligned buffer
  278. * that is (<maxMsgs> * MSG_NODE_SIZE (<maxMsgLength>)).
  279. *
  280. * The queue can be created with the following options:
  281. *
  282. * MSG_Q_FIFO queue pended tasks in FIFO order
  283. * MSG_Q_PRIORITY queue pended tasks in priority order
  284. *
  285. * RETURNS: OK or ERROR.
  286. *
  287. * ERRNO: S_msgQLib_INVALID_QUEUE_TYPE
  288. *
  289. * SEE ALSO: msgQCreate()
  290. *
  291. * NOMANUAL
  292. */
  293. STATUS msgQInit
  294.     (
  295.     FAST MSG_Q *pMsgQ,          /* pointer to msg queue to initialize */
  296.     int         maxMsgs,        /* max messages that can be queued */
  297.     int         maxMsgLength,   /* max bytes in a message */
  298.     int         options,        /* message queue options */
  299.     void *      pMsgPool        /* pointer to memory for messages */
  300.     )
  301.     {
  302.     FAST int nodeSize = MSG_NODE_SIZE (maxMsgLength);
  303.     FAST int ix;
  304.     FAST Q_CLASS_ID msgQType;
  305.     if ((!msgQLibInstalled) && (msgQLibInit () != OK))
  306. return (ERROR); /* package init problem */
  307.     bzero ((char *) pMsgQ, sizeof (*pMsgQ)); /* clear out msg q structure */
  308.     /* initialize internal job queues */
  309.     switch (options & MSG_Q_TYPE_MASK)
  310.         {
  311.         case MSG_Q_FIFO: msgQType = Q_FIFO; break;
  312.         case MSG_Q_PRIORITY: msgQType = Q_PRI_LIST; break;
  313.         default:
  314.             errnoSet (S_msgQLib_INVALID_QUEUE_TYPE);
  315.     return (ERROR);
  316.         }
  317.     if ((qInit ((Q_HEAD *) &pMsgQ->msgQ, qJobClassId, msgQType,
  318.  0, 0, 0, 0, 0, 0, 0, 0, 0) != OK) ||
  319. (qInit ((Q_HEAD *) &pMsgQ->freeQ, qJobClassId, msgQType,
  320.  0, 0, 0, 0, 0, 0, 0, 0, 0) != OK))
  321. return (ERROR);
  322.     /* put msg nodes on free list */
  323.     for (ix = 0; ix < maxMsgs; ix++)
  324. {
  325. qJobPut (pMsgQ, &pMsgQ->freeQ, (Q_JOB_NODE *) pMsgPool,
  326.  Q_JOB_PRI_DONT_CARE);
  327. pMsgPool = (void *) (((char *) pMsgPool) + nodeSize);
  328. }
  329.     /* initialize rest of msg q */
  330.     pMsgQ->options = options;
  331.     pMsgQ->maxMsgs = maxMsgs;
  332.     pMsgQ->maxMsgLength = maxMsgLength;
  333.     eventInit (&pMsgQ->events);
  334. #ifdef WV_INSTRUMENTATION
  335.     if (wvObjIsEnabled)
  336.     {
  337.     /* windview - connect level 1 event logging routine */
  338.     objCoreInit (&pMsgQ->objCore, msgQInstClassId);
  339.     }
  340.     else
  341. #endif
  342.     objCoreInit (&pMsgQ->objCore, msgQClassId);
  343.     return (OK);
  344.     }
  345. /******************************************************************************
  346. *
  347. * msgQTerminate - terminate message queue
  348. *
  349. * This routine terminates a static message queue that was initialized with
  350. * msgQInit.
  351. *
  352. * RETURNS: OK or ERROR.
  353. *
  354. * NOMANUAL
  355. */
  356. STATUS msgQTerminate
  357.     (
  358.     MSG_Q_ID msgQId     /* message queue id to terminate */
  359.     )
  360.     {
  361.     return (msgQDestroy (msgQId, FALSE));
  362.     }
  363. /*******************************************************************************
  364. *
  365. * msgQDelete - delete a message queue
  366. *
  367. * This routine deletes a message queue.  All tasks pending on either
  368. * msgQSend(), msgQReceive() or pending for the reception of events
  369. * meant to be sent from the message queue will unblock and return
  370. * ERROR.  When this function returns, <msgQId> is no longer a valid 
  371. * message queue ID.
  372. *
  373. * RETURNS: OK on success or ERROR otherwise.
  374. *
  375. * ERRNO:
  376. * .iP "S_objLib_OBJ_ID_ERROR"
  377. * Message queue ID is invalid
  378. * .iP "S_intLib_NOT_ISR_CALLABLE"
  379. * Routine cannot be called from ISR
  380. * .iP "S_distLib_NO_OBJECT_DESTROY"
  381. * Deleting a distributed message queue is not permitted
  382. * .iP "S_smObjLib_NO_OBJECT_DESTROY"
  383. * Deleting a shared message queue is not permitted
  384. * SEE ALSO: msgQSmLib
  385. */
  386. STATUS msgQDelete
  387.     (
  388.     MSG_Q_ID msgQId     /* message queue to delete */
  389.     )
  390.     {
  391.     return (msgQDestroy (msgQId, TRUE));
  392.     }
  393. /*******************************************************************************
  394. *
  395. * msgQDestroy - destroy message queue
  396. *
  397. * RETURNS: OK or ERROR.
  398. *
  399. * ERRNO: S_distLib_NO_OBJECT_DESTROY
  400. *
  401. */
  402. LOCAL STATUS msgQDestroy
  403.     (
  404.     MSG_Q_ID msgQId,    /* message queue to destroy */
  405.     BOOL     dealloc    /* deallocate memory associated with message queue */
  406.     )
  407.     {
  408.     Q_JOB_NODE *pNode;
  409.     FAST int timeout;
  410.     FAST int nMsgs;
  411.     int errnoCopy;
  412.     if (ID_IS_SHARED (msgQId))   /* message Q is shared?*/
  413. {
  414. if (ID_IS_DISTRIBUTED (msgQId)) /* message queue is distributed? */
  415. {
  416. errno = S_distLib_NO_OBJECT_DESTROY;
  417.   return (ERROR);             /* cannot delete distributed msgQ */
  418. }
  419. errno = S_smObjLib_NO_OBJECT_DESTROY;
  420.         return (ERROR); /* cannot delete sm. msgQ */
  421. }
  422.     if (INT_RESTRICT () != OK) /* restrict isr use */
  423. return (ERROR);
  424.     TASK_SAFE (); /* TASK SAFE */
  425.     TASK_LOCK (); /* LOCK PREEMPTION */
  426. #ifdef WV_INSTRUMENTATION
  427.     /* Indicate that msgQDelete has been initiated */
  428.     /* windview - level 1 event logging routine */
  429.     EVT_OBJ_1 (OBJ, msgQId, msgQClassId, EVENT_MSGQDELETE, msgQId);
  430. #endif
  431.     if (OBJ_VERIFY (msgQId, msgQClassId) != OK) /* validate message queue id */
  432. {
  433. TASK_UNLOCK (); /* UNLOCK PREEMPTION */
  434. TASK_UNSAFE (); /* TASK UNSAFE */
  435. return (ERROR);
  436. }
  437.     objCoreTerminate (&msgQId->objCore); /* INVALIDATE */
  438. #ifdef WV_INSTRUMENTATION
  439.     /*  Indicate that the msgQDelete has succeeded (before TASK_UNLOCK, as
  440.      *  that causes unnecessary WV parser confusion).
  441.      */
  442.     /* windview - level 2 instrumentation
  443.      * EVENT_OBJ_MSGDELETE needs to return the msgQId so MSG_OFFSET is
  444.      * used to calulate the msgQId from the pQHead
  445.      */
  446.     EVT_TASK_1 (EVENT_OBJ_MSGDELETE, msgQId);
  447. #endif
  448.     TASK_UNLOCK (); /* UNLOCK PREEMPTION */
  449.     /* gobble up all messages in the message and free queues */
  450.     timeout = NO_WAIT; /* first time through gobble without waiting */
  451.     nMsgs = 0;
  452.     errnoCopy = errnoGet ();
  453.     while (nMsgs < msgQId->maxMsgs)
  454. {
  455. while (((pNode = qJobGet (msgQId, &msgQId->freeQ, timeout)) != NULL) &&
  456.        (pNode != (Q_JOB_NODE *) NONE))
  457.     nMsgs++;
  458. while (((pNode = qJobGet (msgQId, &msgQId->msgQ, timeout)) != NULL) &&
  459.        (pNode != (Q_JOB_NODE *) NONE))
  460.     nMsgs++;
  461. timeout = 1; /* after first time, wait a bit */
  462. }
  463.     errnoSet (errnoCopy);
  464.     /* terminate both the queues */
  465.     /*
  466.      * Since eventTerminate() can wake up a task, we want to put all tasks
  467.      * in the ready queue before doing a windExit(), so that it is sure that
  468.      * the task of highest priority runs first. To achieve that, the
  469.      * statements 'kernelState = TRUE;' and 'windExit();' have been moved
  470.      * from qJobTerminate() to here. This is the only place that qJobTerminate
  471.      * is called.
  472.      */
  473.     kernelState = TRUE;
  474.     qJobTerminate (&msgQId->msgQ);
  475.     qJobTerminate (&msgQId->freeQ);
  476.     eventTerminate (&msgQId->events);/* free task waiting for events if any */
  477.     windExit ();
  478.     if (dealloc)
  479. objFree (msgQClassId, (char *) msgQId);
  480.     TASK_UNSAFE (); /* TASK UNSAFE */
  481.     return (OK);
  482.     }
  483. /*******************************************************************************
  484. *
  485. * msgQSend - send a message to a message queue
  486. *
  487. * This routine sends the message in <buffer> of length <nBytes> to the message
  488. * queue <msgQId>.  If any tasks are already waiting to receive messages
  489. * on the queue, the message will immediately be delivered to the first
  490. * waiting task.  If no task is waiting to receive messages, the message
  491. * is saved in the message queue and if a task has previously registered to 
  492. * receive events from the message queue, these events are sent in the context 
  493. * of this call.  This may result in the unpending of the task waiting for 
  494. * the events.  If the message queue fails to send events and if it was 
  495. * created using the MSG_Q_EVENTSEND_ERR_NOTIFY option, ERROR is returned 
  496. * even though the send operation was successful.
  497. *
  498. * The <timeout> parameter specifies the number of ticks to wait for free
  499. * space if the message queue is full.  The <timeout> parameter can also have 
  500. * the following special values:
  501. * .iP "NO_WAIT  (0)" 8
  502. * return immediately, even if the message has not been sent.  
  503. * .iP "WAIT_FOREVER  (-1)"
  504. * never time out.
  505. * .LP
  506. *
  507. * The <priority> parameter specifies the priority of the message being sent.
  508. * The possible values are:
  509. * .iP "MSG_PRI_NORMAL  (0)" 8
  510. * normal priority; add the message to the tail of the list of queued 
  511. * messages.
  512. * .iP "MSG_PRI_URGENT  (1)"
  513. * urgent priority; add the message to the head of the list of queued messages.
  514. * .LP
  515. *
  516. * USE BY INTERRUPT SERVICE ROUTINES
  517. * This routine can be called by interrupt service routines as well as
  518. * by tasks.  This is one of the primary means of communication
  519. * between an interrupt service routine and a task.  When called from an
  520. * interrupt service routine, <timeout> must be NO_WAIT.
  521. *
  522. * RETURNS: OK on success or ERROR otherwise.
  523. *
  524. * ERRNO:
  525. * .iP "S_distLib_NOT_INITIALIZED"
  526. * Distributed objects message queue library (VxFusion) not initialized.
  527. * .iP "S_smObjLib_NOT_INITIALIZED"
  528. * Shared memory message queue library (VxMP Option) not initialized.
  529. * .iP "S_objLib_OBJ_ID_ERROR"
  530. * Invalid message queue ID.
  531. * .iP "S_objLib_OBJ_DELETED"
  532. * Message queue deleted while calling task was pended.
  533. * .iP "S_objLib_OBJ_UNAVAILABLE"
  534. * No free buffer space when NO_WAIT timeout specified.
  535. * .iP "S_objLib_OBJ_TIMEOUT"
  536. * Timeout occurred while waiting for buffer space.
  537. * .iP "S_msgQLib_INVALID_MSG_LENGTH"
  538. * Message length exceeds limit.
  539. * .iP "S_msgQLib_NON_ZERO_TIMEOUT_AT_INT_LEVEL"
  540. * Called from ISR with non-zero timeout.
  541. * .iP "S_eventLib_EVENTSEND_FAILED"
  542. * Message queue failed to send events to registered task.  This errno 
  543. * value can only exist if the message queue was created with the 
  544. * MSG_Q_EVENTSEND_ERR_NOTIFY option.
  545. * .LP
  546. *
  547. * SEE ALSO: msgQSmLib, msgQEvStart
  548. */
  549. STATUS msgQSend
  550.     (
  551.     FAST MSG_Q_ID       msgQId,         /* message queue on which to send */
  552.     char *              buffer,         /* message to send */
  553.     FAST UINT           nBytes,         /* length of message */
  554.     int                 timeout,        /* ticks to wait */
  555.     int                 priority        /* MSG_PRI_NORMAL or MSG_PRI_URGENT */
  556.     )
  557.     {
  558.     FAST MSG_NODE * pMsg;
  559.     if (ID_IS_SHARED (msgQId)) /* message Q is shared? */
  560.         {
  561. if (ID_IS_DISTRIBUTED (msgQId)) /* message queue is distributed? */
  562. {
  563. if (msgQDistSendRtn == NULL)
  564. {
  565. errno = S_distLib_NOT_INITIALIZED; 
  566. return (ERROR);
  567. }
  568.   return ((*msgQDistSendRtn) (msgQId, buffer, nBytes,
  569.   timeout, WAIT_FOREVER, priority));
  570. }
  571.         if (msgQSmSendRtn == NULL)
  572.             {
  573.             errno = S_smObjLib_NOT_INITIALIZED;
  574.             return (ERROR);
  575.             }
  576.         return ((*msgQSmSendRtn) (SM_OBJ_ID_TO_ADRS (msgQId), buffer, nBytes,
  577.   timeout, priority));
  578. }
  579.     /* message queue is local */
  580.     if (!INT_CONTEXT ())
  581. TASK_LOCK ();
  582.     else
  583. {
  584. if (timeout != 0)
  585.     {
  586.     errnoSet (S_msgQLib_NON_ZERO_TIMEOUT_AT_INT_LEVEL);
  587.     return (ERROR);
  588.     }
  589. }
  590. restart:
  591.     if (OBJ_VERIFY (msgQId, msgQClassId) != OK)
  592. {
  593. if (!INT_CONTEXT ())
  594.     TASK_UNLOCK ();
  595. return (ERROR);
  596. }
  597. #ifdef WV_INSTRUMENTATION
  598.     /* windview - level 1 event logging routine */
  599.     EVT_OBJ_5 (OBJ, msgQId, msgQClassId, EVENT_MSGQSEND, msgQId, 
  600.        buffer, nBytes, timeout, priority);
  601. #endif
  602.     if (nBytes > msgQId->maxMsgLength)
  603. {
  604. if (!INT_CONTEXT ())
  605.     TASK_UNLOCK ();
  606. errnoSet (S_msgQLib_INVALID_MSG_LENGTH);
  607. return (ERROR);
  608. }
  609.     pMsg = (MSG_NODE *) qJobGet (msgQId, &msgQId->freeQ, timeout);
  610.     if (pMsg == (MSG_NODE *) NONE)
  611. {
  612. timeout = SIG_TIMEOUT_RECALC(timeout);
  613. goto restart;
  614. }
  615.     if (pMsg == NULL)
  616. {
  617. #if FALSE
  618. msgQId->sendTimeouts++;
  619. #else
  620. /*
  621.  * The timeout stat should only be updated if a timeout has occured.
  622.  * An OBJ_VERIFY needs to be performed to catch the case where a 
  623.  * timeout indeed occured, but the message queue is subsequently 
  624.  * deleted before the current task is rescheduled.
  625.  */
  626. if (errnoGet() == S_objLib_OBJ_TIMEOUT) 
  627.             {
  628.     if (OBJ_VERIFY (msgQId, msgQClassId) == OK)
  629.         msgQId->sendTimeouts++;
  630.             else
  631.                 errnoSet(S_objLib_OBJ_DELETED);
  632.             }
  633. #endif /* FALSE */
  634. if (!INT_CONTEXT ())
  635.     TASK_UNLOCK ();
  636. return (ERROR);
  637. }
  638.     pMsg->msgLength = nBytes;
  639.     bcopy (buffer, MSG_NODE_DATA (pMsg), (int) nBytes);
  640.     if (qJobPut (msgQId, &msgQId->msgQ, &pMsg->node, priority) != OK)
  641. {
  642. if (!INT_CONTEXT ())
  643.     TASK_UNLOCK ();
  644. return (ERROR); /* errno set by qJobPut() */
  645. }
  646.     if (!INT_CONTEXT ())
  647. TASK_UNLOCK ();
  648.     return (OK);
  649.     }
  650. /*******************************************************************************
  651. *
  652. * msgQReceive - receive a message from a message queue
  653. *
  654. * This routine receives a message from the message queue <msgQId>.
  655. * The received message is copied into the specified <buffer>, which is
  656. * <maxNBytes> in length.  If the message is longer than <maxNBytes>,
  657. * the remainder of the message is discarded (no error indication
  658. * is returned).
  659. *
  660. * The <timeout> parameter specifies the number of ticks to wait for 
  661. * a message to be sent to the queue, if no message is available when
  662. * msgQReceive() is called.  The <timeout> parameter can also have 
  663. * the following special values: 
  664. * .iP "NO_WAIT  (0)" 8
  665. * return immediately, whether a message has been received or not.  
  666. * .iP "WAIT_FOREVER  (-1)"
  667. * never time out.
  668. * .LP
  669. *
  670. * WARNING: This routine must not be called by interrupt service routines.
  671. *
  672. * RETURNS:
  673. * The number of bytes copied to <buffer>, or ERROR.
  674. *
  675. * ERRNO: S_distLib_NOT_INITIALIZED, S_smObjLib_NOT_INITIALIZED,
  676. *        S_objLib_OBJ_ID_ERROR, S_objLib_OBJ_DELETED,
  677. *        S_objLib_OBJ_UNAVAILABLE, S_objLib_OBJ_TIMEOUT,
  678. *        S_msgQLib_INVALID_MSG_LENGTH, S_intLib_NOT_ISR_CALLABLE
  679. *
  680. * SEE ALSO: msgQSmLib
  681. */
  682. int msgQReceive
  683.     (
  684.     FAST MSG_Q_ID       msgQId,         /* message queue from which to receive */
  685.     char *              buffer,         /* buffer to receive message */
  686.     UINT                maxNBytes,      /* length of buffer */
  687.     int                 timeout         /* ticks to wait */
  688.     )
  689.     {
  690.     FAST MSG_NODE * pMsg;
  691.     FAST int bytesReturned;
  692.     if (INT_RESTRICT() != OK) /* errno set by INT_RESTRICT() */
  693. return ERROR;
  694.     if (ID_IS_SHARED (msgQId)) /* message Q is shared? */
  695.         {
  696. if (ID_IS_DISTRIBUTED (msgQId)) /* message queue is distributed? */
  697. {
  698. if (msgQDistReceiveRtn == NULL)
  699. {
  700. errno = S_distLib_NOT_INITIALIZED;
  701.   return (ERROR);
  702. }
  703. return ((*msgQDistReceiveRtn) (msgQId, buffer,
  704. maxNBytes, timeout, WAIT_FOREVER));
  705. }
  706.         if (msgQSmReceiveRtn == NULL)
  707.             {
  708.             errno = S_smObjLib_NOT_INITIALIZED;
  709.             return (ERROR);
  710.             }
  711.         return ((*msgQSmReceiveRtn) (SM_OBJ_ID_TO_ADRS (msgQId), buffer,
  712.      maxNBytes, timeout));
  713. }
  714.     /* message queue is local */
  715.     /* even though maxNBytes is unsigned, check for < 0 to catch possible
  716.      * caller errors
  717.      */
  718.     if ((int) maxNBytes < 0)
  719. {
  720. errnoSet (S_msgQLib_INVALID_MSG_LENGTH);
  721. return (ERROR);
  722. }
  723.     TASK_LOCK ();
  724. restart:
  725.     if (OBJ_VERIFY (msgQId, msgQClassId) != OK)
  726. {
  727. TASK_UNLOCK ();
  728. return (ERROR);
  729. }
  730. #ifdef WV_INSTRUMENTATION
  731.     /* windview - level 1 event logging routine */
  732.     EVT_OBJ_4 (OBJ, msgQId, msgQClassId, EVENT_MSGQRECEIVE, msgQId, 
  733.        buffer, maxNBytes, timeout);
  734. #endif
  735.     pMsg = (MSG_NODE *) qJobGet (msgQId, &msgQId->msgQ, timeout);
  736.     if (pMsg == (MSG_NODE *) NONE)
  737. {
  738. timeout = SIG_TIMEOUT_RECALC(timeout);
  739. goto restart;
  740. }
  741.     if (pMsg == NULL)
  742. {
  743. #if FALSE
  744. msgQId->recvTimeouts++;
  745. #else
  746. /*
  747.  * The timeout stat should only be updated if a timeout has occured.
  748.  * An OBJ_VERIFY needs to be performed to catch the case where a 
  749.  * timeout indeed occured, but the message queue is subsequently 
  750.  * deleted before the current task is rescheduled.
  751.  */
  752. if (errnoGet() == S_objLib_OBJ_TIMEOUT) 
  753.             {
  754.     if (OBJ_VERIFY (msgQId, msgQClassId) == OK)
  755.         msgQId->sendTimeouts++;
  756.             else
  757.                 errnoSet(S_objLib_OBJ_DELETED);
  758.             }
  759. #endif /* FALSE */
  760. TASK_UNLOCK ();
  761. return (ERROR);
  762. }
  763.     bytesReturned = min (pMsg->msgLength, maxNBytes);
  764.     bcopy (MSG_NODE_DATA (pMsg), buffer, bytesReturned);
  765.     qJobPut (msgQId, &msgQId->freeQ, &pMsg->node, Q_JOB_PRI_DONT_CARE);
  766.     TASK_UNLOCK ();
  767.     return (bytesReturned);
  768.     }
  769. /*******************************************************************************
  770. *
  771. * msgQNumMsgs - get the number of messages queued to a message queue
  772. *
  773. * This routine returns the number of messages currently queued to a specified
  774. * message queue.
  775. *
  776. * RETURNS:
  777. * The number of messages queued, or ERROR.
  778. *
  779. * ERRNO:  S_distLib_NOT_INITIALIZED, S_smObjLib_NOT_INITIALIZED,
  780. *         S_objLib_OBJ_ID_ERROR
  781. *
  782. * SEE ALSO: msgQSmLib
  783. */
  784. int msgQNumMsgs
  785.     (
  786.     FAST MSG_Q_ID       msgQId          /* message queue to examine */
  787.     )
  788.     {
  789.     if (ID_IS_SHARED (msgQId)) /* message Q is shared? */
  790.         {
  791. if (ID_IS_DISTRIBUTED (msgQId)) /* message queue is distributed? */
  792. {
  793. if (msgQDistNumMsgsRtn == NULL)
  794. {
  795. errno = S_distLib_NOT_INITIALIZED;
  796. return (ERROR);
  797. }
  798. return ((*msgQDistNumMsgsRtn) (msgQId, WAIT_FOREVER));
  799. }
  800.         if (msgQSmNumMsgsRtn == NULL)
  801.             {
  802.             errno = S_smObjLib_NOT_INITIALIZED;
  803.             return (ERROR);
  804.             }
  805.         return ((*msgQSmNumMsgsRtn) (SM_OBJ_ID_TO_ADRS (msgQId)));
  806. }
  807.     /* message queue is local */
  808.     if (OBJ_VERIFY (msgQId, msgQClassId) != OK)
  809. return (ERROR);
  810.     return (msgQId->msgQ.count);
  811.     }