📄 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_CLOCKCyg_Clock *Cyg_Clock::real_time_clock = NULL; // System real time clock#endif//==========================================================================// Constructor for counter objectCyg_Counter::Cyg_Counter( cyg_uint32 incr ){ CYG_REPORT_FUNCTION(); counter = 0; increment = incr;}// -------------------------------------------------------------------------// Destructor for Counter objectCyg_Counter::~Cyg_Counter(){ CYG_REPORT_FUNCTION();}// -------------------------------------------------------------------------// #ifdef CYGDBG_USE_ASSERTScyg_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 functionvoid 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 oragnizations.#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 an unsorted list, we must scan the whole list for // candidates. We move the whole list to a temporary location // before doing this so that we are not disturbed by new // alarms being added to the list. As we consider and // eliminate alarms we put them onto the done_list and at the // end we then move it back to where it belongs. Cyg_Alarm_List done_list; Cyg_Alarm_List alarm_list; alarm_list.merge( *alarm_list_ptr ); while( !alarm_list.empty() ) { Cyg_Alarm *alarm = alarm_list.rem_head(); CYG_ASSERTCLASS(alarm, "Bad alarm in counter list" ); if( alarm->trigger <= counter ) { 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 { // add unused alarm to done list. done_list.add_tail(alarm); } } // Return done list to real list. If any alarms have been // added to the alarm list while we have been scanning then // the done list will be added behind them. alarm_list_ptr->merge( done_list ); #endif Cyg_Scheduler::unlock(); } }// -------------------------------------------------------------------------// Add an alarm to this countervoid Cyg_Counter::add_alarm( Cyg_Alarm *alarm ){ CYG_REPORT_FUNCTION(); CYG_ASSERTCLASS( this, "Bad counter object" ); CYG_ASSERTCLASS( alarm, "Bad alarm passed" ); Cyg_Scheduler::lock(); // 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; Cyg_Scheduler::unlock(); 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 ); goto add_alarm_unlock_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 } alarm_list_ptr->add_tail( alarm ); add_alarm_unlock_return:#else alarm_list_ptr->add_tail( alarm ); #endif Cyg_Scheduler::unlock(); }// -------------------------------------------------------------------------// Remove an alarm from this countervoid Cyg_Counter::rem_alarm( Cyg_Alarm *alarm ){ CYG_REPORT_FUNCTION(); CYG_ASSERTCLASS( this, "Bad counter object" ); CYG_ASSERTCLASS( alarm, "Bad alarm passed" ); 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_Scheduler::lock(); CYG_INSTRUMENT_ALARM( REM, this, alarm ); alarm_list_ptr->remove( alarm ); alarm->enabled = false; Cyg_Scheduler::unlock(); }//==========================================================================// Constructor for clock objectCyg_Clock::Cyg_Clock( cyg_resolution res ){ CYG_REPORT_FUNCTION(); resolution = res;}// -------------------------------------------------------------------------// Destructor for Clock objectsCyg_Clock::~Cyg_Clock(){ CYG_REPORT_FUNCTION();}// -------------------------------------------------------------------------// #ifdef CYGDBG_USE_ASSERTScyg_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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -