⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mutex.cxx

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 CXX
📖 第 1 页 / 共 2 页
字号:
//==========================================================================
//
//      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 + -