📄 mutex.cxx
字号:
// Unlock the scheduler and maybe switch threads Cyg_Scheduler::unlock(); CYG_REPORT_RETURN();}//==========================================================================// Condition variablesCyg_Condition_Variable::Cyg_Condition_Variable( Cyg_Mutex &mx // linked mutex ){ CYG_REPORT_FUNCTION(); mutex = &mx; CYG_ASSERTCLASS( mutex, "Invalid mutex argument"); CYG_REPORT_RETURN();}// -------------------------------------------------------------------------// DestructorCyg_Condition_Variable::~Cyg_Condition_Variable(){ CYG_REPORT_FUNCTION(); CYG_ASSERT( queue.empty(), "Deleting condvar with waiting threads"); CYG_REPORT_RETURN();}// -------------------------------------------------------------------------#ifdef CYGDBG_USE_ASSERTSboolCyg_Condition_Variable::check_this( cyg_assert_class_zeal zeal) const{ 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 ) 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; } } 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.voidCyg_Condition_Variable::wait(void){ CYG_REPORT_FUNCTION(); Cyg_Thread *self = Cyg_Thread::self(); 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"); CYG_ASSERTCLASS( self, "Bad self thread"); CYG_INSTRUMENT_CONDVAR(WAIT, this, 0); mutex->unlock(); self->set_sleep_reason( Cyg_Thread::WAIT ); self->sleep(); queue.enqueue( self ); CYG_ASSERT( Cyg_Scheduler::get_sched_lock() == 1, "Called with non-zero scheduler lock"); // Unlock the scheduler and switch threads Cyg_Scheduler::unlock(); CYG_INSTRUMENT_CONDVAR(WOKE, this, self->get_wake_reason()); CYG_ASSERTCLASS( this, "Bad this pointer"); CYG_ASSERTCLASS( mutex, "Corrupt mutex"); switch( self->get_wake_reason() ) { case Cyg_Thread::EXIT: self->exit(); break; default: break; } // When we awake, we must re-acquire the mutex. Note that while // it is essential to release the mutex and queue on the CV // 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. // 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 threadvoidCyg_Condition_Variable::signal(void){ CYG_REPORT_FUNCTION(); CYG_ASSERTCLASS( this, "Bad this pointer"); CYG_ASSERTCLASS( mutex, "Corrupt mutex"); // Prevent preemption Cyg_Scheduler::lock(); CYG_INSTRUMENT_CONDVAR(SIGNAL, this, 0); 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"); thread->set_wake_reason( Cyg_Thread::DONE ); thread->wake(); CYG_INSTRUMENT_CONDVAR(WAKE, this, thread); } CYG_ASSERTCLASS( this, "Bad this pointer"); CYG_ASSERTCLASS( mutex, "Corrupt mutex"); // Unlock the scheduler and maybe switch threads Cyg_Scheduler::unlock(); CYG_REPORT_RETURN();}// -------------------------------------------------------------------------// Set cond true, wake all threadsvoidCyg_Condition_Variable::broadcast(void){ CYG_REPORT_FUNCTION(); CYG_ASSERTCLASS( this, "Bad this pointer"); CYG_ASSERTCLASS( mutex, "Corrupt mutex"); // Prevent preemption Cyg_Scheduler::lock(); CYG_INSTRUMENT_CONDVAR(BROADCAST, this, 0); // Grab all the threads from the queue and let them // go. while( !queue.empty() ) { Cyg_Thread *thread = queue.dequeue(); CYG_ASSERTCLASS( thread, "Bad thread pointer"); thread->set_wake_reason( Cyg_Thread::DONE ); thread->wake(); CYG_INSTRUMENT_CONDVAR(WAKE, this, thread); } CYG_ASSERTCLASS( this, "Bad this pointer"); CYG_ASSERTCLASS( mutex, "Corrupt mutex"); // 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)cyg_boolCyg_Condition_Variable::wait( cyg_tick_count timeout ){ CYG_REPORT_FUNCTYPE("returning %d"); CYG_REPORT_FUNCARG1("timeout = %d", timeout); CYG_ASSERTCLASS( this, "Bad this pointer"); CYG_ASSERTCLASS( mutex, "Corrupt mutex"); cyg_bool result = true; Cyg_Thread *self = Cyg_Thread::self(); CYG_ASSERTCLASS( self, "Bad self thread"); // Prevent preemption Cyg_Scheduler::lock(); CYG_INSTRUMENT_CONDVAR(TIMED_WAIT, this, 0 ); mutex->unlock(); // The ordering of sleep() and set_timer() here are // important. If the timeout is in the past, the thread // will be woken up immediately and will not sleep. self->sleep(); // Set the timer and sleep reason self->set_timer( timeout, Cyg_Thread::TIMEOUT ); // Only enqueue if the timeout has not already fired. if( self->get_wake_reason() == Cyg_Thread::NONE ) queue.enqueue( self ); CYG_ASSERT( Cyg_Scheduler::get_sched_lock() == 1, "Called with non-zero scheduler lock"); // Unlock the scheduler and switch threads Cyg_Scheduler::unlock(); CYG_ASSERTCLASS( this, "Bad this pointer"); CYG_ASSERTCLASS( mutex, "Corrupt mutex"); self->clear_timer(); CYG_INSTRUMENT_CONDVAR(WOKE, this, self->get_wake_reason()); switch( self->get_wake_reason() ) { case Cyg_Thread::TIMEOUT: case Cyg_Thread::DESTRUCT: // which, the cv or the mutex? case Cyg_Thread::BREAK: result = false; break; case Cyg_Thread::EXIT: self->exit(); break; default: break; } // When we awake, we must re-acquire the mutex. Note that while // it is essential to release the mutex and queue on the CV // 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. // 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;}#endif// -------------------------------------------------------------------------// EOF sync/mutex.cxx
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -