📄 mlqueue.cxx
字号:
cyg_bool
Cyg_Scheduler_Implementation::unique( cyg_priority priority)
{
CYG_REPORT_FUNCTYPE("returning %d");
CYG_REPORT_FUNCARG1("priority=%d", priority);
// Priorities are not unique
CYG_REPORT_RETVAL(true);
return true;
}
//==========================================================================
// Support for timeslicing option
#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
// -------------------------------------------------------------------------
void
Cyg_Scheduler_Implementation::timeslice(void)
{
#ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
CYG_REPORT_FUNCTION();
#endif
#ifdef CYGPKG_KERNEL_SMP_SUPPORT
HAL_SMP_CPU_TYPE cpu;
HAL_SMP_CPU_TYPE cpu_count = CYG_KERNEL_CPU_COUNT();
HAL_SMP_CPU_TYPE cpu_this = CYG_KERNEL_CPU_THIS();
for( cpu = 0; cpu < cpu_count; cpu++ )
{
if( --timeslice_count[cpu] == 0 )
if( cpu == cpu_this )
timeslice_cpu();
else CYG_KERNEL_CPU_TIMESLICE_INTERRUPT( cpu, 0 );
}
#else
if( --timeslice_count[CYG_KERNEL_CPU_THIS()] == 0 )
timeslice_cpu();
#endif
#ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
CYG_REPORT_RETURN();
#endif
}
// -------------------------------------------------------------------------
void
Cyg_Scheduler_Implementation::timeslice_cpu(void)
{
#ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
CYG_REPORT_FUNCTION();
#endif
Cyg_Thread *thread = get_current_thread();
HAL_SMP_CPU_TYPE cpu_this = CYG_KERNEL_CPU_THIS();
CYG_ASSERT( queue_map != 0, "Run queue empty");
CYG_ASSERT( queue_map & (1<<CYG_THREAD_MIN_PRIORITY), "Idle thread vanished!!!");
#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE_ENABLE
if( thread->timeslice_enabled &&
timeslice_count[cpu_this] == 0 )
#else
if( timeslice_count[cpu_this] == 0 )
#endif
{
CYG_INSTRUMENT_SCHED(TIMESLICE,0,0);
#ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
CYG_TRACE0( true, "quantum consumed, time to reschedule" );
#endif
CYG_ASSERT( get_sched_lock() > 0 , "Timeslice called with zero sched_lock");
// Only try to rotate the run queue if the current thread is running.
// Otherwise we are going to reschedule anyway.
if( thread->get_state() == Cyg_Thread::RUNNING )
{
Cyg_Scheduler *sched = &Cyg_Scheduler::scheduler;
CYG_INSTRUMENT_MLQ( TIMESLICE, thread, 0);
CYG_ASSERTCLASS( thread, "Bad current thread");
CYG_ASSERTCLASS( sched, "Bad scheduler");
cyg_priority pri = thread->priority;
Cyg_RunQueue *queue = &sched->run_queue[pri];
#ifdef CYGPKG_KERNEL_SMP_SUPPORT
// In SMP systems we set the head of the queue to point to
// the thread immediately after the current
// thread. schedule() will then pick that thread, or one
// after it to run next.
queue->to_head( thread->get_next() );
#else
queue->rotate();
#endif
if( queue->get_head() != thread )
sched->set_need_reschedule();
timeslice_count[cpu_this] = CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS;
}
}
CYG_ASSERT( queue_map & (1<<CYG_THREAD_MIN_PRIORITY), "Idle thread vanished!!!");
CYG_ASSERT( !run_queue[CYG_THREAD_MIN_PRIORITY].empty(), "Idle thread vanished!!!");
#ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
CYG_REPORT_RETURN();
#endif
}
// -------------------------------------------------------------------------
__externC void cyg_scheduler_timeslice_cpu(void)
{
Cyg_Scheduler::scheduler.timeslice_cpu();
}
#endif
//==========================================================================
// Cyg_SchedThread_Implementation class members
Cyg_SchedThread_Implementation::Cyg_SchedThread_Implementation
(
CYG_ADDRWORD sched_info
)
{
CYG_REPORT_FUNCTION();
CYG_REPORT_FUNCARG1("sched_info=%08x", sched_info);
// Set priority to the supplied value.
priority = (cyg_priority)sched_info;
#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE_ENABLE
// If timeslice_enabled exists, set it true by default
timeslice_enabled = true;
#endif
#ifdef CYGPKG_KERNEL_SMP_SUPPORT
cpu = CYG_KERNEL_CPU_NONE;
#endif
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
// Yield the processor to another thread
void
Cyg_SchedThread_Implementation::yield(void)
{
CYG_REPORT_FUNCTION();
// Prevent preemption
Cyg_Scheduler::lock();
Cyg_Thread *thread = CYG_CLASSFROMBASE(Cyg_Thread,
Cyg_SchedThread_Implementation,
this);
// Only do this if this thread is running. If it is not, there
// is no point.
if( thread->get_state() == Cyg_Thread::RUNNING )
{
// To yield we simply rotate the appropriate
// run queue to the next thread and reschedule.
CYG_INSTRUMENT_MLQ( YIELD, thread, 0);
CYG_ASSERTCLASS( thread, "Bad current thread");
Cyg_Scheduler *sched = &Cyg_Scheduler::scheduler;
CYG_ASSERTCLASS( sched, "Bad scheduler");
cyg_priority pri = thread->priority;
Cyg_RunQueue *queue = &sched->run_queue[pri];
#ifdef CYGPKG_KERNEL_SMP_SUPPORT
// In SMP systems we set the head of the queue to point to
// the thread immediately after the current
// thread. schedule() will then pick that thread, or one
// after it to run next.
queue->to_head( thread->get_next() );
#else
queue->rotate();
#endif
if( queue->get_head() != thread )
sched->set_need_reschedule();
else
{
// Reset the timeslice counter so that this thread gets a
// full quantum as a reward for yielding when it is
// eventually rescheduled.
thread->timeslice_reset();
}
}
// Unlock the scheduler and switch threads
#ifdef CYGDBG_USE_ASSERTS
// This test keeps the assertions in unlock_inner() happy if
// need_reschedule was not set above.
if( !Cyg_Scheduler::get_need_reschedule() )
Cyg_Scheduler::unlock();
else
#endif
Cyg_Scheduler::unlock_reschedule();
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
// Rotate the run queue at a specified priority.
// (pri is the decider, not this, so the routine is static)
void
Cyg_SchedThread_Implementation::rotate_queue( cyg_priority pri )
{
CYG_REPORT_FUNCTION();
CYG_REPORT_FUNCARG1("priority=%d", pri);
// Prevent preemption
Cyg_Scheduler::lock();
Cyg_Scheduler *sched = &Cyg_Scheduler::scheduler;
CYG_ASSERTCLASS( sched, "Bad scheduler");
Cyg_RunQueue *queue = &sched->run_queue[pri];
if ( !queue->empty() ) {
queue->rotate();
sched->set_need_reschedule();
}
// Unlock the scheduler and switch threads
Cyg_Scheduler::unlock();
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
// Move this thread to the head of its queue
// (not necessarily a scheduler queue)
void
Cyg_SchedThread_Implementation::to_queue_head( void )
{
CYG_REPORT_FUNCTION();
// Prevent preemption
Cyg_Scheduler::lock();
Cyg_Thread *thread = CYG_CLASSFROMBASE(Cyg_Thread,
Cyg_SchedThread_Implementation,
this);
CYG_ASSERTCLASS( thread, "Bad current thread");
Cyg_ThreadQueue *q = thread->get_current_queue();
if( q != NULL )
q->to_head( thread );
else if( thread->in_list() )
{
// If the queue pointer is NULL then it is on a run
// queue. Move the thread to the head of it's priority list
// and force a reschedule.
Cyg_Scheduler *sched = &Cyg_Scheduler::scheduler;
sched->run_queue[thread->priority].to_head( thread );
sched->set_need_reschedule( thread );
}
// Unlock the scheduler and switch threads
Cyg_Scheduler::unlock();
CYG_REPORT_RETURN();
}
//==========================================================================
// Cyg_ThreadQueue_Implementation class members
// -------------------------------------------------------------------------
void
Cyg_ThreadQueue_Implementation::enqueue(Cyg_Thread *thread)
{
CYG_REPORT_FUNCTION();
CYG_REPORT_FUNCARG1("thread=%08x", thread);
CYG_INSTRUMENT_MLQ( ENQUEUE, this, thread );
#ifdef CYGIMP_KERNEL_SCHED_SORTED_QUEUES
// Insert the thread into the queue in priority order.
Cyg_Thread *qhead = get_head();
if( qhead == NULL ) add_tail( thread );
else if( qhead == qhead->get_next() )
{
// There is currently only one thread in the queue, join it
// and adjust the queue pointer to point to the highest
// priority of the two. If they are the same priority,
// leave the pointer pointing to the oldest.
qhead->insert( thread );
if( thread->priority < qhead->priority )
to_head(thread);
}
else
{
// There is more than one thread in the queue. First check
// whether we are of higher priority than the head and if
// so just jump in at the front. Also check whether we are
// lower priority than the tail and jump onto the end.
// Otherwise we really have to search the queue to find
// our place.
if( thread->priority < qhead->priority )
{
qhead->insert( thread );
to_head(thread);
}
else if( thread->priority > get_tail()->priority )
{
// We are lower priority than any thread in the queue,
// go in at the end.
add_tail( thread );
}
else
{
// Search the queue. We do this backwards so that we
// always add new threads after any that have the same
// priority.
// Because of the previous tests we know that this
// search will terminate before we hit the head of the
// queue, hence we do not need to check for that
// condition.
Cyg_Thread *qtmp = get_tail();
// Scan the queue until we find a higher or equal
// priority thread.
while( qtmp->priority > thread->priority )
qtmp = qtmp->get_prev();
// Append ourself after the node pointed to by qtmp.
qtmp->append( thread );
}
}
#else
// Just add the thread to the tail of the list
add_tail( thread );
#endif
thread->queue = CYG_CLASSFROMBASE(Cyg_ThreadQueue,
Cyg_ThreadQueue_Implementation,
this);
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
Cyg_Thread *
Cyg_ThreadQueue_Implementation::dequeue(void)
{
CYG_REPORT_FUNCTYPE("returning thread %08x");
Cyg_Thread *thread = rem_head();
CYG_INSTRUMENT_MLQ( DEQUEUE, this, thread );
if( thread != NULL )
thread->queue = NULL;
CYG_REPORT_RETVAL(thread);
return thread;
}
// -------------------------------------------------------------------------
void
Cyg_ThreadQueue_Implementation::remove( Cyg_Thread *thread )
{
CYG_REPORT_FUNCTION();
CYG_REPORT_FUNCARG1("thread=%08x", thread);
CYG_INSTRUMENT_MLQ( REMOVE, this, thread );
thread->queue = NULL;
Cyg_CList_T<Cyg_Thread>::remove( thread );
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
Cyg_Thread *
Cyg_ThreadQueue_Implementation::highpri(void)
{
CYG_REPORT_FUNCTYPE("returning thread %08x");
CYG_REPORT_RETVAL(get_head());
return get_head();
}
// -------------------------------------------------------------------------
inline void
Cyg_ThreadQueue_Implementation::set_thread_queue(Cyg_Thread *thread,
Cyg_ThreadQueue *tq )
{
thread->queue = tq;
}
// -------------------------------------------------------------------------
#endif
// -------------------------------------------------------------------------
// EOF sched/mlqueue.cxx
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -