source: rtems/cpukit/posix/src/mqueue.c @ 67d224a

4.104.114.84.95
Last change on this file since 67d224a was eb5a7e07, checked in by Joel Sherrill <joel.sherrill@…>, on 10/06/95 at 20:48:38

fixed missing CVS IDs

  • 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
25#include <mqueue.h>
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.