diff --git a/headers/private/kernel/UserTimer.h b/headers/private/kernel/UserTimer.h index 026aa55575..ca880be9d4 100644 --- a/headers/private/kernel/UserTimer.h +++ b/headers/private/kernel/UserTimer.h @@ -117,14 +117,16 @@ struct TeamTimeUserTimer : public UserTimer { void Deactivate(); - void Update(Thread* unscheduledThread); + void Update(Thread* unscheduledThread, + Thread* lockedThread = NULL); void TimeWarped(bigtime_t changedBy); protected: virtual void HandleTimer(); private: - void _Update(bool unscheduling); + void _Update(bool unscheduling, + Thread* lockedThread = NULL); private: team_id fTeamID; diff --git a/headers/private/kernel/thread_types.h b/headers/private/kernel/thread_types.h index a48a48099b..1bbab89333 100644 --- a/headers/private/kernel/thread_types.h +++ b/headers/private/kernel/thread_types.h @@ -388,7 +388,8 @@ public: inline TeamUserTimeUserTimerList::ConstIterator UserTimeUserTimerIterator() const; - bigtime_t CPUTime(bool ignoreCurrentRun) const; + bigtime_t CPUTime(bool ignoreCurrentRun, + Thread* lockedThread = NULL) const; bigtime_t UserCPUTime() const; private: diff --git a/src/system/kernel/UserTimer.cpp b/src/system/kernel/UserTimer.cpp index 88aa78a07b..8f1514e3f5 100644 --- a/src/system/kernel/UserTimer.cpp +++ b/src/system/kernel/UserTimer.cpp @@ -625,7 +625,7 @@ TeamTimeUserTimer::Deactivate() currently running and which is in the process of being unscheduled. */ void -TeamTimeUserTimer::Update(Thread* unscheduledThread) +TeamTimeUserTimer::Update(Thread* unscheduledThread, Thread* lockedThread) { if (fTeam == NULL) return; @@ -639,7 +639,7 @@ TeamTimeUserTimer::Update(Thread* unscheduledThread) fRunningThreads++; } - _Update(unscheduledThread != NULL); + _Update(unscheduledThread != NULL, lockedThread); } @@ -695,7 +695,7 @@ TeamTimeUserTimer::HandleTimer() being unscheduled. */ void -TeamTimeUserTimer::_Update(bool unscheduling) +TeamTimeUserTimer::_Update(bool unscheduling, Thread* lockedThread) { // unschedule the kernel timer, if scheduled if (fScheduled) @@ -708,7 +708,7 @@ TeamTimeUserTimer::_Update(bool unscheduling) } // There are still threads running. Reschedule the kernel timer. - bigtime_t now = fTeam->CPUTime(unscheduling); + bigtime_t now = fTeam->CPUTime(unscheduling, lockedThread); // If periodic, check whether the start time is too far in the past. if (fInterval > 0) @@ -1560,7 +1560,7 @@ user_timer_stop_cpu_timers(Thread* thread, Thread* nextThread) for (TeamTimeUserTimerList::ConstIterator it = thread->team->CPUTimeUserTimerIterator(); TeamTimeUserTimer* timer = it.Next();) { - timer->Update(thread); + timer->Update(thread, thread); } } } @@ -1574,7 +1574,7 @@ user_timer_continue_cpu_timers(Thread* thread, Thread* previousThread) for (TeamTimeUserTimerList::ConstIterator it = thread->team->CPUTimeUserTimerIterator(); TeamTimeUserTimer* timer = it.Next();) { - timer->Update(NULL); + timer->Update(NULL, thread); } } diff --git a/src/system/kernel/team.cpp b/src/system/kernel/team.cpp index a775d1bb18..e8c58debf0 100644 --- a/src/system/kernel/team.cpp +++ b/src/system/kernel/team.cpp @@ -924,7 +924,7 @@ Team::DeactivateCPUTimeUserTimers() \return The team's current total CPU time. */ bigtime_t -Team::CPUTime(bool ignoreCurrentRun) const +Team::CPUTime(bool ignoreCurrentRun, Thread* lockedThread) const { bigtime_t time = cpu_clock_offset + dead_threads_kernel_time + dead_threads_user_time; @@ -934,13 +934,17 @@ Team::CPUTime(bool ignoreCurrentRun) const for (Thread* thread = thread_list; thread != NULL; thread = thread->team_next) { - SpinLocker threadTimeLocker(thread->time_lock); + bool alreadyLocked = thread == lockedThread; + SpinLocker threadTimeLocker(thread->time_lock, alreadyLocked); time += thread->kernel_time + thread->user_time; if (thread->last_time != 0) { if (!ignoreCurrentRun || thread != currentThread) time += now - thread->last_time; } + + if (alreadyLocked) + threadTimeLocker.Detach(); } return time;