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

VxWorks

开发平台:

C/C++

  1. /* mqPxLib.c - message queue library (POSIX) */
  2. /* Copyright 1984-2002 Wind River Systems, Inc.  */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01s,17jul00,jgn  merge DOT-4 pthreads changes
  8. 01r,29sep00,pai  added Andrew Gaiarsa's fix for mq_send() during kernelState
  9.                  (SPR #32033)
  10. 01q,16oct96,dgp  doc: modify mq_send to show maximum priority <= 31 
  11.       (SPR #7019)
  12. 01p,19aug96,dbt  added use of MQ_PRIO_MAX (SPR #7039).
  13. 01o,11feb95,jdi  corrected spelling error.
  14. 01n,25jan95,rhp  doc tweaks.
  15.     19jan95,jdi  doc cleanup.
  16. 01m,15apr94,dvs  fix mq_send to unlock interrupts on error.
  17.    +rrr
  18. 01l,08apr94,dvs  doc cleanup of mq_close (SPR #3099).
  19. 01k,08apr94,dvs  fixed error in args when calling symFindByName (SPR #3090).
  20. 01j,03feb94,kdl  moved structure definitions to mqPxLibP.h.
  21. 01i,01feb94,dvs  documentation changes.
  22. 01h,30jan94,kdl  changed #if for conditional ffsMsb() prototype (!=I960).
  23. 01g,28jan94,kdl  added check for invalid msg and queue sizes in mq_open().
  24. 01f,28jan94,dvs  fixed i960 ffsMsb() problem
  25. 01e,24jan94,smb  added instrumentation macros
  26. 01d,12jan94,rrr  fixed bug sending message to self; change to follow wrs 
  27.    +kdl  coding conventions; change mqLibInit() to mqPxLibInit().
  28. 01c,21dec93,kdl  fixed errno if opening non-existant queue.
  29. 01b,12nov93,rrr  rewrite
  30. 01a,06apr93,smb  created
  31. */
  32. /*
  33. DESCRIPTION
  34. This library implements the message-queue interface defined in the
  35. POSIX 1003.1b standard, as an alternative to the VxWorks-specific
  36. message queue design in msgQLib.  These message queues are accessed
  37. through names; each message queue supports multiple sending and receiving 
  38. tasks.
  39. The message queue interface imposes a fixed upper bound on the size of
  40. messages that can be sent to a specific message queue.  The size is set on
  41. an individual queue basis.  The value may not be changed dynamically.
  42. This interface allows a task be notified asynchronously of the
  43. availability of a message on the queue.  The purpose of this feature is to
  44. let the task to perform other functions and yet still be notified that a
  45. message has become available on the queue.
  46. MESSAGE QUEUE DESCRIPTOR DELETION
  47. The mq_close() call terminates a message queue descriptor and
  48. deallocates any associated memory.  When deleting message queue
  49. descriptors, take care to avoid interfering with other tasks that are
  50. using the same descriptor.  Tasks should only close message
  51. queue descriptors that the same task has opened successfully.
  52. The routines in this library conform to POSIX 1003.1b.
  53. INCLUDE FILES: mqueue.h
  54. SEE ALSO: POSIX 1003.1b document, msgQLib,
  55. .pG "Basic OS"
  56. */
  57. #include "vxWorks.h"
  58. #include "errno.h"
  59. #include "stdarg.h"
  60. #include "string.h"
  61. #include "intLib.h"
  62. #include "qLib.h"
  63. #include "fcntl.h"
  64. #include "objLib.h"
  65. #include "taskLib.h"
  66. #include "semLib.h"
  67. #include "private/mqPxLibP.h"
  68. #include "private/sigLibP.h"
  69. #include "private/kernelLibP.h"
  70. #include "private/windLibP.h"
  71. #include "private/workQLibP.h"
  72. #include "private/eventP.h"
  73. #include "symLib.h"
  74. #include "memLib.h"
  75. #define __PTHREAD_SRC
  76. #include "pthread.h"
  77. #if CPU_FAMILY != I960
  78. extern int ffsMsb (unsigned long); /* not in any header except for i960 */
  79. #endif
  80. #undef FREAD
  81. #undef FWRITE
  82. #define FREAD 1
  83. #define FWRITE 2
  84. static OBJ_CLASS  mqClass;
  85. CLASS_ID  mqClassId = &mqClass;
  86. SYMTAB_ID  mqNameTbl;
  87. BOOL  mqLibInstalled = FALSE;
  88. #ifdef __GNUC__
  89. #define INLINE __inline__
  90. #else
  91. #define INLINE
  92. #endif
  93. /*******************************************************************************
  94. *
  95. * sll_ins - insert into a singly linked list
  96. *
  97. * These list have the following form:
  98. *
  99. * ---------
  100. * | head  |-------------
  101. * ---------             
  102. *                        
  103. *          ----------        ----------      ----------        ----------
  104. *      ,-->| New - 1|-------->| Newest |----->| Oldest |--~~~-->|        |-
  105. *     /    ----------         ----------      ----------        ---------- 
  106. *     ____________________________________________________________________/
  107. *
  108. * To insert, put it after the Newest and move the head up one.
  109. */
  110. static INLINE void sll_ins
  111.     (
  112.     struct sll_node *   pNode, /* node to insert */
  113.     struct sll_node **  ppHead /* addr of head of list */
  114.     )
  115.     {
  116.     if (*ppHead == NULL)
  117. *ppHead = pNode->sll_next = pNode;
  118.     else
  119. {
  120. pNode->sll_next = (*ppHead)->sll_next;
  121. (*ppHead)->sll_next = pNode;
  122. *ppHead = pNode;
  123. }
  124.     }
  125. /*******************************************************************************
  126. *
  127. * sll_head - remove the oldest node off a singly linked list
  128. *
  129. * These list have the following form:
  130. *
  131. * ---------
  132. * | head  |-------------
  133. * ---------             
  134. *                        
  135. *          ----------        ----------      ----------        ----------
  136. *      ,-->| New - 1|-------->| Newest |------| Oldest |--~~~-->|        |-
  137. *     /    ----------         ----------      ----------        ---------- 
  138. *     ____________________________________________________________________/
  139. *
  140. * To remove, pull off the one after the Newest, then make sure there are
  141. * still some nodes left otherwise null out the head.
  142. *
  143. * RETURNS: A pointer to the oldest node.
  144. */
  145. static INLINE struct sll_node *sll_head
  146.     (
  147.     struct sll_node ** ppHead /* addr of head of list */
  148.     )
  149.     {
  150.     struct sll_node *pRetval;
  151.     if ((pRetval = (*ppHead)->sll_next) == *ppHead)
  152. *ppHead = NULL;
  153.     else
  154. (*ppHead)->sll_next = pRetval->sll_next;
  155.     return (pRetval);
  156.     }
  157. /*******************************************************************************
  158. *
  159. * mqPxLibInit - initialize the POSIX message queue library
  160. *
  161. * This routine initializes the POSIX message queue facility.  If <hashSize> is
  162. * 0, the default value is taken from MQ_HASH_SIZE_DEFAULT.
  163. *
  164. * RETURNS: OK or ERROR.
  165. */
  166. int mqPxLibInit
  167.     (
  168.     int hashSize /* log2 of number of hash buckets */
  169.     )
  170.     {
  171.     if (!mqLibInstalled)
  172. {
  173. if (hashSize == 0)
  174.     hashSize = MQ_HASH_SIZE_DEFAULT;
  175. if (((mqNameTbl = symTblCreate (hashSize, FALSE, memSysPartId)) != NULL)
  176.     && (classInit (mqClassId, sizeof (struct mq_des),
  177.   OFFSET (struct mq_des, f_objCore),
  178.   (FUNCPTR) NULL,(FUNCPTR) NULL,(FUNCPTR) NULL) == OK))
  179.     mqLibInstalled = TRUE;
  180. }
  181.     return (mqLibInstalled) ? OK : ERROR;
  182.     }
  183. /*******************************************************************************
  184. *
  185. * mq_init - quick and dirty init of the guts of a message queue.
  186. *
  187. * The needs to be redone with objects!!! XXX
  188. *
  189. */
  190. static void mq_init
  191.     (
  192.     void * pMem, /* memory to hold queue */
  193.     int nMsgs, /* number of messages in queue */
  194.     int msgSize /* size of each message */
  195.     )
  196.     {
  197.     struct sll_node *pNode;
  198.     struct msg_que *pMq;
  199.     size_t nBytes;
  200.     nBytes = MEM_ROUND_UP (msgSize + sizeof (struct sll_node));
  201.     pMq = (struct msg_que *) pMem;
  202.     bzero ((void *) pMq, sizeof (struct msg_que));
  203.     qInit (&pMq->msgq_cond_read, Q_PRI_LIST, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  204.     qInit (&pMq->msgq_cond_data, Q_PRI_LIST, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  205.     pMq->msgq_sigTask = -1;
  206.     pMq->msgq_attr.mq_maxmsg = nMsgs;
  207.     pMq->msgq_attr.mq_msgsize = msgSize;
  208.     pNode = (struct sll_node *) (void *) ((char *)pMem +
  209.     MEM_ROUND_UP (sizeof (struct msg_que)));
  210.     while (nMsgs-- > 0)
  211. {
  212. sll_ins (pNode, &pMq->msgq_free_list);
  213. pNode = (struct sll_node *) (void *) ((char *)pNode + nBytes);
  214. }
  215.     }
  216. /*******************************************************************************
  217. *
  218. * mq_terminate - quick and dirty termination of the guts of a message queue.
  219. *
  220. * The needs to be redone with objects!!! XXX
  221. *
  222. */
  223. static void mq_terminate
  224.     (
  225.     struct msg_que *pMq
  226.     )
  227.     {
  228.     kernelState = TRUE; /* ENTER KERNEL */
  229.     /* windview - level 2 instrumentation */
  230.     EVT_TASK_1 (EVENT_OBJ_MSGDELETE, pMq);
  231.     windPendQTerminate (&pMq->msgq_cond_read);
  232.     /* windview - level 2 instrumentation */
  233.     EVT_TASK_1 (EVENT_OBJ_MSGDELETE, pMq);
  234.     windPendQTerminate (&pMq->msgq_cond_data);
  235.     windExit (); /* EXIT KERNEL */
  236.     /*
  237.      * notification processing
  238.      */
  239.     if (pMq->msgq_sigTask != -1)
  240. {
  241. sigPendDestroy (&pMq->msgq_sigPend);
  242. pMq->msgq_sigTask = -1;
  243. }
  244.     free (pMq);
  245.     }
  246. /*******************************************************************************
  247. *
  248. * mq_create - create a message queue
  249. *
  250. * The function mq_create() is used to create a message queue.  The maximum
  251. * size of any message that can be sent is <msgSize>.  The message queue
  252. * can hold <nMsgs> messages before a mq_send() will block.
  253. *
  254. * RETURNS: Upon successful completion, mq_create() will return a
  255. * message queue descriptor.  Otherwise, the function will return (<mqd_t>)-1
  256. * and set <errno> to indicate the error.
  257. *
  258. * ERRORS: If any of the following conditions occur, the mq_create() function
  259. * will return (<mqd_t>)-1 and set <errno> to the corresponding value:
  260. * .iP ENOMEM
  261. *
  262. * NOMANUAL
  263. */
  264. mqd_t mq_create
  265.     (
  266.     size_t nMsgs, /* number of messages in queue */
  267.     size_t msgSize /* size of each message in queue */
  268.     )
  269.     {
  270.     struct mq_des *pMqDesc;
  271.     void *pQMem;
  272.     if (INT_RESTRICT () != OK)
  273. return ((mqd_t) -1); /* restrict ISR from calling */
  274.     if ((!mqLibInstalled) && (mqPxLibInit (0) != OK))
  275. return ((mqd_t) -1); /* package init problem */
  276.     pQMem = malloc (MEM_ROUND_UP (sizeof (struct msg_que)) + 
  277.         nMsgs * MEM_ROUND_UP (msgSize + sizeof (struct sll_node)));
  278.     if (pQMem == NULL)
  279. {
  280. errno = ENOSPC;
  281. return ((mqd_t) -1);
  282. }
  283.     if ((pMqDesc = (mqd_t) objAlloc (mqClassId)) == NULL)
  284. {
  285. free (pQMem);
  286.         errno = ENOSPC;
  287.         return ((mqd_t) -1);
  288. }
  289.     mq_init (pQMem, nMsgs, msgSize);
  290.     pMqDesc->f_flag = FREAD | FWRITE;
  291.     pMqDesc->f_data = pQMem;
  292.     pMqDesc->f_data->msgq_links++;
  293.     objCoreInit (&pMqDesc->f_objCore, mqClassId); /* valid file obj */
  294.     return (pMqDesc);
  295.     }
  296. /*******************************************************************************
  297. *
  298. * mq_open - open a message queue (POSIX)
  299. *
  300. * This routine establishes a connection between a named message queue and the
  301. * calling task.  After a call to mq_open(), the task can reference the
  302. * message queue using the address returned by the call.  The message queue
  303. * remains usable until the queue is closed by a successful call to mq_close().
  304. *
  305. * The <oflags> argument controls whether the message queue is created or merely
  306. * accessed by the mq_open() call.  The following flag bits can be set
  307. * in <oflags>:
  308. * .iP O_RDONLY
  309. * Open the message queue for receiving messages.  The task can use the 
  310. * returned message queue descriptor with mq_receive(), but not mq_send().
  311. * .iP O_WRONLY
  312. * Open the message queue for sending messages.  The task can use the
  313. * returned message queue descriptor with mq_send(), but not mq_receive().
  314. * .iP O_RDWR
  315. * Open the queue for both receiving and sending messages.  The task can use
  316. * any of the functions allowed for O_RDONLY and O_WRONLY.
  317. * .LP
  318. *
  319. * Any combination of the remaining flags can be specified in <oflags>:
  320. * .iP O_CREAT
  321. * This flag is used to create a message queue if it does not already exist.
  322. * If O_CREAT is set and the message queue already exists, then O_CREAT has
  323. * no effect except as noted below under O_EXCL.  Otherwise, mq_open()
  324. * creates a message queue.  The O_CREAT flag requires a third and fourth
  325. * argument: <mode>, which is of type `mode_t', and <pAttr>, which is of type
  326. * pointer to an `mq_attr' structure.  The value of <mode> has no effect in
  327. * this implementation.  If <pAttr> is NULL, the message queue is created
  328. * with implementation-defined default message queue attributes.  If <pAttr>
  329. * is non-NULL, the message queue attributes `mq_maxmsg' and `mq_msgsize' are
  330. * set to the values of the corresponding members in the `mq_attr' structure
  331. * referred to by <pAttr>; if either attribute is less than or equal to zero,
  332. * an error is returned and errno is set to EINVAL.
  333. * .iP O_EXCL
  334. * This flag is used to test whether a message queue already exists.
  335. * If O_EXCL and O_CREAT are set, mq_open() fails if the message queue name
  336. * exists.
  337. * .iP O_NONBLOCK
  338. * The setting of this flag is associated with the open message queue descriptor
  339. * and determines whether a mq_send() or mq_receive() will wait for resources
  340. * or messages that are not currently available, or fail with errno set 
  341. * to EAGAIN.  
  342. * .LP
  343. *
  344. * The mq_open() call does not add or remove messages from the queue.
  345. *
  346. * NOTE:
  347. * Some POSIX functionality is not yet supported:
  348. *
  349. *     - A message queue cannot be closed with calls to _exit() or exec().
  350. *     - A message queue cannot be implemented as a file.
  351. *     - Message queue names will not appear in the file system.
  352. *
  353. * RETURNS: A message queue descriptor, otherwise -1 (ERROR).
  354. *
  355. * ERRNO: EEXIST, EINVAL, ENOENT, ENOSPC
  356. *
  357. * SEE ALSO: mq_send(), mq_receive(), mq_close(), mq_setattr(), mq_getattr(),
  358. * mq_unlink()
  359. *
  360. */ 
  361. mqd_t mq_open
  362.     (
  363.     const char *mqName, /* name of queue to open */
  364.     int oflags, /* open flags */
  365.     ... /* extra optional parameters */
  366.     )
  367.     {
  368.     va_list vaList; /* arg list (if O_CREAT) */
  369.     struct mq_des * pMqDesc; /* memory for queue descriptor */
  370.     struct mq_attr * pAttr; /* pointer to attr passed in */
  371.     void * pQMem; /* memory queue will be placed in */
  372.     mode_t mode; /* not used by vxWorks */
  373.     int nMsgs; /* number of messages in queue */
  374.     int msgSize; /* size of each message in queue */
  375.     int nBytes; /* amount of mem needed for queue */
  376.     SYM_TYPE dummy; /* dummy var for symFindByName */
  377.     if (INT_RESTRICT () != OK) /* restrict ISR from calling */
  378. return ((mqd_t) -1);
  379.     if ((!mqLibInstalled) && (mqPxLibInit (0) != OK))
  380. return ((mqd_t) -1); /* package init problem */
  381.     if ((oflags & 3) == 3)
  382. {
  383. errno = EINVAL;
  384. return ((mqd_t) -1);
  385. }
  386.     semTake (&mqNameTbl->symMutex, WAIT_FOREVER);
  387.     if (symFindByName (mqNameTbl, (char *) mqName, (char **)&pQMem, 
  388.                        &dummy) == OK)
  389. {
  390. /*
  391.  * Found a mq, see if we should use it
  392.  */
  393. if (O_EXCL & oflags)
  394.     {
  395.     semGive (&mqNameTbl->symMutex);
  396.     errno = EEXIST;
  397.     return ((mqd_t) -1);
  398.     }
  399. if ((pMqDesc = (mqd_t) objAlloc (mqClassId)) == NULL)
  400.     {
  401.     semGive (&mqNameTbl->symMutex);
  402.     errno = ENOSPC;
  403.     return ((mqd_t) -1);
  404.     }
  405. }
  406.     else
  407. {
  408. /*
  409.  * There was no mq, create one if asked
  410.  */
  411. if (!(O_CREAT & oflags))
  412.     {
  413.     semGive (&mqNameTbl->symMutex);
  414.     errno = ENOENT;
  415.     return ((mqd_t) -1); /* queue does not exist */
  416.     }
  417. va_start (vaList, oflags);
  418. mode = va_arg (vaList, mode_t);
  419. pAttr = va_arg (vaList, struct mq_attr *);
  420. va_end (vaList);
  421. if (pAttr != NULL)
  422.     {
  423.     nMsgs = pAttr->mq_maxmsg;
  424.     msgSize = pAttr->mq_msgsize;
  425.     if ((nMsgs <= 0) || (msgSize <= 0))
  426. {
  427.      semGive (&mqNameTbl->symMutex);
  428.      errno = EINVAL;
  429.      return ((mqd_t) -1); /* invalid size specified */
  430.      }
  431.     oflags |= (pAttr->mq_flags & O_NONBLOCK);
  432.     }
  433. else
  434.     {
  435.     nMsgs =   MQ_NUM_MSGS_DEFAULT;
  436.     msgSize = MQ_MSG_SIZE_DEFAULT;
  437.     }
  438. nBytes = MEM_ROUND_UP (sizeof(struct msg_que)) + 
  439.  nMsgs * MEM_ROUND_UP (msgSize + sizeof (struct sll_node));
  440. pQMem = malloc (nBytes + strlen (mqName) + 1);
  441. if (pQMem == 0)
  442.     {
  443.     semGive (&mqNameTbl->symMutex);
  444.     errno = ENOSPC;
  445.     return ((mqd_t) -1);
  446.     }
  447. mq_init (pQMem, nMsgs, msgSize);
  448. ((struct msg_que *) pQMem)->msgq_sym.name = (char *) pQMem + nBytes;
  449. ((struct msg_que *) pQMem)->msgq_sym.value = (char *) pQMem;
  450. strcpy ((char *)pQMem + nBytes, mqName);
  451. if ((pMqDesc = (mqd_t) objAlloc (mqClassId)) == NULL)
  452.     {
  453.     free (pQMem);
  454.     semGive (&mqNameTbl->symMutex);
  455.     errno = ENOSPC;
  456.     return ((mqd_t) -1);
  457.     }
  458. symTblAdd (mqNameTbl, &((struct msg_que *) pQMem)->msgq_sym);
  459. }
  460.     /*
  461.      * (oflags & 3) + 1 is magic for transposing O_RDONLY, O_RDWR or
  462.      * O_WRONLY into the bit field flags FREAD and FWRITE
  463.      */
  464.     pMqDesc->f_flag = (oflags & O_NONBLOCK) | ((oflags & 3) + 1);
  465.     pMqDesc->f_data = pQMem;
  466.     pMqDesc->f_data->msgq_links++;
  467.     objCoreInit (&pMqDesc->f_objCore, mqClassId); /* valid file obj */
  468.     semGive (&mqNameTbl->symMutex);
  469.     return (pMqDesc);
  470.     }
  471. /*******************************************************************************
  472. *
  473. * mq_receive - receive a message from a message queue (POSIX)
  474. *
  475. * This routine receives the oldest of the highest priority message from
  476. * the message queue specified by <mqdes>.  If the size of the buffer in
  477. * bytes, specified by the <msgLen> argument, is less than the `mq_msgsize'
  478. * attribute of the message queue, mq_receive() will fail and return an
  479. * error.  Otherwise, the selected message is removed from the queue and
  480. * copied to <pMsg>.
  481. *
  482. * If <pMsgPrio> is not NULL, the priority of the selected message
  483. * will be stored in <pMsgPrio>.
  484. *
  485. * If the message queue is empty and O_NONBLOCK is not set in the message
  486. * queue's description, mq_receive() will block until a message is added to
  487. * the message queue, or until it is interrupted by a signal.  If more than
  488. * one task is waiting to receive a message when a message arrives at an
  489. * empty queue, the task of highest priority that has been waiting the
  490. * longest will be selected to receive the message.  If the specified message
  491. * queue is empty and O_NONBLOCK is set in the message queue's description,
  492. * no message is removed from the queue, and mq_receive() returns an error.
  493. *
  494. * RETURNS: The length of the selected message in bytes, otherwise -1 (ERROR). 
  495. *
  496. * ERRNO: EAGAIN, EBADF, EMSGSIZE, EINTR
  497. *
  498. * SEE ALSO: mq_send()
  499. */
  500. ssize_t mq_receive
  501.     (
  502.     mqd_t mqdes, /* message queue descriptor */
  503.     void *pMsg, /* buffer to receive message */
  504.     size_t msgLen, /* size of buffer, in bytes */
  505.     int *pMsgPrio /* if not NULL, priority of message */
  506.     )
  507.     {
  508.     struct sll_node *pNode;
  509.     struct msg_que *pMq;
  510.     int status;
  511.     int level;
  512.     int prio;
  513.     int error = 0;
  514.     int savtype;
  515.     if (INT_RESTRICT () != OK) /* restrict ISR from calling */
  516. return (-1);
  517.     TASK_LOCK (); /* TASK LOCK */
  518.     if ((OBJ_VERIFY (mqdes, mqClassId) != OK) ||
  519. ((mqdes->f_flag & FREAD) == 0))
  520. {
  521. error = EBADF;
  522. goto bad;
  523. }
  524.     pMq = mqdes->f_data;
  525.     /* Link into pthreads support code */
  526.     if (_func_pthread_setcanceltype != NULL)
  527.         {
  528.         _func_pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &savtype);
  529.         }
  530.     if (msgLen < pMq->msgq_attr.mq_msgsize)
  531. {
  532. error = EMSGSIZE;
  533. goto bad;
  534. }
  535.     level = intLock (); /* LOCK INTERRUPTS */
  536.     if (pMq->msgq_bmap == 0)
  537. {
  538. if (mqdes->f_flag & O_NONBLOCK)
  539.     {
  540.     intUnlock (level); /* UNLOCK INTERRUPTS */
  541.     error = EAGAIN;
  542.     goto bad;
  543.     }
  544. /*
  545.  * This needs to be in a loop, the reason is that someone
  546.  * can wake us up but we may not run.  During that time someone
  547.  * else can come in and steal our message.
  548.  */
  549. while (pMq->msgq_bmap == 0)
  550.     {
  551.     kernelState = TRUE; /* ENTER KERNEL */
  552.     intUnlock (level); /* UNLOCK INTERRUPTS */
  553.     /* windview - level 2 instrumentation */
  554.             EVT_TASK_1 (EVENT_OBJ_MSGRECEIVE, pMq);
  555.     if (windPendQPut (&pMq->msgq_cond_data, WAIT_FOREVER) != OK)
  556. {
  557. windExit (); /* EXIT KERNEL */
  558. error = EBADF; /* what should ernno be??? */
  559. goto bad;
  560. }
  561.     status = windExit (); /* EXIT KERNEL */
  562.     if (status != 0)
  563. {
  564. error = (status == RESTART) ? EINTR : EAGAIN;
  565. goto bad;
  566. }
  567.     level = intLock (); /* LOCK INTERRUPTS */
  568.     }
  569. }
  570.     prio = ffsMsb (pMq->msgq_bmap) - 1;
  571.     pNode = sll_head (&pMq->msgq_data_list[prio]);
  572.     --pMq->msgq_attr.mq_curmsgs;
  573.     if (pMq->msgq_data_list[prio] == NULL)
  574. pMq->msgq_bmap &= ~(1 << prio);
  575.     intUnlock (level); /* UNLOCK INTERRUPTS */
  576.     msgLen = pNode->sll_size;
  577.     bcopy ((void *) (pNode + 1), pMsg, msgLen);
  578.     if (pMsgPrio != 0)
  579. *pMsgPrio = prio;
  580.     level = intLock (); /* LOCK INTERRUPTS */
  581.     sll_ins (pNode, &pMq->msgq_free_list);
  582.     if (Q_FIRST (&pMq->msgq_cond_read) != 0)
  583. {
  584. kernelState = TRUE; /* ENTER KERNEL */
  585. intUnlock (level); /* UNLOCK INTERRUPTS */
  586. /* windview - level 2 instrumentation */
  587.         EVT_TASK_1 (EVENT_OBJ_MSGRECEIVE, pMq);
  588. windPendQGet (&pMq->msgq_cond_read);
  589. windExit (); /* EXIT KERNEL */
  590. }
  591.     else
  592. intUnlock (level); /* UNLOCK INTERRUPTS */
  593. bad:
  594.     TASK_UNLOCK(); /* TASK UNLOCK */
  595.     /* Link into pthreads support code */
  596.     if (_func_pthread_setcanceltype != NULL)
  597.         {
  598.         _func_pthread_setcanceltype(savtype, NULL);
  599.         }
  600.     if (error != 0)
  601. {
  602. errno = error;
  603. return (-1);
  604. }
  605.     return (msgLen);
  606.     }
  607. /*******************************************************************************
  608. *
  609. * mq_work - handle mq work
  610. *
  611. * The routine is always done as work. It is needed because windPendQGet
  612. * does not check it the queue is empty.
  613. */
  614. LOCAL void mq_work
  615.     (
  616.     struct msg_que *pMq,
  617.     int flag
  618.     )
  619.     {
  620.     if (Q_FIRST (&pMq->msgq_cond_data) != NULL)
  621. {
  622. /* windview - level 2 instrumentation */
  623.         EVT_TASK_1 (EVENT_OBJ_MSGSEND, pMq);
  624. windPendQGet (&pMq->msgq_cond_data);
  625. }
  626.     else if ((flag == 0) && (pMq->msgq_sigTask != -1))
  627. {
  628.         /* SPR #32033
  629.          * An interrupt context is faked while executing sigPendKill().  
  630.          * Since the work queue is drained with kernelState set to TRUE,
  631.          * sigPendKill() will perform an excJobAdd() of itself.  Without
  632.          * faking an interrupt context, the ensuing msgQSend() will perform
  633.          * taskLock/taskUnlock to protect it's critical section.  The 
  634.          * taskUnlock() would then re-enter the kernel via windExit().
  635.          * The kernel cannot be re-entered while in the process of draining
  636.          * the work queue.
  637.          */
  638.    
  639. ++intCnt;     /* no need to lock interrupts around increment */
  640. sigPendKill (pMq->msgq_sigTask, &pMq->msgq_sigPend);
  641. --intCnt;     /* no need to lock interrupts around decrement */
  642. pMq->msgq_sigTask = -1;
  643. }
  644.     }
  645. /*******************************************************************************
  646. *
  647. * mq_send - send a message to a message queue (POSIX)
  648. *
  649. * This routine adds the message <pMsg> to the message queue
  650. * <mqdes>.  The <msgLen> parameter specifies the length of the message in
  651. * bytes pointed to by <pMsg>.  The value of <pMsg> must be less than or
  652. * equal to the `mq_msgsize' attribute of the message queue, or mq_send()
  653. * will fail.
  654. *
  655. * If the message queue is not full, mq_send() will behave as if the message
  656. * is inserted into the message queue at the position indicated by the 
  657. * <msgPrio> argument.  A message with a higher numeric value for <msgPrio>
  658. * is inserted before messages with a lower value.  The value
  659. * of <msgPrio> must be less than or equal to 31.
  660. *
  661. * If the specified message queue is full and O_NONBLOCK is not set in the
  662. * message queue's, mq_send() will block until space becomes available to
  663. * queue the message, or until it is interrupted by a signal.  The priority
  664. * scheduling option is supported in the event that there is more than one
  665. * task waiting on space becoming available.  If the message queue is full
  666. * and O_NONBLOCK is set in the message queue's description, the message is
  667. * not queued, and mq_send() returns an error.
  668. *
  669. * USE BY INTERRUPT SERVICE ROUTINES
  670. * This routine can be called by interrupt service routines as well as
  671. * by tasks.  This is one of the primary means of communication
  672. * between an interrupt service routine and a task.  If mq_send()
  673. * is called from an interrupt service routine, it will behave as if
  674. * the O_NONBLOCK flag were set.
  675. *
  676. * RETURNS: 0 (OK), otherwise -1 (ERROR).
  677. *
  678. * ERRNO: EAGAIN, EBADF, EINTR, EINVAL, EMSGSIZE
  679. *
  680. * SEE ALSO: mq_receive()
  681. */
  682. int mq_send
  683.     (
  684.     mqd_t mqdes, /* message queue descriptor */
  685.     const void *pMsg, /* message to send */
  686.     size_t msgLen, /* size of message, in bytes */
  687.     int msgPrio /* priority of message */
  688.     )
  689.     {
  690.     struct sll_node *pNode;
  691.     struct msg_que *pMq;
  692.     int status;
  693.     int level;
  694.     int flag;
  695.     int sigTaskSave; /* saved task id */
  696.     int error = 0;
  697.     int savtype; /* saved cancellation type */
  698.     if (msgPrio > MQ_PRIORITY_MAX)
  699. {
  700. errno = EINVAL;
  701. return (-1);
  702. }
  703.     /* Link into pthreads support code */
  704.     
  705.     if (_func_pthread_setcanceltype != NULL)
  706.         {
  707.         _func_pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &savtype);
  708.         }
  709.      if (!INT_CONTEXT ())
  710. TASK_LOCK (); /* TASK LOCK */
  711.     if ((OBJ_VERIFY (mqdes, mqClassId) != OK) ||
  712. ((mqdes->f_flag & FWRITE) == 0))
  713. {
  714. error = EBADF;
  715. goto bad;
  716. }
  717.     pMq = mqdes->f_data;
  718.     if (msgLen > pMq->msgq_attr.mq_msgsize)
  719. {
  720. error = EMSGSIZE;
  721. goto bad;
  722. }
  723.     level = intLock (); /* LOCK INTERRUPTS */
  724.     if (pMq->msgq_free_list == NULL)
  725. {
  726. if (mqdes->f_flag & O_NONBLOCK)
  727.     {
  728.     intUnlock (level); /* UNLOCK INTERRUPTS */
  729.     error = EAGAIN;
  730.     goto bad;
  731.     }
  732. if (INT_CONTEXT ())
  733.     {
  734.     intUnlock (level); /* UNLOCK INTERRUPTS */
  735.     error = EAGAIN; /* what should errno be??? */
  736.     goto bad;
  737.     }
  738. while (pMq->msgq_free_list == NULL)
  739.     {
  740.     kernelState = TRUE; /* ENTER KERNEL */
  741.     intUnlock (level); /* UNLOCK INTERRUPTS */
  742.     /* windview - level 2 instrumentation */
  743.             EVT_TASK_1 (EVENT_OBJ_MSGSEND, pMq);
  744.     if (windPendQPut (&pMq->msgq_cond_read, WAIT_FOREVER) != OK)
  745. {
  746. windExit (); /* EXIT KERNEL */
  747. error = EBADF; /* what should errno be??? */
  748. goto bad;
  749. }
  750.     if ((status = windExit ()) != 0) /* EXIT KERNEL */
  751. {
  752. error = (status == RESTART) ? EINTR : EAGAIN;
  753. goto bad;
  754. }
  755.     level = intLock (); /* LOCK INTERRUPTS */
  756.     }
  757. }
  758.     pNode = sll_head (&pMq->msgq_free_list);
  759.     intUnlock (level); /* UNLOCK INTERRUPTS */
  760.     bcopy (pMsg, (void *) (pNode + 1), msgLen);
  761.     pNode->sll_size = msgLen;
  762.     level = intLock (); /* LOCK INTERRUPTS */
  763.     sll_ins (pNode, &pMq->msgq_data_list[msgPrio]);
  764.     flag = pMq->msgq_attr.mq_curmsgs++;
  765.     pMq->msgq_bmap |= 1 << (msgPrio);
  766.     if (kernelState)
  767. {
  768. intUnlock (level); /* UNLOCK INTERRUPTS */
  769. workQAdd2 ((FUNCPTR)mq_work, (int) pMq, flag);
  770. }
  771.     else
  772. {
  773. if (Q_FIRST (&pMq->msgq_cond_data) != 0)
  774.     {
  775.     kernelState = TRUE; /* ENTER KERNEL */
  776.     intUnlock (level); /* UNLOCK INTERRUPTS */
  777.     /* windview - level 2 instrumentation */
  778.             EVT_TASK_1 (EVENT_OBJ_MSGSEND, pMq);
  779.     windPendQGet (&pMq->msgq_cond_data);
  780.     windExit (); /* EXIT KERNEL */
  781.     }
  782. else
  783.     {
  784.     intUnlock (level); /* UNLOCK INTERRUPTS */
  785.     if ((flag == 0) && (pMq->msgq_sigTask != -1))
  786. {
  787. sigTaskSave = pMq->msgq_sigTask;
  788. pMq->msgq_sigTask = -1;
  789. sigPendKill (sigTaskSave, &pMq->msgq_sigPend);
  790. }
  791.     }
  792. }
  793. bad:
  794.     if (!INT_CONTEXT ())
  795. TASK_UNLOCK (); /* TASK UNLOCK */
  796.     /* Link into pthreads support code */
  797.     if (_func_pthread_setcanceltype != NULL)
  798.         {
  799.         _func_pthread_setcanceltype(savtype, NULL);
  800.         }
  801.     if (error)
  802. {
  803. errno = error;
  804. return (-1);
  805. }
  806.     return (0);
  807.     }
  808. /*******************************************************************************
  809. *
  810. * mq_close - close a message queue (POSIX)
  811. *
  812. * This routine is used to indicate that the calling task is finished
  813. * with the specified message queue <mqdes>.  
  814. * The mq_close() call deallocates any system resources allocated 
  815. * by the system for use by this task for its message queue.
  816. * The behavior of a task that is blocked on either a mq_send() or
  817. * mq_receive() is undefined when mq_close() is called.
  818. * The <mqdes> parameter will no longer be a valid message queue ID.
  819. *
  820. * RETURNS: 0 (OK) if the message queue is closed successfully,
  821. * otherwise -1 (ERROR).
  822. *
  823. * ERRNO: EBADF
  824. *
  825. * SEE ALSO: mq_open()
  826. */
  827. int mq_close 
  828.     (
  829.     mqd_t mqdes /* message queue descriptor */
  830.     )
  831.     {
  832.     if (INT_RESTRICT () != OK) /* restrict ISR from calling */
  833. return (-1);
  834.     TASK_SAFE (); /* TASK SAFE */
  835.     TASK_LOCK (); /* LOCK PREEMPTION */
  836.     /*
  837.      * validate message queue
  838.      */
  839.     if (OBJ_VERIFY (mqdes, mqClassId) != OK)
  840.    {
  841.         TASK_UNLOCK (); /* TASK UNLOCK */
  842.         TASK_UNSAFE (); /* TASK UNSAFE */
  843. errno = EBADF;
  844.         return (-1); /* invalid object */
  845. }
  846.     /*
  847.      * invalidate message queue descriptor
  848.      */
  849.     objCoreTerminate (&mqdes->f_objCore);
  850.     TASK_UNLOCK (); /* TASK UNLOCK */
  851.     semTake (&mqNameTbl->symMutex, WAIT_FOREVER);
  852.     /*
  853.      * No effect unless the name has been unlinked from name table
  854.      */
  855.     if ((--mqdes->f_data->msgq_links == 0) &&
  856. (mqdes->f_data->msgq_sym.name == NULL))
  857. mq_terminate(mqdes->f_data);
  858.     semGive (&mqNameTbl->symMutex);
  859.     /*
  860.      * free message queue descriptor
  861.      */
  862.     objFree (mqClassId, (char *) mqdes);
  863.     TASK_UNSAFE (); /* TASK UNSAFE */
  864.     return (0);
  865.     }
  866. /*******************************************************************************
  867. *
  868. * mq_unlink - remove a message queue (POSIX)
  869. *
  870. * This routine removes the message queue named by the pathname <mqName>.
  871. * After a successful call to mq_unlink(), a call to mq_open() on the same
  872. * message queue will fail if the flag O_CREAT is not set.  If one or more
  873. * tasks have the message queue open when mq_unlink() is called, removal of
  874. * the message queue is postponed until all references to the message queue
  875. * have been closed.
  876. *
  877. * RETURNS: 0 (OK) if the message queue is unlinked successfully,
  878. * otherwise -1 (ERROR).
  879. *
  880. * ERRNO: ENOENT
  881. *
  882. * SEE ALSO: mq_close(), mq_open()
  883. *
  884. */
  885. int mq_unlink 
  886.     (
  887.     const char * mqName /* name of message queue */
  888.     )
  889.     {
  890.     struct msg_que *pMq;
  891.     SYM_TYPE dummy; /* dummy var for symFindByName */
  892.     /*
  893.      * The following semTake is used to insure that mq_open cannot
  894.      * attach a task to the message queue between finding the message queue
  895.      * name in the table and unlinking it from the table.
  896.      */
  897.     semTake (&mqNameTbl->symMutex, WAIT_FOREVER);
  898.     if (symFindByName (mqNameTbl, (char *) mqName, (char **) &pMq, 
  899.        &dummy) == ERROR)
  900.         {
  901. semGive (&mqNameTbl->symMutex);
  902.         errno = ENOENT;
  903.         return (-1);
  904.         }
  905.     /*
  906.      * Remove name from table
  907.      */
  908.     symTblRemove (mqNameTbl, &pMq->msgq_sym);
  909.     pMq->msgq_sym.name = 0;
  910.     if (pMq->msgq_links == 0)
  911. mq_terminate (pMq);
  912.     semGive (&mqNameTbl->symMutex);
  913.     return (0);
  914.     }
  915. /*******************************************************************************
  916. *
  917. * mq_notify - notify a task that a message is available on a queue (POSIX)
  918. *
  919. * If <pNotification> is not NULL, this routine attaches the specified
  920. * <pNotification> request by the calling task to the specified message queue
  921. * <mqdes> associated with the calling task.  The real-time signal specified
  922. * by <pNotification> will be sent to the task when the message queue changes
  923. * from empty to non-empty.  If a task has already attached a notification
  924. * request to the message queue, all subsequent attempts to attach a
  925. * notification to the message queue will fail.  A task is able to attach a
  926. * single notification to each <mqdes> it has unless another task has already
  927. * attached one.
  928. *
  929. * If <pNotification> is NULL and the task has previously attached a
  930. * notification request to the message queue, the attached notification
  931. * request is detached and the queue is available for another task to attach
  932. * a notification request.
  933. *
  934. * If a notification request is attached to a message queue and any task
  935. * is blocked in mq_receive() waiting to receive a message when a message
  936. * arrives at the queue, then the appropriate mq_receive() will be completed
  937. * and the notification request remains pending.
  938. *
  939. * RETURNS: 0 (OK) if successful, otherwise -1 (ERROR).
  940. *
  941. * ERRNO: EBADF, EBUSY, EINVAL
  942. *
  943. * SEE ALSO: mq_open(), mq_send()
  944. *
  945. */
  946. int mq_notify 
  947.     (
  948.     mqd_t      mqdes,  /* message queue descriptor */
  949.     const struct sigevent * pNotification /* real-time signal */
  950.     )
  951.     {
  952.     struct siginfo * sigInfoP;
  953.     int error = 0;
  954.     if (INT_RESTRICT () != OK) /* restrict ISR from calling */
  955. return (-1);
  956.     TASK_LOCK (); /* TASK LOCK */
  957.     if (OBJ_VERIFY (mqdes, mqClassId) != OK)
  958.    {
  959. error = EBADF;
  960.         goto done; /* invalid object */
  961. }
  962.     /*
  963.      * free realtime signal
  964.      */
  965.     if (pNotification == NULL) 
  966. {
  967. if (taskIdSelf () == mqdes->f_data->msgq_sigTask)
  968.     {
  969.     mqdes->f_data->msgq_sigTask = -1;
  970.     sigPendDestroy (&mqdes->f_data->msgq_sigPend);
  971.     }
  972.         else
  973.     error = EINVAL;
  974. goto done;
  975. }
  976.     /*
  977.      * already in use
  978.      */
  979.     if (mqdes->f_data->msgq_sigTask != -1)
  980. {
  981. error = EBUSY;
  982. goto done;
  983. }
  984.     mqdes->f_data->msgq_sigTask = taskIdSelf ();
  985.     sigInfoP = &mqdes->f_data->msgq_sigPend.sigp_info;
  986.     sigInfoP->si_signo = pNotification->sigev_signo; /* signal number */
  987.     sigInfoP->si_code  = SI_MESGQ; /* signal code */
  988.     sigInfoP->si_value = pNotification->sigev_value; /* signal value */
  989.     /* initialize signal */
  990.     sigPendInit (&mqdes->f_data->msgq_sigPend);
  991. done:
  992.     TASK_UNLOCK (); /* TASK UNLOCK */
  993.     if (error != 0)
  994. {
  995. errno = error;
  996. return (-1);
  997. }
  998.     return (0);
  999.     }
  1000. /*******************************************************************************
  1001. *
  1002. * mq_setattr - set message queue attributes (POSIX)
  1003. *
  1004. * This routine sets attributes associated with the specified message
  1005. * queue <mqdes>.
  1006. *
  1007. * The message queue attributes corresponding to the following members
  1008. * defined in the `mq_attr' structure are set to the specified values upon
  1009. * successful completion of the call:
  1010. * .iP `mq_flags'
  1011. * The value the O_NONBLOCK flag.
  1012. * .LP
  1013. *
  1014. * If <pOldMqStat> is non-NULL, mq_setattr() will store, in the
  1015. * location referenced by <pOldMqStat>, the previous message queue attributes
  1016. * and the current queue status.  These values are the same as would be returned
  1017. * by a call to mq_getattr() at that point.
  1018. *
  1019. * RETURNS: 0 (OK) if attributes are set successfully, otherwise -1 (ERROR).
  1020. *
  1021. * ERRNO: EBADF
  1022. *
  1023. * SEE ALSO: mq_open(), mq_send(), mq_getattr()
  1024. */
  1025. int mq_setattr 
  1026.     (
  1027.     mqd_t     mqdes,  /* message queue descriptor */
  1028.     const struct mq_attr * pMqStat, /* new attributes */
  1029.     struct mq_attr *       pOldMqStat /* old attributes */
  1030.     )
  1031.     {
  1032.     if (INT_RESTRICT () != OK) /* restrict ISR from calling */
  1033. return (-1);
  1034.     TASK_LOCK (); /* TASK LOCK */
  1035.     if (OBJ_VERIFY (mqdes, mqClassId) != OK)
  1036.    {
  1037.      TASK_UNLOCK (); /* TASK UNLOCK */
  1038. errno = EBADF;
  1039.         return (-1); /* invalid object */
  1040. }
  1041.     if (pOldMqStat)
  1042. {
  1043. *pOldMqStat = mqdes->f_data->msgq_attr;
  1044. pOldMqStat->mq_flags = mqdes->f_flag;
  1045. }
  1046.     if (pMqStat)
  1047. {
  1048. mqdes->f_flag &= ~O_NONBLOCK;
  1049. mqdes->f_flag |= (pMqStat->mq_flags & O_NONBLOCK);
  1050. }
  1051.     TASK_UNLOCK (); /* TASK UNLOCK */
  1052.     return (0);
  1053.     }
  1054. /*******************************************************************************
  1055. *
  1056. * mq_getattr - get message queue attributes (POSIX)
  1057. *
  1058. * This routine gets status information and attributes associated with a
  1059. * specified message queue <mqdes>.  Upon return, the following members of
  1060. * the `mq_attr' structure referenced by <pMqStat> will contain the values
  1061. * set when the message queue was created but with modifications made by
  1062. * subsequent calls to mq_setattr():
  1063. * .iP `mq_flags'
  1064. * May be modified by mq_setattr().
  1065. * .LP
  1066. *
  1067. * The following were set at message queue creation:
  1068. * .iP `mq_maxmsg'
  1069. * Maximum number of messages.
  1070. * .iP `mq_msgsize'
  1071. * Maximum message size.
  1072. * .LP
  1073. *
  1074. * .iP `mq_curmsgs'
  1075. * The number of messages currently in the queue.
  1076. * .LP
  1077. *
  1078. * RETURNS: 0 (OK) if message attributes can be determined, otherwise -1 (ERROR).
  1079. *
  1080. * ERRNO: EBADF
  1081. *
  1082. * SEE ALSO: mq_open(), mq_send(), mq_setattr()
  1083. *
  1084. */
  1085. int mq_getattr 
  1086.     (
  1087.     mqd_t       mqdes,  /* message queue descriptor */
  1088.     struct mq_attr * pMqStat /* buffer in which to return attributes */
  1089.     )
  1090.     {
  1091.     return (mq_setattr (mqdes, NULL, pMqStat));
  1092.     }