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

4.104.114.84.95
Last change on this file since f4719d5a was f4719d5a, checked in by Joel Sherrill <joel.sherrill@…>, on 05/22/96 at 22:32:39

These files have been modified in the initial pass at getting the portion
of the POSIX API necessary to support the GNAT runtime to initially compile.
We now have verified that the specifications for the necessary routines
are correct per the POSIX standards we have.

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