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

VxWorks

开发平台:

C/C++

  1. /* msgQSmLib.c - shared memory message queue library (VxMP Option) */
  2. /* Copyright 1990-2002 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01q,06may02,mas  cache flush and volatile fix (SPR 68334); bridge flush fix
  7.  (SPR 68844)
  8. 01p,24oct01,mas  doc update (SPR 71149)
  9. 01o,13sep01,tcr  Fix SPR 29673 - Windview event logging macro
  10. 01n,14mar99,jdi  doc: removed refs to config.h and/or configAll.h (SPR 25663).
  11. 01m,22feb99,wsl  doc: correct typo in name of errno code
  12. 01l,05oct98,jmp  doc: cleanup.
  13. 01k,17apr98,rlp  canceled msgQSmInit and msgQSmSend modifications for backward
  14.                  compatibility.
  15. 01j,04nov97,rlp  modified msgQSmInit and msgQSmSend for tracking messages
  16.                  sent.
  17. 01i,16oct95,jdi  doc: added msgQSmLib.h to list of include files (SPR 4353).
  18. 01h,22mar94,pme  added WindView level 2 event logging.
  19. 01g,23feb93,jdi  more documentation cleanup for 5.1 manual.
  20. 01f,14feb93,jdi  documentation cleanup 5.1.
  21. 01e,29jan93,pme  added little endian support.
  22.  added #include "private/smObjLibP.h"
  23. 01d,23nov92,jdi  documentation cleanup.
  24. 01c,02oct92,pme  added SPARC support. documentation cleanup.
  25. 01b,29sep92,pme  changed calls to smFree and smMalloc to smMemFree 
  26.  and smMemMalloc.
  27. 01a,19jul92,pme  added msgQSmLibInit() to reduce coupling.
  28.  changed function name to msgQSm...
  29.  cleaned up after code review.
  30.  written from 01k of msgQLib
  31. */
  32. /*
  33. DESCRIPTION
  34. This library provides the interface to shared memory message queues.
  35. Shared memory message queues allow a variable number of messages (varying
  36. in length) to be queued in first-in-first-out order.  Any task running on
  37. any CPU in the system can send messages to or receive messages from a
  38. shared message queue.  Tasks can also send to and receive from the
  39. same shared message queue.  Full-duplex communication between two
  40. tasks generally requires two shared message queues, one for each
  41. direction.
  42. Shared memory message queues are created with msgQSmCreate().  Once
  43. created, they can be manipulated using the generic routines for local
  44. message queues; for more information on the use of these routines, see the
  45. manual entry for msgQLib.
  46. MEMORY REQUIREMENTS
  47. The shared memory message queue structure is allocated from a dedicated 
  48. shared memory partition.  This shared memory partition is initialized by
  49. the shared memory objects master CPU.  The size of this partition is
  50. defined by the maximum number of shared message queues, SM_OBJ_MAX_MSG_Q.
  51. The message queue buffers are allocated from the shared memory system 
  52. partition. 
  53. RESTRICTIONS
  54. Shared memory message queues differ from local message queues in the
  55. following ways:
  56. is
  57. i `Interrupt Use:'
  58. Shared memory message queues may not be used (sent to or received from) at
  59. interrupt level.
  60. i `Deletion:'
  61. There is no way to delete a shared memory message queue and free its associated
  62. shared memory.  Attempts to delete a shared message queue return ERROR and
  63. set `errno' to S_smObjLib_NO_OBJECT_DESTROY.
  64. i `Queuing Style:'
  65. The shared message queue task queueing order specified when a message queue is
  66. created must be FIFO.
  67. ie
  68. CONFIGURATION
  69. Before routines in this library can be called, the shared memory objects
  70. facility must be initialized by calling usrSmObjInit().  This is done
  71. automatically during VxWorks initialization if the component INCLUDE_SM_OBJ
  72. is included.
  73. AVAILABILITY: This module is distributed as a component of the unbundled shared
  74. objects memory support option, VxMP.
  75. INCLUDE FILES: msgQSmLib.h, msgQLib.h, smMemLib.h, smObjLib.h
  76. SEE ALSO: msgQLib, smObjLib, msgQShow, usrSmObjInit(),
  77. tb VxWorks Programmer's Guide: Shared Memory Objects
  78. */
  79. /* LINTLIBRARY */
  80. #include "vxWorks.h"
  81. #include "errnoLib.h"
  82. #include "objLib.h"
  83. #include "intLib.h"
  84. #include "taskLib.h"
  85. #include "cacheLib.h"
  86. #include "semLib.h"
  87. #include "smMemLib.h"
  88. #include "smObjLib.h"
  89. #include "msgQLib.h"
  90. #include "stdarg.h"
  91. #include "string.h"
  92. #include "netinet/in.h"
  93. #include "private/msgQSmLibP.h"
  94. #include "private/msgQLibP.h"
  95. #include "private/semSmLibP.h"
  96. #include "private/smMemLibP.h"
  97. #include "private/smObjLibP.h"
  98. #include "private/eventP.h"
  99. /*****************************************************************************
  100. *
  101. * msgSmLibInit - initialize the shared memory message queue package
  102. *
  103. * SEE ALSO: smObjLibInit().
  104. *
  105. * RETURNS: OK
  106. *
  107. * NOMANUAL
  108. */
  109. void msgQSmLibInit (void)
  110.     {
  111.     msgQSmSendRtn    = (FUNCPTR) msgQSmSend;
  112.     msgQSmReceiveRtn = (FUNCPTR) msgQSmReceive;
  113.     msgQSmNumMsgsRtn = (FUNCPTR) msgQSmNumMsgs;
  114.     }
  115. /*****************************************************************************
  116. *
  117. * msgQSmCreate - create and initialize a shared memory message queue (VxMP Option)
  118. *
  119. * This routine creates a shared memory message queue capable of holding up
  120. * to <maxMsgs> messages, each up to <maxMsgLength> bytes long.  It returns a
  121. * message queue ID used to identify the created message queue.  The queue
  122. * can only be created with the option MSG_Q_FIFO (0), thus queuing pended
  123. * tasks in FIFO order.
  124. *
  125. * The global message queue identifier returned can be used directly by generic
  126. * message queue handling routines in msgQLib -- msgQSend(), msgQReceive(), 
  127. * and msgQNumMsgs() -- and by the show routines show() and msgQShow().
  128. *
  129. * If there is insufficient memory to store the message queue structure
  130. * in the shared memory message queue partition or if the shared memory system
  131. * pool cannot handle the requested message queue size, shared memory message 
  132. * queue creation will fail with `errno' set to S_memLib_NOT_ENOUGH_MEMORY.
  133. * This problem can be solved by incrementing the value of SM_OBJ_MAX_MSG_Q
  134. * and/or the shared memory objects dedicated memory size SM_OBJ_MEM_SIZE .
  135. *
  136. * Before this routine can be called, the shared memory objects facility must
  137. * be initialized (see msgQSmLib).
  138. *
  139. * AVAILABILITY:
  140. * This routine is distributed as a component of the unbundled shared memory
  141. * objects support option, VxMP.
  142. *
  143. * RETURNS: MSG_Q_ID, or NULL if error.
  144. *
  145. * ERRNO: S_memLib_NOT_ENOUGH_MEMORY, S_intLib_NOT_ISR_CALLABLE,
  146. * S_msgQLib_INVALID_QUEUE_TYPE, S_smObjLib_LOCK_TIMEOUT
  147. *
  148. * SEE ALSO: smObjLib, msgQLib, msgQShow
  149. */
  150. MSG_Q_ID msgQSmCreate 
  151.     (
  152.     int maxMsgs, /* max messages that can be queued */
  153.     int maxMsgLength, /* max bytes in a message */
  154.     int options /* message queue options */
  155.     )
  156.     {
  157.     SM_MSG_Q_ID smMsgQId;
  158.     void * pSmMsgPool; /* pointer to memory for messages */
  159.     int         nodeSize = SM_MSG_NODE_SIZE (maxMsgLength);
  160.     int         temp;           /* temp storage */
  161.     if (INT_RESTRICT () != OK) /* restrict ISR from calling */
  162.         {
  163. return (NULL);
  164.         }
  165.     /* 
  166.      * allocate shared memory message queue descriptor from 
  167.      * dedicated shared memory pool.
  168.      */
  169.     smMsgQId = (SM_MSG_Q_ID) smMemPartAlloc ((SM_PART_ID) smMsgQPartId,
  170.                                              sizeof (SM_MSG_Q));
  171.     if (smMsgQId == NULL)
  172.         {
  173. return (NULL);
  174.         }
  175.     /* 
  176.      * allocate shared memory message queue data buffers from 
  177.      * shared memory system pool.
  178.      */
  179.     pSmMsgPool = smMemMalloc (nodeSize * maxMsgs);
  180.     if (pSmMsgPool == NULL)
  181.      { 
  182. smMemPartFree ((SM_PART_ID) smMsgQPartId, (char *) smMsgQId);
  183. return (NULL);
  184. }
  185.     /* Initialize shared memory message queue structure */
  186.     if (msgQSmInit (smMsgQId, maxMsgs, maxMsgLength, options, pSmMsgPool) !=OK)
  187. {
  188. smMemPartFree ((SM_PART_ID) smMsgQPartId, (char *) smMsgQId);
  189. smMemFree ((char *) pSmMsgPool);
  190. return (NULL);
  191. }
  192.     /* update shared infos data */
  193.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  194.     temp = pSmObjHdr->curNumMsgQ;               /* PCI bridge bug [SPR 68844]*/
  195.     pSmObjHdr->curNumMsgQ = htonl (ntohl (pSmObjHdr->curNumMsgQ) + 1);
  196.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  197.     temp = pSmObjHdr->curNumMsgQ;               /* BRIDGE FLUSH  [SPR 68334] */
  198.     return ((MSG_Q_ID) (SM_OBJ_ADRS_TO_ID (smMsgQId)));
  199.     }
  200. /*****************************************************************************
  201. *
  202. * msgQSmInit - initialize a shared memory message queue
  203. *
  204. * This routine initializes a shared memory message queue data structure.  Like
  205. * msgQSmCreate() the resulting message queue is capable of holding up to
  206. * <maxMsgs> messages, each of up to <maxMsgLength> bytes long.  However,
  207. * instead of dynamically allocating the SM_MSG_Q data structure, this
  208. * routine takes a pointer <pSmMsgQ> to the SM_MSG_Q data structure to be
  209. * initialized, and a local pointer <pSmMsgPool> to the buffer to be use to
  210. * hold queued messages.  <pSmMsgPool> must point to a 4-byte aligned buffer
  211. * that is (<maxMsgs> * SM_MSG_NODE_SIZE (<maxMsgLength>)).
  212. *
  213. * The queue can be created with the following option:
  214. *
  215. *     MSG_Q_FIFO      queue pended tasks in FIFO order 
  216. *
  217. * RETURNS: OK or ERROR.
  218. *
  219. * ERRNO: S_msgQLib_INVALID_QUEUE_TYPE
  220. *
  221. * SEE ALSO: msgQSmCreate()
  222. *
  223. * NOMANUAL
  224. */
  225. STATUS msgQSmInit 
  226.     (
  227.     SM_MSG_Q * pSmMsgQ,      /* local pointer to msg queue to initialize */
  228.     int        maxMsgs,      /* max messages that can be queued */
  229.     int        maxMsgLength, /* max bytes in a message */
  230.     int        options,      /* message queue options */
  231.     void *     pSmMsgPool    /* local pointer to memory for messages */
  232.     )
  233.     {
  234.     int                 ix;
  235.     int                 nodeSize = SM_MSG_NODE_SIZE (maxMsgLength);
  236.     SM_MSG_Q volatile * pSmMsgQv = (SM_MSG_Q volatile *) pSmMsgQ;
  237.     int                 temp;           /* temp storage */
  238.     bzero ((char *) pSmMsgQ, sizeof (*pSmMsgQ));/* clear out msg q structure */
  239.     /* initialize msgQ semaphores */
  240.     switch (options & MSG_Q_TYPE_MASK)
  241.         {
  242.         case MSG_Q_FIFO:    
  243.     {
  244.     semSmCInit (&pSmMsgQ->msgQSem, SEM_Q_FIFO, 0);
  245.             semSmCInit (&pSmMsgQ->freeQSem, SEM_Q_FIFO, maxMsgs);
  246.          break;
  247.     }
  248.         default:
  249.             errno = S_msgQLib_INVALID_QUEUE_TYPE;
  250.             return (ERROR);
  251.         }
  252.     /* put msg nodes on free list */
  253.     for (ix = 0; ix < maxMsgs; ix++)
  254. {
  255. smDllAdd (&pSmMsgQ->freeQ, (SM_DL_NODE *) pSmMsgPool);
  256. pSmMsgPool = (void *) (((char *) pSmMsgPool) + nodeSize);
  257. }
  258.     /* initialize rest of message queue */
  259.     pSmMsgQv->options    = htonl (options);
  260.     pSmMsgQv->maxMsgs    = htonl (maxMsgs);
  261.     pSmMsgQv->maxMsgLength = htonl (maxMsgLength);
  262.     pSmMsgQv->objType      = htonl (MSG_Q_TYPE_SM);
  263.     pSmMsgQv->verify       = (UINT32) htonl (LOC_TO_GLOB_ADRS (pSmMsgQ));
  264.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  265.     temp = pSmMsgQv->objType;                   /* BRIDGE FLUSH  [SPR 68334] */
  266.     return (OK);
  267.     }
  268. /*****************************************************************************
  269. *
  270. * msgQSmSend - send a message to a shared memory message queue
  271. *
  272. * This routine sends the message in <buffer> of length <nBytes> to the
  273. * shared memory message queue <smMsgQId>.  If any tasks are already waiting to
  274. * receive messages on the queue, the message will immediately be delivered
  275. * to the first waiting task.  If no task is waiting to receive messages, the
  276. * message is saved in the message queue.
  277. *
  278. * The <timeout> parameter specifies the number of ticks to wait for free
  279. * space if the message queue is full.  <timeout> can have the special value
  280. * NO_WAIT that indicates msgQSend() will return immediately even if the
  281. * message has not been sent.  Another value for <timeout> is WAIT_FOREVER
  282. * that indicates that msgQSend() will never timeout.
  283. *
  284. * The <priority> parameter specifies the priority of the message being sent.
  285. * Normal priority messages (MSG_PRI_NORMAL) are added to the tail
  286. * of the list of queued messages.  Urgent priority messages
  287. * (MSG_PRI_URGENT) are added to the head of the list.
  288. *
  289. * This routine is normally called by the generic msgQSend() system call. 
  290. * The lower bit of the identifier passed to msgQSend() is used to 
  291. * differentiate local and shared memory message queues.
  292. *
  293. * This routine not callable at interrupt level.
  294. *
  295. * RETURNS: OK or ERROR.
  296. *
  297. * ERRNO: S_objLib_OBJ_ID_ERROR, S_objLib_OBJ_UNAVAILABLE,
  298. *        S_objLib_OBJ_TIMEOUT, S_msgQLib_INVALID_MSG_LENGTH,
  299. *        S_smObjLib_LOCK_TIMEOUT
  300. *
  301. * NOMANUAL
  302. */
  303. STATUS msgQSmSend 
  304.     (
  305.     SM_MSG_Q_ID    smMsgQId,       /* message queue on which to send */
  306.     char *         buffer,         /* message to send */
  307.     UINT           nBytes,         /* length of message */
  308.     int            timeout,        /* ticks to wait */
  309.     int            priority        /* MSG_PRI_NORMAL or MSG_PRI_URGENT */
  310.     )
  311.     {
  312.     SM_MSG_NODE volatile * pMsg;
  313.     SM_DL_NODE *           prevNode;
  314.     int                    level;
  315.     SM_MSG_Q_ID volatile   smMsgQIdv = (SM_MSG_Q_ID volatile) smMsgQId;
  316.     int                    temp;   /* temp storage */
  317.     if (INT_RESTRICT () != OK)          /* not ISR callable */
  318.         {
  319.         return (ERROR);
  320.         }
  321.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  322.     temp = smMsgQIdv->verify;                   /* PCI bridge bug [SPR 68844]*/
  323.     if (SM_OBJ_VERIFY (smMsgQIdv) != OK)
  324.         {
  325. return (ERROR);
  326.         }
  327.     if (nBytes > ntohl (smMsgQId->maxMsgLength))
  328. {
  329. errno = S_msgQLib_INVALID_MSG_LENGTH;
  330. return (ERROR);
  331. }
  332.     TASK_LOCK ();
  333.     /* windview level 2 event logging, uses the OSE logging routine */
  334.     EVT_OBJ_SM_MSGQ (EVENT_MSGQSEND, smMsgQId, buffer, nBytes, timeout, 
  335.      priority,5);
  336.     /* get a free message by taking free msg Q shared counting semaphore */
  337.     if (semSmTake (&smMsgQId->freeQSem, timeout) != OK)
  338. {
  339. smMsgQId->sendTimeouts = htonl (ntohl (smMsgQId->sendTimeouts) + 1);
  340. TASK_UNLOCK ();
  341. return (ERROR);
  342. }
  343.     /* a free message was available before timeout, get it */
  344.     if (SM_OBJ_LOCK_TAKE (&smMsgQId->freeQLock, &level) != OK)
  345.         {
  346. smObjTimeoutLogMsg ("msgQSend", (char *) &smMsgQId->freeQLock);
  347.         TASK_UNLOCK ();
  348.         return (ERROR);                         /* can't take lock */
  349. }
  350.     pMsg = (SM_MSG_NODE volatile *) smDllGet (&smMsgQId->freeQ);
  351.     SM_OBJ_LOCK_GIVE (&smMsgQId->freeQLock, level);/* release lock */
  352.     pMsg->msgLength = htonl (nBytes);
  353.     bcopy (buffer, SM_MSG_NODE_DATA (pMsg), (int) nBytes);
  354.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  355.     temp = pMsg->msgLength;                     /* BRIDGE FLUSH  [SPR 68334] */
  356.     /* now send message */
  357.     if (SM_OBJ_LOCK_TAKE (&smMsgQId->msgQLock, &level) != OK)
  358.         {
  359. smObjTimeoutLogMsg ("msgQSend", (char *) &smMsgQId->msgQLock);
  360.         TASK_UNLOCK ();
  361.         return (ERROR);                         /* can't take lock */
  362. }
  363.     /* insert message in message list according to its priority */
  364.     if (priority == MSG_PRI_NORMAL) 
  365. {
  366. prevNode = (SM_DL_NODE *) SM_DL_LAST (&smMsgQId->msgQ);
  367. }
  368.     else prevNode = NULL; 
  369.     smDllInsert (&smMsgQId->msgQ, prevNode, (SM_DL_NODE *) pMsg);
  370.     SM_OBJ_LOCK_GIVE (&smMsgQId->msgQLock, level);/* release lock */
  371.     
  372.       /*
  373.        * If another CPU is currently doing a msgQ send
  374.        * we can have a case where the other CPU has put a message and
  375.        * is delayed by an interrupt before Giving the shared
  376.        * semaphore. In that case, this CPU can put its message and Give
  377.        * the shared semaphore, the receiver will be unblocked by
  378.        * the Give done by this CPU but the message obtained will
  379.        * be the one put by the other CPU (FIFO order of messages will be kept).
  380.        */
  381.     /* unblock receiver */
  382.     if (semSmGive (&smMsgQId->msgQSem) != OK)
  383.         {
  384.         TASK_UNLOCK (); 
  385. return (ERROR);
  386. }
  387.     TASK_UNLOCK ();
  388.     return (OK);
  389.     }
  390. /*****************************************************************************
  391. *
  392. * msgQSmReceive - receive a message from a shared memory message queue
  393. *
  394. * This routine receives a message from the shared memory message queue
  395. * <smMsgQId>.  The received message is copied into the specified <buffer>,
  396. * which is <maxNBytes> in length.  If the message is longer than <maxNBytes>,
  397. * the remainder of the message is discarded (no error indication is returned).
  398. *
  399. * The <timeout> parameter specifies the number of ticks to wait for a
  400. * message to be sent to the queue, if no message is available when
  401. * msgQSmReceive() is called. <timeout> can have the special value NO_WAIT
  402. * that indicates msgQSmReceive() will return immediately even if a message
  403. * is available.  Another value for <timeout> is WAIT_FOREVER that indicates
  404. * that msgQSmReceive() will never timeout.
  405. *
  406. * This routine is normally called by the generic msgQReceive() system call. 
  407. * The lower bit of the identifier passed to msgQReceive() is used to 
  408. * differentiate local and shared memory message queues.
  409. *
  410. * This routine cannot be called by interrupt service routines.
  411. *
  412. * RETURNS:
  413. * The number of bytes copied to <buffer>, or ERROR.
  414. *
  415. * ERRNO: S_smObjLib_OBJ_ID_ERROR, S_objLib_OBJ_UNAVAILABLE,
  416. *        S_objLib_OBJ_TIMEOUT, S_msgQLib_INVALID_MSG_LENGTH,
  417. *        S_smObjLib_LOCK_TIMEOUT
  418. *
  419. * NOMANUAL
  420. */
  421. int msgQSmReceive 
  422.     (
  423.     SM_MSG_Q_ID    smMsgQId,       /* message queue from which to receive*/
  424.     char *         buffer,         /* buffer to receive message */
  425.     UINT           maxNBytes,      /* length of buffer */
  426.     int            timeout         /* ticks to wait */
  427.     )
  428.     {
  429.     SM_MSG_NODE volatile * pMsg;
  430.     int                    bytesReturned;
  431.     int                    level;
  432.     SM_MSG_Q_ID volatile   smMsgQIdv = (SM_MSG_Q_ID volatile) smMsgQId;
  433.     int                    temp;   /* temp storage */
  434.     /* 
  435.      * even though maxNBytes is unsigned, check for < 0 to catch 
  436.      * possible caller errors
  437.      */
  438.     if ((int) maxNBytes < 0)
  439. {
  440. errno = S_msgQLib_INVALID_MSG_LENGTH;
  441. return (ERROR);
  442. }
  443.     TASK_LOCK ();
  444.     /* windview level 2 event logging, uses the OSE logging routine */
  445.     EVT_OBJ_SM_MSGQ (EVENT_MSGQRECEIVE, smMsgQId, buffer, maxNBytes, 
  446.      timeout, 0,4);
  447.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  448.     temp = smMsgQIdv->verify;                   /* PCI bridge bug [SPR 68844]*/
  449.     if (SM_OBJ_VERIFY (smMsgQIdv) != OK)
  450. {
  451. TASK_UNLOCK ();
  452. return (ERROR);
  453. }
  454.     /* block until a message is available */
  455.     if (semSmTake (&smMsgQId->msgQSem, timeout) != OK)
  456.         {
  457.         smMsgQId->recvTimeouts = htonl (ntohl (smMsgQId->recvTimeouts) + 1);
  458.         TASK_UNLOCK ();
  459.         return (ERROR);
  460.         }
  461.     /* a message was available before timeout, get it */
  462.     if (SM_OBJ_LOCK_TAKE (&smMsgQId->msgQLock, &level) != OK)
  463.         {
  464. smObjTimeoutLogMsg ("msgQReceive", (char *) &smMsgQId->msgQLock);
  465.         TASK_UNLOCK ();
  466.         return (ERROR);                         /* can't take lock */
  467.         }
  468.     pMsg = (SM_MSG_NODE volatile *) smDllGet (&smMsgQId->msgQ);
  469.     SM_OBJ_LOCK_GIVE (&smMsgQId->msgQLock, level);/* release lock */
  470.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  471.     temp = pMsg->msgLength;                     /* PCI bridge bug [SPR 68844]*/
  472.     bytesReturned = min (ntohl (pMsg->msgLength), maxNBytes);
  473.     bcopy (SM_MSG_NODE_DATA (pMsg), buffer, bytesReturned);
  474.     /* now give back message to free queue */
  475.     if (SM_OBJ_LOCK_TAKE (&smMsgQId->freeQLock, &level) != OK)
  476.         {
  477. smObjTimeoutLogMsg ("msgQReceive", (char *) &smMsgQId->freeQLock);
  478.         TASK_UNLOCK ();
  479.         return (ERROR);                         /* can't take lock */
  480.         }
  481.     smDllAdd (&smMsgQId->freeQ, (SM_DL_NODE *) pMsg);
  482.     SM_OBJ_LOCK_GIVE (&smMsgQId->freeQLock, level);/* release lock */
  483.     /* now give free queue semaphore */
  484.     if (semSmGive (&smMsgQId->freeQSem) != OK)
  485.         {
  486.         TASK_UNLOCK ();
  487.         return (ERROR);
  488.         }
  489.     TASK_UNLOCK ();
  490.     return (bytesReturned);
  491.     }
  492. /*****************************************************************************
  493. *
  494. * msgQSmNumMsgs - get number of messages queued to shared memory message queue
  495. *
  496. * This routine returns the number of messages currently queued to a specified
  497. * message queue <smMsgQId>.
  498. *
  499. * This routine is normally called by the generic msgQNumMsgs() system call. 
  500. * The lower bit of the identifier passed to msgQNumMsgs() is used to 
  501. * differentiate local and shared memory message queues.
  502. *
  503. * RETURNS:
  504. * The number of messages queued, or ERROR.
  505. *
  506. * ERRNO: S_objLib_OBJ_ID_ERROR
  507. *
  508. * NOMANUAL
  509. */
  510. int msgQSmNumMsgs 
  511.     (
  512.     SM_MSG_Q_ID       smMsgQId          /* message queue to examine */
  513.     )
  514.     {
  515.     SM_MSG_Q_ID volatile smMsgQIdv = (SM_MSG_Q_ID volatile) smMsgQId;
  516.     int                  temp;         /* temp storage */
  517.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  518.     temp = smMsgQIdv->verify;                   /* PCI bridge bug [SPR 68844]*/
  519.     if (SM_OBJ_VERIFY (smMsgQIdv) != OK)
  520.         {
  521. return (ERROR);
  522.         }
  523.     temp = smMsgQIdv->msgQSem.state.count;      /* PCI bridge bug [SPR 68844]*/
  524.     temp = smMsgQIdv->msgQSem.state.count;
  525.     return (ntohl (temp));
  526.     }