kernel: Add support for pinned threads

This commit is contained in:
Pawel Dziepak
2013-10-15 01:47:28 +02:00
parent 51d1e9ada0
commit 3de2c5ceec
+101 -17
View File
@@ -55,6 +55,7 @@ static SimpleCPUHeap* sCPUHeap;
// The run queue. Holds the threads ready to run ordered by priority.
typedef RunQueue<Thread, THREAD_MAX_SET_PRIORITY> SimpleRunQueue;
static SimpleRunQueue* sRunQueue;
static SimpleRunQueue* sCPURunQueues;
struct scheduler_thread_data {
@@ -153,8 +154,19 @@ static int
dump_run_queue(int argc, char** argv)
{
SimpleRunQueue::ConstIterator iterator = sRunQueue->GetConstIterator();
kprintf("Shared run queue:\n");
dump_queue(iterator);
int32 cpuCount = smp_get_num_cpus();
if (cpuCount < 2)
return 0;
for (int32 i = 0; i < cpuCount; i++) {
kprintf("\nCPU %d run queue:\n", i);
sCPURunQueues[i].GetConstIterator();
dump_queue(iterator);
}
return 0;
}
@@ -162,7 +174,7 @@ dump_run_queue(int argc, char** argv)
static int
dump_cpu_heap(int argc, char** argv)
{
kprintf("\ncpu priority actual priority\n");
kprintf("cpu priority actual priority\n");
CPUHeapEntry* entry = sCPUHeap->PeekRoot();
while (entry) {
int32 cpu = entry->fCPUNumber;
@@ -254,7 +266,13 @@ simple_enqueue(Thread* thread, bool newOne)
T(EnqueueThread(thread, threadPriority));
sRunQueue->PushBack(thread, threadPriority);
bool pinned = sCPURunQueues != NULL && thread->pinned_to_cpu > 0;
int32 pinnedCPU = -1;
if (pinned) {
pinnedCPU = thread->previous_cpu->cpu_num;
sCPURunQueues[pinnedCPU].PushBack(thread, threadPriority);
} else
sRunQueue->PushBack(thread, threadPriority);
schedulerThreadData->cpu_bound = true;
schedulerThreadData->time_left = 0;
@@ -264,24 +282,32 @@ simple_enqueue(Thread* thread, bool newOne)
NotifySchedulerListeners(&SchedulerListener::ThreadEnqueuedInRunQueue,
thread);
// TODO: pinned threads
// TODO: disabled CPUs
CPUHeapEntry* cpuEntry = sCPUHeap->PeekRoot();
ASSERT(cpuEntry != NULL);
int32 thisCPU = smp_get_current_cpu();
int32 targetCPU = cpuEntry->fCPUNumber;
int32 targetCPU = pinnedCPU;
if (!pinned) {
CPUHeapEntry* cpuEntry = sCPUHeap->PeekRoot();
ASSERT(cpuEntry != NULL);
targetCPU = cpuEntry->fCPUNumber;
}
ASSERT(targetCPU >= 0);
Thread* targetThread = gCPU[targetCPU].running_thread;
int32 targetPriority = simple_get_effective_priority(targetThread);
ASSERT((targetCPU != thisCPU && targetThread != thread)
|| targetCPU == thisCPU);
int32 currentThreadPriority
= simple_get_effective_priority(thread_get_current_thread());
if (targetPriority == currentThreadPriority) {
targetCPU = thisCPU;
targetPriority = currentThreadPriority;
if (!pinned) {
int32 currentThreadPriority
= simple_get_effective_priority(thread_get_current_thread());
if (targetPriority == currentThreadPriority) {
targetCPU = thisCPU;
targetPriority = currentThreadPriority;
}
}
TRACE("choosing CPU %ld with current priority %ld\n", targetCPU,
@@ -293,7 +319,7 @@ simple_enqueue(Thread* thread, bool newOne)
// It is possible that another CPU schedules the thread before the
// target CPU. However, since the target CPU is sent an ICI it will
// reschedule anyway and update its heap key to the correct value.
sCPUHeap->ModifyKey(cpuEntry, threadPriority);
sCPUHeap->ModifyKey(&sCPUEntries[targetCPU], threadPriority);
if (targetCPU == smp_get_current_cpu()) {
gCPU[targetCPU].invoke_scheduler = true;
@@ -318,6 +344,21 @@ simple_enqueue_in_run_queue(Thread* thread)
}
static inline void
simple_put_back(Thread* thread)
{
bool pinned = sCPURunQueues != NULL && thread->pinned_to_cpu > 0;
if (!pinned)
sRunQueue->PushFront(thread, simple_get_effective_priority(thread));
else {
int32 pinnedCPU = thread->previous_cpu->cpu_num;
sCPURunQueues[pinnedCPU].PushFront(thread,
simple_get_effective_priority(thread));
}
}
/*! Sets the priority of a thread.
Note: thread lock must be held when entering this function
*/
@@ -466,6 +507,36 @@ simple_compute_quantum(Thread* thread)
}
static inline Thread*
simple_dequeue_thread(int32 thisCPU)
{
Thread* sharedThread = sRunQueue->PeekMaximum();
Thread* pinnedThread = NULL;
if (sCPURunQueues != NULL)
pinnedThread = sCPURunQueues[thisCPU].PeekMaximum();
if (sharedThread == NULL && pinnedThread == NULL)
return NULL;
int32 pinnedPriority = -1;
if (pinnedThread != NULL)
pinnedPriority = simple_get_effective_priority(pinnedThread);
int32 sharedPriority = -1;
if (sharedThread != NULL)
sharedPriority = simple_get_effective_priority(sharedThread);
if (sharedPriority > pinnedPriority) {
sRunQueue->Remove(sharedThread);
return sharedThread;
}
sCPURunQueues[thisCPU].Remove(pinnedThread);
return pinnedThread;
}
/*! Runs the scheduler.
Note: expects thread spinlock to be held
*/
@@ -517,8 +588,7 @@ simple_reschedule(void)
} else {
TRACE("putting thread %ld back in run queue priority = %ld\n",
oldThread->id, simple_get_effective_priority(oldThread));
sRunQueue->PushFront(oldThread,
simple_get_effective_priority(oldThread));
simple_put_back(oldThread);
}
break;
@@ -539,10 +609,9 @@ simple_reschedule(void)
schedulerOldThreadData->lost_cpu = false;
// select thread with the biggest priority
nextThread = sRunQueue->PeekMaximum();
nextThread = simple_dequeue_thread(thisCPU);
if (!nextThread)
panic("reschedule(): run queues are empty!\n");
sRunQueue->Remove(nextThread);
TRACE("reschedule(): cpu %ld, next thread = %ld\n", thisCPU,
nextThread->id);
@@ -676,6 +745,20 @@ scheduler_simple_init()
if (result != B_OK)
return result;
ArrayDeleter<SimpleRunQueue> cpuRunQueuesDeleter;
if (cpuCount > 1) {
sCPURunQueues = new(std::nothrow) SimpleRunQueue[cpuCount];
if (sCPURunQueues == NULL)
return B_NO_MEMORY;
cpuRunQueuesDeleter.SetTo(sCPURunQueues);
for (int i = 0; i < cpuCount; i++) {
result = sCPURunQueues[i].GetInitStatus();
if (result != B_OK)
return result;
}
}
gScheduler = &kSimpleOps;
add_debugger_command_etc("run_queue", &dump_run_queue,
@@ -687,5 +770,6 @@ scheduler_simple_init()
cpuHeapDeleter.Detach();
cpuEntriesDeleter.Detach();
runQueueDeleter.Detach();
cpuRunQueuesDeleter.Detach();
return B_OK;
}