📄 mutex.cxx
字号:
//==========================================================================
//
// sync/mutex.cxx
//
// Mutex and condition variable 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): nickg
// Contributors: nickg, jlarmour
// Date: 1999-02-17
// Purpose: Mutex implementation
// Description: This file contains the implementations of the mutex
// and condition variable classes.
//
//####DESCRIPTIONEND####
//
//==========================================================================
#include <pkgconf/kernel.h>
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
#include <cyg/kernel/instrmnt.h> // instrumentation
#include <cyg/kernel/mutex.hxx> // our header
#include <cyg/kernel/thread.inl> // thread inlines
#include <cyg/kernel/sched.inl> // scheduler inlines
#include <cyg/kernel/clock.inl> // clock inlines
// -------------------------------------------------------------------------
// Mutex protocol test macros.
// If the dynamic protocol option is enabled, then these generate appropriate
// tests on the protocol field. If there is no dynamic choice then they simply
// result in empty statements.
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
#define IF_PROTOCOL_INHERIT if( protocol == INHERIT )
#define IF_PROTOCOL_CEILING if( protocol == CEILING )
#define IF_PROTOCOL_ACTIVE if( protocol != NONE )
#else
#define IF_PROTOCOL_INHERIT
#define IF_PROTOCOL_CEILING
#define IF_PROTOCOL_ACTIVE
#endif
// -------------------------------------------------------------------------
// Constructor
Cyg_Mutex::Cyg_Mutex()
{
CYG_REPORT_FUNCTION();
locked = false;
owner = NULL;
#if defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT) && \ defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC)
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_INHERIT
protocol = INHERIT;
#endif
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_CEILING
protocol = CEILING;
ceiling = CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY;
#endif
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_NONE
protocol = NONE;
#endif
#else // not (DYNAMIC and DEFAULT defined)
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY
// if there is a default priority ceiling defined, use that to initialize
// the ceiling.
ceiling = CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY;
#else
// Otherwise set it to zero.
ceiling = 0;
#endif
#endif
#endif // DYNAMIC and DEFAULT defined
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
// Construct with defined protocol
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
Cyg_Mutex::Cyg_Mutex( cyg_protcol protocol_arg )
{
CYG_REPORT_FUNCTION();
locked = false;
owner = NULL;
protocol = protocol_arg;
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY
// if there is a default priority ceiling defined, use that to initialize
// the ceiling.
ceiling = CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY;
#else
// Otherwise set it to zero.
ceiling = 0;
#endif
#endif
CYG_REPORT_RETURN();
}
#endif
// -------------------------------------------------------------------------
// Destructor
Cyg_Mutex::~Cyg_Mutex()
{
CYG_REPORT_FUNCTION();
CYG_ASSERT( owner == NULL, "Deleting mutex with owner");
CYG_ASSERT( queue.empty(), "Deleting mutex with waiting threads");
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
#ifdef CYGDBG_USE_ASSERTS
cyg_bool
Cyg_Mutex::check_this( cyg_assert_class_zeal zeal) const
{
// CYG_REPORT_FUNCTION();
// check that we have a non-NULL pointer first
if( this == NULL ) return false;
switch( zeal )
{
case cyg_system_test:
case cyg_extreme:
case cyg_thorough:
case cyg_quick:
case cyg_trivial:
if( locked && owner == NULL ) return false;
if( !locked && owner != NULL ) return false;
case cyg_none:
default:
break;
};
return true;
}
#endif
// -------------------------------------------------------------------------
// Lock and/or wait
cyg_bool
Cyg_Mutex::lock(void)
{
CYG_REPORT_FUNCTYPE("returning %d");
cyg_bool result = true;
Cyg_Thread *self = Cyg_Thread::self();
// Prevent preemption
Cyg_Scheduler::lock();
CYG_ASSERTCLASS( this, "Bad this pointer");
CYG_INSTRUMENT_MUTEX(LOCK, this, 0);
// Loop while the mutex is locked, sleeping each time around
// the loop. This copes with the possibility of a higher priority
// thread grabbing the mutex between the wakeup in unlock() and
// this thread actually starting.
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
IF_PROTOCOL_ACTIVE
self->count_mutex();
#endif
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
IF_PROTOCOL_CEILING
self->set_priority_ceiling(ceiling);
#endif
while( locked && result )
{
CYG_ASSERT( self != owner, "Locking mutex I already own");
self->set_sleep_reason( Cyg_Thread::WAIT );
self->sleep();
queue.enqueue( self );
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
IF_PROTOCOL_INHERIT
owner->inherit_priority(self);
#endif
CYG_INSTRUMENT_MUTEX(WAIT, this, 0);
// Allow other threads to run
Cyg_Scheduler::reschedule();
CYG_ASSERTCLASS( this, "Bad this pointer");
switch( self->get_wake_reason() )
{
case Cyg_Thread::DESTRUCT:
case Cyg_Thread::BREAK:
result = false;
break;
case Cyg_Thread::EXIT:
self->exit();
break;
default:
break;
}
}
if( result )
{
locked = true;
owner = self;
CYG_INSTRUMENT_MUTEX(LOCKED, this, 0);
}
else
{
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
IF_PROTOCOL_ACTIVE
self->uncount_mutex();
#endif
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
IF_PROTOCOL_INHERIT
self->disinherit_priority();
#endif
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
IF_PROTOCOL_CEILING
self->clear_priority_ceiling();
#endif
}
// Unlock the scheduler and maybe switch threads
Cyg_Scheduler::unlock();
CYG_ASSERTCLASS( this, "Bad this pointer");
CYG_REPORT_RETVAL(result);
return result;
}
// -------------------------------------------------------------------------
// Try to lock and return success
cyg_bool
Cyg_Mutex::trylock(void)
{
CYG_REPORT_FUNCTYPE("returning %d");
CYG_ASSERTCLASS( this, "Bad this pointer");
cyg_bool result = true;
// Prevent preemption
Cyg_Scheduler::lock();
// If the mutex is not locked, grab it
// for ourself. Otherwise return failure.
if( !locked )
{
Cyg_Thread *self = Cyg_Thread::self();
locked = true;
owner = self;
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
IF_PROTOCOL_ACTIVE
self->count_mutex();
#endif
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
IF_PROTOCOL_CEILING
self->set_priority_ceiling(ceiling);
#endif
}
else result = false;
CYG_INSTRUMENT_MUTEX(TRY, this, result);
// Unlock the scheduler and maybe switch threads
Cyg_Scheduler::unlock();
CYG_REPORT_RETVAL(result);
return result;
}
// -------------------------------------------------------------------------
// unlock
void
Cyg_Mutex::unlock(void)
{
CYG_REPORT_FUNCTION();
// Prevent preemption
Cyg_Scheduler::lock();
CYG_INSTRUMENT_MUTEX(UNLOCK, this, 0);
CYG_ASSERTCLASS( this, "Bad this pointer");
CYG_ASSERT( locked, "Unlock mutex that is not locked");
CYG_ASSERT( owner == Cyg_Thread::self(), "Unlock mutex I do not own");
if( !queue.empty() ) {
// The queue is non-empty, so grab the next
// thread from it and wake it up.
Cyg_Thread *thread = queue.dequeue();
CYG_ASSERTCLASS( thread, "Bad thread pointer");
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
// Give the owner-to-be a chance to inherit from the remaining
// queue or the relinquishing thread:
IF_PROTOCOL_INHERIT
thread->relay_priority(owner, &queue);
#endif
thread->set_wake_reason( Cyg_Thread::DONE );
thread->wake();
CYG_INSTRUMENT_MUTEX(WAKE, this, thread);
}
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
IF_PROTOCOL_ACTIVE
owner->uncount_mutex();
#endif
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
IF_PROTOCOL_INHERIT
owner->disinherit_priority();
#endif
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -