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;
}

 

arrow
arrow
    全站熱搜

    kaogold3 發表在 痞客邦 留言(0) 人氣()