📄 thread.cxx
字号:
//==========================================================================
//
// common/thread.cxx
//
// Thread class implementations
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####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
#ifdef CYGDBG_KERNEL_THREADS_STACK_MEASUREMENT_VERBOSE_EXIT
#include <cyg/infra/diag.h>
#endif
// =========================================================================
// 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.
void
Cyg_HardwareThread::thread_entry( Cyg_Thread *thread )
{
CYG_REPORT_FUNCTION();
Cyg_Scheduler::scheduler.clear_need_reschedule(); // finished rescheduling
Cyg_Scheduler::scheduler.set_current_thread(thread); // restore current thread pointer
CYG_INSTRUMENT_THREAD(ENTER,thread,0);
#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::zero_sched_lock(); // 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 threads
Cyg_Thread *Cyg_Thread::thread_list = 0;
inline void
Cyg_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 void
Cyg_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();
}
#endif
static 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; };
// Constructor
Cyg_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();
CYG_INSTRUMENT_THREAD(CREATE,this,0);
// Start the thread in suspended state.
state = SUSPENDED;
suspend_count = 1;
wakeup_count = 0;
// 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 CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
for (int j=0; j<CYGNUM_KERNEL_THREADS_DESTRUCTORS; j++) {
destructors[j].fn = NULL;
}
#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.
void
Cyg_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,
get_stack_base(), get_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
// Zero the unique_id to render this thread inconsistent.
unique_id = 0;
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
// Thread consistency checker.
#ifdef CYGDBG_USE_ASSERTS
cyg_bool
Cyg_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;
#ifdef CYGFUN_KERNEL_THREADS_STACK_LIMIT
if( stack_ptr < stack_limit ) return false;
#endif
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.
void
Cyg_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.
void
Cyg_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.
void
Cyg_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
}
else
// there is a queued wakeup, do not sleep
current->wakeup_count--;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -