1 /*========================================================================
5 // Message queues tests
7 //========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //========================================================================
41 //#####DESCRIPTIONBEGIN####
43 // Author(s): jlarmour
46 // Purpose: This file provides the implementation for POSIX message
48 // Description: It uses eCos kernel mqueues as the underlying
52 //####DESCRIPTIONEND####
54 //======================================================================
59 #include <pkgconf/posix.h>
61 #include <pkgconf/kernel.h>
65 #include <cyg/infra/cyg_type.h> // common types etc.
66 #include <cyg/infra/cyg_ass.h> // Assertion support
67 #include <cyg/infra/cyg_trac.h> // Tracing support
68 #include <cyg/kernel/mqueue.hxx> // eCos Mqueue Header
69 #include <cyg/kernel/sched.hxx> // Cyg_Scheduler::lock()
70 #include <cyg/kernel/sched.inl> // inlines for above
71 #include <mqueue.h> // Standard POSIX mqueue header
72 #include <sys/types.h> // mode_t, ssize_t
73 #include <limits.h> // PATH_MAX
74 #include <stdlib.h> // malloc, etc.
75 #include <errno.h> // errno
76 #include <fcntl.h> // O_*
77 #include <stdarg.h> // varargs
78 #include <pthread.h> // mutexes
79 #include <string.h> // strncpy
80 #ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
82 # include "pprivate.h" // cyg_sigqueue()
84 #ifdef CYGFUN_KERNEL_THREADS_TIMER
86 # include "pprivate.h" // cyg_timespec_to_ticks()
91 #define MQ_VALID_MAGIC 0x6db256c1
93 /* TYPE DEFINITIONS */
97 // this is a queue user - each one of these corresponds to a mqd_t
99 int flags; // O_RDONLY, O_WRONLY, O_RDWR, O_NONBLOCK
100 struct mqtabent *tabent; // back pointer to table entry
102 bool notifieruser; // POSIX sucks so bad. It requires a mq_close
103 // to only deregister the notification if it
104 // was done via this descriptor. So we have to
105 // know if it was this one
106 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
107 cyg_uint32 magic; // magic number: MQ_VALID_MAGIC if valid
112 char name[ PATH_MAX ]; // ascii name - set to "" when unused
113 Cyg_Mqueue *mq; // the underlying queue object
114 long maxmsg; // as set on creation
115 long msgsize; // as set on creation
116 bool unlinkme; // unlink when final user closes?
117 struct mquser *users; // each user
119 #ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
120 const struct sigevent *sigev; // notification event
126 static struct mqtabent mqtab[ CYGNUM_POSIX_MQUEUE_OPEN_MAX ];
127 static pthread_mutex_t mqtab_mut = PTHREAD_MUTEX_INITIALIZER;
129 /* LOCAL FUNCTIONS */
131 //------------------------------------------------------------------------
133 // placement new definition
134 inline void *operator new(size_t size, void *ptr)
136 CYG_CHECK_DATA_PTR( ptr, "Bad pointer" );
140 // Deallocation callback from Cyg_Mqueue
142 my_free( void *ptr, size_t )
147 //------------------------------------------------------------------------
149 // Do the actual "unlink" of a queue, i.e. mark it invalid in the table.
150 // The table mutex is assumed to be locked
152 do_mq_unlink( struct mqtabent *tabent )
154 CYG_REPORT_FUNCTION();
155 CYG_CHECK_DATA_PTRC( tabent );
157 tabent->name[0] = '\0'; // won't match anything the user sends now
158 tabent->mq->~Cyg_Mqueue();
165 //------------------------------------------------------------------------
167 #ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
170 notifyme( Cyg_Mqueue &q, CYG_ADDRWORD data )
172 CYG_REPORT_FUNCTION();
173 struct mquser *user = (struct mquser *)data;
174 CYG_CHECK_DATA_PTRC( user );
175 struct mqtabent *tabent = user->tabent;
176 CYG_CHECK_DATA_PTRC( tabent );
178 Cyg_Scheduler::lock();
179 // we may have been pre-empted before this, so check there's still a
180 // notification to do
182 if ( NULL == tabent->sigev ) {
183 Cyg_Scheduler::unlock();
188 const struct sigevent *ev = tabent->sigev;
191 q.setnotify( NULL, 0 );
192 tabent->sigev = NULL;
193 user->notifieruser = false; // not any more
195 // now the rest of the world can go
196 Cyg_Scheduler::unlock();
198 // queue event. If it fails... nothing we can do :-( so ignore return code
199 cyg_sigqueue( ev, SI_MESGQ );
201 cyg_deliver_signals();
206 #endif // ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
208 //------------------------------------------------------------------------
210 /* EXPORTED FUNCTIONS */
213 mq_open( const char *name, int oflag, ... )
215 CYG_REPORT_FUNCTYPE( "returning %08x" );
216 CYG_REPORT_FUNCARG2( "name=%08x, oflag=%d", name, oflag );
217 CYG_CHECK_DATA_PTRC( name );
219 if ( ((oflag & O_RDONLY) != O_RDONLY) &&
220 ((oflag & O_WRONLY) != O_WRONLY) &&
221 ((oflag & O_RDWR) != O_RDWR)) {
222 // user didn't specify mode
224 CYG_REPORT_RETVAL( -1 );
230 struct mqtabent *qtabent=NULL;
233 interr = pthread_mutex_lock( &mqtab_mut );
235 CYG_ASSERT( interr == 0, "internal lock failed!" );
237 // find if a matching entry exists first
238 // FIXME: Should check for length and return ENAMETOOLONG
239 for ( i=0; i < CYGNUM_POSIX_MQUEUE_OPEN_MAX; i++ ) {
240 if ( 0 == strncmp(name, mqtab[i].name, PATH_MAX) ) {
246 if ( (NULL != qtabent) && (O_EXCL == (oflag & O_EXCL)) ) {
252 if ( (NULL == qtabent) && (O_CREAT != (oflag & O_CREAT)) ) {
258 // so if we didn't find something, we must be being asked to create it
259 if (NULL == qtabent) {
260 mode_t mode; // FIXME: mode ignored for now
261 const struct mq_attr *attr;
262 const struct mq_attr default_attr = { 0, MQ_OPEN_MAX, 128 };
265 va_start( args, oflag );
266 mode = va_arg( args, mode_t );
267 attr = va_arg( args, struct mq_attr * );
270 // find an empty table entry
271 for ( i=0; i < CYGNUM_POSIX_MQUEUE_OPEN_MAX; i++ ) {
272 if ( NULL == mqtab[i].mq )
276 // if not found, table is full
277 if ( i == CYGNUM_POSIX_MQUEUE_OPEN_MAX ) {
283 Cyg_Mqueue::qerr_t qerr;
285 // user can specify NULL attr, which means arbitrary message queue
288 attr = &default_attr;
290 // if they do supply one, POSIX says we're meant to check it
291 if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0) {
298 // allocate the underlying queue
299 Cyg_Mqueue *mqholder = (Cyg_Mqueue *)malloc( sizeof(Cyg_Mqueue) );
300 if ( NULL == mqholder ) {
306 // construct it with placement new
307 mqtab[i].mq = new (mqholder) Cyg_Mqueue( attr->mq_maxmsg,
309 &malloc, &my_free, &qerr );
314 case Cyg_Mqueue::NOMEM:
320 CYG_FAIL("Unhandled Cyg_Mqueue constructor return error");
324 mqtab[i].users = (struct mquser *) malloc( sizeof(struct mquser) );
325 if ( NULL == mqtab[i].users ) {
326 mqtab[i].mq->~Cyg_Mqueue();
333 // initialize mqtab[i]
334 mqtab[i].maxmsg = attr->mq_maxmsg;
335 mqtab[i].msgsize = attr->mq_msgsize;
336 mqtab[i].unlinkme = false;
337 #ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
338 mqtab[i].sigev = NULL;
340 strncpy( mqtab[i].name, name, PATH_MAX );
342 // initialize first mqtab[i].users
343 mqtab[i].users->next = NULL;
344 // set the mode for later, but also note that O_NONBLOCK can
345 // be set in oflags *or* the attr the user passed
346 mqtab[i].users->flags = oflag | (attr->mq_flags & O_NONBLOCK);
348 // set back pointer so that message queue handle can find actual queue
349 mqtab[i].users->tabent = &mqtab[i];
351 mqtab[i].users->notifieruser = false;
353 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
354 mqtab[i].users->magic = MQ_VALID_MAGIC; // now valid
357 retval=(mqd_t)mqtab[i].users;
360 } // if (NULL == qtabent)
362 // so we're not creating, and we have a valid qtabent
364 // But this qtabent may be being unlinked. If so, we are permitted
365 // to return an error, so we will. (see under mq_unlink() in POSIX)
366 // Which error though? EINVAL seems best, but POSIX doesn't say :-/
368 if (true == qtabent->unlinkme) {
374 // now we have a usable qtabent
377 user = (struct mquser *) malloc( sizeof(struct mquser) );
378 if ( NULL == user ) {
384 // prepend to qtab user list
385 user->next = qtabent->users;
386 qtabent->users = user;
388 // set back pointer so that message queue handle can find actual queue
389 user->tabent = qtabent;
393 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
394 user->magic = MQ_VALID_MAGIC; // now valid
400 interr = pthread_mutex_unlock( &mqtab_mut );
402 CYG_ASSERT( interr == 0, "internal lock failed!" );
403 CYG_REPORT_RETVAL( retval );
407 //------------------------------------------------------------------------
409 // NOTE: It is the *user*'s responsibility to ensure that nothing is
410 // blocked in mq_send() or mq_receive() when closing the queue with
411 // that descriptor. The standard does not specify the behaviour, so that's
412 // what I am assuming
415 mq_close( mqd_t mqdes )
417 CYG_REPORT_FUNCTYPE( "returning %d" );
418 CYG_REPORT_FUNCARG1XV( mqdes );
420 struct mquser *user = (struct mquser *)mqdes;
422 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
423 if ( user->magic != MQ_VALID_MAGIC ) {
425 CYG_REPORT_RETVAL( -1 );
432 interr = pthread_mutex_lock( &mqtab_mut );
434 CYG_ASSERT( interr == 0, "internal lock failed!" );
436 struct mqtabent *tabent = user->tabent;
437 struct mquser *usertmp;
439 // perhaps should return EBADF instead of assert?
440 CYG_ASSERT( tabent->users != NULL, "Null message queue user list" );
442 #ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
443 // deregister notification iff this was the message queue descriptor
444 // that was used to register it (POSIX says)
445 if ( true == user->notifieruser ) {
446 tabent->mq->setnotify( NULL, 0 );
447 tabent->sigev = NULL;
448 // not worth clearing notifieruser
452 // find in the list for this queue and remove - sucks a bit, but seems
453 // best over all - the list shouldn't be too long
454 if ( tabent->users == user ) {
455 tabent->users = user->next; // remove
457 for ( usertmp=tabent->users;
458 NULL != usertmp->next;
459 usertmp = usertmp->next ) {
460 if ( usertmp->next == user )
464 // perhaps should return EBADF instead of assert?
465 CYG_ASSERT( usertmp->next != NULL, "Couldn't find message queue user" );
467 usertmp->next = user->next; // remove
470 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
471 user->magic = 0; // invalidate
477 if ( (true == tabent->unlinkme) && (NULL == tabent->users) ) {
478 do_mq_unlink( tabent );
481 interr = pthread_mutex_unlock( &mqtab_mut );
483 CYG_ASSERT( interr == 0, "internal lock failed!" );
484 CYG_REPORT_RETVAL( 0 );
489 //------------------------------------------------------------------------
492 mq_unlink( const char *name )
494 CYG_REPORT_FUNCTYPE( "returning %d" );
495 CYG_REPORT_FUNCARG1( "name=%s", name );
499 struct mqtabent *qtabent=NULL;
501 interr = pthread_mutex_lock( &mqtab_mut );
503 CYG_ASSERT( interr == 0, "internal lock failed!" );
505 // find the entry first
506 // FIXME: Should check for length and return ENAMETOOLONG
507 for ( i=0; i < CYGNUM_POSIX_MQUEUE_OPEN_MAX; i++ ) {
508 if ( 0 == strncmp(name, mqtab[i].name, PATH_MAX) ) {
514 if ( NULL == qtabent ) { // not found
520 if ( NULL != qtabent->users ) { // still in use
521 qtabent->unlinkme = true; // so mark it as pending deletion
523 do_mq_unlink( qtabent );
529 interr = pthread_mutex_unlock( &mqtab_mut );
531 CYG_ASSERT( interr == 0, "internal lock failed!" );
532 CYG_REPORT_RETVAL( retval );
536 //------------------------------------------------------------------------
539 mq_send( mqd_t mqdes, const char *msg_ptr, size_t msg_len,
540 unsigned int msg_prio )
542 CYG_REPORT_FUNCTYPE( "returning %d" );
543 CYG_REPORT_FUNCARG4( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%u",
544 mqdes, msg_ptr, msg_len, msg_prio );
545 CYG_CHECK_DATA_PTRC( msg_ptr );
547 struct mquser *user = (struct mquser *)mqdes;
548 struct mqtabent *tabent = user->tabent;
550 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
551 if ( user->magic != MQ_VALID_MAGIC ) {
553 CYG_REPORT_RETVAL( -1 );
558 if ( msg_len > (size_t)tabent->msgsize ) {
560 CYG_REPORT_RETVAL( -1 );
564 if ( msg_prio > MQ_PRIO_MAX ) {
566 CYG_REPORT_RETVAL( -1 );
570 if ( (O_WRONLY != (user->flags & O_WRONLY)) &&
571 (O_RDWR != (user->flags & O_RDWR)) ) {
573 CYG_REPORT_RETVAL( -1 );
578 Cyg_Mqueue::qerr_t err;
579 err = tabent->mq->put( msg_ptr, msg_len, msg_prio,
580 ((user->flags & O_NONBLOCK) != O_NONBLOCK) );
583 case Cyg_Mqueue::INTR:
585 CYG_REPORT_RETVAL( -1 );
588 case Cyg_Mqueue::WOULDBLOCK:
589 CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
590 "Message queue assumed non-blocking when blocking requested"
593 CYG_REPORT_RETVAL( -1 );
597 CYG_REPORT_RETVAL( 0 );
601 CYG_FAIL( "unhandled message queue return code" );
602 return -1; // keep compiler happy
606 //------------------------------------------------------------------------
610 mq_receive( mqd_t mqdes, char *msg_ptr, size_t msg_len,
611 unsigned int *msg_prio )
613 CYG_REPORT_FUNCTYPE( "returning %ld" );
614 CYG_REPORT_FUNCARG4( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%08x",
615 mqdes, msg_ptr, msg_len, msg_prio );
616 CYG_CHECK_DATA_PTRC( msg_ptr );
617 CYG_CHECK_DATA_PTRC( msg_ptr+msg_len-1 );
618 if ( NULL != msg_prio )
619 CYG_CHECK_DATA_PTRC( msg_prio );
622 struct mquser *user = (struct mquser *)mqdes;
623 struct mqtabent *tabent = user->tabent;
625 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
626 if ( user->magic != MQ_VALID_MAGIC ) {
628 CYG_REPORT_RETVAL( -1 );
633 if ( (O_RDONLY != (user->flags & O_RDONLY)) &&
634 (O_RDWR != (user->flags & O_RDWR)) ) {
636 CYG_REPORT_RETVAL( -1 );
640 if ( msg_len < (size_t)tabent->msgsize ) {
642 CYG_REPORT_RETVAL( -1 );
647 Cyg_Mqueue::qerr_t err;
648 err = tabent->mq->get( msg_ptr, &msg_len, msg_prio,
649 ((user->flags & O_NONBLOCK) != O_NONBLOCK) );
652 case Cyg_Mqueue::INTR:
654 CYG_REPORT_RETVAL( -1 );
657 case Cyg_Mqueue::WOULDBLOCK:
658 CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
659 "Message queue assumed non-blocking when blocking requested"
662 CYG_REPORT_RETVAL( -1 );
666 CYG_ASSERT( msg_len <= (size_t)tabent->msgsize,
667 "returned message too long" );
668 if ( NULL != msg_prio )
669 CYG_ASSERT( *msg_prio <= MQ_PRIO_MAX,
670 "returned message has invalid priority" );
671 CYG_REPORT_RETVAL( msg_len );
672 return (ssize_t)msg_len;
675 CYG_FAIL( "unhandled message queue return code" );
676 return (ssize_t)-1; // keep compiler happy
682 //------------------------------------------------------------------------
683 #ifdef CYGFUN_KERNEL_THREADS_TIMER
685 mq_timedsend( mqd_t mqdes, const char *msg_ptr, size_t msg_len,
686 unsigned int msg_prio, const struct timespec *abs_timeout)
688 CYG_REPORT_FUNCTYPE( "returning %d" );
689 CYG_REPORT_FUNCARG6( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%u, "
690 "abs_timeout = %lu, %ld",
691 mqdes, msg_ptr, msg_len, msg_prio,
692 abs_timeout->tv_sec, abs_timeout->tv_nsec);
693 CYG_CHECK_DATA_PTRC( msg_ptr );
695 struct mquser *user = (struct mquser *)mqdes;
696 struct mqtabent *tabent = user->tabent;
698 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
699 if ( user->magic != MQ_VALID_MAGIC ) {
701 CYG_REPORT_RETVAL( -1 );
706 if ( msg_len > (size_t)tabent->msgsize ) {
708 CYG_REPORT_RETVAL( -1 );
712 if ( msg_prio > MQ_PRIO_MAX ) {
714 CYG_REPORT_RETVAL( -1 );
718 if ( (O_WRONLY != (user->flags & O_WRONLY)) &&
719 (O_RDWR != (user->flags & O_RDWR)) ) {
721 CYG_REPORT_RETVAL( -1 );
726 Cyg_Mqueue::qerr_t err;
727 bool nonblocking = ((user->flags & O_NONBLOCK) == O_NONBLOCK);
728 bool badtimespec = (abs_timeout->tv_nsec < 0) ||
729 (abs_timeout->tv_nsec > 999999999l);
730 cyg_tick_count abs_ticks = cyg_timespec_to_ticks(abs_timeout);
732 // We should never time out if there is room in the queue. Simplest
733 // way to ensure this is to try the non-blocking put() first.
734 err = tabent->mq->put( msg_ptr, msg_len, msg_prio, false, abs_ticks );
736 // If the blocking variant would have blocked and that is what's wanted
737 if ( Cyg_Mqueue::WOULDBLOCK == err && !nonblocking && !badtimespec ) {
738 err = tabent->mq->put( msg_ptr, msg_len, msg_prio, true,
744 case Cyg_Mqueue::INTR:
746 CYG_REPORT_RETVAL( -1 );
749 case Cyg_Mqueue::WOULDBLOCK:
752 CYG_REPORT_RETVAL( -1 );
755 CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
756 "Message queue assumed non-blocking when blocking requested"
759 CYG_REPORT_RETVAL( -1 );
762 case Cyg_Mqueue::TIMEOUT:
764 CYG_REPORT_RETVAL( -1 );
768 CYG_REPORT_RETVAL( 0 );
772 CYG_FAIL( "unhandled message queue return code" );
773 return -1; // keep compiler happy
777 //------------------------------------------------------------------------
781 mq_timedreceive( mqd_t mqdes, char *msg_ptr, size_t msg_len,
782 unsigned int *msg_prio, const struct timespec *abs_timeout)
784 CYG_REPORT_FUNCTYPE( "returning %ld" );
785 CYG_REPORT_FUNCARG6( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%08x, "
786 "abs_timeout = %lu, %ld",
787 mqdes, msg_ptr, msg_len, msg_prio,
788 abs_timeout->tv_sec, abs_timeout->tv_nsec );
789 CYG_CHECK_DATA_PTRC( msg_ptr );
790 CYG_CHECK_DATA_PTRC( msg_ptr+msg_len-1 );
791 if ( NULL != msg_prio )
792 CYG_CHECK_DATA_PTRC( msg_prio );
795 struct mquser *user = (struct mquser *)mqdes;
796 struct mqtabent *tabent = user->tabent;
798 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
799 if ( user->magic != MQ_VALID_MAGIC ) {
801 CYG_REPORT_RETVAL( -1 );
806 if ( (O_RDONLY != (user->flags & O_RDONLY)) &&
807 (O_RDWR != (user->flags & O_RDWR)) ) {
809 CYG_REPORT_RETVAL( -1 );
813 if ( msg_len < (size_t)tabent->msgsize ) {
815 CYG_REPORT_RETVAL( -1 );
820 Cyg_Mqueue::qerr_t err;
821 bool nonblocking = ((user->flags & O_NONBLOCK) == O_NONBLOCK);
822 bool badtimespec = (abs_timeout->tv_nsec < 0) ||
823 (abs_timeout->tv_nsec > 999999999l);
824 cyg_tick_count abs_ticks = cyg_timespec_to_ticks(abs_timeout);
826 // We should never time out if there is something to read. Simplest
827 // way to ensure this is to try the non-blocking get() first.
828 err = tabent->mq->get( msg_ptr, &msg_len, msg_prio, false, abs_ticks );
830 // If the blocking variant would have blocked and that is what's wanted
831 if ( Cyg_Mqueue::WOULDBLOCK == err && !nonblocking && !badtimespec ) {
832 err = tabent->mq->get( msg_ptr, &msg_len, msg_prio, true, abs_ticks );
837 case Cyg_Mqueue::INTR:
839 CYG_REPORT_RETVAL( -1 );
842 case Cyg_Mqueue::WOULDBLOCK:
845 CYG_REPORT_RETVAL( -1 );
848 CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
849 "Message queue assumed non-blocking when blocking requested"
852 CYG_REPORT_RETVAL( -1 );
855 case Cyg_Mqueue::TIMEOUT:
857 CYG_REPORT_RETVAL( -1 );
861 CYG_ASSERT( msg_len <= (size_t)tabent->msgsize,
862 "returned message too long" );
863 if ( NULL != msg_prio )
864 CYG_ASSERT( *msg_prio <= MQ_PRIO_MAX,
865 "returned message has invalid priority" );
866 CYG_REPORT_RETVAL( msg_len );
867 return (ssize_t)msg_len;
870 CYG_FAIL( "unhandled message queue return code" );
871 return (ssize_t)-1; // keep compiler happy
874 } // mq_timedreceive()
876 //------------------------------------------------------------------------
879 #ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
882 mq_notify( mqd_t mqdes, const struct sigevent *notification )
884 CYG_REPORT_FUNCTYPE( "returning %d" );
885 CYG_REPORT_FUNCARG2( "mqdes=%08x, notification=%08x", mqdes, notification );
886 if ( NULL != notification )
887 CYG_CHECK_DATA_PTRC( notification );
889 struct mquser *user = (struct mquser *)mqdes;
890 struct mqtabent *tabent = user->tabent;
892 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
893 if ( user->magic != MQ_VALID_MAGIC ) {
895 CYG_REPORT_RETVAL( -1 );
900 // lock scheduler since we test and set non-atomically
901 Cyg_Scheduler::lock();
903 // we are being told to clear the notification function
904 if ( NULL == notification ) {
905 tabent->mq->setnotify( NULL, 0 );
906 tabent->sigev = NULL;
907 Cyg_Scheduler::unlock();
908 CYG_REPORT_RETVAL( 0 );
912 if ( NULL != tabent->sigev ) { // already registered
913 Cyg_Scheduler::unlock();
915 CYG_REPORT_RETVAL( -1 );
919 tabent->sigev = notification;
920 user->notifieruser = true; // Used for deciding about whether to
921 // deregister in mq_close()
922 tabent->mq->setnotify( ¬ifyme, (CYG_ADDRWORD) user );
923 Cyg_Scheduler::unlock();
925 CYG_REPORT_RETVAL( 0 );
929 #endif // ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
931 //------------------------------------------------------------------------
934 mq_setattr( mqd_t mqdes, const struct mq_attr *mqstat,
935 struct mq_attr *omqstat )
937 CYG_REPORT_FUNCTYPE( "returning %d" );
938 CYG_REPORT_FUNCARG3( "mqdes=%08x, mqstat=%08x, omqstat=%08x",
939 mqdes, mqstat, omqstat );
940 CYG_CHECK_DATA_PTRC( mqstat );
942 struct mquser *user = (struct mquser *)mqdes;
944 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
945 if ( user->magic != MQ_VALID_MAGIC ) {
947 CYG_REPORT_RETVAL( -1 );
952 if ( NULL != omqstat ) {
953 CYG_CHECK_DATA_PTRC( omqstat );
954 mq_getattr( mqdes, omqstat );
957 // Two-stage update, so lock sched since it's quick
958 Cyg_Scheduler::lock();
959 user->flags &= ~O_NONBLOCK; // clear
960 if ( (mqstat->mq_flags & O_NONBLOCK) == O_NONBLOCK ) {
961 user->flags |= O_NONBLOCK;
963 Cyg_Scheduler::unlock();
965 CYG_REPORT_RETVAL( 0 );
969 //------------------------------------------------------------------------
972 mq_getattr( mqd_t mqdes, struct mq_attr *mqstat )
974 CYG_REPORT_FUNCTYPE( "returning %d" );
975 CYG_REPORT_FUNCARG2( "mqdes=%08x, mqstat=%08x", mqdes, mqstat );
976 CYG_CHECK_DATA_PTRC( mqstat );
978 struct mquser *user = (struct mquser *)mqdes;
979 struct mqtabent *tabent = user->tabent;
981 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
982 if ( user->magic != MQ_VALID_MAGIC ) {
984 CYG_REPORT_RETVAL( -1 );
989 mqstat->mq_flags = user->flags;
990 mqstat->mq_maxmsg = tabent->maxmsg;
991 mqstat->mq_msgsize = tabent->msgsize;
992 mqstat->mq_curmsgs = tabent->mq->count();
994 CYG_REPORT_RETVAL( 0 );
999 //------------------------------------------------------------------------
1001 /* EOF mqueue.cxx */