hrev48139 adds 1 changeset to branch 'master' old head: 4ed39e6a62d82721004656c5a1ecf19cb8e73e75 new head: 52d500e5b4abc36a9c2106de52412da5324ca9ee overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=52d500e+%5E4ed39e6 ---------------------------------------------------------------------------- 52d500e: kernel: Workaround for double lock of spinlock in user timers. The thread that is being [un]scheduled already has its time_lock locked in {stop|continue}_cpu_timers(). When updating the TeamTimeUserTimer, the team is asked for its cpu time. Team::CPUTime() then iterates the threads of the team and locks the time_lock of the thread again. This workaround passes a possibly locked thread through the relevant functions so Team::CPUTime() can decide whether or not a thread it iterates needs to be locked or not. This works around #11032 and its duplicates #11314 and #11344. [ Michael Lotz <mmlr@xxxxxxxx> ] ---------------------------------------------------------------------------- Revision: hrev48139 Commit: 52d500e5b4abc36a9c2106de52412da5324ca9ee URL: http://cgit.haiku-os.org/haiku/commit/?id=52d500e Author: Michael Lotz <mmlr@xxxxxxxx> Date: Tue Oct 28 22:37:30 2014 UTC Ticket: https://dev.haiku-os.org/ticket/11032 Ticket: https://dev.haiku-os.org/ticket/11314 Ticket: https://dev.haiku-os.org/ticket/11344 ---------------------------------------------------------------------------- 4 files changed, 18 insertions(+), 11 deletions(-) headers/private/kernel/UserTimer.h | 6 ++++-- headers/private/kernel/thread_types.h | 3 ++- src/system/kernel/UserTimer.cpp | 12 ++++++------ src/system/kernel/team.cpp | 8 ++++++-- ---------------------------------------------------------------------------- diff --git a/headers/private/kernel/UserTimer.h b/headers/private/kernel/UserTimer.h index 026aa55..ca880be 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 a48a480..1bbab89 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 88aa78a..8f1514e 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 a775d1b..e8c58de 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;