source: rtems/c/src/exec/posix/src/mqueue.c @ 5e9b32b

4.104.114.84.95
Last change on this file since 5e9b32b was 5e9b32b, checked in by Joel Sherrill <joel.sherrill@…>, on 09/26/95 at 19:27:15

posix support initially added

  • Property mode set to 100644
File size: 16.5 KB
Line 
1/* mqueue.c
2 *
3 *  NOTE:  The structure of the routines is identical to that of POSIX
4 *         Message_queues to leave the option of having unnamed message
5 *         queues at a future date.  They are currently not part of the
6 *         POSIX standard but unnamed message_queues are.  This is also
7 *         the reason for the apparently unnecessary tracking of
8 *         the process_shared attribute.  [In addition to the fact that
9 *         it would be trivial to add pshared to the mq_attr structure
10 *         and have process private message queues.]
11 *
12 *         This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open
13 *         time.
14 */
15
16#include <stdarg.h>
17
18#include <pthread.h>
19#include <limits.h>
20#include <errno.h>
21#include <fcntl.h>
22
23#include <mqueue.h>
24#include <rtems/system.h>
25#include <rtems/score/watchdog.h>
26#include <rtems/posix/mqueue.h>
27#include <rtems/posix/time.h>
28
29/*PAGE
30 *
31 *  _POSIX_Message_queue_Manager_initialization
32 *
33 *  This routine initializes all message_queue manager related data structures.
34 *
35 *  Input parameters:
36 *    maximum_message_queues - maximum configured message_queues
37 *
38 *  Output parameters:  NONE
39 */
40 
41void _POSIX_Message_queue_Manager_initialization(
42  unsigned32 maximum_message_queues
43)
44{
45  _Objects_Initialize_information(
46    &_POSIX_Message_queue_Information,
47    OBJECTS_POSIX_MESSAGE_QUEUES,
48    TRUE,
49    maximum_message_queues,
50    sizeof( POSIX_Message_queue_Control ),
51    TRUE,
52    _POSIX_PATH_MAX,
53    FALSE
54  );
55}
56
57/*PAGE
58 *
59 *  _POSIX_Message_queue_Create_support
60 */
61 
62int _POSIX_Message_queue_Create_support(
63  const char                    *name,
64  int                            pshared,
65  unsigned int                   oflag,
66  struct mq_attr                *attr,
67  POSIX_Message_queue_Control  **message_queue
68)
69{
70  POSIX_Message_queue_Control   *the_mq;
71 
72  _Thread_Disable_dispatch();
73 
74  the_mq = _POSIX_Message_queue_Allocate();
75 
76  if ( !the_mq ) {
77    _Thread_Enable_dispatch();
78    seterrno( ENFILE );
79    return -1;
80  }
81 
82  if ( pshared == PTHREAD_PROCESS_SHARED &&
83       !( _Objects_MP_Allocate_and_open( &_POSIX_Message_queue_Information, 0,
84                            the_mq->Object.id, FALSE ) ) ) {
85    _POSIX_Message_queue_Free( the_mq );
86    _Thread_Enable_dispatch();
87    seterrno( ENFILE );
88    return -1;
89  }
90 
91  the_mq->process_shared  = pshared;
92 
93  if ( name ) {
94    the_mq->named = TRUE;
95    the_mq->open_count = 1;
96    the_mq->linked = TRUE;
97  }
98  else
99    the_mq->named = FALSE;
100 
101  if ( oflag & O_NONBLOCK )
102    the_mq->blocking = FALSE;
103  else
104    the_mq->blocking = TRUE;
105 
106  /* XXX
107   *
108   *  Note that this should be based on the current scheduling policy.
109   */
110
111  /* XXX
112   *
113   *  Message and waiting disciplines are not distinguished.
114   */
115/*
116  the_mq_attr->message_discipline = CORE_MESSAGE_QUEUE_DISCIPLINES_FIFO;
117  the_mq_attr->waiting_discipline = CORE_MESSAGE_QUEUE_DISCIPLINES_FIFO;
118 */
119
120  the_mq->Message_queue.Attributes.discipline =
121                                         CORE_MESSAGE_QUEUE_DISCIPLINES_FIFO;
122 
123  if ( ! _CORE_message_queue_Initialize(
124           &the_mq->Message_queue,
125           OBJECTS_POSIX_MESSAGE_QUEUES,
126           &the_mq->Message_queue.Attributes,
127           attr->mq_maxmsg,
128           attr->mq_msgsize,
129           _POSIX_Message_queue_MP_Send_extract_proxy ) ) {
130
131    if ( pshared == PTHREAD_PROCESS_SHARED )
132      _Objects_MP_Close( &_POSIX_Message_queue_Information, the_mq->Object.id );
133 
134    _POSIX_Message_queue_Free( the_mq );
135    _Thread_Enable_dispatch();
136    seterrno( ENOSPC );
137    return -1;
138  }
139
140 
141  /* XXX - need Names to be a string!!! */
142  _Objects_Open(
143    &_POSIX_Message_queue_Information,
144    &the_mq->Object,
145    (char *) name
146  );
147 
148  *message_queue = the_mq;
149 
150  if ( pshared == PTHREAD_PROCESS_SHARED )
151    _POSIX_Message_queue_MP_Send_process_packet(
152      POSIX_MESSAGE_QUEUE_MP_ANNOUNCE_CREATE,
153      the_mq->Object.id,
154      (char *) name,
155      0                          /* Not used */
156    );
157 
158  _Thread_Enable_dispatch();
159  return 0;
160}
161
162/*PAGE
163 *
164 *  15.2.2 Open a Message Queue, P1003.1b-1993, p. 272
165 */
166
167mqd_t mq_open(
168  const char *name,
169  int         oflag,
170  ...
171  /* mode_t mode, */
172  /* struct mq_attr  attr */
173)
174{
175  va_list arg;
176  mode_t mode;
177  struct mq_attr *attr;
178  int                        status;
179  Objects_Id                 the_mq_id;
180  POSIX_Message_queue_Control   *the_mq;
181 
182  if ( oflag & O_CREAT ) {
183    va_start(arg, oflag);
184    mode = (mode_t) va_arg( arg, mode_t * );
185    attr = (struct mq_attr *) va_arg( arg, struct mq_attr ** );
186    va_end(arg);
187  }
188 
189  status = _POSIX_Message_queue_Name_to_id( name, &the_mq_id );
190 
191  /*
192   *  If the name to id translation worked, then the message queue exists
193   *  and we can just return a pointer to the id.  Otherwise we may
194   *  need to check to see if this is a "message queue does not exist"
195   *  or some other miscellaneous error on the name.
196   */
197 
198  if ( status ) {
199 
200    if ( status == EINVAL ) {      /* name -> ID translation failed */
201      if ( !(oflag & O_CREAT) ) {  /* willing to create it? */
202        seterrno( ENOENT );
203        return (mqd_t) -1;
204      }
205      /* we are willing to create it */
206    }
207    seterrno( status );               /* some type of error */
208    return (mqd_t) -1;
209 
210  } else {                /* name -> ID translation succeeded */
211 
212    if ( (oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL) ) {
213      seterrno( EEXIST );
214      return (mqd_t) -1;
215    }
216 
217    /*
218     * XXX In this case we need to do an ID->pointer conversion to
219     *     check the mode.   This is probably a good place for a subroutine.
220     */
221 
222    the_mq->open_count += 1;
223 
224    return (mqd_t)&the_mq->Object.id;
225 
226  }
227 
228  /* XXX verify this comment...
229   *
230   *  At this point, the message queue does not exist and everything has been
231   *  checked. We should go ahead and create a message queue.
232   */
233 
234  status = _POSIX_Message_queue_Create_support(
235    name,
236    TRUE,         /* shared across processes */
237    oflag,
238    attr,
239    &the_mq
240  );
241 
242  if ( status == -1 )
243    return (mqd_t) -1;
244 
245  return (mqd_t) &the_mq->Object.id;
246}
247
248/*PAGE
249 *
250 *  _POSIX_Message_queue_Delete
251 */
252 
253void _POSIX_Message_queue_Delete(
254  POSIX_Message_queue_Control *the_mq
255)
256{
257  if ( !the_mq->linked && !the_mq->open_count ) {
258    _POSIX_Message_queue_Free( the_mq );
259 
260    if ( the_mq->process_shared == PTHREAD_PROCESS_SHARED ) {
261 
262      _Objects_MP_Close(
263        &_POSIX_Message_queue_Information,
264        the_mq->Object.id
265      );
266 
267      _POSIX_Message_queue_MP_Send_process_packet(
268        POSIX_MESSAGE_QUEUE_MP_ANNOUNCE_DELETE,
269        the_mq->Object.id,
270        0,                         /* Not used */
271        0                          /* Not used */
272      );
273    }
274 
275  }
276}
277
278/*PAGE
279 *
280 *  15.2.2 Close a Message Queue, P1003.1b-1993, p. 275
281 */
282
283int mq_close(
284  mqd_t  mqdes
285)
286{
287  register POSIX_Message_queue_Control *the_mq;
288  Objects_Locations                     location;
289 
290  the_mq = _POSIX_Message_queue_Get( mqdes, &location );
291  switch ( location ) {
292    case OBJECTS_ERROR:
293      seterrno( EINVAL );
294      return( -1 );
295    case OBJECTS_REMOTE:
296      _Thread_Dispatch();
297      return POSIX_MP_NOT_IMPLEMENTED();
298      seterrno( EINVAL );
299      return( -1 );
300    case OBJECTS_LOCAL:
301      the_mq->open_count -= 1;
302      _POSIX_Message_queue_Delete( the_mq );
303      _Thread_Enable_dispatch();
304      return 0;
305  }
306  return POSIX_BOTTOM_REACHED();
307}
308
309/*PAGE
310 *
311 *  15.2.2 Remove a Message Queue, P1003.1b-1993, p. 276
312 */
313
314int mq_unlink(
315  const char *name
316)
317{
318  int  status;
319  register POSIX_Message_queue_Control *the_mq;
320  Objects_Id                        the_mq_id;
321  Objects_Locations                 location;
322 
323  status = _POSIX_Message_queue_Name_to_id( name, &the_mq_id );
324 
325  if ( !status ) {
326    seterrno( status );
327    return -1;
328  }
329 
330  the_mq = _POSIX_Message_queue_Get( the_mq_id, &location );
331  switch ( location ) {
332    case OBJECTS_ERROR:
333      seterrno( EINVAL );
334      return( -1 );
335    case OBJECTS_REMOTE:
336      _Thread_Dispatch();
337      return POSIX_MP_NOT_IMPLEMENTED();
338      seterrno( EINVAL );
339      return( -1 );
340    case OBJECTS_LOCAL:
341 
342      _Objects_MP_Close(
343        &_POSIX_Message_queue_Information,
344        the_mq->Object.id
345      );
346 
347      the_mq->linked = FALSE;
348 
349      _POSIX_Message_queue_Delete( the_mq );
350 
351      _Thread_Enable_dispatch();
352      return 0;
353  }
354  return POSIX_BOTTOM_REACHED();
355}
356
357/*PAGE
358 *
359 *  _POSIX_Message_queue_Send_support
360 */
361 
362int _POSIX_Message_queue_Send_support(
363  mqd_t               mqdes,
364  const char         *msg_ptr,
365  unsigned32          msg_len,
366  Priority_Control    msg_prio,
367  Watchdog_Interval   timeout
368)
369{
370  register POSIX_Message_queue_Control *the_mq;
371  Objects_Locations                     location;
372 
373  the_mq = _POSIX_Message_queue_Get( mqdes, &location );
374  switch ( location ) {
375    case OBJECTS_ERROR:
376      seterrno( EINVAL );
377      return( -1 );
378    case OBJECTS_REMOTE:
379      _Thread_Dispatch();
380      return POSIX_MP_NOT_IMPLEMENTED();
381      seterrno( EINVAL );
382      return( -1 );
383    case OBJECTS_LOCAL:
384      /* XXX must add support for timeout and priority */
385      _CORE_message_queue_Send(
386        &the_mq->Message_queue,
387        (void *) msg_ptr,
388        msg_len,
389        mqdes,
390        NULL       /* XXX _POSIX_Message_queue_Core_message_queue_mp_support*/
391      );
392      _Thread_Enable_dispatch();
393      return _Thread_Executing->Wait.return_code;
394  }
395  return POSIX_BOTTOM_REACHED();
396}
397
398/*PAGE
399 *
400 *  15.2.4 Send a Message to a Message Queue, P1003.1b-1993, p. 277
401 *
402 *  NOTE: P1003.4b/D8, p. 45 adds mq_timedsend().
403 */
404
405int mq_send(
406  mqd_t         mqdes,
407  const char   *msg_ptr,
408  size_t        msg_len,
409  unsigned int  msg_prio
410)
411{
412  return _POSIX_Message_queue_Send_support(
413    mqdes,
414    msg_ptr,
415    msg_len,
416    msg_prio,
417    THREAD_QUEUE_WAIT_FOREVER
418  );
419}
420
421/*PAGE
422 *
423 *  15.2.4 Send a Message to a Message Queue, P1003.1b-1993, p. 277
424 *
425 *  NOTE: P1003.4b/D8, p. 45 adds mq_timedsend().
426 */
427
428int mq_timedsend(
429  mqd_t                  mqdes,
430  const char            *msg_ptr,
431  size_t                 msg_len,
432  unsigned int           msg_prio,
433  const struct timespec *timeout
434)
435{
436  return _POSIX_Message_queue_Send_support(
437    mqdes,
438    msg_ptr,
439    msg_len,
440    msg_prio,
441    _POSIX_Time_Spec_to_interval( timeout )
442  );
443}
444
445/*PAGE
446 *
447 *  _POSIX_Message_queue_Receive_support
448 */
449 
450/* XXX be careful ... watch the size going through all the layers ... */
451
452ssize_t _POSIX_Message_queue_Receive_support(
453  mqd_t               mqdes,
454  char               *msg_ptr,
455  size_t              msg_len,
456  unsigned int       *msg_prio,
457  Watchdog_Interval   timeout
458)
459{
460  register POSIX_Message_queue_Control *the_mq;
461  Objects_Locations                     location;
462  unsigned32                            status = 0;
463  unsigned32                            length_out;
464 
465  the_mq = _POSIX_Message_queue_Get( mqdes, &location );
466  switch ( location ) {
467    case OBJECTS_ERROR:
468      seterrno( EINVAL );
469      return( -1 );
470    case OBJECTS_REMOTE:
471      _Thread_Dispatch();
472      return POSIX_MP_NOT_IMPLEMENTED();
473      seterrno( EINVAL );
474      return( -1 );
475    case OBJECTS_LOCAL:
476      /* XXX need to define the options argument to this */
477      length_out = msg_len;
478      _CORE_message_queue_Seize(
479        &the_mq->Message_queue,
480        mqdes,
481        msg_ptr,
482        &length_out,
483        /* msg_prio,    XXXX */
484        the_mq->blocking,
485        timeout
486      );
487      _Thread_Enable_dispatch();
488      if ( !status )
489        return length_out;
490      /* XXX --- the return codes gotta be looked at .. fix this */
491      return _Thread_Executing->Wait.return_code;
492  }
493  return POSIX_BOTTOM_REACHED();
494}
495
496/*PAGE
497 *
498 *  15.2.5 Receive a Message From a Message Queue, P1003.1b-1993, p. 279
499 *
500 *  NOTE: P1003.4b/D8, p. 45 adds mq_timedreceive().
501 */
502
503ssize_t mq_receive(
504  mqd_t         mqdes,
505  char         *msg_ptr,
506  size_t        msg_len,
507  unsigned int *msg_prio
508)
509{
510  return _POSIX_Message_queue_Receive_support(
511    mqdes,
512    msg_ptr,
513    msg_len,
514    msg_prio,
515    THREAD_QUEUE_WAIT_FOREVER
516  );
517}
518
519/*PAGE
520 *
521 *  15.2.5 Receive a Message From a Message Queue, P1003.1b-1993, p. 279
522 *
523 *  NOTE: P1003.4b/D8, p. 45 adds mq_timedreceive().
524 */
525
526int mq_timedreceive(                  /* XXX: should this be ssize_t */
527  mqd_t                  mqdes,
528  char                  *msg_ptr,
529  size_t                 msg_len,
530  unsigned int          *msg_prio,
531  const struct timespec *timeout
532)
533{
534  return _POSIX_Message_queue_Receive_support(
535    mqdes,
536    msg_ptr,
537    msg_len,
538    msg_prio,
539    _POSIX_Time_Spec_to_interval( timeout )
540  );
541}
542
543/*PAGE
544 *
545 *  _POSIX_Message_queue_Notify_handler
546 *
547 */
548
549void _POSIX_Message_queue_Notify_handler(
550  void    *user_data
551)
552{
553  POSIX_Message_queue_Control *the_mq;
554
555  the_mq = user_data;
556
557  /* XXX do something with signals here!!!! */
558}
559
560/*PAGE
561 *
562 *  15.2.6 Notify Process that a Message is Available on a Queue,
563 *         P1003.1b-1993, p. 280
564 */
565
566int mq_notify(
567  mqd_t                  mqdes,
568  const struct sigevent *notification
569)
570{
571  register POSIX_Message_queue_Control *the_mq;
572  Objects_Locations                     location;
573 
574  the_mq = _POSIX_Message_queue_Get( mqdes, &location );
575  switch ( location ) {
576    case OBJECTS_ERROR:
577      seterrno( EBADF );
578      return( -1 );
579    case OBJECTS_REMOTE:
580      _Thread_Dispatch();
581      return POSIX_MP_NOT_IMPLEMENTED();
582      seterrno( EINVAL );
583      return( -1 );
584    case OBJECTS_LOCAL:
585      if ( notification ) {
586        if ( _CORE_message_queue_Is_notify_enabled( &the_mq->Message_queue ) ) {
587          _Thread_Enable_dispatch();
588          seterrno( EBUSY );
589          return( -1 );
590        }
591
592        _CORE_message_queue_Set_notify( &the_mq->Message_queue, NULL, NULL );
593
594        the_mq->notification = *notification;
595     
596        _CORE_message_queue_Set_notify(
597          &the_mq->Message_queue,
598          _POSIX_Message_queue_Notify_handler,
599          the_mq
600        );
601      } else {
602
603        _CORE_message_queue_Set_notify( &the_mq->Message_queue, NULL, NULL );
604
605      }
606
607      _Thread_Enable_dispatch();
608      return 0;
609  }
610  return POSIX_BOTTOM_REACHED();
611}
612
613/*PAGE
614 *
615 *  15.2.7 Set Message Queue Attributes, P1003.1b-1993, p. 281
616 */
617
618int mq_setattr(
619  mqd_t                 mqdes,
620  const struct mq_attr *mqstat,
621  struct mq_attr       *omqstat
622)
623{
624  register POSIX_Message_queue_Control *the_mq;
625  Objects_Locations                     location;
626  CORE_message_queue_Attributes        *the_mq_attr;
627 
628  the_mq = _POSIX_Message_queue_Get( mqdes, &location );
629  switch ( location ) {
630    case OBJECTS_ERROR:
631      seterrno( EINVAL );
632      return( -1 );
633    case OBJECTS_REMOTE:
634      _Thread_Dispatch();
635      return POSIX_MP_NOT_IMPLEMENTED();
636      seterrno( EINVAL );
637      return( -1 );
638    case OBJECTS_LOCAL:
639      /*
640       *  Return the old values.
641       */
642
643      /* XXX this is the same stuff as is in mq_getattr... and probably */
644      /* XXX should be in an inlined private routine */
645
646      the_mq_attr = &the_mq->Message_queue.Attributes;
647
648      omqstat->mq_flags   = the_mq->flags;
649      omqstat->mq_msgsize = the_mq->Message_queue.maximum_message_size;
650      omqstat->mq_maxmsg  = the_mq->Message_queue.maximum_pending_messages;
651      omqstat->mq_curmsgs = the_mq->Message_queue.number_of_pending_messages;
652 
653      /*
654       *  Ignore everything except the O_NONBLOCK bit.
655       */
656
657      if (  mqstat->mq_flags & O_NONBLOCK )
658        the_mq->blocking = FALSE;
659      else
660        the_mq->blocking = TRUE;
661 
662      the_mq->flags = mqstat->mq_flags;
663
664      _Thread_Enable_dispatch();
665      return 0;
666  }
667  return POSIX_BOTTOM_REACHED();
668}
669
670/*PAGE
671 *
672 *  15.2.8 Get Message Queue Attributes, P1003.1b-1993, p. 283
673 */
674
675int mq_getattr(
676  mqd_t           mqdes,
677  struct mq_attr *mqstat
678)
679{
680  register POSIX_Message_queue_Control *the_mq;
681  Objects_Locations                     location;
682  CORE_message_queue_Attributes        *the_mq_attr;
683 
684  the_mq = _POSIX_Message_queue_Get( mqdes, &location );
685  switch ( location ) {
686    case OBJECTS_ERROR:
687      seterrno( EINVAL );
688      return( -1 );
689    case OBJECTS_REMOTE:
690      _Thread_Dispatch();
691      return POSIX_MP_NOT_IMPLEMENTED();
692      seterrno( EINVAL );
693      return( -1 );
694    case OBJECTS_LOCAL:
695      /*
696       *  Return the old values.
697       */
698 
699      /* XXX this is the same stuff as is in mq_setattr... and probably */
700      /* XXX should be in an inlined private routine */
701 
702      the_mq_attr = &the_mq->Message_queue.Attributes;
703 
704      mqstat->mq_flags   = the_mq->flags;
705      mqstat->mq_msgsize = the_mq->Message_queue.maximum_message_size;
706      mqstat->mq_maxmsg  = the_mq->Message_queue.maximum_pending_messages;
707      mqstat->mq_curmsgs = the_mq->Message_queue.number_of_pending_messages;
708 
709      _Thread_Enable_dispatch();
710      return 0;
711  }
712  return POSIX_BOTTOM_REACHED();
713}
Note: See TracBrowser for help on using the repository browser.