scheduler: Check team user time timers before entering scheduler
User timers may cause another thread to become ready in which case we would like this to happen before scheduler_reschedule() chooses next thread to be executed.
This commit is contained in:
@@ -328,55 +328,28 @@ switch_thread(Thread* fromThread, Thread* toThread)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
update_thread_times(Thread* oldThread, Thread* nextThread)
|
|
||||||
{
|
|
||||||
SCHEDULER_ENTER_FUNCTION();
|
|
||||||
|
|
||||||
bigtime_t now = system_time();
|
|
||||||
if (oldThread == nextThread) {
|
|
||||||
SpinLocker _(oldThread->time_lock);
|
|
||||||
oldThread->kernel_time += now - oldThread->last_time;
|
|
||||||
oldThread->last_time = now;
|
|
||||||
} else {
|
|
||||||
SpinLocker locker(oldThread->time_lock);
|
|
||||||
oldThread->kernel_time += now - oldThread->last_time;
|
|
||||||
oldThread->last_time = 0;
|
|
||||||
locker.Unlock();
|
|
||||||
|
|
||||||
locker.SetTo(nextThread->time_lock, false);
|
|
||||||
nextThread->last_time = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the old thread's team has user time timers, check them now.
|
|
||||||
Team* team = oldThread->team;
|
|
||||||
|
|
||||||
SpinLocker _(team->time_lock);
|
|
||||||
if (team->HasActiveUserTimeUserTimers())
|
|
||||||
user_timer_check_team_user_timers(team);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
reschedule(int32 nextState)
|
reschedule(int32 nextState)
|
||||||
{
|
{
|
||||||
ASSERT(!are_interrupts_enabled());
|
ASSERT(!are_interrupts_enabled());
|
||||||
SCHEDULER_ENTER_FUNCTION();
|
SCHEDULER_ENTER_FUNCTION();
|
||||||
|
|
||||||
SchedulerModeLocker modeLocker;
|
|
||||||
|
|
||||||
Thread* oldThread = thread_get_current_thread();
|
|
||||||
|
|
||||||
int32 thisCPU = smp_get_current_cpu();
|
int32 thisCPU = smp_get_current_cpu();
|
||||||
|
|
||||||
CPUEntry* cpu = CPUEntry::GetCPU(thisCPU);
|
CPUEntry* cpu = CPUEntry::GetCPU(thisCPU);
|
||||||
CoreEntry* core = CoreEntry::GetCore(thisCPU);
|
CoreEntry* core = CoreEntry::GetCore(thisCPU);
|
||||||
|
|
||||||
|
Thread* oldThread = thread_get_current_thread();
|
||||||
|
ThreadData* oldThreadData = oldThread->scheduler_data;
|
||||||
|
|
||||||
|
oldThreadData->StopCPUTime();
|
||||||
|
|
||||||
|
SchedulerModeLocker modeLocker;
|
||||||
|
|
||||||
TRACE("reschedule(): cpu %ld, current thread = %ld\n", thisCPU,
|
TRACE("reschedule(): cpu %ld, current thread = %ld\n", thisCPU,
|
||||||
oldThread->id);
|
oldThread->id);
|
||||||
|
|
||||||
oldThread->state = nextState;
|
oldThread->state = nextState;
|
||||||
ThreadData* oldThreadData = oldThread->scheduler_data;
|
|
||||||
|
|
||||||
// return time spent in interrupts
|
// return time spent in interrupts
|
||||||
oldThreadData->SetStolenInterruptTime(gCPU[thisCPU].interrupt_time);
|
oldThreadData->SetStolenInterruptTime(gCPU[thisCPU].interrupt_time);
|
||||||
@@ -470,9 +443,7 @@ reschedule(int32 nextState)
|
|||||||
|
|
||||||
ASSERT(nextThreadData->Core() == core);
|
ASSERT(nextThreadData->Core() == core);
|
||||||
nextThread->state = B_THREAD_RUNNING;
|
nextThread->state = B_THREAD_RUNNING;
|
||||||
|
nextThreadData->StartCPUTime();
|
||||||
// track kernel time (user time is tracked in thread_at_kernel_entry())
|
|
||||||
update_thread_times(oldThread, nextThread);
|
|
||||||
|
|
||||||
// track CPU activity
|
// track CPU activity
|
||||||
cpu->TrackActivity(oldThreadData, nextThreadData);
|
cpu->TrackActivity(oldThreadData, nextThreadData);
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ public:
|
|||||||
|
|
||||||
inline bool IsCPUBound() const { return fCPUBound; }
|
inline bool IsCPUBound() const { return fCPUBound; }
|
||||||
|
|
||||||
|
inline void StartCPUTime();
|
||||||
|
inline void StopCPUTime();
|
||||||
|
|
||||||
inline void CancelPenalty();
|
inline void CancelPenalty();
|
||||||
inline bool ShouldCancelPenalty() const;
|
inline bool ShouldCancelPenalty() const;
|
||||||
|
|
||||||
@@ -216,6 +219,35 @@ ThreadData::_IncreasePenalty()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void
|
||||||
|
ThreadData::StartCPUTime()
|
||||||
|
{
|
||||||
|
SCHEDULER_ENTER_FUNCTION();
|
||||||
|
|
||||||
|
SpinLocker threadTimeLocker(fThread->time_lock);
|
||||||
|
fThread->last_time = system_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void
|
||||||
|
ThreadData::StopCPUTime()
|
||||||
|
{
|
||||||
|
SCHEDULER_ENTER_FUNCTION();
|
||||||
|
|
||||||
|
// User time is tracked in thread_at_kernel_entry()
|
||||||
|
SpinLocker threadTimeLocker(fThread->time_lock);
|
||||||
|
fThread->kernel_time += system_time() - fThread->last_time;
|
||||||
|
fThread->last_time = 0;
|
||||||
|
threadTimeLocker.Unlock();
|
||||||
|
|
||||||
|
// If the old thread's team has user time timers, check them now.
|
||||||
|
Team* team = fThread->team;
|
||||||
|
SpinLocker teamTimeLocker(team->time_lock);
|
||||||
|
if (team->HasActiveUserTimeUserTimers())
|
||||||
|
user_timer_check_team_user_timers(team);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
ThreadData::CancelPenalty()
|
ThreadData::CancelPenalty()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user