📄 thread.cxx
字号:
//==========================================================================//// common/thread.cxx//// Thread 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: Thread class implementation// Description: This file contains the definitions of the thread class// member functions that are common to all thread implementations.////####DESCRIPTIONEND####////==========================================================================#include <pkgconf/kernel.h> // kernel configuration file#include <cyg/hal/hal_arch.h> // HAL_REORDER_BARRIER & // CYGNUM_HAL_STACK_SIZE_TYPICAL#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/thread.hxx> // our header#include <cyg/kernel/intr.hxx> // Interrupt support#include <cyg/kernel/thread.inl> // thread inlines#include <cyg/kernel/sched.inl> // scheduler inlines#include <cyg/kernel/clock.inl> // clock inlines// =========================================================================// Cyg_HardwareThread members// -------------------------------------------------------------------------// Thread entry point.// This is inserted as the PC value in all initial thread contexts.// It does some housekeeping and then calls the real entry point.voidCyg_HardwareThread::thread_entry( Cyg_Thread *thread ){ CYG_REPORT_FUNCTION(); Cyg_Scheduler::scheduler.need_reschedule = false; // finished rescheduling Cyg_Scheduler::scheduler.current_thread = thread; // restore current thread pointer#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE // Reset the timeslice counter so that this thread gets a full // quantum. Cyg_Scheduler::reset_timeslice_count();#endif // Zero the lock HAL_REORDER_BARRIER (); // Prevent the compiler from moving Cyg_Scheduler::sched_lock = 0; // the assignment into the code above. HAL_REORDER_BARRIER(); // Call entry point in a loop. for(;;) { thread->entry_point(thread->entry_data); thread->exit(); }}// =========================================================================// Cyg_Thread members// -------------------------------------------------------------------------// Statics and thread list functions#ifdef CYGVAR_KERNEL_THREADS_LIST// List of all extant threadsCyg_Thread *Cyg_Thread::thread_list = 0;inline voidCyg_Thread::add_to_list( void ){ // Add thread to housekeeping list Cyg_Scheduler::lock(); if( thread_list == 0 ) list_next = this; else { Cyg_Thread *prev = thread_list; do { if ( this == prev ) break; // found it already! prev = prev->list_next; } while ( prev != thread_list ); if ( this != prev ) { // insert it in the list: list_next = thread_list->list_next; thread_list->list_next = this; } } thread_list = this; Cyg_Scheduler::unlock();}inline voidCyg_Thread::remove_from_list( void ){ // remove thread from housekeeping list Cyg_Scheduler::lock(); Cyg_Thread *prev = thread_list; do { if( prev->list_next == this ) { prev->list_next = list_next; if( thread_list == this ) thread_list = list_next; break; } prev = prev->list_next; } while ( prev != thread_list ); Cyg_Scheduler::unlock();}#endifstatic cyg_uint16 next_unique_id = 1;// -------------------------------------------------------------------------// Magic new operator to allow the thread constructor to be// recalled.inline void *operator new(size_t size, Cyg_Thread *ptr){ return (void *)ptr; };// ConstructorCyg_Thread::Cyg_Thread( CYG_ADDRWORD sched_info, // Scheduling parameter(s) cyg_thread_entry *entry, // entry point function CYG_ADDRWORD entry_data, // entry data char *name_arg, // thread name cookie CYG_ADDRESS stack_base, // stack base, NULL = allocate cyg_ucount32 stack_size // stack size, 0 = use default ): Cyg_HardwareThread(entry, entry_data, stack_size, stack_base), Cyg_SchedThread(this, sched_info)#ifdef CYGFUN_KERNEL_THREADS_TIMER ,timer(this)#endif{ CYG_REPORT_FUNCTION(); // Start the thread in suspended state. state = SUSPENDED; suspend_count = 1; // Initialize sleep_reason which is used by kill, release sleep_reason = NONE; wake_reason = NONE; // Assign a 16 bit id to the thread. unique_id = next_unique_id++;#ifdef CYGVAR_KERNEL_THREADS_DATA // Zero all per-thread data entries. for( int i = 0; i < CYGNUM_KERNEL_THREADS_DATA_MAX; i++ ) thread_data[i] = 0;#endif#ifdef CYGVAR_KERNEL_THREADS_NAME name = name_arg;#endif#ifdef CYGVAR_KERNEL_THREADS_LIST // Add thread to housekeeping list add_to_list();#endif Cyg_Scheduler::scheduler.register_thread(this); init_context(this); CYG_REPORT_RETURN();}// -------------------------------------------------------------------------// Re-initialize this thread.// We do this by re-invoking the constructor with the original// arguments, which are still available in the object.voidCyg_Thread::reinitialize(){ CYG_REPORT_FUNCTION(); CYG_ASSERTCLASS( this, "Bad thread"); CYG_ASSERT( this != Cyg_Scheduler::get_current_thread(), "Attempt to reinitialize current thread"); CYG_ASSERT( get_current_queue() == NULL , "Thread is still on a queue");#ifdef CYGFUN_KERNEL_THREADS_TIMER // Clear the timeout. It is irrelevant whether there was // actually a timeout pending. timer.disable();#endif // Ensure the scheduler has let go of us. Cyg_Scheduler::scheduler.deregister_thread(this); cyg_priority pri = get_priority();#ifdef CYGVAR_KERNEL_THREADS_NAME char * name_arg = name;#else char * name_arg = NULL;#endif new(this) Cyg_Thread( pri, entry_point, entry_data, name_arg, stack_base, stack_size ); // the constructor re-registers the thread with the scheduler. CYG_ASSERTCLASS( this, "Thread corrupted by reinitialize"); CYG_REPORT_RETURN();}// -------------------------------------------------------------------------// Destructor.Cyg_Thread::~Cyg_Thread(){ CYG_REPORT_FUNCTION(); Cyg_Scheduler::scheduler.deregister_thread(this);#ifdef CYGVAR_KERNEL_THREADS_LIST // Remove thread from housekeeping list. remove_from_list();#endif CYG_REPORT_RETURN();}// -------------------------------------------------------------------------// Thread consistency checker.#ifdef CYGDBG_USE_ASSERTSboolCyg_Thread::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( (state & SUSPENDED) && (suspend_count == 0) ) return false; case cyg_quick: // Check that the stackpointer is within its limits. // Note: This does not check the current stackpointer value // of the executing thread. if( (stack_ptr > (stack_base + stack_size)) || (stack_ptr < stack_base) ) return false; case cyg_trivial: case cyg_none: default: break; }; return true;}#endif// -------------------------------------------------------------------------// Put the thread to sleep.// This can only be called by the current thread on itself, hence// it is a static function.voidCyg_Thread::sleep(){ 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 running, remove from run qs if ( current->state == RUNNING ) Cyg_Scheduler::scheduler.rem_thread(current); // Set the state current->state |= SLEEPING; // Unlock the scheduler and switch threads Cyg_Scheduler::unlock(); CYG_REPORT_RETURN();}// -------------------------------------------------------------------------// Awaken the thread from sleep.voidCyg_Thread::wake(){ CYG_REPORT_FUNCTION(); CYG_INSTRUMENT_THREAD(WAKE,this,Cyg_Scheduler::current_thread); // Prevent preemption Cyg_Scheduler::lock(); if( 0 != (state & SLEEPSET) ) { // Set the state state &= ~SLEEPSET; // remove from any queue we were on remove(); // If the thread is now runnable, return it to run queue if( state == RUNNING ) Cyg_Scheduler::scheduler.add_thread(this); } // Unlock the scheduler and maybe switch threads Cyg_Scheduler::unlock(); CYG_REPORT_RETURN();}// -------------------------------------------------------------------------// Put the thread to sleep, with wakeup count.// This can only be called by the current thread on itself, hence// it is a static function.voidCyg_Thread::counted_sleep(){ 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_sleep_reason( Cyg_Thread::WAIT ); current->sleep(); // prepare to sleep current->state |= COUNTSLEEP; // Set the state }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -