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

📄 clock.cxx

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 CXX
📖 第 1 页 / 共 2 页
字号:
//==========================================================================
//
//      common/clock.cxx
//
//      Clock class implementations
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2002 Jonathan Larmour
//
// 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:     Clock class implementation
// Description: This file contains the definitions of the counter,
//              clock and alarm class member functions that are common
//              to all clock 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/clock.hxx>        // our header

#include <cyg/kernel/sched.hxx>        // scheduler definitions
#include <cyg/kernel/thread.hxx>       // thread definitions
#include <cyg/kernel/intr.hxx>         // interrupt definitions

#include <cyg/kernel/sched.inl>        // scheduler inlines
#include <cyg/kernel/clock.inl>        // Clock inlines

// -------------------------------------------------------------------------
// Static variables

#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK

Cyg_Clock *Cyg_Clock::real_time_clock = NULL;   // System real time clock

#endif

//==========================================================================
// Constructor for counter object

Cyg_Counter::Cyg_Counter(
    cyg_uint32      incr
    )
{
    CYG_REPORT_FUNCTION();

    counter = 0;
    increment = incr;

}

// -------------------------------------------------------------------------
// Destructor for Counter object

Cyg_Counter::~Cyg_Counter()
{
    CYG_REPORT_FUNCTION();


}

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

#ifdef CYGDBG_USE_ASSERTS

cyg_bool Cyg_Counter::check_this( cyg_assert_class_zeal zeal) const
{
    // 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:
    case cyg_quick:
    case cyg_trivial:
    case cyg_none:
    default:
        break;
    };

    return true;
}

#endif

// -------------------------------------------------------------------------
// Counter tick function

void Cyg_Counter::tick( cyg_uint32 ticks )
{
//    CYG_REPORT_FUNCTION();

    CYG_ASSERTCLASS( this, "Bad counter object" );

    // Increment the counter in a loop so we process
    // each tick separately. This is easier than trying
    // to cope with a range of increments.
    
    while( ticks-- )
    {
        Cyg_Scheduler::lock();

        // increment the counter, note that it is
        // allowed to wrap.
        counter += increment;

        // now check for any expired alarms

        Cyg_Alarm_List *alarm_list_ptr;     // pointer to list

#if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST)

        alarm_list_ptr = &alarm_list;

#elif defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST)

        // With multiple lists, each one contains only the alarms
        // that will expire at a given tick modulo the list number.
        // So we only have a fraction of the alarms to check here.
        
        alarm_list_ptr = &(alarm_list[
                               (counter/increment) % CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE ] );
    
#else
#error "No CYGIMP_KERNEL_COUNTERS_x_LIST config"
#endif

        // Now that we have the list pointer, we can use common code for
        // both list organizations.

#ifdef CYGIMP_KERNEL_COUNTERS_SORT_LIST

        // With a sorted alarm list, we can simply pick alarms off the
        // front of the list until we find one that is in the future.

        while( !alarm_list_ptr->empty() )
        {
            Cyg_Alarm *alarm = alarm_list_ptr->get_head();
        
            CYG_ASSERTCLASS(alarm, "Bad alarm in counter list" );
            
            if( alarm->trigger <= counter )
            {
                // remove alarm from list
                alarm_list_ptr->rem_head();

                if( alarm->interval != 0 )
                {
                    // The alarm has a retrigger interval.
                    // Reset the trigger time and requeue
                    // the alarm.
                    alarm->trigger += alarm->interval;
                    add_alarm( alarm );
                }
                else alarm->enabled = false;

                CYG_INSTRUMENT_ALARM( CALL, this, alarm );
                
                // call alarm function
                alarm->alarm(alarm, alarm->data);

                // all done, loop
            }
            else break;
            
        } 
#else

        // With unsorted lists we must scan the whole list for
        // candidates. However, we must be careful here since it is
        // possible for the function of one alarm to add or remove
        // other alarms to/from this list. Having the list shift under
        // our feet in this way could be disasterous. We solve this by
        // restarting the scan from the beginning whenever we call an
        // alarm function.

        cyg_bool rescan = true;

        while( rescan )
        {
            Cyg_DNode_T<Cyg_Alarm> *node = alarm_list_ptr->get_head();

            rescan = false;
            
            while( node != NULL )
            {
                Cyg_Alarm *alarm = CYG_CLASSFROMBASE( Cyg_Alarm, Cyg_DNode, node );
                Cyg_DNode_T<Cyg_Alarm> *next = alarm->get_next();

                CYG_ASSERTCLASS(alarm, "Bad alarm in counter list" );

                if( alarm->trigger <= counter )
                {
                    alarm_list_ptr->remove(alarm);

                    if( alarm->interval != 0 )
                    {
                        // The alarm has a retrigger interval.
                        // Reset the trigger time and requeue
                        // the alarm.
                        alarm->trigger += alarm->interval;
                        add_alarm( alarm );
                    }
                    else alarm->enabled = false;

                    CYG_INSTRUMENT_ALARM( CALL, this, alarm );
                
                    // Call alarm function
                    alarm->alarm(alarm, alarm->data);

                    rescan = true;

                    break;
                }

                // If the next node is the head of the list, then we have
                // looped all the way around. The node == next test
                // catches the case where we only had one element to start
                // with.
                if( next == alarm_list_ptr->get_head() || node == next )
                    node = NULL;
                else
                    node = next;
            }

        }
        
#endif        
        Cyg_Scheduler::unlock();

    }
    
}

// -------------------------------------------------------------------------
// Add an alarm to this counter

void Cyg_Counter::add_alarm( Cyg_Alarm *alarm )
{
    CYG_REPORT_FUNCTION();

    CYG_ASSERTCLASS( this, "Bad counter object" );
    CYG_ASSERTCLASS( alarm, "Bad alarm passed" );
    CYG_ASSERT( Cyg_Scheduler::get_sched_lock() > 0, "Scheduler not locked");
    
    // set this now to allow an immediate handler call to manipulate
    // this alarm sensibly.
    alarm->enabled = true;

    // Check here for an alarm that triggers now or in the past and
    // call its alarm function immediately. 
    if( alarm->trigger <= counter )
    {
        CYG_INSTRUMENT_ALARM( CALL, this, alarm );

        // call alarm function. Note that this is being
        // called here before the add_alarm has returned.
        // Note that this function may disable the alarm.
        
        alarm->alarm(alarm, alarm->data);

        // Note that this extra check on alarm->enabled is in case the
        // handler function disables this alarm!
        if( alarm->interval != 0 && alarm->enabled )
        {
            // The alarm has a retrigger interval.
            // Reset the trigger interval and drop
            // through to queue it.
            alarm->trigger += alarm->interval;
            // ensure the next alarm time is in our future, and in phase
            // with the original time requested.
            alarm->synchronize();
        }
        else
        {
            // The alarm is all done with, disable it
            // unlock and return.
            alarm->enabled = false;
            return;
        }
    }
    
    CYG_INSTRUMENT_ALARM( ADD, this, alarm );
 
    // Find the pointer to the relevant list _after_ a retrigger
    // alarm has been given its new trigger time.

    Cyg_Alarm_List *alarm_list_ptr;     // pointer to list

#if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST)

    alarm_list_ptr = &alarm_list;

#elif defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST)

    // Each alarm must go into the list that covers the tick that is
    // going to happen _after_ the trigger time (or at it if trigger
    // happens to fall on a tick.
    
    alarm_list_ptr = &(alarm_list[
        ((alarm->trigger+increment-1)/increment) %
        CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE ] );
    
#else
#error "No CYGIMP_KERNEL_COUNTERS_x_LIST config"
#endif

#ifdef CYGIMP_KERNEL_COUNTERS_SORT_LIST
        
    // Now that we have the list pointer, we can use common code for
    // both list organizations.

    Cyg_Alarm *list_alarm = alarm_list_ptr->get_head();

    if( list_alarm != NULL )
    {
        do
        {
            CYG_ASSERTCLASS(list_alarm, "Bad alarm in counter list" );

            // The alarms are in ascending trigger order. If we
            // find an alarm that triggers later than us, we go
            // in front of it.
        
            if( list_alarm->trigger > alarm->trigger )
            {
                alarm_list_ptr->insert( list_alarm, alarm );
                return;
            }

            list_alarm = list_alarm->get_next();
            
        } while( list_alarm != alarm_list_ptr->get_head() );
        // a lower or equal alarm time was not found, so drop through
        // so it is added to the list tail
    }
#endif

    alarm_list_ptr->add_tail( alarm );
}

// -------------------------------------------------------------------------
// Remove an alarm from this counter

void Cyg_Counter::rem_alarm( Cyg_Alarm *alarm )
{
    CYG_REPORT_FUNCTION();

    CYG_ASSERTCLASS( this, "Bad counter object" );
    CYG_ASSERTCLASS( alarm, "Bad alarm passed" );
    CYG_ASSERT( Cyg_Scheduler::get_sched_lock() > 0, "Scheduler not locked");
    
    Cyg_Alarm_List *alarm_list_ptr;     // pointer to list

#if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST)

    alarm_list_ptr = &alarm_list;

#elif defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST)

    alarm_list_ptr = &(alarm_list[
        ((alarm->trigger+increment-1)/increment) %
                              CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE ] );
    
#else
#error "No CYGIMP_KERNEL_COUNTERS_x_LIST config"
#endif

    // Now that we have the list pointer, we can use common code for
    // both list organizations.

    CYG_INSTRUMENT_ALARM( REM, this, alarm );

    alarm_list_ptr->remove( alarm );
    
    alarm->enabled = false;

}

//==========================================================================
// Constructor for clock object

Cyg_Clock::Cyg_Clock(
    cyg_resolution      res
    )
{
    CYG_REPORT_FUNCTION();

    resolution = res;
}

// -------------------------------------------------------------------------
// Destructor for Clock objects

Cyg_Clock::~Cyg_Clock()
{
    CYG_REPORT_FUNCTION();

}

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

#ifdef CYGDBG_USE_ASSERTS

cyg_bool Cyg_Clock::check_this( cyg_assert_class_zeal zeal) const
{
    // 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:
    case cyg_quick:
    case cyg_trivial:
    case cyg_none:
    default:
        break;
    };

    return true;
}

#endif

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

⌨️ 快捷键说明

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