📄 mqueue.cxx
字号:
/*========================================================================
//
// mqueue.cxx
//
// Message queues tests
//
//========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): jlarmour
// Contributors:
// Date: 2000-05-14
// Purpose: This file provides the implementation for POSIX message
// queues
// Description: It uses eCos kernel mqueues as the underlying
// implementation
// Usage:
//
//####DESCRIPTIONEND####
//
//======================================================================
*/
/* CONFIGURATION */
#include <pkgconf/posix.h>
#ifdef CYGPKG_POSIX_MQUEUES
#include <pkgconf/kernel.h>
/* INCLUDES */
#include <cyg/infra/cyg_type.h> // common types etc.
#include <cyg/infra/cyg_ass.h> // Assertion support
#include <cyg/infra/cyg_trac.h> // Tracing support
#include <cyg/kernel/mqueue.hxx> // eCos Mqueue Header
#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::lock()
#include <cyg/kernel/sched.inl> // inlines for above
#include <mqueue.h> // Standard POSIX mqueue header
#include <sys/types.h> // mode_t, ssize_t
#include <limits.h> // PATH_MAX
#include <stdlib.h> // malloc, etc.
#include <errno.h> // errno
#include <fcntl.h> // O_*
#include <stdarg.h> // varargs
#include <pthread.h> // mutexes
#include <string.h> // strncpy
#ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
# include <signal.h>
# include "pprivate.h" // cyg_sigqueue()
#endif
#ifdef CYGFUN_KERNEL_THREADS_TIMER
# include <time.h>
# include "pprivate.h" // cyg_timespec_to_ticks()
#endif
/* CONSTANTS */
#define MQ_VALID_MAGIC 0x6db256c1
/* TYPE DEFINITIONS */
struct mqtabent;
// this is a queue user - each one of these corresponds to a mqd_t
struct mquser {
int flags; // O_RDONLY, O_WRONLY, O_RDWR, O_NONBLOCK
struct mqtabent *tabent; // back pointer to table entry
struct mquser *next;
bool notifieruser; // POSIX sucks so bad. It requires a mq_close
// to only deregister the notification if it
// was done via this descriptor. So we have to
// know if it was this one
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
cyg_uint32 magic; // magic number: MQ_VALID_MAGIC if valid
#endif
};
struct mqtabent {
char name[ PATH_MAX ]; // ascii name - set to "" when unused
Cyg_Mqueue *mq; // the underlying queue object
long maxmsg; // as set on creation
long msgsize; // as set on creation
bool unlinkme; // unlink when final user closes?
struct mquser *users; // each user
#ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
const struct sigevent *sigev; // notification event
#endif
};
/* GLOBALS */
static struct mqtabent mqtab[ CYGNUM_POSIX_MQUEUE_OPEN_MAX ];
static pthread_mutex_t mqtab_mut = PTHREAD_MUTEX_INITIALIZER;
/* LOCAL FUNCTIONS */
//------------------------------------------------------------------------
// placement new definition
inline void *operator new(size_t size, void *ptr)
{
CYG_CHECK_DATA_PTR( ptr, "Bad pointer" );
return ptr;
}
// Deallocation callback from Cyg_Mqueue
static void
my_free( void *ptr, size_t )
{
free( ptr );
}
//------------------------------------------------------------------------
// Do the actual "unlink" of a queue, i.e. mark it invalid in the table.
// The table mutex is assumed to be locked
static void
do_mq_unlink( struct mqtabent *tabent )
{
CYG_REPORT_FUNCTION();
CYG_CHECK_DATA_PTRC( tabent );
tabent->name[0] = '\0'; // won't match anything the user sends now
tabent->mq->~Cyg_Mqueue();
free( tabent->mq );
tabent->mq=NULL;
CYG_REPORT_RETURN();
}
//------------------------------------------------------------------------
#ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
static void
notifyme( Cyg_Mqueue &q, CYG_ADDRWORD data )
{
CYG_REPORT_FUNCTION();
struct mquser *user = (struct mquser *)data;
CYG_CHECK_DATA_PTRC( user );
struct mqtabent *tabent = user->tabent;
CYG_CHECK_DATA_PTRC( tabent );
Cyg_Scheduler::lock();
// we may have been pre-empted before this, so check there's still a
// notification to do
if ( NULL == tabent->sigev ) {
Cyg_Scheduler::unlock();
CYG_REPORT_RETURN();
return;
} // if
const struct sigevent *ev = tabent->sigev;
// first deregister
q.setnotify( NULL, 0 );
tabent->sigev = NULL;
user->notifieruser = false; // not any more
// now the rest of the world can go
Cyg_Scheduler::unlock();
// queue event. If it fails... nothing we can do :-( so ignore return code
cyg_sigqueue( ev, SI_MESGQ );
cyg_deliver_signals();
CYG_REPORT_RETURN();
}
#endif // ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
//------------------------------------------------------------------------
/* EXPORTED FUNCTIONS */
externC mqd_t
mq_open( const char *name, int oflag, ... )
{
CYG_REPORT_FUNCTYPE( "returning %08x" );
CYG_REPORT_FUNCARG2( "name=%08x, oflag=%d", name, oflag );
CYG_CHECK_DATA_PTRC( name );
if ( ((oflag & O_RDONLY) != O_RDONLY) &&
((oflag & O_WRONLY) != O_WRONLY) &&
((oflag & O_RDWR) != O_RDWR)) {
// user didn't specify mode
errno = EINVAL;
CYG_REPORT_RETVAL( -1 );
return (mqd_t)-1;
} // if
mqd_t retval;
cyg_ucount32 i;
struct mqtabent *qtabent=NULL;
int interr;
interr = pthread_mutex_lock( &mqtab_mut );
// should never fail
CYG_ASSERT( interr == 0, "internal lock failed!" );
// find if a matching entry exists first
// FIXME: Should check for length and return ENAMETOOLONG
for ( i=0; i < CYGNUM_POSIX_MQUEUE_OPEN_MAX; i++ ) {
if ( 0 == strncmp(name, mqtab[i].name, PATH_MAX) ) {
qtabent = &mqtab[i];
break;
} // if
} // for
if ( (NULL != qtabent) && (O_EXCL == (oflag & O_EXCL)) ) {
errno = EEXIST;
retval = (mqd_t)-1;
goto exit_unlock;
}
if ( (NULL == qtabent) && (O_CREAT != (oflag & O_CREAT)) ) {
errno = ENOENT;
retval = (mqd_t)-1;
goto exit_unlock;
}
// so if we didn't find something, we must be being asked to create it
if (NULL == qtabent) {
mode_t mode; // FIXME: mode ignored for now
const struct mq_attr *attr;
const struct mq_attr default_attr = { 0, MQ_OPEN_MAX, 128 };
va_list args;
va_start( args, oflag );
mode = va_arg( args, mode_t );
attr = va_arg( args, struct mq_attr * );
va_end( args );
// find an empty table entry
for ( i=0; i < CYGNUM_POSIX_MQUEUE_OPEN_MAX; i++ ) {
if ( NULL == mqtab[i].mq )
break;
}
// if not found, table is full
if ( i == CYGNUM_POSIX_MQUEUE_OPEN_MAX ) {
errno = ENFILE;
retval = (mqd_t)-1;
goto exit_unlock;
}
Cyg_Mqueue::qerr_t qerr;
// user can specify NULL attr, which means arbitrary message queue
// size! Duh.
if ( NULL == attr )
attr = &default_attr;
else {
// if they do supply one, POSIX says we're meant to check it
if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0) {
errno = EINVAL;
retval = (mqd_t)-1;
goto exit_unlock;
}
} // else
// allocate the underlying queue
Cyg_Mqueue *mqholder = (Cyg_Mqueue *)malloc( sizeof(Cyg_Mqueue) );
if ( NULL == mqholder ) {
errno = ENOSPC;
retval = (mqd_t)-1;
goto exit_unlock;
}
// construct it with placement new
mqtab[i].mq = new (mqholder) Cyg_Mqueue( attr->mq_maxmsg,
attr->mq_msgsize,
&malloc, &my_free, &qerr );
switch (qerr) {
case Cyg_Mqueue::OK:
break;
case Cyg_Mqueue::NOMEM:
free( mqholder );
errno = ENOSPC;
retval = (mqd_t)-1;
goto exit_unlock;
default:
CYG_FAIL("Unhandled Cyg_Mqueue constructor return error");
break;
} // switch
mqtab[i].users = (struct mquser *) malloc( sizeof(struct mquser) );
if ( NULL == mqtab[i].users ) {
mqtab[i].mq->~Cyg_Mqueue();
free( mqholder );
errno = ENOSPC;
retval = (mqd_t)-1;
goto exit_unlock;
}
// initialize mqtab[i]
mqtab[i].maxmsg = attr->mq_maxmsg;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -