Author: bonefish Date: 2011-06-08 04:05:04 +0200 (Wed, 08 Jun 2011) New Revision: 42040 Changeset: https://dev.haiku-os.org/changeset/42040 Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/timer.cpp Log: * Use a small wrapper function for calling arch_timer_set_hardware_timer(). Prevent an underflow when computing the timeout to be passed on. * per_cpu_real_time_clock_changed(): Deal with over-/underflows. * add_timer(): Prevent a negative schedule_time for absolute real-time timers. Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/timer.cpp =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/timer.cpp 2011-06-08 01:57:25 UTC (rev 42039) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/timer.cpp 2011-06-08 02:05:04 UTC (rev 42040) @@ -44,6 +44,29 @@ #endif +/*! Sets the hardware timer to the given absolute time. + + \param scheduleTime The absolute system time for the timer expiration. + \param now The current system time. +*/ +static void +set_hardware_timer(bigtime_t scheduleTime, bigtime_t now) +{ + arch_timer_set_hardware_timer(scheduleTime > now ? scheduleTime - now : 0); +} + + +/*! Sets the hardware timer to the given absolute time. + + \param scheduleTime The absolute system time for the timer expiration. +*/ +static inline void +set_hardware_timer(bigtime_t scheduleTime) +{ + set_hardware_timer(scheduleTime, system_time()); +} + + /*! NOTE: expects interrupts to be off */ static void add_event_to_list(timer* event, timer* volatile* list) @@ -109,17 +132,26 @@ timer* event = affectedTimers; affectedTimers = event->next; + bigtime_t oldTime = event->schedule_time; event->schedule_time += timeDiff; + + // handle over-/underflows + if (timeDiff >= 0) { + if (event->schedule_time < oldTime) + event->schedule_time = B_INFINITE_TIMEOUT; + } else { + if (event->schedule_time < 0) + event->schedule_time = 0; + } + add_event_to_list(event, &cpuData.events); } firstEventChanged |= cpuData.events != firstEvent; // If the first event has changed, reset the hardware timer. - if (firstEventChanged) { - arch_timer_set_hardware_timer( - cpuData.events->schedule_time - system_time()); - } + if (firstEventChanged) + set_hardware_timer(cpuData.events->schedule_time); } @@ -289,13 +321,8 @@ } // setup the next hardware timer - if (cpuData.events != NULL) { - bigtime_t timeout = (bigtime_t)cpuData.events->schedule_time - - system_time(); - if (timeout <= 0) - timeout = 1; - arch_timer_set_hardware_timer(timeout); - } + if (cpuData.events != NULL) + set_hardware_timer(cpuData.events->schedule_time); release_spinlock(spinlock); @@ -342,7 +369,10 @@ // time to system time. if ((flags & ~B_TIMER_FLAGS) == B_ONE_SHOT_ABSOLUTE_TIMER && (flags & B_TIMER_REAL_TIME_BASE) != 0) { - event->schedule_time -= cpuData.real_time_offset; + if (event->schedule_time > cpuData.real_time_offset) + event->schedule_time -= cpuData.real_time_offset; + else + event->schedule_time = 0; } add_event_to_list(event, &cpuData.events); @@ -350,7 +380,7 @@ // if we were stuck at the head of the list, set the hardware timer if (event == cpuData.events) - arch_timer_set_hardware_timer(scheduleTime - currentTime); + set_hardware_timer(scheduleTime, currentTime); release_spinlock(&cpuData.lock); restore_interrupts(state); @@ -416,10 +446,8 @@ if (cpu == smp_get_current_cpu()) { if (cpuData.events == NULL) arch_timer_clear_hardware_timer(); - else { - arch_timer_set_hardware_timer( - (bigtime_t)cpuData.events->schedule_time - system_time()); - } + else + set_hardware_timer(cpuData.events->schedule_time); } return false;