📄 sched.cxx
字号:
//==========================================================================//// sched/sched.cxx//// Scheduler class implementations////==========================================================================//####COPYRIGHTBEGIN####//// -------------------------------------------// The contents of this file are subject to the Cygnus eCos Public License// Version 1.0 (the "License"); you may not use this file except in// compliance with the License. You may obtain a copy of the License at// http://sourceware.cygnus.com/ecos// // Software distributed under the License is distributed on an "AS IS"// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the// License for the specific language governing rights and limitations under// the License.// // The Original Code is eCos - Embedded Cygnus Operating System, released// September 30, 1998.// // The Initial Developer of the Original Code is Cygnus. Portions created// by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions. All Rights Reserved.// -------------------------------------------////####COPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s): nickg// Contributors: nickg// Date: 1997-09-15// Purpose: Scheduler class implementation// Description: This file contains the definitions of the scheduler class// member functions that are common to all scheduler// implementations.////####DESCRIPTIONEND####////==========================================================================#include <pkgconf/kernel.h>#include <cyg/kernel/ktypes.h> // base kernel types#include <cyg/infra/cyg_trac.h> // tracing macros#include <cyg/infra/cyg_ass.h> // assertion macros#include <cyg/kernel/instrmnt.h> // instrumentation#include <cyg/kernel/sched.hxx> // our header#include <cyg/kernel/thread.hxx> // thread classes#include <cyg/kernel/intr.hxx> // Interrupt interface#include <cyg/hal/hal_arch.h> // Architecture specific definitions#include <cyg/kernel/thread.inl> // thread inlines//-------------------------------------------------------------------------// Some local tracing control - a default.#ifdef CYGDBG_USE_TRACING# if !defined( CYGDBG_INFRA_DEBUG_TRACE_ASSERT_SIMPLE ) && \ !defined( CYGDBG_INFRA_DEBUG_TRACE_ASSERT_FANCY ) // ie. not a tracing implementation that takes a long time to output# ifndef CYGDBG_KERNEL_TRACE_UNLOCK_INNER# define CYGDBG_KERNEL_TRACE_UNLOCK_INNER# endif // control not already defined# endif // trace implementation not ..._SIMPLE && not ..._FANCY#endif // CYGDBG_USE_TRACING// -------------------------------------------------------------------------// Static Cyg_Scheduler class members// We start with sched_lock at 1 so that any kernel code we// call during initialization will not try to reschedule.volatile cyg_ucount32 Cyg_Scheduler_Base::sched_lock = 1;Cyg_Thread *Cyg_Scheduler_Base::current_thread = NULL;cyg_bool Cyg_Scheduler_Base::need_reschedule = false;Cyg_Scheduler Cyg_Scheduler::scheduler CYG_INIT_PRIORITY( SCHEDULER );cyg_ucount32 Cyg_Scheduler_Base::thread_switches = 0;// -------------------------------------------------------------------------// Scheduler unlock function.// This is only called when the lock is to be decremented to zero and there// is the potential for real work to be done. Other cases are handled in// Cyg_Scheduler::unlock() which is an inline.void Cyg_Scheduler::unlock_inner(){#ifdef CYGDBG_KERNEL_TRACE_UNLOCK_INNER CYG_REPORT_FUNCTION();#endif do { CYG_PRECONDITION( sched_lock == 1 , "sched_lock not 1" ); #ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS // Call any pending DSRs. Do this here to ensure that any // threads that get awakened are properly scheduled. if( Cyg_Interrupt::DSRs_pending() ) Cyg_Interrupt::call_pending_DSRs();#endif Cyg_Thread *current = current_thread; CYG_ASSERTCLASS( current, "Bad current thread" ); // If the current thread is going to sleep, or someone // wants a reschedule, choose another thread to run if( current->state != Cyg_Thread::RUNNING || need_reschedule ) { CYG_INSTRUMENT_SCHED(RESCHEDULE,0,0); // Get the next thread to run from scheduler Cyg_Thread *next = scheduler.schedule(); CYG_CHECK_DATA_PTR( next, "Invalid next thread pointer"); CYG_ASSERTCLASS( next, "Bad next thread" ); if( current != next ) { CYG_INSTRUMENT_THREAD(SWITCH,current,next); // Count this thread switch thread_switches++; // Switch contexts HAL_THREAD_SWITCH_CONTEXT( ¤t->stack_ptr, &next->stack_ptr ); // Worry here about possible compiler // optimizations across the above call that may try to // propogate common subexpresions. We would end up // with the expression from one thread in its // successor. This is only a worry if we do not save // and restore the complete register set. We need a // way of marking functions that return into a // different context. A temporary fix would be to // disable CSE (-fdisable-cse) in the compiler. // We return here only when the current thread is // rescheduled. There is a bit of housekeeping to do // here before we are allowed to go on our way. CYG_CHECK_DATA_PTR( current, "Invalid current thread pointer"); CYG_ASSERTCLASS( current, "Bad current thread" ); current_thread = current; // restore current thread pointer }#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE // Reset the timeslice counter so that this thread gets a full // quantum. reset_timeslice_count();#endif need_reschedule = false; // finished rescheduling } HAL_REORDER_BARRIER(); // Make sure everything above has happened // by this point sched_lock = 0; // Clear the lock HAL_REORDER_BARRIER(); #ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS // Now check whether any DSRs got posted during the thread // switch and if so, go around again. Making this test after // the lock has been zeroed avoids a race condition in which // a DSR could have been posted during a reschedule, but would // not be run until the _next_ time we release the sched lock. if( Cyg_Interrupt::DSRs_pending() ) { sched_lock = 1; // reclaim the lock continue; // go back to head of loop }#endif // Otherwise the lock is zero, we can return. CYG_POSTCONDITION( sched_lock == 0, "sched_lock not zero" ); #ifdef CYGDBG_KERNEL_TRACE_UNLOCK_INNER CYG_REPORT_RETURN();#endif return; } while( 1 ); CYG_FAIL( "Should not be executed" );}// -------------------------------------------------------------------------// Start the scheduler. This is called after the initial threads have been// created to start scheduling.void Cyg_Scheduler::start(){ CYG_REPORT_FUNCTION(); // Get the first thread to run from scheduler register Cyg_Thread *next = scheduler.schedule(); CYG_ASSERTCLASS( next, "Bad initial thread" ); need_reschedule = false; // finished rescheduling current_thread = next; // restore current thread pointer#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK // Reference the real time clock. This ensures that at least one // reference to the kernel_clock.o object exists, without which // the object will not be included while linking. CYG_REFERENCE_OBJECT( Cyg_Clock::real_time_clock );#endif // Let the interrupts go Cyg_Interrupt::enable_interrupts(); HAL_THREAD_LOAD_CONTEXT( &next->stack_ptr ); }// -------------------------------------------------------------------------// Consistency checker#ifdef CYGDBG_USE_ASSERTSbool Cyg_Scheduler::check_this( cyg_assert_class_zeal zeal) const{ CYG_REPORT_FUNCTION(); // check that we have a non-NULL pointer first if( this == NULL ) return false; switch( zeal ) { case cyg_system_test: case cyg_extreme: case cyg_thorough: if( !current_thread->check_this(zeal) ) return false; case cyg_quick: case cyg_trivial: case cyg_none: default: break; }; return true;}#endif//==========================================================================// SchedThread members// -------------------------------------------------------------------------// ConstructorCyg_SchedThread::Cyg_SchedThread(Cyg_Thread *thread, CYG_ADDRWORD sched_info): Cyg_SchedThread_Implementation(sched_info){ CYG_REPORT_FUNCTION(); queue = NULL; if( Cyg_Scheduler::current_thread == NULL ) Cyg_Scheduler::current_thread = thread;#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE_SIMPLE mutex_count = 0; priority_inherited = false; #endif }// -------------------------------------------------------------------------// Priority inheritance support.#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE// -------------------------------------------------------------------------// Inherit the priority of the provided thread if it// has a higher priority than ours.void Cyg_SchedThread::inherit_priority( Cyg_Thread *thread){#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE_SIMPLE // A simple implementation of priority inheritance. If the other // thread is of higher priority, reset our priority to his. The // first time we do this, save our original priority. Cyg_Thread *self = CYG_CLASSFROMBASE(Cyg_Thread, Cyg_SchedThread, this); CYG_ASSERT( mutex_count > 0, "Non-positive mutex count"); CYG_ASSERT( self != thread, "Trying to inherit from self!"); if( thread->get_priority() < priority ) { cyg_priority mypri = priority; if( !priority_inherited ) { // If this is first inheritance, copy the old pri // and set inherited flag. We do this after setting the // pri since set_priority() is inheritance aware. self->set_priority( thread->get_priority() ); priority_inherited = true, original_priority = mypri; } else { // Already in inherited state, and new pri is higher // than old. Just change the pri. self->set_priority( thread->get_priority() ); } }#endif}// -------------------------------------------------------------------------// Lose a priority inheritancevoid Cyg_SchedThread::disinherit_priority(){#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE_SIMPLE // A simple implementation of priority inheritance. The // simplification in this algorithm is that we do not reduce our // priority until we have freed all mutexes claimed. Hence we can // continue to run at an artificially high priority even when we // should not. However, since nested mutexes are rare, the thread // we have inherited from is likely to be locking the same mutexes // we are, and mutex claim periods should be very short, the // performance difference between this and a more complex algorithm // should be negligible. The most important advantage of this // algorithm is that it is fast and deterministic. Cyg_Thread *self = CYG_CLASSFROMBASE(Cyg_Thread, Cyg_SchedThread, this); CYG_ASSERT( mutex_count >= 0, "Non-positive mutex count"); if( mutex_count == 0 && priority_inherited ) { priority_inherited = false; // Only make an effort if the priority must change if( priority < original_priority ) self->set_priority( original_priority ); } #endif }#endif// -------------------------------------------------------------------------// EOF sched/sched.cxx
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -