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

📄 thread.cxx

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 CXX
📖 第 1 页 / 共 3 页
字号:
{
    CYG_REPORT_FUNCTION();

//    CYG_ASSERT( new_priority >=  CYG_THREAD_MAX_PRIORITY, "Priority out of range");
//    CYG_ASSERT( new_priority <=  CYG_THREAD_MIN_PRIORITY, "Priority out of range");
    
    CYG_INSTRUMENT_THREAD(PRIORITY,this,new_priority);
        
    // Prevent preemption
    Cyg_Scheduler::lock();

    Cyg_ThreadQueue *queue = NULL;
    
    // If running, remove from run qs
    if( state == RUNNING )
        Cyg_Scheduler::scheduler.rem_thread(this);
    else if( state & SLEEPING )
    {
        // Remove thread from current queue.
        queue = get_current_queue();
        // if indeed we are on a queue
        if ( NULL != queue ) {
            CYG_CHECK_DATA_PTR(queue, "Bad queue pointer");        
            remove();
        }
    }

    Cyg_Scheduler::scheduler.deregister_thread(this);
    
#if CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES

    // Check that there are no other threads at this priority.
    // If so, leave is as it is.

    CYG_ASSERT( Cyg_Scheduler::scheduler.unique(new_priority), "Priority not unique");
    
    if( Cyg_Scheduler::scheduler.unique(new_priority) )
        priority = new_priority;

#else // !CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES

#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_SIMPLE

    // When we have priority inheritance, we must update the original
    // priority and not the inherited one.  If the new priority is
    // better than the current inherited one, then use that
    // immediately. We remain in inherited state to avoid problems
    // with multiple mutex inheritances.
    
    if( priority_inherited )
    {
        original_priority = new_priority;
        if( priority > new_priority ) priority = new_priority;
    }
    else priority = new_priority;
    
#else    

    priority = new_priority;

#endif
    
#endif // CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES

    Cyg_Scheduler::scheduler.register_thread(this);
    
    // Return thread to scheduler if runnable
    if( state == RUNNING )
        Cyg_Scheduler::scheduler.add_thread(this);
    else if ( state & SLEEPING )
    {
        // return to current queue
        // if indeed we are on a queue
        if ( NULL != queue ) {
            CYG_CHECK_DATA_PTR(queue, "Bad queue pointer");
            queue->enqueue(this);
        }
    }

    // If the current thread is being reprioritized, set the
    // reschedule flag to ensure that it gets rescheduled if
    // necessary. (Strictly we only need to do this if the new
    // priority is less than that of some other runnable thread, in
    // practice checking that is as expensive as what the scheduler
    // will do anyway).
    // If it is not the current thread then we need to see whether
    // it is more worthy of execution than any current thread and
    // rescheduled if necessary.
    
    if( this == Cyg_Scheduler::get_current_thread() )
         Cyg_Scheduler::set_need_reschedule();
    else Cyg_Scheduler::set_need_reschedule(this);
    
    // Unlock the scheduler and maybe switch threads
    Cyg_Scheduler::unlock();
    CYG_REPORT_RETURN();
}

#endif


// -------------------------------------------------------------------------
// Thread delay function

void
Cyg_Thread::delay( cyg_tick_count delay)
{
    CYG_REPORT_FUNCTION();

#ifdef CYGFUN_KERNEL_THREADS_TIMER

    CYG_INSTRUMENT_THREAD(DELAY,this,delay);

    // Prevent preemption
    Cyg_Scheduler::lock();
    
    sleep();

    set_timer( Cyg_Clock::real_time_clock->current_value()+delay, DELAY );

    // Unlock the scheduler and maybe switch threads
    Cyg_Scheduler::unlock();

    // Clear the timeout. It is irrelevant whether the alarm has
    // actually gone off or not.
    clear_timer();

    // and deal with anything else we must do when we return
    switch( wake_reason ) {
    case DESTRUCT:
    case EXIT:            
        exit();
        break;
        
    default:
        break;
    }
#endif
    CYG_REPORT_RETURN();
}

// -------------------------------------------------------------------------
//

#ifdef CYGPKG_KERNEL_EXCEPTIONS

void
Cyg_Thread::deliver_exception(
    cyg_code            exception_number,       // exception being raised
    CYG_ADDRWORD        exception_info          // exception specific info
    )
{
    if( this == Cyg_Scheduler::get_current_thread() )
    {
        // Delivering to current thread, probably as a result
        // of a real hardware exception. Simply invoke the appropriate
        // handler.

        exception_control.deliver_exception( exception_number, exception_info );
    }
#ifdef CYGIMP_EXCEPTION_ASYNC    
    else
    {
        // Delivering to another thread, probably as a result of one thread
        // invoking this function on another thread. Adjust the other thread's
        // state to make it execute the exception routine when it next runs.

        // At present there is an unresolved problem here. We do not know what
        // state the destination thread is in. It may not be a suitable point at
        // which to invoke an exception routine. In most cases the exception
        // routine will be run in the scheduler thread switch code, where the world is
        // in an inconsistent state. We really need to run the routine at the
        // end of unlock_inner(). However this would add extra code to the scheduler,
        // and require a way of storing pending exceptions. So for now this option is
        // disabled and not yet implemented, it may never be.
        
    }
#endif    
}

#endif

// -------------------------------------------------------------------------
// Per-thread data support

#ifdef CYGVAR_KERNEL_THREADS_DATA

// Set the data map bits for each free slot in the data array.
cyg_ucount32 Cyg_Thread::thread_data_map = (~CYGNUM_KERNEL_THREADS_DATA_ALL) &
             (1+(((cyg_ucount32)(1<<(CYGNUM_KERNEL_THREADS_DATA_MAX-1))-1)<<1));
// the second expression is equivalent to ((1<<CYGNUM_KERNEL_THREADS_DATA_MAX)-1);
// but avoids overflow. The compiler will compile to a constant just fine.

Cyg_Thread::cyg_data_index
Cyg_Thread::new_data_index()
{
    Cyg_Scheduler::lock();

    Cyg_Thread::cyg_data_index index;

    if (0 == thread_data_map)
        return -1;
    
    // find ls set bit
    HAL_LSBIT_INDEX( index, thread_data_map );

    // clear the bit
    thread_data_map &= ~(1<<index);
    
    Cyg_Scheduler::unlock();

    return index;
}

void Cyg_Thread::free_data_index( Cyg_Thread::cyg_data_index index )
{
    Cyg_Scheduler::lock();

    thread_data_map |= (1<<index);
    
    Cyg_Scheduler::unlock();    
}


#endif

// -------------------------------------------------------------------------
// Allocate some memory at the lower end of the stack
// by moving the stack limit pointer.

#if defined(CYGFUN_KERNEL_THREADS_STACK_LIMIT) && \    defined(CYGFUN_KERNEL_THREADS_STACK_CHECKING)
// if not doing stack checking, implementation can be found in thread.inl
// This implementation puts the magic buffer area (to watch for overruns
// *above* the stack limit, i.e. there is no official demarcation between
// the stack and the buffer. But that's okay if you think about it... having
// a demarcation would not accomplish anything more.
void *Cyg_HardwareThread::increment_stack_limit( cyg_ucount32 size )
{
    void *ret = (void *)stack_limit;

    // First lock the scheduler because we're going to be tinkering with
    // the check data
    Cyg_Scheduler::lock();

    // if we've inc'd the limit before, it will be off by the check data
    // size, so lets correct it
    if (stack_limit != stack_base)
        stack_limit -= CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE;
    stack_limit += size;

    // determine base of check data by rounding up to nearest word aligned
    // address if not already aligned
    cyg_uint32 *p = (cyg_uint32 *)((stack_limit + 3) & ~3);
    // i.e. + sizeof(cyg_uint32)-1) & ~(sizeof(cyg_uint32)-1);
    cyg_ucount32 i;
    cyg_uint32 sig = (cyg_uint32)this;
    
    for ( i = 0;
          i < CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE/sizeof(cyg_uint32);
          i++ ) {
        p[i] = (sig ^ (i * 0x01010101));
    }

    // increment limit by the check size. Note this will not necessarily
    // reach the end of the check data. But that doesn't really matter.
    // Doing this allows better checking of the saved stack pointer in
    // Cyg_Thread::check_this()
    stack_limit += CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE;

    Cyg_Scheduler::unlock();
    
    return ret;
}
#endif
    
// =========================================================================
// Cyg_ThreadTimer member functions

// -------------------------------------------------------------------------
// Timer alarm function. Inspect the sleep_reason and if necessary wake
// up the thread with an appropriate wake_reason.

#ifdef CYGFUN_KERNEL_THREADS_TIMER

void
Cyg_ThreadTimer::alarm(
    Cyg_Alarm           *alarm,
    CYG_ADDRWORD        data
)
{
    CYG_REPORT_FUNCTION();

    Cyg_ThreadTimer *self = (Cyg_ThreadTimer *)data;
    Cyg_Thread *thread = self->thread;
    
    CYG_INSTRUMENT_THREAD(ALARM, 0, 0);
    
    Cyg_Scheduler::lock();

    Cyg_Thread::cyg_reason sleep_reason = thread->get_sleep_reason();
    
    switch( sleep_reason ) {
        
    case Cyg_Thread::DESTRUCT:
    case Cyg_Thread::BREAK:
    case Cyg_Thread::EXIT:
    case Cyg_Thread::NONE:
    case Cyg_Thread::WAIT:
    case Cyg_Thread::DONE:
        // Do nothing in any of these cases. Most are here to
        // keep the compiler happy.
        Cyg_Scheduler::unlock();
        CYG_REPORT_RETURN();
        return;

    case Cyg_Thread::DELAY:
        // The thread was simply delaying, unless it has been
        // woken up for some other reason, wake it now.
        thread->set_wake_reason(Cyg_Thread::DONE);
        break;

    case Cyg_Thread::TIMEOUT:
        // The thread has timed out, set the wake reason to
        // TIMEOUT and restart.
        thread->set_wake_reason(Cyg_Thread::TIMEOUT);
        break;
    }

    thread->wake();

    Cyg_Scheduler::unlock();
    CYG_REPORT_RETURN();
}

#endif

// =========================================================================
// The Idle thread
// The idle thread is implemented as a single instance of the
// Cyg_IdleThread class. This is so that it can be initialized before
// main in a static constructor.

// -------------------------------------------------------------------------
// Data definitions

// stack
#ifdef CYGNUM_HAL_STACK_SIZE_MINIMUM
# ifdef CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE
#  if CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE < CYGNUM_HAL_STACK_SIZE_MINIMUM

// then override the configured stack size
#   undef CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE
#   define CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE CYGNUM_HAL_STACK_SIZE_MINIMUM

#  endif // CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE < CYGNUM_HAL_STACK_SIZE_MINIMUM
# endif // CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE
#endif // CYGNUM_HAL_STACK_SIZE_MINIMUM

static char idle_thread_stack[CYGNUM_KERNEL_CPU_MAX][CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE];

// Loop counter for debugging/housekeeping
cyg_uint32 idle_thread_loops[CYGNUM_KERNEL_CPU_MAX];

// -------------------------------------------------------------------------
// Idle thread code.

void
idle_thread_main( CYG_ADDRESS data )
{
    CYG_REPORT_FUNCTION();

    for(;;)
    {
        idle_thread_loops[CYG_KERNEL_CPU_THIS()]++;

        HAL_IDLE_THREAD_ACTION(idle_thread_loops[CYG_KERNEL_CPU_THIS()]);

#if 0
        // For testing, it is useful to be able to fake
        // clock interrupts in the idle thread.
        
        Cyg_Clock::real_time_clock->tick();
#endif
#ifdef CYGIMP_IDLE_THREAD_YIELD
        // In single priority and non-preemptive systems,
        // the idle thread should yield repeatedly to
        // other threads.
        Cyg_Thread::yield();
#endif
    }
}

// -------------------------------------------------------------------------
// Idle thread class

class Cyg_IdleThread : public Cyg_Thread
{
public:
    Cyg_IdleThread();
        
};

// -------------------------------------------------------------------------
// Instantiate the idle thread

Cyg_IdleThread idle_thread[CYGNUM_KERNEL_CPU_MAX] CYG_INIT_PRIORITY( IDLE_THREAD );

// -------------------------------------------------------------------------
// Idle threads constructor

Cyg_IdleThread::Cyg_IdleThread()
    : Cyg_Thread( CYG_THREAD_MIN_PRIORITY,
                  idle_thread_main,
                  0,
                  "Idle Thread",
                  (CYG_ADDRESS)idle_thread_stack[this-&idle_thread[0]],
                  CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE)
{
    CYG_REPORT_FUNCTION();

    // Call into scheduler to set up this thread as the default
    // current thread for its CPU.
    
    Cyg_Scheduler::scheduler.set_idle_thread( this, this-&idle_thread[0] );

    CYG_REPORT_RETURN();
}

// -------------------------------------------------------------------------
// EOF common/thread.cxx

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -