📄 mqueue.inl
字号:
#ifndef CYGONCE_KERNEL_MQUEUE_INL
#define CYGONCE_KERNEL_MQUEUE_INL
/*========================================================================
//
// mqueue.inl
//
// Message queues implementation
//
//========================================================================
//####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-09
// Purpose: This file provides the implementation for eCos message
// queues
// Description: This differs from the message boxes also supported
// by eCos primarily because the requirements of message
// queues are driven by POSIX semantics. POSIX semantics are
// more dynamic and therefore heavyweight than Mboxes,
// including prioritization, and variable sized queues and
// message lengths
// Usage: Do not include this file directly - instead
// #include <cyg/kernel/mqueue.hxx>
//
//####DESCRIPTIONEND####
//
//======================================================================
*/
/* CONFIGURATION */
#include <pkgconf/system.h>
#include <pkgconf/kernel.h> // Configuration header
/* INCLUDES */
#include <stddef.h> // size_t, NULL
#include <cyg/infra/cyg_type.h> // Types
#include <cyg/kernel/mqueue.hxx> // Header for this file, just in case
#include <cyg/infra/cyg_ass.h> // Assertion support
#include <cyg/infra/cyg_trac.h> // Tracing support
#include <cyg/kernel/sched.hxx> // scheduler
#include <cyg/kernel/sched.inl> // scheduler inlines
#include <cyg/kernel/sema.hxx> // Cyg_Counting_Semaphore
#ifdef CYGPKG_ISOINFRA
# include <string.h> // memcpy
#else
externC void * memcpy( void *, const void *, size_t );
#endif
// NOTE:
// An alternative implementation based on mutexes and condition variables
// rather than semaphores/scheduler locking was considered. But it was
// not thought quite as good because it isn't driver safe. You would
// also have to manage explicitly what counting semaphores do for you
// intrinsically. Also with the mutex approach, the message queue would
// be locked the whole time a new entry was being filled in, or copied out
//
// It also makes the non-blocking case properly non-blocking rather than
// still being able to block while waiting for a mutex protecting
// the message queue internal structures
/* INLINE FUNCTIONS */
#ifndef CYGPRI_KERNEL_SYNCH_MQUEUE_INLINE
# define CYGPRI_KERNEL_SYNCH_MQUEUE_INLINE inline
#endif
//------------------------------------------------------------------------
CYGPRI_KERNEL_SYNCH_MQUEUE_INLINE cyg_bool
Cyg_Mqueue::check_this( cyg_assert_class_zeal zeal ) const
{
if (zeal != cyg_none) {
CYG_CHECK_DATA_PTRC(this); // extreme paranoia
#ifdef CYGDBG_USE_ASSERTS
if ( qlen <= 0 || msgsize <= 0 )
return false;
#endif
if ( queuespacesize < sizeof(struct qentry)+1 )
return false;
CYG_CHECK_DATA_PTRC(queuespace);
CYG_CHECK_FUNC_PTRC(free_fn);
// prevent pre-emption through this. Not so bad since
// this is only a diagnostic function
Cyg_Scheduler::lock();
if (NULL != q)
CYG_CHECK_DATA_PTRC(q);
if (NULL != freelist)
CYG_CHECK_DATA_PTRC(freelist);
if (NULL != callback)
CYG_CHECK_FUNC_PTRC(callback);
// check each queue entry
long msgs=0, busymsgs=0;
unsigned int oldprio=0;
struct qentry *qtmp;
if ( NULL != q )
oldprio = q->priority;
for ( qtmp=q; NULL != qtmp; qtmp=qtmp->next ) {
if ( NULL != qtmp->next )
CYG_CHECK_DATA_PTRC( qtmp->next );
// queue should be priority ordered
if ( qtmp->priority > oldprio )
goto fail;
oldprio = qtmp->priority;
#ifdef CYGDBG_USE_ASSERTS
// valid length
if ( !qtmp->busy )
if ( qtmp->buflen > msgsize )
goto fail;
#endif
if ( qtmp->busy )
busymsgs++;
else
msgs++;
} // for
long freemsgs=0;
// check that number of used and unused messages == q length
for ( qtmp=freelist; NULL != qtmp; qtmp=qtmp->next ) {
if ( NULL != qtmp->next )
CYG_CHECK_DATA_PTRC( qtmp->next );
if ( qtmp->busy )
busymsgs++;
else
freemsgs++;
}
#ifdef CYGDBG_USE_ASSERTS
// and sum of all messages should be the total q length
if ( qlen != (msgs+freemsgs+busymsgs) )
goto fail;
#endif
Cyg_Scheduler::unlock();
}
return true; // object OK
fail:
Cyg_Scheduler::unlock();
return false; // object fubar'd
}
//------------------------------------------------------------------------
CYGPRI_KERNEL_SYNCH_MQUEUE_INLINE
Cyg_Mqueue::Cyg_Mqueue( long maxmsgs, long maxmsgsize,
qalloc_fn_t qalloc, qfree_fn_t qfree, qerr_t *err )
: putsem(maxmsgs), getsem(0)
{
CYG_REPORT_FUNCTION();
CYG_REPORT_FUNCARG5( "maxmsgs=%ld, maxmsgsize=%ld, qalloc=%08x, "
"qfree=%08x, &err=%08x", maxmsgs, maxmsgsize,
qalloc, qfree, err);
CYG_PRECONDITIONC( (maxmsgs > 0) && (maxmsgsize > 0) );
CYG_CHECK_DATA_PTRC( err );
CYG_CHECK_FUNC_PTRC( qalloc );
CYG_CHECK_FUNC_PTRC( qfree );
// mem to allocate for entire queue size. Also wants to be rounded
// up so that the structs are aligned.
const long addralign = sizeof(void *) - 1;
long entrysize = (sizeof(struct qentry) + maxmsgsize + addralign)
& ~addralign;
queuespacesize = entrysize * maxmsgs;
queuespace = qalloc( queuespacesize );
if (NULL == queuespace) {
*err=NOMEM;
CYG_REPORT_RETURN();
return;
}
// link up freelist
long i;
struct qentry *qtmp;
for ( i=0, qtmp=(struct qentry *)queuespace;
i<maxmsgs-1;
i++, qtmp=qtmp->next ) {
qtmp->busy = false;
qtmp->next = (struct qentry *)((char *)qtmp + entrysize);
} // for
freelist = (struct qentry *)queuespace;
// set the last entry in the chain to the start to make the list circular
qtmp->next = NULL;
qtmp->busy = false;
callback = NULL;
q = NULL;
free_fn = qfree;
#ifdef CYGDBG_USE_ASSERTS
qlen = maxmsgs;
msgsize = maxmsgsize;
#endif
*err = OK;
// object should be valid now
CYG_ASSERT_THISC();
CYG_REPORT_RETURN();
}
//------------------------------------------------------------------------
CYGPRI_KERNEL_SYNCH_MQUEUE_INLINE
Cyg_Mqueue::~Cyg_Mqueue()
{
CYG_REPORT_FUNCTION();
if ( NULL != queuespace ) {
// object should be valid if queuespace was successfully allocated
CYG_ASSERT_THISC();
free_fn( queuespace, queuespacesize );
}
#ifdef CYGDBG_USE_ASSERTS
qlen = msgsize = 0; // deliberately make it fail check_this() if used
#endif
CYG_REPORT_RETURN();
}
//------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -