[haiku-commits] r42020 - in haiku/branches/developer/bonefish/signals: headers/private/kernel src/system/kernel

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Tue, 7 Jun 2011 21:24:17 +0200 (CEST)

Author: bonefish
Date: 2011-06-07 21:24:17 +0200 (Tue, 07 Jun 2011)
New Revision: 42020
Changeset: https://dev.haiku-os.org/changeset/42020

Modified:
   haiku/branches/developer/bonefish/signals/headers/private/kernel/UserTimer.h
   haiku/branches/developer/bonefish/signals/src/system/kernel/UserTimer.cpp
Log:
* SystemTimeUserTimer, RealTimeUserTimer: Moved the kernel timer scheduling to
  new method ScheduleKernelTimer().
* Changed all UserTimer implementations to not use periodic kernel timers
  anymore. Instead one-shot kernel timers are used and rescheduled after the
  event was fired. This is necessary to maintain a precise overrun count.
* Introduced a minimum interval by which the kernel timer start time is advanced
  for periodic timers. For user timers with a shorter interval we adjust the
  overrun count respectively.


Modified: 
haiku/branches/developer/bonefish/signals/headers/private/kernel/UserTimer.h
===================================================================
--- 
haiku/branches/developer/bonefish/signals/headers/private/kernel/UserTimer.h    
    2011-06-07 18:17:08 UTC (rev 42019)
+++ 
haiku/branches/developer/bonefish/signals/headers/private/kernel/UserTimer.h    
    2011-06-07 19:24:17 UTC (rev 42020)
@@ -51,6 +51,8 @@
        static  int32                           HandleTimerHook(struct timer* 
timer);
        virtual void                            HandleTimer();
 
+       inline  void                            
UpdatePeriodicStartTime(bigtime_t& startTime,
+                                                                       
bigtime_t interval);
        inline  void                            CheckPeriodicOverrun(bigtime_t 
now,
                                                                        
bigtime_t& startTime, bigtime_t interval);
 
@@ -70,6 +72,12 @@
        virtual void                            GetInfo(bigtime_t& 
_remainingTime,
                                                                        
bigtime_t& _interval,
                                                                        uint32& 
_overrunCount);
+
+protected:
+       virtual void                            HandleTimer();
+
+                       void                            
ScheduleKernelTimer(bigtime_t now,
+                                                                       bool 
checkPeriodicOverrun);
 };
 
 

Modified: 
haiku/branches/developer/bonefish/signals/src/system/kernel/UserTimer.cpp
===================================================================
--- haiku/branches/developer/bonefish/signals/src/system/kernel/UserTimer.cpp   
2011-06-07 18:17:08 UTC (rev 42019)
+++ haiku/branches/developer/bonefish/signals/src/system/kernel/UserTimer.cpp   
2011-06-07 19:24:17 UTC (rev 42020)
@@ -17,6 +17,13 @@
 #include <util/AutoLock.h>
 
 
+// Minimum interval length in microseconds for a periodic timer. This is not a
+// restriction on the user timer interval length itself, but the minimum time
+// span by which we advance the start time for kernel timers. A shorted user
+// timer interval will result in the overrun count to be increased every time
+// the kernel timer is rescheduled.
+static const bigtime_t kMinPeriodicTimerInterval = 100;
+
 static RealTimeUserTimerList sAbsoluteRealTimeTimers;
 static spinlock sAbsoluteRealTimeTimersLock = B_SPINLOCK_INITIALIZER;
 
@@ -198,12 +205,35 @@
                        fOverrunCount = 0;
        }
 
-       // If it's not a periodic timer, it isn't scheduled anymore.
-       if (fTimer.period == 0)
-               fScheduled = false;
+       // Since we don't use periodic kernel timers, it isn't scheduled 
anymore.
+       // If the timer is periodic, the derived class' version will schedule it
+       // again.
+       fScheduled = false;
 }
 
 
+/*!    Updates the start time for a periodic timer after it expired, enforcing
+       sanity limits and updating \c fOverrunCount, if necessary.
+
+       \param startTime The start time of the timer. Will be adjusted.
+       \param interval The timer interval. Must be <tt> > 0 <\tt>.
+*/
+void
+UserTimer::UpdatePeriodicStartTime(bigtime_t& startTime, bigtime_t interval)
+{
+       if (interval < kMinPeriodicTimerInterval) {
+               bigtime_t skip = (kMinPeriodicTimerInterval + interval - 1) / 
interval;
+               startTime += skip * interval;
+
+               if (skip + fOverrunCount > MAX_USER_TIMER_OVERRUN_COUNT)
+                       fOverrunCount = MAX_USER_TIMER_OVERRUN_COUNT;
+               else
+                       fOverrunCount += skip;
+       } else
+               startTime += interval;
+}
+
+
 /*!    Checks whether the given time start time lies too much in the past and, 
if
        so, adjusts it and updates \c fOverrunCount.
 
@@ -249,6 +279,8 @@
 
                _oldRemainingTime = fTimer.schedule_time - now;
                _oldInterval = fTimer.period;
+
+               fScheduled = false;
        } else {
                _oldRemainingTime = B_INFINITE_TIMEOUT;
                _oldInterval = 0;
@@ -258,27 +290,13 @@
        fTimer.schedule_time = nextTime;
        fTimer.period = interval;
 
-       if (nextTime != B_INFINITE_TIMEOUT) {
-               if ((flags & B_RELATIVE_TIMEOUT) != 0)
-                       fTimer.schedule_time += now;
+       if (nextTime == B_INFINITE_TIMEOUT)
+               return;
 
-               // If periodic, check whether the start time is too far in the 
past.
-               if (fTimer.period > 0)
-                       CheckPeriodicOverrun(now, fTimer.schedule_time, 
fTimer.period);
+       if ((flags & B_RELATIVE_TIMEOUT) != 0)
+               fTimer.schedule_time += now;
 
-               uint32 timerFlags = (interval > 0
-                               ? B_PERIODIC_TIMER : B_ONE_SHOT_ABSOLUTE_TIMER)
-                        | B_TIMER_USE_TIMER_STRUCT_TIMES | 
B_TIMER_ACQUIRE_SCHEDULER_LOCK;
-                       // We use B_TIMER_ACQUIRE_SCHEDULER_LOCK to avoid race 
conditions
-                       // between setting/canceling the timer and the event 
handler.
-
-               add_timer(&fTimer, &HandleTimerHook, interval, timerFlags);
-
-               fScheduled = true;
-       } else {
-               // mark the timer canceled
-               fScheduled = false;
-       }
+       ScheduleKernelTimer(now, fTimer.period > 0);
 }
 
 
@@ -300,6 +318,44 @@
 }
 
 
+void
+SystemTimeUserTimer::HandleTimer()
+{
+       UserTimer::HandleTimer();
+
+       // if periodic, reschedule the kernel timer
+       if (fTimer.period > 0) {
+               UpdatePeriodicStartTime(fTimer.schedule_time, fTimer.period);
+               ScheduleKernelTimer(system_time(), true);
+       }
+}
+
+
+/*!    Schedules the kernel timer.
+
+       \param now The current system time to be used.
+       \param checkPeriodicOverrun If \c true, calls CheckPeriodicOverrun() 
first,
+               i.e. the start time will be adjusted to not lie too much in the 
past.
+*/
+void
+SystemTimeUserTimer::ScheduleKernelTimer(bigtime_t now,
+       bool checkPeriodicOverrun)
+{
+       // If periodic, check whether the start time is too far in the past.
+       if (checkPeriodicOverrun)
+               CheckPeriodicOverrun(now, fTimer.schedule_time, fTimer.period);
+
+       uint32 timerFlags = B_ONE_SHOT_ABSOLUTE_TIMER
+                       | B_TIMER_USE_TIMER_STRUCT_TIMES | 
B_TIMER_ACQUIRE_SCHEDULER_LOCK;
+               // We use B_TIMER_ACQUIRE_SCHEDULER_LOCK to avoid race 
conditions
+               // between setting/canceling the timer and the event handler.
+
+       add_timer(&fTimer, &HandleTimerHook, fTimer.schedule_time, timerFlags);
+
+       fScheduled = true;
+}
+
+
 // #pragma mark - RealTimeUserTimer
 
 
@@ -353,15 +409,7 @@
        } else
                fTimer.schedule_time += now;
 
-       uint32 timerFlags = (interval > 0
-                       ? B_PERIODIC_TIMER : B_ONE_SHOT_ABSOLUTE_TIMER)
-                       | B_TIMER_USE_TIMER_STRUCT_TIMES | 
B_TIMER_ACQUIRE_SCHEDULER_LOCK;
-               // We use B_TIMER_ACQUIRE_SCHEDULER_LOCK to avoid race 
conditions
-               // between setting/canceling the timer and the event handler.
-
-       add_timer(&fTimer, &HandleTimerHook, interval, timerFlags);
-
-       fScheduled = true;
+       ScheduleKernelTimer(now, false);
 }
 
 
@@ -386,26 +434,14 @@
 
        fTimer.schedule_time += oldRealTimeOffset - fRealTimeOffset;
 
-       // If periodic, check whether we've moved too far into the past.
-       if (fTimer.period > 0) {
-               CheckPeriodicOverrun(system_time(), fTimer.schedule_time,
-                       fTimer.period);
-       }
-
-       uint32 timerFlags = (fTimer.period > 0
-                       ? B_PERIODIC_TIMER : B_ONE_SHOT_ABSOLUTE_TIMER)
-                       | B_TIMER_USE_TIMER_STRUCT_TIMES | 
B_TIMER_ACQUIRE_SCHEDULER_LOCK;
-               // We use B_TIMER_ACQUIRE_SCHEDULER_LOCK to avoid race 
conditions
-               // between setting/canceling the timer and the event handler.
-
-       add_timer(&fTimer, &HandleTimerHook, fTimer.period, timerFlags);
+       ScheduleKernelTimer(system_time(), fTimer.period > 0);
 }
 
 
 void
 RealTimeUserTimer::HandleTimer()
 {
-       UserTimer::HandleTimer();
+       SystemTimeUserTimer::HandleTimer();
 
        // remove from global list, if no longer scheduled
        if (!fScheduled && fAbsolute) {
@@ -597,7 +633,7 @@
                        fTeam->ReleaseReference();
                        fTeam = NULL;
                } else {
-                       fNextTime += fInterval;
+                       UpdatePeriodicStartTime(fNextTime, fInterval);
                        _Update(false);
                }
        }
@@ -658,9 +694,6 @@
        fTeamID(teamID),
        fTeam(NULL)
 {
-       fTimer.period = 0;
-               // initialize, since UserTimer::HandleTimer() reads it -- 
doesn't matter
-               // though
 }
 
 
@@ -785,6 +818,7 @@
        // (CheckPeriodicOverrun() only makes it > now - fInterval).
        CheckPeriodicOverrun(now, fNextTime, fInterval);
        fNextTime += fInterval;
+       fScheduled = true;
 }
 
 
@@ -930,8 +964,7 @@
        fTimer.schedule_time = system_time() + fNextTime - now;
        fTimer.period = fInterval;
 
-       uint32 flags = (fInterval > 0
-                       ? B_PERIODIC_TIMER : B_ONE_SHOT_ABSOLUTE_TIMER)
+       uint32 flags = B_ONE_SHOT_ABSOLUTE_TIMER
                | B_TIMER_USE_TIMER_STRUCT_TIMES | 
B_TIMER_ACQUIRE_SCHEDULER_LOCK;
                // We use B_TIMER_ACQUIRE_SCHEDULER_LOCK to avoid race 
conditions
                // between setting/canceling the timer and the event handler.
@@ -998,11 +1031,17 @@
 {
        UserTimer::HandleTimer();
 
-       // If the timer is not periodic, it is no longer active.
-       if (fInterval == 0 && fThread != NULL) {
-               fThread->UserTimerDeactivated(this);
-               fThread->ReleaseReference();
-               fThread = NULL;
+       if (fThread != NULL) {
+               // If the timer is periodic, reschedule the kernel timer. 
Otherwise it
+               // is no longer active.
+               if (fInterval > 0) {
+                       UpdatePeriodicStartTime(fNextTime, fInterval);
+                       Start();
+               } else {
+                       fThread->UserTimerDeactivated(this);
+                       fThread->ReleaseReference();
+                       fThread = NULL;
+               }
        }
 }
 


Other related posts:

  • » [haiku-commits] r42020 - in haiku/branches/developer/bonefish/signals: headers/private/kernel src/system/kernel - ingo_weinhold