scheduler: Protect per CPU run queue with its own lock
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -234,17 +234,23 @@ ThreadData::PutBack()
|
|||||||
|
|
||||||
int32 priority = GetEffectivePriority();
|
int32 priority = GetEffectivePriority();
|
||||||
|
|
||||||
|
if (fThread->pinned_to_cpu > 0) {
|
||||||
|
ASSERT(fThread->cpu != NULL);
|
||||||
|
CPUEntry* cpu = CPUEntry::GetCPU(fThread->cpu->cpu_num);
|
||||||
|
|
||||||
|
CPURunQueueLocker _(cpu);
|
||||||
|
ASSERT(!fEnqueued);
|
||||||
|
fEnqueued = true;
|
||||||
|
|
||||||
|
cpu->PushFront(this, priority);
|
||||||
|
} else {
|
||||||
CoreRunQueueLocker _(fCore);
|
CoreRunQueueLocker _(fCore);
|
||||||
ASSERT(!fEnqueued);
|
ASSERT(!fEnqueued);
|
||||||
fEnqueued = true;
|
fEnqueued = true;
|
||||||
if (fThread->pinned_to_cpu > 0) {
|
|
||||||
ASSERT(fThread->cpu != NULL);
|
|
||||||
|
|
||||||
CPUEntry* cpu = CPUEntry::GetCPU(fThread->cpu->cpu_num);
|
|
||||||
cpu->PushFront(this, priority);
|
|
||||||
} else
|
|
||||||
fCore->PushFront(this, priority);
|
fCore->PushFront(this, priority);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
@@ -258,17 +264,23 @@ ThreadData::Enqueue()
|
|||||||
|
|
||||||
int32 priority = GetEffectivePriority();
|
int32 priority = GetEffectivePriority();
|
||||||
|
|
||||||
|
if (fThread->pinned_to_cpu > 0) {
|
||||||
|
ASSERT(fThread->previous_cpu != NULL);
|
||||||
|
CPUEntry* cpu = CPUEntry::GetCPU(fThread->previous_cpu->cpu_num);
|
||||||
|
|
||||||
|
CPURunQueueLocker _(cpu);
|
||||||
|
ASSERT(!fEnqueued);
|
||||||
|
fEnqueued = true;
|
||||||
|
|
||||||
|
cpu->PushBack(this, priority);
|
||||||
|
} else {
|
||||||
CoreRunQueueLocker _(fCore);
|
CoreRunQueueLocker _(fCore);
|
||||||
ASSERT(!fEnqueued);
|
ASSERT(!fEnqueued);
|
||||||
fEnqueued = true;
|
fEnqueued = true;
|
||||||
if (fThread->pinned_to_cpu > 0) {
|
|
||||||
ASSERT(fThread->previous_cpu != NULL);
|
|
||||||
|
|
||||||
CPUEntry* cpu = CPUEntry::GetCPU(fThread->previous_cpu->cpu_num);
|
|
||||||
cpu->PushBack(this, priority);
|
|
||||||
} else
|
|
||||||
fCore->PushBack(this, priority);
|
fCore->PushBack(this, priority);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
@@ -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;
|
||||||
|
|
||||||
if (fThread->pinned_to_cpu > 0) {
|
|
||||||
ASSERT(fThread->previous_cpu != NULL);
|
|
||||||
|
|
||||||
CPUEntry* cpu = CPUEntry::GetCPU(fThread->previous_cpu->cpu_num);
|
|
||||||
cpu->Remove(this);
|
|
||||||
} else {
|
|
||||||
ASSERT(fWentSleepCount < 1);
|
ASSERT(fWentSleepCount < 1);
|
||||||
fCore->Remove(this);
|
fCore->Remove(this);
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(!fEnqueued);
|
ASSERT(!fEnqueued);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user