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 #ifdef CYGPKG_POSIX_MQUEUES
63 #include <pkgconf/kernel.h>
67 #include <cyg/infra/cyg_type.h> // common types etc.
68 #include <cyg/infra/cyg_ass.h> // Assertion support
69 #include <cyg/infra/cyg_trac.h> // Tracing support
70 #include <cyg/kernel/mqueue.hxx> // eCos Mqueue Header
71 #include <cyg/kernel/sched.hxx> // Cyg_Scheduler::lock()
72 #include <cyg/kernel/sched.inl> // inlines for above
73 #include <mqueue.h> // Standard POSIX mqueue header
74 #include <sys/types.h> // mode_t, ssize_t
75 #include <limits.h> // PATH_MAX
76 #include <stdlib.h> // malloc, etc.
77 #include <errno.h> // errno
78 #include <fcntl.h> // O_*
79 #include <stdarg.h> // varargs
80 #include <pthread.h> // mutexes
81 #include <string.h> // strncpy
82 #ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
84 # include "pprivate.h" // cyg_sigqueue()
86 #ifdef CYGFUN_KERNEL_THREADS_TIMER
88 # include "pprivate.h" // cyg_timespec_to_ticks()
93 #define MQ_VALID_MAGIC 0x6db256c1
95 /* TYPE DEFINITIONS */
99 // this is a queue user - each one of these corresponds to a mqd_t
101 int flags; // O_RDONLY, O_WRONLY, O_RDWR, O_NONBLOCK
102 struct mqtabent *tabent; // back pointer to table entry
104 bool notifieruser; // POSIX sucks so bad. It requires a mq_close
105 // to only deregister the notification if it
106 // was done via this descriptor. So we have to
107 // know if it was this one
108 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
109 cyg_uint32 magic; // magic number: MQ_VALID_MAGIC if valid
114 char name[ PATH_MAX ]; // ascii name - set to "" when unused
115 Cyg_Mqueue *mq; // the underlying queue object
116 long maxmsg; // as set on creation
117 long msgsize; // as set on creation
118 bool unlinkme; // unlink when final user closes?
119 struct mquser *users; // each user
121 #ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
122 const struct sigevent *sigev; // notification event
128 static struct mqtabent mqtab[ CYGNUM_POSIX_MQUEUE_OPEN_MAX ];
129 static pthread_mutex_t mqtab_mut = PTHREAD_MUTEX_INITIALIZER;
131 /* LOCAL FUNCTIONS */
133 //------------------------------------------------------------------------
135 // placement new definition
136 inline void *operator new(size_t size, void *ptr)
138 CYG_CHECK_DATA_PTR( ptr, "Bad pointer" );
142 // Deallocation callback from Cyg_Mqueue
144 my_free( void *ptr, size_t )
149 //------------------------------------------------------------------------
151 // Do the actual "unlink" of a queue, i.e. mark it invalid in the table.
152 // The table mutex is assumed to be locked
154 do_mq_unlink( struct mqtabent *tabent )
156 CYG_REPORT_FUNCTION();
157 CYG_CHECK_DATA_PTRC( tabent );
159 tabent->name[0] = '\0'; // won't match anything the user sends now
160 tabent->mq->~Cyg_Mqueue();
167 //------------------------------------------------------------------------
169 #ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
172 notifyme( Cyg_Mqueue &q, CYG_ADDRWORD data )
174 CYG_REPORT_FUNCTION();
175 struct mquser *user = (struct mquser *)data;
176 CYG_CHECK_DATA_PTRC( user );
177 struct mqtabent *tabent = user->tabent;
178 CYG_CHECK_DATA_PTRC( tabent );
180 Cyg_Scheduler::lock();
181 // we may have been pre-empted before this, so check there's still a
182 // notification to do
184 if ( NULL == tabent->sigev ) {
185 Cyg_Scheduler::unlock();
190 const struct sigevent *ev = tabent->sigev;
193 q.setnotify( NULL, 0 );
194 tabent->sigev = NULL;
195 user->notifieruser = false; // not any more
197 // now the rest of the world can go
198 Cyg_Scheduler::unlock();
200 // queue event. If it fails... nothing we can do :-( so ignore return code
201 cyg_sigqueue( ev, SI_MESGQ );
203 cyg_deliver_signals();
208 #endif // ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
210 //------------------------------------------------------------------------
212 /* EXPORTED FUNCTIONS */
215 mq_open( const char *name, int oflag, ... )
217 CYG_REPORT_FUNCTYPE( "returning %08x" );
218 CYG_REPORT_FUNCARG2( "name=%08x, oflag=%d", name, oflag );
219 CYG_CHECK_DATA_PTRC( name );
221 if ( ((oflag & O_RDONLY) != O_RDONLY) &&
222 ((oflag & O_WRONLY) != O_WRONLY) &&
223 ((oflag & O_RDWR) != O_RDWR)) {
224 // user didn't specify mode
226 CYG_REPORT_RETVAL( -1 );
232 struct mqtabent *qtabent=NULL;
235 interr = pthread_mutex_lock( &mqtab_mut );
237 CYG_ASSERT( interr == 0, "internal lock failed!" );
239 // find if a matching entry exists first
240 // FIXME: Should check for length and return ENAMETOOLONG
241 for ( i=0; i < CYGNUM_POSIX_MQUEUE_OPEN_MAX; i++ ) {
242 if ( 0 == strncmp(name, mqtab[i].name, PATH_MAX) ) {
248 if ( (NULL != qtabent) && (O_EXCL == (oflag & O_EXCL)) ) {
254 if ( (NULL == qtabent) && (O_CREAT != (oflag & O_CREAT)) ) {
260 // so if we didn't find something, we must be being asked to create it
261 if (NULL == qtabent) {
262 mode_t mode; // FIXME: mode ignored for now
263 const struct mq_attr *attr;
264 const struct mq_attr default_attr = { 0, MQ_OPEN_MAX, 128 };
267 va_start( args, oflag );
268 mode = va_arg( args, mode_t );
269 attr = va_arg( args, struct mq_attr * );
272 // find an empty table entry
273 for ( i=0; i < CYGNUM_POSIX_MQUEUE_OPEN_MAX; i++ ) {
274 if ( NULL == mqtab[i].mq )
278 // if not found, table is full
279 if ( i == CYGNUM_POSIX_MQUEUE_OPEN_MAX ) {
285 Cyg_Mqueue::qerr_t qerr;
287 // user can specify NULL attr, which means arbitrary message queue
290 attr = &default_attr;
292 // if they do supply one, POSIX says we're meant to check it
293 if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0) {
300 // allocate the underlying queue
301 Cyg_Mqueue *mqholder = (Cyg_Mqueue *)malloc( sizeof(Cyg_Mqueue) );
302 if ( NULL == mqholder ) {
308 // construct it with placement new
309 mqtab[i].mq = new (mqholder) Cyg_Mqueue( attr->mq_maxmsg,
311 &malloc, &my_free, &qerr );
316 case Cyg_Mqueue::NOMEM:
322 CYG_FAIL("Unhandled Cyg_Mqueue constructor return error");
326 mqtab[i].users = (struct mquser *) malloc( sizeof(struct mquser) );
327 if ( NULL == mqtab[i].users ) {
328 mqtab[i].mq->~Cyg_Mqueue();
335 // initialize mqtab[i]
336 mqtab[i].maxmsg = attr->mq_maxmsg;
337 mqtab[i].msgsize = attr->mq_msgsize;
338 mqtab[i].unlinkme = false;
339 #ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
340 mqtab[i].sigev = NULL;
342 strncpy( mqtab[i].name, name, PATH_MAX );
344 // initialize first mqtab[i].users
345 mqtab[i].users->next = NULL;
346 // set the mode for later, but also note that O_NONBLOCK can
347 // be set in oflags *or* the attr the user passed
348 mqtab[i].users->flags = oflag | (attr->mq_flags & O_NONBLOCK);
350 // set back pointer so that message queue handle can find actual queue
351 mqtab[i].users->tabent = &mqtab[i];
353 mqtab[i].users->notifieruser = false;
355 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
356 mqtab[i].users->magic = MQ_VALID_MAGIC; // now valid
359 retval=(mqd_t)mqtab[i].users;
362 } // if (NULL == qtabent)
364 // so we're not creating, and we have a valid qtabent
366 // But this qtabent may be being unlinked. If so, we are permitted
367 // to return an error, so we will. (see under mq_unlink() in POSIX)
368 // Which error though? EINVAL seems best, but POSIX doesn't say :-/
370 if (true == qtabent->unlinkme) {
376 // now we have a usable qtabent
379 user = (struct mquser *) malloc( sizeof(struct mquser) );
380 if ( NULL == user ) {
386 // prepend to qtab user list
387 user->next = qtabent->users;
388 qtabent->users = user;
390 // set back pointer so that message queue handle can find actual queue
391 user->tabent = qtabent;
395 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
396 user->magic = MQ_VALID_MAGIC; // now valid
402 interr = pthread_mutex_unlock( &mqtab_mut );
404 CYG_ASSERT( interr == 0, "internal lock failed!" );
405 CYG_REPORT_RETVAL( retval );
409 //------------------------------------------------------------------------
411 // NOTE: It is the *user*'s responsibility to ensure that nothing is
412 // blocked in mq_send() or mq_receive() when closing the queue with
413 // that descriptor. The standard does not specify the behaviour, so that's
414 // what I am assuming
417 mq_close( mqd_t mqdes )
419 CYG_REPORT_FUNCTYPE( "returning %d" );
420 CYG_REPORT_FUNCARG1XV( mqdes );
422 struct mquser *user = (struct mquser *)mqdes;
424 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
425 if ( user->magic != MQ_VALID_MAGIC ) {
427 CYG_REPORT_RETVAL( -1 );
434 interr = pthread_mutex_lock( &mqtab_mut );
436 CYG_ASSERT( interr == 0, "internal lock failed!" );
438 struct mqtabent *tabent = user->tabent;
439 struct mquser *usertmp;
441 // perhaps should return EBADF instead of assert?
442 CYG_ASSERT( tabent->users != NULL, "Null message queue user list" );
444 #ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
445 // deregister notification iff this was the message queue descriptor
446 // that was used to register it (POSIX says)
447 if ( true == user->notifieruser ) {
448 tabent->mq->setnotify( NULL, 0 );
449 tabent->sigev = NULL;
450 // not worth clearing notifieruser
454 // find in the list for this queue and remove - sucks a bit, but seems
455 // best over all - the list shouldn't be too long
456 if ( tabent->users == user ) {
457 tabent->users = user->next; // remove
459 for ( usertmp=tabent->users;
460 NULL != usertmp->next;
461 usertmp = usertmp->next ) {
462 if ( usertmp->next == user )
466 // perhaps should return EBADF instead of assert?
467 CYG_ASSERT( usertmp->next != NULL, "Couldn't find message queue user" );
469 usertmp->next = user->next; // remove
472 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
473 user->magic = 0; // invalidate
479 if ( (true == tabent->unlinkme) && (NULL == tabent->users) ) {
480 do_mq_unlink( tabent );
483 interr = pthread_mutex_unlock( &mqtab_mut );
485 CYG_ASSERT( interr == 0, "internal lock failed!" );
486 CYG_REPORT_RETVAL( 0 );
491 //------------------------------------------------------------------------
494 mq_unlink( const char *name )
496 CYG_REPORT_FUNCTYPE( "returning %d" );
497 CYG_REPORT_FUNCARG1( "name=%s", name );
501 struct mqtabent *qtabent=NULL;
503 interr = pthread_mutex_lock( &mqtab_mut );
505 CYG_ASSERT( interr == 0, "internal lock failed!" );
507 // find the entry first
508 // FIXME: Should check for length and return ENAMETOOLONG
509 for ( i=0; i < CYGNUM_POSIX_MQUEUE_OPEN_MAX; i++ ) {
510 if ( 0 == strncmp(name, mqtab[i].name, PATH_MAX) ) {
516 if ( NULL == qtabent ) { // not found
522 if ( NULL != qtabent->users ) { // still in use
523 qtabent->unlinkme = true; // so mark it as pending deletion
525 do_mq_unlink( qtabent );
531 interr = pthread_mutex_unlock( &mqtab_mut );
533 CYG_ASSERT( interr == 0, "internal lock failed!" );
534 CYG_REPORT_RETVAL( retval );
538 //------------------------------------------------------------------------
541 mq_send( mqd_t mqdes, const char *msg_ptr, size_t msg_len,
542 unsigned int msg_prio )
544 CYG_REPORT_FUNCTYPE( "returning %d" );
545 CYG_REPORT_FUNCARG4( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%u",
546 mqdes, msg_ptr, msg_len, msg_prio );
547 CYG_CHECK_DATA_PTRC( msg_ptr );
549 struct mquser *user = (struct mquser *)mqdes;
550 struct mqtabent *tabent = user->tabent;
552 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
553 if ( user->magic != MQ_VALID_MAGIC ) {
555 CYG_REPORT_RETVAL( -1 );
560 if ( msg_len > (size_t)tabent->msgsize ) {
562 CYG_REPORT_RETVAL( -1 );
566 if ( msg_prio > MQ_PRIO_MAX ) {
568 CYG_REPORT_RETVAL( -1 );
572 if ( (O_WRONLY != (user->flags & O_WRONLY)) &&
573 (O_RDWR != (user->flags & O_RDWR)) ) {
575 CYG_REPORT_RETVAL( -1 );
580 Cyg_Mqueue::qerr_t err;
581 err = tabent->mq->put( msg_ptr, msg_len, msg_prio,
582 ((user->flags & O_NONBLOCK) != O_NONBLOCK) );
585 case Cyg_Mqueue::INTR:
587 CYG_REPORT_RETVAL( -1 );
590 case Cyg_Mqueue::WOULDBLOCK:
591 CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
592 "Message queue assumed non-blocking when blocking requested"
595 CYG_REPORT_RETVAL( -1 );
599 CYG_REPORT_RETVAL( 0 );
603 CYG_FAIL( "unhandled message queue return code" );
604 return -1; // keep compiler happy
608 //------------------------------------------------------------------------
612 mq_receive( mqd_t mqdes, char *msg_ptr, size_t msg_len,
613 unsigned int *msg_prio )
615 CYG_REPORT_FUNCTYPE( "returning %ld" );
616 CYG_REPORT_FUNCARG4( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%08x",
617 mqdes, msg_ptr, msg_len, msg_prio );
618 CYG_CHECK_DATA_PTRC( msg_ptr );
619 CYG_CHECK_DATA_PTRC( msg_ptr+msg_len-1 );
620 if ( NULL != msg_prio )
621 CYG_CHECK_DATA_PTRC( msg_prio );
624 struct mquser *user = (struct mquser *)mqdes;
625 struct mqtabent *tabent = user->tabent;
627 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
628 if ( user->magic != MQ_VALID_MAGIC ) {
630 CYG_REPORT_RETVAL( -1 );
635 if ( (O_RDONLY != (user->flags & O_RDONLY)) &&
636 (O_RDWR != (user->flags & O_RDWR)) ) {
638 CYG_REPORT_RETVAL( -1 );
642 if ( msg_len < (size_t)tabent->msgsize ) {
644 CYG_REPORT_RETVAL( -1 );
649 Cyg_Mqueue::qerr_t err;
650 err = tabent->mq->get( msg_ptr, &msg_len, msg_prio,
651 ((user->flags & O_NONBLOCK) != O_NONBLOCK) );
654 case Cyg_Mqueue::INTR:
656 CYG_REPORT_RETVAL( -1 );
659 case Cyg_Mqueue::WOULDBLOCK:
660 CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
661 "Message queue assumed non-blocking when blocking requested"
664 CYG_REPORT_RETVAL( -1 );
668 CYG_ASSERT( msg_len <= (size_t)tabent->msgsize,
669 "returned message too long" );
670 if ( NULL != msg_prio )
671 CYG_ASSERT( *msg_prio <= MQ_PRIO_MAX,
672 "returned message has invalid priority" );
673 CYG_REPORT_RETVAL( msg_len );
674 return (ssize_t)msg_len;
677 CYG_FAIL( "unhandled message queue return code" );
678 return (ssize_t)-1; // keep compiler happy
684 //------------------------------------------------------------------------
685 #ifdef CYGFUN_KERNEL_THREADS_TIMER
687 mq_timedsend( mqd_t mqdes, const char *msg_ptr, size_t msg_len,
688 unsigned int msg_prio, const struct timespec *abs_timeout)
690 CYG_REPORT_FUNCTYPE( "returning %d" );
691 CYG_REPORT_FUNCARG6( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%u, "
692 "abs_timeout = %lu, %ld",
693 mqdes, msg_ptr, msg_len, msg_prio,
694 abs_timeout->tv_sec, abs_timeout->tv_nsec);
695 CYG_CHECK_DATA_PTRC( msg_ptr );
697 struct mquser *user = (struct mquser *)mqdes;
698 struct mqtabent *tabent = user->tabent;
700 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
701 if ( user->magic != MQ_VALID_MAGIC ) {
703 CYG_REPORT_RETVAL( -1 );
708 if ( msg_len > (size_t)tabent->msgsize ) {
710 CYG_REPORT_RETVAL( -1 );
714 if ( msg_prio > MQ_PRIO_MAX ) {
716 CYG_REPORT_RETVAL( -1 );
720 if ( (O_WRONLY != (user->flags & O_WRONLY)) &&
721 (O_RDWR != (user->flags & O_RDWR)) ) {
723 CYG_REPORT_RETVAL( -1 );
728 Cyg_Mqueue::qerr_t err;
729 bool nonblocking = ((user->flags & O_NONBLOCK) == O_NONBLOCK);
730 bool badtimespec = (abs_timeout->tv_nsec < 0) ||
731 (abs_timeout->tv_nsec > 999999999l);
732 cyg_tick_count abs_ticks = cyg_timespec_to_ticks(abs_timeout);
734 // We should never time out if there is room in the queue. Simplest
735 // way to ensure this is to try the non-blocking put() first.
736 err = tabent->mq->put( msg_ptr, msg_len, msg_prio, false, abs_ticks );
738 // If the blocking variant would have blocked and that is what's wanted
739 if ( Cyg_Mqueue::WOULDBLOCK == err && !nonblocking && !badtimespec ) {
740 err = tabent->mq->put( msg_ptr, msg_len, msg_prio, true,
746 case Cyg_Mqueue::INTR:
748 CYG_REPORT_RETVAL( -1 );
751 case Cyg_Mqueue::WOULDBLOCK:
754 CYG_REPORT_RETVAL( -1 );
757 CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
758 "Message queue assumed non-blocking when blocking requested"
761 CYG_REPORT_RETVAL( -1 );
764 case Cyg_Mqueue::TIMEOUT:
766 CYG_REPORT_RETVAL( -1 );
770 CYG_REPORT_RETVAL( 0 );
774 CYG_FAIL( "unhandled message queue return code" );
775 return -1; // keep compiler happy
779 //------------------------------------------------------------------------
783 mq_timedreceive( mqd_t mqdes, char *msg_ptr, size_t msg_len,
784 unsigned int *msg_prio, const struct timespec *abs_timeout)
786 CYG_REPORT_FUNCTYPE( "returning %ld" );
787 CYG_REPORT_FUNCARG6( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%08x, "
788 "abs_timeout = %lu, %ld",
789 mqdes, msg_ptr, msg_len, msg_prio,
790 abs_timeout->tv_sec, abs_timeout->tv_nsec );
791 CYG_CHECK_DATA_PTRC( msg_ptr );
792 CYG_CHECK_DATA_PTRC( msg_ptr+msg_len-1 );
793 if ( NULL != msg_prio )
794 CYG_CHECK_DATA_PTRC( msg_prio );
797 struct mquser *user = (struct mquser *)mqdes;
798 struct mqtabent *tabent = user->tabent;
800 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
801 if ( user->magic != MQ_VALID_MAGIC ) {
803 CYG_REPORT_RETVAL( -1 );
808 if ( (O_RDONLY != (user->flags & O_RDONLY)) &&
809 (O_RDWR != (user->flags & O_RDWR)) ) {
811 CYG_REPORT_RETVAL( -1 );
815 if ( msg_len < (size_t)tabent->msgsize ) {
817 CYG_REPORT_RETVAL( -1 );
822 Cyg_Mqueue::qerr_t err;
823 bool nonblocking = ((user->flags & O_NONBLOCK) == O_NONBLOCK);
824 bool badtimespec = (abs_timeout->tv_nsec < 0) ||
825 (abs_timeout->tv_nsec > 999999999l);
826 cyg_tick_count abs_ticks = cyg_timespec_to_ticks(abs_timeout);
828 // We should never time out if there is something to read. Simplest
829 // way to ensure this is to try the non-blocking get() first.
830 err = tabent->mq->get( msg_ptr, &msg_len, msg_prio, false, abs_ticks );
832 // If the blocking variant would have blocked and that is what's wanted
833 if ( Cyg_Mqueue::WOULDBLOCK == err && !nonblocking && !badtimespec ) {
834 err = tabent->mq->get( msg_ptr, &msg_len, msg_prio, true, abs_ticks );
839 case Cyg_Mqueue::INTR:
841 CYG_REPORT_RETVAL( -1 );
844 case Cyg_Mqueue::WOULDBLOCK:
847 CYG_REPORT_RETVAL( -1 );
850 CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
851 "Message queue assumed non-blocking when blocking requested"
854 CYG_REPORT_RETVAL( -1 );
857 case Cyg_Mqueue::TIMEOUT:
859 CYG_REPORT_RETVAL( -1 );
863 CYG_ASSERT( msg_len <= (size_t)tabent->msgsize,
864 "returned message too long" );
865 if ( NULL != msg_prio )
866 CYG_ASSERT( *msg_prio <= MQ_PRIO_MAX,
867 "returned message has invalid priority" );
868 CYG_REPORT_RETVAL( msg_len );
869 return (ssize_t)msg_len;
872 CYG_FAIL( "unhandled message queue return code" );
873 return (ssize_t)-1; // keep compiler happy
876 } // mq_timedreceive()
878 //------------------------------------------------------------------------
881 #ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
884 mq_notify( mqd_t mqdes, const struct sigevent *notification )
886 CYG_REPORT_FUNCTYPE( "returning %d" );
887 CYG_REPORT_FUNCARG2( "mqdes=%08x, notification=%08x", mqdes, notification );
888 if ( NULL != notification )
889 CYG_CHECK_DATA_PTRC( notification );
891 struct mquser *user = (struct mquser *)mqdes;
892 struct mqtabent *tabent = user->tabent;
894 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
895 if ( user->magic != MQ_VALID_MAGIC ) {
897 CYG_REPORT_RETVAL( -1 );
902 // lock scheduler since we test and set non-atomically
903 Cyg_Scheduler::lock();
905 // we are being told to clear the notification function
906 if ( NULL == notification ) {
907 tabent->mq->setnotify( NULL, 0 );
908 tabent->sigev = NULL;
909 Cyg_Scheduler::unlock();
910 CYG_REPORT_RETVAL( 0 );
914 if ( NULL != tabent->sigev ) { // already registered
915 Cyg_Scheduler::unlock();
917 CYG_REPORT_RETVAL( -1 );
921 tabent->sigev = notification;
922 user->notifieruser = true; // Used for deciding about whether to
923 // deregister in mq_close()
924 tabent->mq->setnotify( ¬ifyme, (CYG_ADDRWORD) user );
925 Cyg_Scheduler::unlock();
927 CYG_REPORT_RETVAL( 0 );
931 #endif // ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
933 //------------------------------------------------------------------------
936 mq_setattr( mqd_t mqdes, const struct mq_attr *mqstat,
937 struct mq_attr *omqstat )
939 CYG_REPORT_FUNCTYPE( "returning %d" );
940 CYG_REPORT_FUNCARG3( "mqdes=%08x, mqstat=%08x, omqstat=%08x",
941 mqdes, mqstat, omqstat );
942 CYG_CHECK_DATA_PTRC( mqstat );
944 struct mquser *user = (struct mquser *)mqdes;
946 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
947 if ( user->magic != MQ_VALID_MAGIC ) {
949 CYG_REPORT_RETVAL( -1 );
954 if ( NULL != omqstat ) {
955 CYG_CHECK_DATA_PTRC( omqstat );
956 mq_getattr( mqdes, omqstat );
959 // Two-stage update, so lock sched since it's quick
960 Cyg_Scheduler::lock();
961 user->flags &= ~O_NONBLOCK; // clear
962 if ( (mqstat->mq_flags & O_NONBLOCK) == O_NONBLOCK ) {
963 user->flags |= O_NONBLOCK;
965 Cyg_Scheduler::unlock();
967 CYG_REPORT_RETVAL( 0 );
971 //------------------------------------------------------------------------
974 mq_getattr( mqd_t mqdes, struct mq_attr *mqstat )
976 CYG_REPORT_FUNCTYPE( "returning %d" );
977 CYG_REPORT_FUNCARG2( "mqdes=%08x, mqstat=%08x", mqdes, mqstat );
978 CYG_CHECK_DATA_PTRC( mqstat );
980 struct mquser *user = (struct mquser *)mqdes;
981 struct mqtabent *tabent = user->tabent;
983 #ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
984 if ( user->magic != MQ_VALID_MAGIC ) {
986 CYG_REPORT_RETVAL( -1 );
991 mqstat->mq_flags = user->flags;
992 mqstat->mq_maxmsg = tabent->maxmsg;
993 mqstat->mq_msgsize = tabent->msgsize;
994 mqstat->mq_curmsgs = tabent->mq->count();
996 CYG_REPORT_RETVAL( 0 );
1001 //------------------------------------------------------------------------
1003 #endif // ifdef CYGPKG_POSIX_MQUEUES
1005 /* EOF mqueue.cxx */