📄 thread.cxx
字号:
// Unlock the scheduler and switch threads
Cyg_Scheduler::unlock();
// and deal with anything we must do when we return
switch( current->wake_reason ) {
case DESTRUCT:
case EXIT:
current->exit();
break;
default:
break;
}
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
// Put the thread to sleep for a delay, with wakeup count.
// This can only be called by the current thread on itself, hence
// it is a static function.
#ifdef CYGFUN_KERNEL_THREADS_TIMER
void
Cyg_Thread::counted_sleep( cyg_tick_count delay )
{
CYG_REPORT_FUNCTION();
Cyg_Thread *current = Cyg_Scheduler::get_current_thread();
CYG_ASSERTCLASS( current, "Bad current thread" );
CYG_INSTRUMENT_THREAD(SLEEP,current,0);
// Prevent preemption
Cyg_Scheduler::lock();
if ( 0 == current->wakeup_count ) {
// Set the timer (once outside any waiting loop.)
set_timer( Cyg_Clock::real_time_clock->current_value()+delay,
Cyg_Thread::TIMEOUT );
// If the timeout is in the past, the wake reason will have been
// set to something other than NONE already.
if( current->get_wake_reason() == Cyg_Thread::NONE )
{
set_sleep_reason( Cyg_Thread::TIMEOUT );
current->sleep(); // prepare to sleep
current->state |= COUNTSLEEP; // Set the state
Cyg_Scheduler::reschedule();
// clear the timer; if it actually fired, no worries.
clear_timer();
}
}
else
// there is a queued wakeup, do not sleep
current->wakeup_count--;
// Unlock the scheduler and switch threads
Cyg_Scheduler::unlock();
// and deal with anything we must do when we return
switch( current->wake_reason ) {
case DESTRUCT:
case EXIT:
current->exit();
break;
default:
break;
}
CYG_REPORT_RETURN();
}
#endif
// -------------------------------------------------------------------------
// Awaken the thread from sleep.
void
Cyg_Thread::counted_wake()
{
CYG_REPORT_FUNCTION();
CYG_INSTRUMENT_THREAD(WAKE,this,Cyg_Scheduler::current_thread);
// Prevent preemption
Cyg_Scheduler::lock();
if ( 0 == (state & COUNTSLEEP) ) // already awake, or waiting:
wakeup_count++; // not in a counted sleep anyway.
else {
sleep_reason = NONE;
wake_reason = DONE;
wake(); // and awaken the thread
}
#ifdef CYGNUM_KERNEL_MAX_COUNTED_WAKE_COUNT_ASSERT
CYG_ASSERT( CYGNUM_KERNEL_MAX_COUNTED_WAKE_COUNT_ASSERT > wakeup_count,
"wakeup_count overflow" );
#endif
// Unlock the scheduler and maybe switch threads
Cyg_Scheduler::unlock();
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
// Cancel wakeups for this thread and return how many were pending
cyg_uint32
Cyg_Thread::cancel_counted_wake()
{
CYG_REPORT_FUNCTION();
CYG_INSTRUMENT_THREAD(WAKE,this,Cyg_Scheduler::current_thread);
// Prevent preemption
Cyg_Scheduler::lock();
cyg_uint32 result = wakeup_count;
wakeup_count = 0;
// Unlock the scheduler
Cyg_Scheduler::unlock();
CYG_REPORT_RETVAL( result );
return result;
}
// -------------------------------------------------------------------------
// Suspend thread. Increment suspend count and deschedule thread
// if still running.
void
Cyg_Thread::suspend()
{
CYG_REPORT_FUNCTION();
CYG_INSTRUMENT_THREAD(SUSPEND,this,Cyg_Scheduler::current_thread);
// Prevent preemption
Cyg_Scheduler::lock();
suspend_count++;
#ifdef CYGNUM_KERNEL_MAX_SUSPEND_COUNT_ASSERT
CYG_ASSERT( CYGNUM_KERNEL_MAX_SUSPEND_COUNT_ASSERT > suspend_count,
"suspend_count overflow" );
#endif
// If running, remove from run qs
if( state == RUNNING )
Cyg_Scheduler::scheduler.rem_thread(this);
// Set the state
state |= SUSPENDED;
// Unlock the scheduler and maybe switch threads
Cyg_Scheduler::unlock();
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
// Resume thread. Decrement suspend count and reschedule if it
// is zero.
void
Cyg_Thread::resume()
{
CYG_REPORT_FUNCTION();
CYG_INSTRUMENT_THREAD(RESUME,this,Cyg_Scheduler::current_thread);
// Prevent preemption
Cyg_Scheduler::lock();
// If we are about to zero the count, clear the state bit and
// reschedule the thread if possible.
if( suspend_count == 1 )
{
suspend_count = 0;
CYG_ASSERT( (state & SUSPENDED) != 0, "SUSPENDED bit not set" );
// Set the state
state &= ~SUSPENDED;
// Return thread to scheduler if runnable
if( state == RUNNING )
Cyg_Scheduler::scheduler.add_thread(this);
}
else
if( suspend_count > 0 )
suspend_count--;
// else ignore attempt to resume
// Unlock the scheduler and maybe switch threads
Cyg_Scheduler::unlock();
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
// Forced Resume thread. Zero suspend count and reschedule...
void
Cyg_Thread::force_resume()
{
CYG_REPORT_FUNCTION();
CYG_INSTRUMENT_THREAD(RESUME,this,Cyg_Scheduler::current_thread);
// Prevent preemption
Cyg_Scheduler::lock();
// If we are about to zero the count, clear the state bit and
// reschedule the thread if possible.
if ( 0 < suspend_count ) {
suspend_count = 0;
CYG_ASSERT( (state & SUSPENDED) != 0, "SUSPENDED bit not set" );
// Set the state
state &= ~SUSPENDED;
// Return thread to scheduler if runnable
if( state == RUNNING )
Cyg_Scheduler::scheduler.add_thread(this);
}
// Unlock the scheduler and maybe switch threads
Cyg_Scheduler::unlock();
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
// Force thread to wake up from a sleep with a wake_reason of
// BREAK. It is the responsibility of the woken thread to detect
// the release() and do the right thing.
void
Cyg_Thread::release()
{
CYG_REPORT_FUNCTION();
// Prevent preemption
Cyg_Scheduler::lock();
// If the thread is in any of the sleep states, set the
// wake reason and wake it up.
switch( sleep_reason )
{
case NONE:
// The thread is not sleeping for any reason, do nothing.
// drop through...
case DESTRUCT:
case BREAK:
case EXIT:
case DONE:
// Do nothing in any of these cases. They are here to
// keep the compiler happy.
Cyg_Scheduler::unlock();
CYG_REPORT_RETURN();
return;
case WAIT:
// The thread was waiting for some sync object to do
// something.
// drop through...
case TIMEOUT:
// The thread was waiting on a sync object with a timeout.
// drop through...
case DELAY:
// The thread was simply delaying, unless it has been
// woken up for some other reason, wake it now.
sleep_reason = NONE;
wake_reason = BREAK;
break;
}
wake();
// Allow preemption
Cyg_Scheduler::unlock();
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
// Exit thread. This puts the thread into EXITED state.
#ifdef CYGPKG_KERNEL_THREADS_DESTRUCTORS
#ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
Cyg_Thread::Cyg_Destructor_Entry
Cyg_Thread::destructors[ CYGNUM_KERNEL_THREADS_DESTRUCTORS ];
#endif
#endif
void
Cyg_Thread::exit()
{
CYG_REPORT_FUNCTION();
// The thread should never return from this function.
Cyg_Thread *self = Cyg_Thread::self();
#ifdef CYGPKG_KERNEL_THREADS_DESTRUCTORS
cyg_ucount16 i;
for (i=0; i<CYGNUM_KERNEL_THREADS_DESTRUCTORS; i++) {
if (NULL != self->destructors[i].fn) {
destructor_fn fn = self->destructors[i].fn;
CYG_ADDRWORD data = self->destructors[i].data;
fn(data);
}
}
#endif
#ifdef CYGDBG_KERNEL_THREADS_STACK_MEASUREMENT_VERBOSE_EXIT
diag_printf( "Stack usage for thread %08x: %d\n", self,
self->measure_stack_usage() );
#endif
Cyg_Scheduler::lock();
// clear the timer; if there was none, no worries.
clear_timer();
// It is possible that we have already been killed by another
// thread, in which case we do not want to try and take ourself
// out of the scheduler again.
if( self->state != EXITED )
{
self->state = EXITED;
Cyg_Scheduler::scheduler.rem_thread(self);
}
Cyg_Scheduler::reschedule();
}
// -------------------------------------------------------------------------
// Kill thread. Force the thread into EXITED state externally, or
// make it wake up and call exit().
void
Cyg_Thread::kill()
{
CYG_REPORT_FUNCTION();
// If this is called by the current thread on itself,
// just call exit(), which is what he should have done
// in the first place.
if( this == Cyg_Scheduler::get_current_thread() )
exit();
// Prevent preemption
Cyg_Scheduler::lock();
// We are killing someone else. Find out what state he is
// in and force him to wakeup and call exit().
force_resume(); // this is necessary for when
// he is asleep AND suspended.
#ifdef CYGFUN_KERNEL_THREADS_TIMER
timer.disable(); // and make sure the timer
// does not persist.
#endif
if ( EXIT != wake_reason ) switch( sleep_reason ) {
// Only do any of this if the thread is not in pending death already:
case NONE:
// The thread is not sleeping for any reason, it must be
// on a run queue.
// We can safely deschedule and set its state.
if( state == RUNNING ) Cyg_Scheduler::scheduler.rem_thread(this);
state = EXITED;
break;
case DESTRUCT:
case BREAK:
case EXIT:
case DONE:
// Do nothing in any of these cases. They are here to
// keep the compiler happy.
Cyg_Scheduler::unlock();
CYG_REPORT_RETURN();
return;
case WAIT:
// The thread was waiting for some sync object to do
// something.
// drop through...
case TIMEOUT:
// The thread was waiting on a sync object with a timeout.
// drop through...
case DELAY:
// The thread was simply delaying, unless it has been
// woken up for some other reason, wake it now.
sleep_reason = NONE;
wake_reason = EXIT;
break;
}
wake();
// Allow preemption
Cyg_Scheduler::unlock();
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
// Set thread priority
#ifdef CYGIMP_THREAD_PRIORITY
void
Cyg_Thread::set_priority( cyg_priority new_priority )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -