⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 thread.cxx

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 CXX
📖 第 1 页 / 共 3 页
字号:
//==========================================================================
//
//      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 + -