source: rtems/c/src/exec/posix/src/mqueue.c @ 05ce4e09

4.104.114.84.95
Last change on this file since 05ce4e09 was 05ce4e09, checked in by Joel Sherrill <joel.sherrill@…>, on 06/07/96 at 15:21:27

changed code which set errno and then returned -1 to use the macro
set_errno_and_return_minus_one.

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