📄 clock.cxx
字号:
//==========================================================================
//
// 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 + -