scheduler: Protect per CPU run queue with its own lock

This commit is contained in:
Pawel Dziepak
2013-12-31 03:53:55 +01:00
parent 1524fbf742
commit 265927509d
4 changed files with 86 additions and 31 deletions
+1 -1
View File
@@ -517,7 +517,7 @@ reschedule(int32 nextState)
ThreadData* nextThreadData; ThreadData* nextThreadData;
if (gCPU[thisCPU].disabled) { if (gCPU[thisCPU].disabled) {
if (!thread_is_idle_thread(oldThread)) { if (!thread_is_idle_thread(oldThread)) {
CoreRunQueueLocker _(core); CPURunQueueLocker _(cpu);
nextThreadData = cpu->PeekIdleThread(); nextThreadData = cpu->PeekIdleThread();
cpu->Remove(nextThreadData); cpu->Remove(nextThreadData);
+13 -9
View File
@@ -56,6 +56,7 @@ CPUEntry::CPUEntry()
fMeasureTime(0) fMeasureTime(0)
{ {
B_INITIALIZE_RW_SPINLOCK(&fSchedulerModeLock); B_INITIALIZE_RW_SPINLOCK(&fSchedulerModeLock);
B_INITIALIZE_SPINLOCK(&fQueueLock);
} }
@@ -185,25 +186,26 @@ CPUEntry::ChooseNextThread(ThreadData* oldThread, bool putAtBack)
{ {
SCHEDULER_ENTER_FUNCTION(); SCHEDULER_ENTER_FUNCTION();
CoreRunQueueLocker _(fCore); int32 oldPriority = -1;
if (oldThread != NULL)
oldPriority = oldThread->GetEffectivePriority();
CPURunQueueLocker cpuLocker(this);
ThreadData* sharedThread = fCore->PeekThread();
ThreadData* pinnedThread = fRunQueue.PeekMaximum(); ThreadData* pinnedThread = fRunQueue.PeekMaximum();
ASSERT(sharedThread != NULL || pinnedThread != NULL || oldThread != NULL);
int32 pinnedPriority = -1; int32 pinnedPriority = -1;
if (pinnedThread != NULL) if (pinnedThread != NULL)
pinnedPriority = pinnedThread->GetEffectivePriority(); pinnedPriority = pinnedThread->GetEffectivePriority();
CoreRunQueueLocker coreLocker(fCore);
ThreadData* sharedThread = fCore->PeekThread();
ASSERT(sharedThread != NULL || pinnedThread != NULL || oldThread != NULL);
int32 sharedPriority = -1; int32 sharedPriority = -1;
if (sharedThread != NULL) if (sharedThread != NULL)
sharedPriority = sharedThread->GetEffectivePriority(); sharedPriority = sharedThread->GetEffectivePriority();
int32 oldPriority = -1;
if (oldThread != NULL)
oldPriority = oldThread->GetEffectivePriority();
int32 rest = std::max(pinnedPriority, sharedPriority); int32 rest = std::max(pinnedPriority, sharedPriority);
if (oldPriority > rest || (!putAtBack && oldPriority == rest)) if (oldPriority > rest || (!putAtBack && oldPriority == rest))
return oldThread; return oldThread;
@@ -213,6 +215,8 @@ CPUEntry::ChooseNextThread(ThreadData* oldThread, bool putAtBack)
return sharedThread; return sharedThread;
} }
coreLocker.Unlock();
Remove(pinnedThread); Remove(pinnedThread);
return pinnedThread; return pinnedThread;
} }
@@ -60,6 +60,9 @@ public:
inline void LockScheduler(); inline void LockScheduler();
inline void UnlockScheduler(); inline void UnlockScheduler();
inline void LockRunQueue();
inline void UnlockRunQueue();
void PushFront(ThreadData* thread, void PushFront(ThreadData* thread,
int32 priority); int32 priority);
void PushBack(ThreadData* thread, void PushBack(ThreadData* thread,
@@ -91,6 +94,7 @@ private:
rw_spinlock fSchedulerModeLock; rw_spinlock fSchedulerModeLock;
ThreadRunQueue fRunQueue; ThreadRunQueue fRunQueue;
spinlock fQueueLock;
int32 fLoad; int32 fLoad;
@@ -108,6 +112,22 @@ public:
void Dump(); void Dump();
}; };
class CPURunQueueLocking {
public:
inline bool Lock(CPUEntry* cpu)
{
cpu->LockRunQueue();
return true;
}
inline void Unlock(CPUEntry* cpu)
{
cpu->UnlockRunQueue();
}
};
typedef AutoLocker<CPUEntry, CPURunQueueLocking> CPURunQueueLocker;
class CoreEntry : public MinMaxHeapLinkImpl<CoreEntry, int32>, class CoreEntry : public MinMaxHeapLinkImpl<CoreEntry, int32>,
public DoublyLinkedListLinkImpl<CoreEntry> { public DoublyLinkedListLinkImpl<CoreEntry> {
public: public:
@@ -309,6 +329,22 @@ CPUEntry::UnlockScheduler()
} }
inline void
CPUEntry::LockRunQueue()
{
SCHEDULER_ENTER_FUNCTION();
acquire_spinlock(&fQueueLock);
}
inline void
CPUEntry::UnlockRunQueue()
{
SCHEDULER_ENTER_FUNCTION();
release_spinlock(&fQueueLock);
}
/* static */ inline CPUEntry* /* static */ inline CPUEntry*
CPUEntry::GetCPU(int32 cpu) CPUEntry::GetCPU(int32 cpu)
{ {
+36 -21
View File
@@ -234,16 +234,22 @@ ThreadData::PutBack()
int32 priority = GetEffectivePriority(); int32 priority = GetEffectivePriority();
CoreRunQueueLocker _(fCore);
ASSERT(!fEnqueued);
fEnqueued = true;
if (fThread->pinned_to_cpu > 0) { if (fThread->pinned_to_cpu > 0) {
ASSERT(fThread->cpu != NULL); ASSERT(fThread->cpu != NULL);
CPUEntry* cpu = CPUEntry::GetCPU(fThread->cpu->cpu_num); CPUEntry* cpu = CPUEntry::GetCPU(fThread->cpu->cpu_num);
CPURunQueueLocker _(cpu);
ASSERT(!fEnqueued);
fEnqueued = true;
cpu->PushFront(this, priority); cpu->PushFront(this, priority);
} else } else {
CoreRunQueueLocker _(fCore);
ASSERT(!fEnqueued);
fEnqueued = true;
fCore->PushFront(this, priority); fCore->PushFront(this, priority);
}
} }
@@ -258,16 +264,22 @@ ThreadData::Enqueue()
int32 priority = GetEffectivePriority(); int32 priority = GetEffectivePriority();
CoreRunQueueLocker _(fCore);
ASSERT(!fEnqueued);
fEnqueued = true;
if (fThread->pinned_to_cpu > 0) { if (fThread->pinned_to_cpu > 0) {
ASSERT(fThread->previous_cpu != NULL); ASSERT(fThread->previous_cpu != NULL);
CPUEntry* cpu = CPUEntry::GetCPU(fThread->previous_cpu->cpu_num); CPUEntry* cpu = CPUEntry::GetCPU(fThread->previous_cpu->cpu_num);
CPURunQueueLocker _(cpu);
ASSERT(!fEnqueued);
fEnqueued = true;
cpu->PushBack(this, priority); cpu->PushBack(this, priority);
} else } else {
CoreRunQueueLocker _(fCore);
ASSERT(!fEnqueued);
fEnqueued = true;
fCore->PushBack(this, priority); fCore->PushBack(this, priority);
}
} }
@@ -276,20 +288,23 @@ ThreadData::Dequeue()
{ {
SCHEDULER_ENTER_FUNCTION(); SCHEDULER_ENTER_FUNCTION();
if (fThread->pinned_to_cpu > 0) {
ASSERT(fThread->previous_cpu != NULL);
CPUEntry* cpu = CPUEntry::GetCPU(fThread->previous_cpu->cpu_num);
CPURunQueueLocker _(cpu);
if (!fEnqueued)
return false;
cpu->Remove(this);
ASSERT(!fEnqueued);
return true;
}
CoreRunQueueLocker _(fCore); CoreRunQueueLocker _(fCore);
if (!fEnqueued) if (!fEnqueued)
return false; return false;
ASSERT(fWentSleepCount < 1);
if (fThread->pinned_to_cpu > 0) { fCore->Remove(this);
ASSERT(fThread->previous_cpu != NULL);
CPUEntry* cpu = CPUEntry::GetCPU(fThread->previous_cpu->cpu_num);
cpu->Remove(this);
} else {
ASSERT(fWentSleepCount < 1);
fCore->Remove(this);
}
ASSERT(!fEnqueued); ASSERT(!fEnqueued);
return true; return true;
} }