source: rtems/cpukit/posix/src/mqueue.c @ fa03f08

4.104.114.84.95
Last change on this file since fa03f08 was 5b748a1, checked in by Joel Sherrill <joel.sherrill@…>, on 06/03/96 at 17:32:19

renamed _POSIX_Time_Spec_to_interval to _POSIX_Timespec_to_interval

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