From 15b7cecb6b5415a0b2e15a0f4079be05c436e80e Mon Sep 17 00:00:00 2001 From: chatty Date: Wed, 7 Apr 1993 11:56:59 +0000 Subject: Reshaped to allow the derivation of timers associated to other sources: Creation of CCuCoreTimer, base class to CcuBaseTimer --- utils/Timer.cc | 309 +++++++++++++++++++++++++++++++-------------------------- utils/Timer.h | 68 +++++++++---- 2 files changed, 217 insertions(+), 160 deletions(-) (limited to 'utils') diff --git a/utils/Timer.cc b/utils/Timer.cc index 7911f9a..a8c4a65 100644 --- a/utils/Timer.cc +++ b/utils/Timer.cc @@ -3,7 +3,7 @@ * * by Stephane Chatty * - * Copyright 1992 + * Copyright 1992-1993 * Centre d'Etudes de la Navigation Aerienne (CENA) * * timers @@ -59,95 +59,28 @@ and if we make sure that a timer is flagged as inactive when we insert it, all w occurences before the right one will be removed. !*/ -CcuSignalHandler* CcuBaseTimer::TimeOutHandler = 0; -CcuBaseTimer* CcuBaseTimer::FirstActive = 0; -#ifndef CPLUS_BUG19 -CcuListOf * CcuBaseTimer::OtherActive = 0; -#else -CcuList* CcuBaseTimer::OtherActive = 0; -#endif - -/*?nodoc?*/ -void -CcuBaseTimer :: ClassInit () -{ - TimeOutHandler = new CcuSignalHandler (SigAlrm, &CcuBaseTimer::HandleSignal); -#ifndef CPLUS_BUG19 - OtherActive = new CcuListOf ; -#else - OtherActive = new CcuList; -#endif -} - -/*?hidden?*/ -void -CcuBaseTimer :: StopAlarm () -{ - struct itimerval itval; - timerclear (&itval.it_value); - timerclear (&itval.it_interval); - setitimer (ITIMER_REAL, &itval, 0); -} - -/*?hidden?*/ -void -CcuBaseTimer :: SetAlarm (Millisecond delay) -{ - if (delay <= 0) { - StopAlarm (); - kill (getpid (), SigAlrm); - return; - } - - struct itimerval itval; - timerclear (&itval.it_interval); - itval.it_value.tv_sec = delay / 1000; - itval.it_value.tv_usec = 1000 * (delay % 1000); - setitimer (ITIMER_REAL, &itval, 0); -} /*! Remove and return the first active timer in the active timer list. Timers in that list can actually be inactive. !*/ /*?hidden?*/ -CcuBaseTimer* -CcuBaseTimer :: ExtractNextActive () +CcuCoreTimer* +CcuTimerSet :: ExtractNextActive () { - CcuBaseTimer* t; + CcuCoreTimer* t; - /* all entries of OtherActive are valid pointers, - hence t == 0 iff OtherActive is empty */ + /* all entries of OtherTimers are valid pointers, + hence t == 0 iff OtherTimers is empty */ #ifndef CPLUS_BUG19 - while ((t = OtherActive->RemoveFirst ()) && (t->Status != Active)) + while ((t = OtherTimers.RemoveFirst ()) && (t->StatusFlag != CcuCoreTimer::Active)) #else - while ((t = (CcuBaseTimer*) OtherActive->RemoveFirst ()) && (t->Status != Active)) + while ((t = (CcuCoreTimer*) OtherTimers.RemoveFirst ()) && (t->StatusFlag != CcuCoreTimer::Active)) #endif ; return t; } -#ifndef CPLUS_BUG19 - -/*?hidden?*/ -int -CcuBaseTimer :: IsInactive (CcuBaseTimer* t) -{ - return (t->Status != Active); -} - -#else - -/*?hidden?*/ -int -CcuBaseTimer :: IsInactive (CcuListItem* t) -{ - return (((CcuBaseTimer*) t)->Status != Active); -} - -#endif /* CPLUS_BUG19 */ - - /*! This function is called by the signal handler. The first active timer is expired and scheduled again. Then all the timers whose expiration time is earlier @@ -159,17 +92,24 @@ active timer. !*/ /*?hidden?*/ void -CcuBaseTimer :: HandleSignal (int) +CcuCoreTimer :: Fire (CcuTimerSet* s) { + CcuCoreTimer*& first = s->FirstTimer; + + /* If the first timer is not mature yet, ignore this call */ + if (!first) + return; CcuTimeStamp now; + if (first->NextDate > now) + return; /* Handle the first timer */ - FirstActive->Reschedule (); - FirstActive->Handle (now); + first->Reschedule (); + first->Handle (now); /* handle all other expired timers. */ - CcuBaseTimer* t; - while (t = ExtractNextActive ()) { + CcuCoreTimer* t; + while (t = s->ExtractNextActive ()) { /* Problem : if one Handle () is long, "now" will then be wrong. */ if (t->NextDate > now) break; @@ -177,14 +117,33 @@ CcuBaseTimer :: HandleSignal (int) t->Handle (now); } - CcuTimeStamp then; if (t) - SetAlarm (t->NextDate - then); + t->SetAlarm (t->NextDate); + + first = t; +} + + +#ifndef CPLUS_BUG19 + +/*?hidden?*/ +int +CcuCoreTimer :: IsInactive (CcuCoreTimer* t) +{ + return (t->StatusFlag != Active); +} +#else - FirstActive = t; +/*?hidden?*/ +int +CcuCoreTimer :: IsInactive (CcuListItem* t) +{ + return (((CcuCoreTimer*) t)->StatusFlag != Active); } +#endif /* CPLUS_BUG19 */ + /*? Create a timer that will send a signal every \var{period} milliseconds, \var{pulses} times. @@ -192,29 +151,22 @@ If \var{pulses} is negative, the timer will send signals forever. Timers are activated at creation time. They are disactivated, but not destroyed, after their last signal. ?*/ -CcuBaseTimer :: CcuBaseTimer (Millisecond period, int pulses) -: Status (Active), +CcuCoreTimer :: CcuCoreTimer (Millisecond period, int pulses, CcuTimerSet* set) +: MySet (set), + StatusFlag (Active), Period (period), PulsesLeft (pulses) { - CcuSignalBlocker b (SigAlrm); - - if (!TimeOutHandler) - ClassInit (); - if (PulsesLeft != 0) - Activate (); } /*?hidden?*/ -CcuBaseTimer :: ~CcuBaseTimer () +CcuCoreTimer :: ~CcuCoreTimer () { - /* stop it */ - if (Status == Active) - Stop (); - + /* the timer has to be stopped in the derived class */ /* Remove all entries pointing to inactive timers, including this one */ - OtherActive->Remove (IsInactive, CcuList::All); + if (MySet) + MySet->OtherTimers.Remove (IsInactive, CcuList::All); } /*? @@ -222,7 +174,7 @@ Change the period of a timer. The new period will not be taken into account before the next time-out. ?*/ void -CcuBaseTimer :: ChangePeriod (Millisecond period) +CcuCoreTimer :: ChangePeriod (Millisecond period) { CcuSignalBlocker b (SigAlrm); Period = period; @@ -233,14 +185,14 @@ Stop this timer if it was running, then start it with its current period. This function can be used to reset a timer to the beginning of a period. ?*/ void -CcuBaseTimer :: Restart () +CcuCoreTimer :: Restart () { if (PulsesLeft == 0) return; /* this function could be optimized: sometimes SetAlarm is called twice. */ CcuSignalBlocker b (SigAlrm); - if (Status == Active) + if (StatusFlag == Active) Stop (); Activate (); } @@ -252,26 +204,28 @@ first one, the alarm is updated. !*/ /*?hidden?*/ void -CcuBaseTimer :: Activate () +CcuCoreTimer :: Activate () { + if (!MySet) + return; CcuTimeStamp now; NextDate = now + Period; - - if (!FirstActive) { - FirstActive = this; - SetAlarm (Period); - } else if (NextDate < FirstActive->NextDate ) { - SetAlarm (Period); - OtherActive->Prepend (FirstActive); - FirstActive = this; + CcuCoreTimer*& first = MySet->FirstTimer; + if (!first) { + first = this; + SetAlarm (NextDate); + } else if (NextDate < first->NextDate ) { + SetAlarm (NextDate); + MySet->OtherTimers.Prepend (first); + first = this; } else Schedule (NextDate); - Status = Active; + StatusFlag = Active; } /*?hidden?*/ void -CcuBaseTimer :: Reschedule () +CcuCoreTimer :: Reschedule () { if (PulsesLeft == 0) // this should not happen... return; @@ -285,39 +239,40 @@ CcuBaseTimer :: Reschedule () /*?hidden?*/ void -CcuBaseTimer :: Schedule (Millisecond when) +CcuCoreTimer :: Schedule (Millisecond when) { NextDate = when; /* temporarily set status to inactive so that obsolete entries - in OtherActive pointing to this timer can be removed */ - Status = Inactive; + in OtherTimers pointing to this timer can be removed */ + StatusFlag = Inactive; + CcuListOf & others = MySet->OtherTimers; #ifndef CPLUS_BUG19 - CcuListIterOf li (*OtherActive); - CcuListIterOf lj (*OtherActive); + CcuListIterOf li (others); + CcuListIterOf lj (others); #else - CcuListIter li (*OtherActive); - CcuListIter lj (*OtherActive); + CcuListIter li (others); + CcuListIter lj (others); #endif while (++li) { /* while we're at it, remove inactive timers from the list */ #ifndef CPLUS_BUG19 - CcuBaseTimer* cur = *li; + CcuCoreTimer* cur = *li; #else - CcuBaseTimer* cur = (CcuBaseTimer*) *li; + CcuCoreTimer* cur = (CcuCoreTimer*) *li; #endif - if (cur->Status != Active) { - OtherActive->RemoveAfter (lj); + if (cur->StatusFlag != Active) { + others.RemoveAfter (lj); li = lj; } else if (cur->NextDate < NextDate) ++lj; else break; } - OtherActive->InsertAfter (lj, this); - Status = Active; + others.InsertAfter (lj, this); + StatusFlag = Active; } /*? @@ -325,24 +280,23 @@ Stop a timer. This timer will not deliver any signal until \fun{Restart} is called. ?*/ void -CcuBaseTimer :: Stop () +CcuCoreTimer :: Stop () { - if (Status != Active) + if (StatusFlag != Active) return; CcuSignalBlocker b (SigAlrm); - - Status = Inactive; + CcuCoreTimer*& first = MySet->FirstTimer; + + StatusFlag = Inactive; /* if this timer was the first active one, find another one to replace it */ - if (this == FirstActive) { - FirstActive = ExtractNextActive (); - if (FirstActive == 0) + if (this == first) { + first = MySet->ExtractNextActive (); + if (first == 0) StopAlarm (); - else { - CcuTimeStamp now; - SetAlarm (FirstActive->NextDate -now); - } + else + first->SetAlarm (first->NextDate); } } @@ -350,26 +304,103 @@ CcuBaseTimer :: Stop () Wait for this timer to expire. If it is stopped, return immediately. ?*/ void -CcuBaseTimer :: Wait () +CcuCoreTimer :: Wait () { - if (Status != Active) + if (StatusFlag != Active) return; Millisecond next_date = NextDate; for (;;) { if (wait (0) >= 0) // not an interrupt continue; - if (Status != Active || next_date != NextDate) + if (StatusFlag != Active || next_date != NextDate) return; } } /*?hidden?*/ void -CcuBaseTimer :: Handle (Millisecond) +CcuCoreTimer :: Handle (Millisecond) +{ +} + +CcuSignalHandler* CcuBaseTimer::TimeOutHandler = 0; +CcuTimerSet* CcuBaseTimer::TimerSet = 0; + +/*?nodoc?*/ +void +CcuBaseTimer :: ClassInit () +{ + TimeOutHandler = new CcuSignalHandler (SigAlrm, &CcuBaseTimer::HandleSignal); + TimerSet = new CcuTimerSet; +} + +CcuBaseTimer :: CcuBaseTimer (Millisecond period, int pulses) +: CcuCoreTimer (period, pulses, (TimerSet ? TimerSet : (ClassInit (), TimerSet))) +{ + CcuSignalBlocker b (SigAlrm); + + if (PulsesLeft != 0) + Activate (); +} + +/*?hidden?*/ +CcuBaseTimer :: ~CcuBaseTimer () { + /* stop it */ + if (StatusFlag == Active) + Stop (); } +/*?hidden?*/ +void +CcuBaseTimer :: StopAlarm () +{ + struct itimerval itval; + timerclear (&itval.it_value); + timerclear (&itval.it_interval); + setitimer (ITIMER_REAL, &itval, 0); +} + +/*?hidden?*/ +void +CcuBaseTimer :: SetAlarm (Millisecond when) +{ + CcuTimeStamp now; + Millisecond delay = when - now; + + if (delay <= 0) { + StopAlarm (); + kill (getpid (), SigAlrm); + return; + } + + struct itimerval itval; + timerclear (&itval.it_interval); + itval.it_value.tv_sec = delay / 1000; + itval.it_value.tv_usec = 1000 * (delay % 1000); + setitimer (ITIMER_REAL, &itval, 0); +} + + +/*! +This function is called by the signal handler. The first active timer is expired +and scheduled again. Then all the timers whose expiration time is earlier +that the current time are removed from the list, expired and scheduled again. +The first non-expired timer, if any, is removed from the list and saved +as the first active timer. +Finally, the alarm is set up to expire at the expiration time of the new first +active timer. +!*/ +/*?hidden?*/ +void +CcuBaseTimer :: HandleSignal (int) +{ + Fire (TimerSet); +} + + + /*?class CcuTimer The class \typ{CcuTimer} is a derived class of \typ{CcuBaseTimer} that can be used without deriving a new class. diff --git a/utils/Timer.h b/utils/Timer.h index d361802..77c1b70 100644 --- a/utils/Timer.h +++ b/utils/Timer.h @@ -3,7 +3,7 @@ * * by Stephane Chatty * - * Copyright 1992 + * Copyright 1992-1993 * Centre d'Etudes de la Navigation Aerienne (CENA) * * timers @@ -25,48 +25,74 @@ template class CcuListOf; #include "List.h" #endif -class CcuBaseTimer { -public: - enum timer_status { Active, Inactive }; +class CcuCoreTimer; + +class CcuTimerSet { +friend class CcuCoreTimer; private: -static CcuSignalHandler* TimeOutHandler; -static CcuBaseTimer* FirstActive; + CcuCoreTimer* FirstTimer; #ifndef CPLUS_BUG19 -static CcuListOf * OtherActive; + CcuListOf OtherTimers; #else -static CcuList* OtherActive; + CcuList OtherTimers; #endif + CcuCoreTimer* ExtractNextActive (); +public: +inline CcuTimerSet () : FirstTimer (0), OtherTimers () {} +inline ~CcuTimerSet () {} +}; -static void ClassInit (); -static void HandleSignal (int); -static void SetAlarm (Millisecond); -static void StopAlarm (); -static CcuBaseTimer* ExtractNextActive (); -static int IsInactive (CcuBaseTimer*); + +class CcuCoreTimer { +friend class CcuTimerSet; +public: + enum timer_status { Active, Inactive }; + +protected: +static int IsInactive (CcuCoreTimer*); + + CcuTimerSet* MySet; Millisecond NextDate; Millisecond Period; int PulsesLeft; - timer_status Status; + timer_status StatusFlag; + CcuCoreTimer (Millisecond, int, CcuTimerSet*); + ~CcuCoreTimer (); void Activate (); void Schedule (Millisecond); void Reschedule (); - -protected: +virtual void SetAlarm (Millisecond) = 0; +virtual void StopAlarm () = 0; virtual void Handle (Millisecond); -public: - CcuBaseTimer (Millisecond, int = -1); -virtual ~CcuBaseTimer (); +public: void ChangePeriod (Millisecond first); void Stop (); void Restart (); void Wait (); inline Millisecond GetPeriod () const { return Period; } inline int GetNbPulses () const { return PulsesLeft; } -inline timer_status GetStatus () const { return Status; } +inline timer_status GetStatus () const { return StatusFlag; } +static void Fire (CcuTimerSet*); +}; + +class CcuBaseTimer : public CcuCoreTimer { +private: +static CcuSignalHandler* TimeOutHandler; +static CcuTimerSet* TimerSet; +static void HandleSignal (int); +static void ClassInit (); + +protected: + void SetAlarm (Millisecond); + void StopAlarm (); + +public: + CcuBaseTimer (Millisecond, int = -1); + ~CcuBaseTimer (); }; class CcuTimer : public CcuBaseTimer { -- cgit v1.1