Mercurial > flash_v2
diff packages/kernel/current/src/sync/mutex.cxx @ 2:443894e2e912 ecos-v1_2_1-release
Block commit of eCos version 1.2.1
| author | jlarmour |
|---|---|
| date | Tue, 11 May 1999 12:24:34 +0000 |
| parents | 3111d98ba7b3 |
| children | 18ee5a9c102e |
line wrap: on
line diff
--- a/packages/kernel/current/src/sync/mutex.cxx +++ b/packages/kernel/current/src/sync/mutex.cxx @@ -1,8 +1,8 @@ //========================================================================== // -// sync/mutex.cxx +// sync/mutex.cxx // -// Mutex and condition variable implementation +// Mutex and condition variable implementation // //========================================================================== //####COPYRIGHTBEGIN#### @@ -22,19 +22,19 @@ // September 30, 1998. // // The Initial Developer of the Original Code is Cygnus. Portions created -// by Cygnus are Copyright (C) 1998 Cygnus Solutions. All Rights Reserved. +// by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions. All Rights Reserved. // ------------------------------------------- // //####COPYRIGHTEND#### //========================================================================== //#####DESCRIPTIONBEGIN#### // -// Author(s): nickg -// Contributors: nickg -// Date: 1997-10-21 -// Purpose: Mutex implementation -// Description: This file contains the implementations of the mutex -// and condition variable classes. +// 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#### // @@ -63,6 +63,8 @@ Cyg_Mutex::Cyg_Mutex() locked = false; owner = NULL; + + CYG_REPORT_RETURN(); } // ------------------------------------------------------------------------- @@ -74,13 +76,15 @@ Cyg_Mutex::~Cyg_Mutex() CYG_ASSERT( owner == NULL, "Deleting mutex with owner"); CYG_ASSERT( queue.empty(), "Deleting mutex with waiting threads"); + CYG_REPORT_RETURN(); } // ------------------------------------------------------------------------- #ifdef CYGDBG_USE_ASSERTS -bool Cyg_Mutex::check_this( cyg_assert_class_zeal zeal) +bool +Cyg_Mutex::check_this( cyg_assert_class_zeal zeal) const { // CYG_REPORT_FUNCTION(); @@ -109,9 +113,10 @@ bool Cyg_Mutex::check_this( cyg_assert_c // ------------------------------------------------------------------------- // Lock and/or wait -cyg_bool Cyg_Mutex::lock() +cyg_bool +Cyg_Mutex::lock(void) { - CYG_REPORT_FUNCTION(); + CYG_REPORT_FUNCTYPE("returning %d"); cyg_bool result = true; Cyg_Thread *self = Cyg_Thread::self(); @@ -128,7 +133,7 @@ cyg_bool Cyg_Mutex::lock() // thread grabbing the mutex between the wakeup in unlock() and // this thread actually starting. - while( locked ) + while( locked && result ) { CYG_ASSERT( self != owner, "Locking mutex I already own"); @@ -191,15 +196,18 @@ cyg_bool Cyg_Mutex::lock() CYG_ASSERTCLASS( this, "Bad this pointer"); + CYG_REPORT_RETVAL(result); + return result; } // ------------------------------------------------------------------------- // Try to lock and return success -cyg_bool Cyg_Mutex::trylock() +cyg_bool +Cyg_Mutex::trylock(void) { - CYG_REPORT_FUNCTION(); + CYG_REPORT_FUNCTYPE("returning %d"); CYG_ASSERTCLASS( this, "Bad this pointer"); @@ -230,13 +238,15 @@ cyg_bool Cyg_Mutex::trylock() // Unlock the scheduler and maybe switch threads Cyg_Scheduler::unlock(); + CYG_REPORT_RETVAL(result); return result; } // ------------------------------------------------------------------------- // unlock -void Cyg_Mutex::unlock() +void +Cyg_Mutex::unlock(void) { CYG_REPORT_FUNCTION(); @@ -281,6 +291,44 @@ void Cyg_Mutex::unlock() // Unlock the scheduler and maybe switch threads Cyg_Scheduler::unlock(); + CYG_REPORT_RETURN(); +} + +// ------------------------------------------------------------------------- +// Release all waiting threads. + +void Cyg_Mutex::release() +{ + CYG_REPORT_FUNCTION(); + + // Prevent preemption + Cyg_Scheduler::lock(); + + CYG_INSTRUMENT_MUTEX(RELEASE, this, 0); + + CYG_ASSERTCLASS( this, "Bad this pointer"); + + while( !queue.empty() ) + { + // The queue is non-empty, so grab each + // thread from it and release it. + + Cyg_Thread *thread = queue.dequeue(); + + CYG_ASSERTCLASS( thread, "Bad thread pointer"); + + thread->release(); + + CYG_INSTRUMENT_MUTEX(RELEASED, this, thread); + + } + + CYG_ASSERTCLASS( this, "Bad this pointer"); + + // Unlock the scheduler and maybe switch threads + Cyg_Scheduler::unlock(); + + CYG_REPORT_RETURN(); } //========================================================================== @@ -295,6 +343,8 @@ Cyg_Condition_Variable::Cyg_Condition_Va mutex = &mx; CYG_ASSERTCLASS( mutex, "Invalid mutex argument"); + + CYG_REPORT_RETURN(); } // ------------------------------------------------------------------------- @@ -305,48 +355,67 @@ Cyg_Condition_Variable::~Cyg_Condition_V CYG_REPORT_FUNCTION(); CYG_ASSERT( queue.empty(), "Deleting condvar with waiting threads"); + + CYG_REPORT_RETURN(); } // ------------------------------------------------------------------------- #ifdef CYGDBG_USE_ASSERTS -bool Cyg_Condition_Variable::check_this( cyg_assert_class_zeal zeal) +bool +Cyg_Condition_Variable::check_this( cyg_assert_class_zeal zeal) const { - CYG_REPORT_FUNCTION(); + bool result = true; + + CYG_REPORT_FUNCTYPE("returning %d"); + CYG_REPORT_FUNCARG1("zeal = %d", zeal); // 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: - if( !mutex->check_this(zeal) ) return false; - case cyg_quick: - case cyg_trivial: - case cyg_none: - default: - break; - }; + if( this == NULL ) + result = false; + else { + + switch( zeal ) + { + case cyg_system_test: + case cyg_extreme: + case cyg_thorough: + if( !mutex->check_this(zeal) ) + result = false; + case cyg_quick: + case cyg_trivial: + case cyg_none: + default: + break; + } + } - return true; + CYG_REPORT_RETVAL(result); + return result; } #endif // ------------------------------------------------------------------------- // Wait for condition to be true +// Note: if this function is entered with the scheduler locked (e.g. to +// suspend DSR processing) then there is no need to take the lock. Also +// in this case, exit with the scheduler locked, which allows this function +// to be used in a totally thread-safe manner. -void Cyg_Condition_Variable::wait() +void +Cyg_Condition_Variable::wait(void) { CYG_REPORT_FUNCTION(); Cyg_Thread *self = Cyg_Thread::self(); - // Prevent preemption - Cyg_Scheduler::lock(); + cyg_int32 current_lock = Cyg_Scheduler::get_sched_lock(); + + if (current_lock == 0) + // Prevent preemption + Cyg_Scheduler::lock(); CYG_ASSERTCLASS( this, "Bad this pointer"); CYG_ASSERTCLASS( mutex, "Corrupt mutex"); @@ -388,18 +457,29 @@ void Cyg_Condition_Variable::wait() // atomically relative to other threads, to avoid races, it is not // necessary for us to re-acquire the mutex in the same atomic // action. Hence we can do it after unlocking the scheduler. - - mutex->lock(); + // We need to loop here in case the thread is released while waiting + // for the mutex. It is essential that we exit this function with the + // mutex claimed. + + while ( !mutex->lock() ) + continue; CYG_ASSERTCLASS( this, "Bad this pointer"); CYG_ASSERTCLASS( mutex, "Corrupt mutex"); CYG_ASSERT( mutex->owner == self, "Not mutex owner"); + + CYG_REPORT_RETURN(); + + if (current_lock) + // Reacquire the DSR pseudo lock + Cyg_Scheduler::lock(); } // ------------------------------------------------------------------------- // Wake one thread -void Cyg_Condition_Variable::signal() +void +Cyg_Condition_Variable::signal(void) { CYG_REPORT_FUNCTION(); @@ -434,12 +514,14 @@ void Cyg_Condition_Variable::signal() // Unlock the scheduler and maybe switch threads Cyg_Scheduler::unlock(); + CYG_REPORT_RETURN(); } // ------------------------------------------------------------------------- // Set cond true, wake all threads -void Cyg_Condition_Variable::broadcast() +void +Cyg_Condition_Variable::broadcast(void) { CYG_REPORT_FUNCTION(); @@ -472,16 +554,20 @@ void Cyg_Condition_Variable::broadcast() // Unlock the scheduler and maybe switch threads Cyg_Scheduler::unlock(); + + CYG_REPORT_RETURN(); } // ------------------------------------------------------------------------- // Optional timed wait on a CV -#if defined(CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT) && defined(CYGFUN_KERNEL_THREADS_TIMER) +#if defined(CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT) -cyg_bool Cyg_Condition_Variable::wait( cyg_tick_count timeout ) +cyg_bool +Cyg_Condition_Variable::wait( cyg_tick_count timeout ) { - CYG_REPORT_FUNCTION(); + CYG_REPORT_FUNCTYPE("returning %d"); + CYG_REPORT_FUNCARG1("timeout = %d", timeout); CYG_ASSERTCLASS( this, "Bad this pointer"); CYG_ASSERTCLASS( mutex, "Corrupt mutex"); @@ -547,10 +633,15 @@ cyg_bool Cyg_Condition_Variable::wait( c // necessary for us to re-acquire the mutex in the same atomic // action. Hence we can do it after unlocking the scheduler. - mutex->lock(); + // FIXME: what if we woke up above due to TIMEOUT/DESTRUCT/BREAK? + // In that situation is it correct to not lock the mutex? + if (false != result) + result = mutex->lock(); CYG_ASSERTCLASS( this, "Bad this pointer"); CYG_ASSERTCLASS( mutex, "Corrupt mutex"); + + CYG_REPORT_RETVAL(result); return result; }
