📄 mqueue.cxx
字号:
mqtab[i].msgsize = attr->mq_msgsize;
mqtab[i].unlinkme = false;
#ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
mqtab[i].sigev = NULL;
#endif
strncpy( mqtab[i].name, name, PATH_MAX );
// initialize first mqtab[i].users
mqtab[i].users->next = NULL;
// set the mode for later, but also note that O_NONBLOCK can
// be set in oflags *or* the attr the user passed
mqtab[i].users->flags = oflag | (attr->mq_flags & O_NONBLOCK);
// set back pointer so that message queue handle can find actual queue
mqtab[i].users->tabent = &mqtab[i];
mqtab[i].users->notifieruser = false;
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
mqtab[i].users->magic = MQ_VALID_MAGIC; // now valid
#endif
retval=(mqd_t)mqtab[i].users;
goto exit_unlock;
} // if (NULL == qtabent)
// so we're not creating, and we have a valid qtabent
// But this qtabent may be being unlinked. If so, we are permitted
// to return an error, so we will. (see under mq_unlink() in POSIX)
// Which error though? EINVAL seems best, but POSIX doesn't say :-/
if (true == qtabent->unlinkme) {
errno = EINVAL;
retval = (mqd_t)-1;
goto exit_unlock;
}
// now we have a usable qtabent
struct mquser *user;
user = (struct mquser *) malloc( sizeof(struct mquser) );
if ( NULL == user ) {
errno = ENOSPC;
retval = (mqd_t)-1;
goto exit_unlock;
}
// prepend to qtab user list
user->next = qtabent->users;
qtabent->users = user;
// set back pointer so that message queue handle can find actual queue
user->tabent = qtabent;
user->flags = oflag;
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
user->magic = MQ_VALID_MAGIC; // now valid
#endif
retval=(mqd_t)user;
exit_unlock:
interr = pthread_mutex_unlock( &mqtab_mut );
// should never fail
CYG_ASSERT( interr == 0, "internal lock failed!" );
CYG_REPORT_RETVAL( retval );
return retval;
} // mq_open()
//------------------------------------------------------------------------
// NOTE: It is the *user*'s responsibility to ensure that nothing is
// blocked in mq_send() or mq_receive() when closing the queue with
// that descriptor. The standard does not specify the behaviour, so that's
// what I am assuming
externC int
mq_close( mqd_t mqdes )
{
CYG_REPORT_FUNCTYPE( "returning %d" );
CYG_REPORT_FUNCARG1XV( mqdes );
struct mquser *user = (struct mquser *)mqdes;
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
if ( user->magic != MQ_VALID_MAGIC ) {
errno = EBADF;
CYG_REPORT_RETVAL( -1 );
return -1;
}
#endif
int interr;
interr = pthread_mutex_lock( &mqtab_mut );
// should never fail
CYG_ASSERT( interr == 0, "internal lock failed!" );
struct mqtabent *tabent = user->tabent;
struct mquser *usertmp;
// perhaps should return EBADF instead of assert?
CYG_ASSERT( tabent->users != NULL, "Null message queue user list" );
#ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
// deregister notification iff this was the message queue descriptor
// that was used to register it (POSIX says)
if ( true == user->notifieruser ) {
tabent->mq->setnotify( NULL, 0 );
tabent->sigev = NULL;
// not worth clearing notifieruser
}
#endif
// find in the list for this queue and remove - sucks a bit, but seems
// best over all - the list shouldn't be too long
if ( tabent->users == user ) {
tabent->users = user->next; // remove
} else {
for ( usertmp=tabent->users;
NULL != usertmp->next;
usertmp = usertmp->next ) {
if ( usertmp->next == user )
break;
} // for
// perhaps should return EBADF instead of assert?
CYG_ASSERT( usertmp->next != NULL, "Couldn't find message queue user" );
usertmp->next = user->next; // remove
} // else
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
user->magic = 0; // invalidate
#endif
// free it up
free( user );
if ( (true == tabent->unlinkme) && (NULL == tabent->users) ) {
do_mq_unlink( tabent );
} // if
interr = pthread_mutex_unlock( &mqtab_mut );
// should never fail
CYG_ASSERT( interr == 0, "internal lock failed!" );
CYG_REPORT_RETVAL( 0 );
return 0;
} // mq_close()
//------------------------------------------------------------------------
externC int
mq_unlink( const char *name )
{
CYG_REPORT_FUNCTYPE( "returning %d" );
CYG_REPORT_FUNCARG1( "name=%s", name );
int retval, interr;
cyg_ucount32 i;
struct mqtabent *qtabent=NULL;
interr = pthread_mutex_lock( &mqtab_mut );
// should never fail
CYG_ASSERT( interr == 0, "internal lock failed!" );
// find the entry 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 ) { // not found
errno = ENOENT;
retval = -1;
goto exit_unlock;
}
if ( NULL != qtabent->users ) { // still in use
qtabent->unlinkme = true; // so mark it as pending deletion
} else {
do_mq_unlink( qtabent );
} // else
retval = 0;
exit_unlock:
interr = pthread_mutex_unlock( &mqtab_mut );
// should never fail
CYG_ASSERT( interr == 0, "internal lock failed!" );
CYG_REPORT_RETVAL( retval );
return retval;
} // mq_unlink()
//------------------------------------------------------------------------
externC int
mq_send( mqd_t mqdes, const char *msg_ptr, size_t msg_len,
unsigned int msg_prio )
{
CYG_REPORT_FUNCTYPE( "returning %d" );
CYG_REPORT_FUNCARG4( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%u",
mqdes, msg_ptr, msg_len, msg_prio );
CYG_CHECK_DATA_PTRC( msg_ptr );
struct mquser *user = (struct mquser *)mqdes;
struct mqtabent *tabent = user->tabent;
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
if ( user->magic != MQ_VALID_MAGIC ) {
errno = EBADF;
CYG_REPORT_RETVAL( -1 );
return -1;
}
#endif
if ( msg_len > (size_t)tabent->msgsize ) {
errno = EMSGSIZE;
CYG_REPORT_RETVAL( -1 );
return -1;
}
if ( msg_prio > MQ_PRIO_MAX ) {
errno = EINVAL;
CYG_REPORT_RETVAL( -1 );
return -1;
}
if ( (O_WRONLY != (user->flags & O_WRONLY)) &&
(O_RDWR != (user->flags & O_RDWR)) ) {
errno = EBADF;
CYG_REPORT_RETVAL( -1 );
return -1;
}
// go for it
Cyg_Mqueue::qerr_t err;
err = tabent->mq->put( msg_ptr, msg_len, msg_prio,
((user->flags & O_NONBLOCK) != O_NONBLOCK) );
switch (err) {
case Cyg_Mqueue::INTR:
errno = EINTR;
CYG_REPORT_RETVAL( -1 );
return -1;
case Cyg_Mqueue::WOULDBLOCK:
CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
"Message queue assumed non-blocking when blocking requested"
);
errno = EAGAIN;
CYG_REPORT_RETVAL( -1 );
return -1;
case Cyg_Mqueue::OK:
CYG_REPORT_RETVAL( 0 );
return 0;
default:
CYG_FAIL( "unhandled message queue return code" );
return -1; // keep compiler happy
} // switch
} // mq_send()
//------------------------------------------------------------------------
externC ssize_t
mq_receive( mqd_t mqdes, char *msg_ptr, size_t msg_len,
unsigned int *msg_prio )
{
CYG_REPORT_FUNCTYPE( "returning %ld" );
CYG_REPORT_FUNCARG4( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%08x",
mqdes, msg_ptr, msg_len, msg_prio );
CYG_CHECK_DATA_PTRC( msg_ptr );
CYG_CHECK_DATA_PTRC( msg_ptr+msg_len-1 );
if ( NULL != msg_prio )
CYG_CHECK_DATA_PTRC( msg_prio );
struct mquser *user = (struct mquser *)mqdes;
struct mqtabent *tabent = user->tabent;
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
if ( user->magic != MQ_VALID_MAGIC ) {
errno = EBADF;
CYG_REPORT_RETVAL( -1 );
return (ssize_t)-1;
}
#endif
if ( (O_RDONLY != (user->flags & O_RDONLY)) &&
(O_RDWR != (user->flags & O_RDWR)) ) {
errno = EBADF;
CYG_REPORT_RETVAL( -1 );
return (ssize_t)-1;
}
if ( msg_len < (size_t)tabent->msgsize ) {
errno = EMSGSIZE;
CYG_REPORT_RETVAL( -1 );
return (ssize_t)-1;
}
// go for it
Cyg_Mqueue::qerr_t err;
err = tabent->mq->get( msg_ptr, &msg_len, msg_prio,
((user->flags & O_NONBLOCK) != O_NONBLOCK) );
switch (err) {
case Cyg_Mqueue::INTR:
errno = EINTR;
CYG_REPORT_RETVAL( -1 );
return (ssize_t)-1;
case Cyg_Mqueue::WOULDBLOCK:
CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
"Message queue assumed non-blocking when blocking requested"
);
errno = EAGAIN;
CYG_REPORT_RETVAL( -1 );
return (ssize_t)-1;
case Cyg_Mqueue::OK:
CYG_ASSERT( msg_len <= (size_t)tabent->msgsize,
"returned message too long" );
if ( NULL != msg_prio )
CYG_ASSERT( *msg_prio <= MQ_PRIO_MAX,
"returned message has invalid priority" );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -