Author: bonefish Date: 2011-06-05 17:46:22 +0200 (Sun, 05 Jun 2011) New Revision: 41937 Changeset: https://dev.haiku-os.org/changeset/41937 Modified: haiku/branches/developer/bonefish/signals/headers/private/kernel/UserTimer.h haiku/branches/developer/bonefish/signals/src/system/kernel/UserTimer.cpp Log: When a team or thread CPU clock are set, update the timers based on the clock. Modified: haiku/branches/developer/bonefish/signals/headers/private/kernel/UserTimer.h =================================================================== --- haiku/branches/developer/bonefish/signals/headers/private/kernel/UserTimer.h 2011-06-05 15:03:31 UTC (rev 41936) +++ haiku/branches/developer/bonefish/signals/headers/private/kernel/UserTimer.h 2011-06-05 15:46:22 UTC (rev 41937) @@ -101,6 +101,7 @@ void Deactivate(); void Update(Thread* unscheduledThread); + void TimeWarped(bigtime_t changedBy); protected: virtual void HandleTimer(); @@ -114,6 +115,7 @@ bigtime_t fNextTime; bigtime_t fInterval; int32 fRunningThreads; + bool fAbsolute; public: // conceptually package private @@ -136,6 +138,7 @@ void Start(); void Stop(); + void TimeWarped(bigtime_t changedBy); protected: virtual void HandleTimer(); @@ -145,6 +148,7 @@ Thread* fThread; // != NULL only when active bigtime_t fNextTime; bigtime_t fInterval; + bool fAbsolute; public: // conceptually package private Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/UserTimer.cpp =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/UserTimer.cpp 2011-06-05 15:03:31 UTC (rev 41936) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/UserTimer.cpp 2011-06-05 15:46:22 UTC (rev 41937) @@ -343,6 +343,11 @@ } +/*! Called when the real-time clock has been changed. + + The caller must hold the scheduler lock. Optionally the caller may also + hold \c sAbsoluteRealTimeTimersLock. +*/ void RealTimeUserTimer::TimeWarped() { @@ -456,8 +461,10 @@ if (fTeam == NULL) return; + fAbsolute = (flags & B_RELATIVE_TIMEOUT) == 0; + // convert relative to absolute timeouts - if ((flags & B_RELATIVE_TIMEOUT) != 0) { + if (!fAbsolute) { if (!nowValid) now = fTeam->CPUTime(false); fNextTime += now; @@ -542,7 +549,30 @@ } +/*! Called when the team's CPU time clock which this timer refers to has been + set. + + The caller must hold the scheduler lock. + + \param changedBy The value by which the clock has changed. +*/ void +TeamTimeUserTimer::TimeWarped(bigtime_t changedBy) +{ + if (fTeam == NULL || changedBy == 0) + return; + + // If this is a relative timer, adjust fNextTime by the value the clock has + // changed. + if (!fAbsolute) + fNextTime += changedBy; + + // reschedule the kernel timer + _Update(false); +} + + +void TeamTimeUserTimer::HandleTimer() { UserTimer::HandleTimer(); @@ -662,8 +692,10 @@ if (fThread == NULL) return; + fAbsolute = (flags & B_RELATIVE_TIMEOUT) == 0; + // convert relative to absolute timeouts - if ((flags & B_RELATIVE_TIMEOUT) != 0) { + if (!fAbsolute) { if (!nowValid) now = fThread->CPUTime(false); fNextTime += now; @@ -777,7 +809,33 @@ } +/*! Called when the team's CPU time clock which this timer refers to has been + set. + + The caller must hold the scheduler lock. + + \param changedBy The value by which the clock has changed. +*/ void +ThreadTimeUserTimer::TimeWarped(bigtime_t changedBy) +{ + if (fThread == NULL || changedBy == 0) + return; + + // If this is a relative timer, adjust fNextTime by the value the clock has + // changed. + if (!fAbsolute) + fNextTime += changedBy; + + // reschedule the kernel timer + if (fScheduled) { + Stop(); + Start(); + } +} + + +void ThreadTimeUserTimer::HandleTimer() { UserTimer::HandleTimer(); @@ -1022,6 +1080,44 @@ } +/*! Called when the CPU time clock of the given thread has been set. + + The caller must hold the scheduler lock. + + \param thread The thread whose CPU time clock has been set. + \param changedBy The value by which the CPU time clock has changed + (new = old + changedBy). +*/ +static void +thread_clock_changed(Thread* thread, bigtime_t changedBy) +{ + for (ThreadTimeUserTimerList::ConstIterator it + = thread->CPUTimeUserTimerIterator(); + ThreadTimeUserTimer* timer = it.Next();) { + timer->TimeWarped(changedBy); + } +} + + +/*! Called when the CPU time clock of the given team has been set. + + The caller must hold the scheduler lock. + + \param team The team whose CPU time clock has been set. + \param changedBy The value by which the CPU time clock has changed + (new = old + changedBy). +*/ +static void +team_clock_changed(Team* team, bigtime_t changedBy) +{ + for (TeamTimeUserTimerList::ConstIterator it + = team->CPUTimeUserTimerIterator(); + TeamTimeUserTimer* timer = it.Next();) { + timer->TimeWarped(changedBy); + } +} + + // #pragma mark - kernel private @@ -1221,8 +1317,6 @@ status_t _user_set_clock(clockid_t clockID, bigtime_t time) { - // TODO: Setting a clock should update absolute timers! - switch (clockID) { case CLOCK_MONOTONIC: return B_BAD_VALUE; @@ -1239,7 +1333,10 @@ { Thread* thread = thread_get_current_thread(); InterruptsSpinLocker schedulerLocker(gSchedulerLock); - thread->cpu_clock_offset += time - thread->CPUTime(false); + bigtime_t diff = time - thread->CPUTime(false); + thread->cpu_clock_offset += diff; + + thread_clock_changed(thread, diff); return B_OK; } @@ -1267,8 +1364,10 @@ // set the time offset InterruptsSpinLocker schedulerLocker(gSchedulerLock); - team->cpu_clock_offset += time - team->CPUTime(false); + bigtime_t diff = time - team->CPUTime(false); + team->cpu_clock_offset += diff; + team_clock_changed(team, diff); return B_OK; } }