Cyg_FlagValue
Cyg_Flag::wait( Cyg_FlagValue pattern, WaitMode mode )
{
CYG_REPORT_FUNCTION();
CYG_ASSERTCLASS( this, "Bad this pointer");
CYG_ASSERT( Cyg_Flag::MASK >= mode, "Bad mode" );
Cyg_FlagValue result;
// Prevent preemption so that we compare atomically
Cyg_Scheduler::lock();
// try the current value
result = poll( pattern, mode );
if ( 0 != result ) {
Cyg_Scheduler::unlock();
CYG_REPORT_RETVAL( result );
return result; // all done
} // kaogold3: 若wait條件已經成立, 則直接跳出不等待
// we have to wait until we are awoken
Cyg_Thread *self = Cyg_Thread::self();
FlagWaitInfo saveme;
saveme.allmask = (Cyg_Flag::OR & mode) ? 0 : pattern;
saveme.anymask = (Cyg_Flag::OR & mode) ? pattern : 0;
saveme.do_clear = (0 != (Cyg_Flag::CLR & mode));
self->set_wait_info( (CYG_ADDRWORD)&saveme );
result = true; // just being used as an early-out flag now
// this loop allows us to deal correctly with spurious wakeups
while ( result && (0 == saveme.value_out) ) {
self->set_sleep_reason( Cyg_Thread::WAIT );
self->sleep();
// keep track of myself on the queue of waiting threads
queue.enqueue( self );
// Allow other threads to run
Cyg_Scheduler::reschedule();
// kaogold3: 上面這段重點是將自己的thread state改成sleeping,
// 並放入waiting queue等待喚醒,
// reschedule後即造成context switch,
// 直到thread wake up後繼續執行底下的code
CYG_ASSERT( ((CYG_ADDRWORD)&saveme) ==
Cyg_Thread::self()->get_wait_info(),
"Wait info lost" );
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;
}
}
// kaogold3: saveme.value_out一但有值後就會讓迴圈停止(即等待條件成立)
CYG_ASSERT( (false == result) ^ (0 != saveme.value_out),
"Break out but also good result!" );
// Unlock scheduler and allow other threads to run
Cyg_Scheduler::unlock();
CYG_REPORT_RETVAL( saveme.value_out );
return saveme.value_out;
}