kernel: Add support for pinned threads
This commit is contained in:
@@ -55,6 +55,7 @@ static SimpleCPUHeap* sCPUHeap;
|
|||||||
// The run queue. Holds the threads ready to run ordered by priority.
|
// The run queue. Holds the threads ready to run ordered by priority.
|
||||||
typedef RunQueue<Thread, THREAD_MAX_SET_PRIORITY> SimpleRunQueue;
|
typedef RunQueue<Thread, THREAD_MAX_SET_PRIORITY> SimpleRunQueue;
|
||||||
static SimpleRunQueue* sRunQueue;
|
static SimpleRunQueue* sRunQueue;
|
||||||
|
static SimpleRunQueue* sCPURunQueues;
|
||||||
|
|
||||||
|
|
||||||
struct scheduler_thread_data {
|
struct scheduler_thread_data {
|
||||||
@@ -153,8 +154,19 @@ static int
|
|||||||
dump_run_queue(int argc, char** argv)
|
dump_run_queue(int argc, char** argv)
|
||||||
{
|
{
|
||||||
SimpleRunQueue::ConstIterator iterator = sRunQueue->GetConstIterator();
|
SimpleRunQueue::ConstIterator iterator = sRunQueue->GetConstIterator();
|
||||||
|
kprintf("Shared run queue:\n");
|
||||||
dump_queue(iterator);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +174,7 @@ dump_run_queue(int argc, char** argv)
|
|||||||
static int
|
static int
|
||||||
dump_cpu_heap(int argc, char** argv)
|
dump_cpu_heap(int argc, char** argv)
|
||||||
{
|
{
|
||||||
kprintf("\ncpu priority actual priority\n");
|
kprintf("cpu priority actual priority\n");
|
||||||
CPUHeapEntry* entry = sCPUHeap->PeekRoot();
|
CPUHeapEntry* entry = sCPUHeap->PeekRoot();
|
||||||
while (entry) {
|
while (entry) {
|
||||||
int32 cpu = entry->fCPUNumber;
|
int32 cpu = entry->fCPUNumber;
|
||||||
@@ -254,7 +266,13 @@ simple_enqueue(Thread* thread, bool newOne)
|
|||||||
|
|
||||||
T(EnqueueThread(thread, threadPriority));
|
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->cpu_bound = true;
|
||||||
schedulerThreadData->time_left = 0;
|
schedulerThreadData->time_left = 0;
|
||||||
@@ -264,24 +282,32 @@ simple_enqueue(Thread* thread, bool newOne)
|
|||||||
NotifySchedulerListeners(&SchedulerListener::ThreadEnqueuedInRunQueue,
|
NotifySchedulerListeners(&SchedulerListener::ThreadEnqueuedInRunQueue,
|
||||||
thread);
|
thread);
|
||||||
|
|
||||||
// TODO: pinned threads
|
|
||||||
// TODO: disabled CPUs
|
// TODO: disabled CPUs
|
||||||
CPUHeapEntry* cpuEntry = sCPUHeap->PeekRoot();
|
|
||||||
ASSERT(cpuEntry != NULL);
|
|
||||||
|
|
||||||
int32 thisCPU = smp_get_current_cpu();
|
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;
|
Thread* targetThread = gCPU[targetCPU].running_thread;
|
||||||
int32 targetPriority = simple_get_effective_priority(targetThread);
|
int32 targetPriority = simple_get_effective_priority(targetThread);
|
||||||
|
|
||||||
ASSERT((targetCPU != thisCPU && targetThread != thread)
|
ASSERT((targetCPU != thisCPU && targetThread != thread)
|
||||||
|| targetCPU == thisCPU);
|
|| targetCPU == thisCPU);
|
||||||
|
|
||||||
int32 currentThreadPriority
|
if (!pinned) {
|
||||||
= simple_get_effective_priority(thread_get_current_thread());
|
int32 currentThreadPriority
|
||||||
if (targetPriority == currentThreadPriority) {
|
= simple_get_effective_priority(thread_get_current_thread());
|
||||||
targetCPU = thisCPU;
|
if (targetPriority == currentThreadPriority) {
|
||||||
targetPriority = currentThreadPriority;
|
targetCPU = thisCPU;
|
||||||
|
targetPriority = currentThreadPriority;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("choosing CPU %ld with current priority %ld\n", targetCPU,
|
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
|
// It is possible that another CPU schedules the thread before the
|
||||||
// target CPU. However, since the target CPU is sent an ICI it will
|
// target CPU. However, since the target CPU is sent an ICI it will
|
||||||
// reschedule anyway and update its heap key to the correct value.
|
// 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()) {
|
if (targetCPU == smp_get_current_cpu()) {
|
||||||
gCPU[targetCPU].invoke_scheduler = true;
|
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.
|
/*! Sets the priority of a thread.
|
||||||
Note: thread lock must be held when entering this function
|
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.
|
/*! Runs the scheduler.
|
||||||
Note: expects thread spinlock to be held
|
Note: expects thread spinlock to be held
|
||||||
*/
|
*/
|
||||||
@@ -517,8 +588,7 @@ simple_reschedule(void)
|
|||||||
} else {
|
} else {
|
||||||
TRACE("putting thread %ld back in run queue priority = %ld\n",
|
TRACE("putting thread %ld back in run queue priority = %ld\n",
|
||||||
oldThread->id, simple_get_effective_priority(oldThread));
|
oldThread->id, simple_get_effective_priority(oldThread));
|
||||||
sRunQueue->PushFront(oldThread,
|
simple_put_back(oldThread);
|
||||||
simple_get_effective_priority(oldThread));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -539,10 +609,9 @@ simple_reschedule(void)
|
|||||||
schedulerOldThreadData->lost_cpu = false;
|
schedulerOldThreadData->lost_cpu = false;
|
||||||
|
|
||||||
// select thread with the biggest priority
|
// select thread with the biggest priority
|
||||||
nextThread = sRunQueue->PeekMaximum();
|
nextThread = simple_dequeue_thread(thisCPU);
|
||||||
if (!nextThread)
|
if (!nextThread)
|
||||||
panic("reschedule(): run queues are empty!\n");
|
panic("reschedule(): run queues are empty!\n");
|
||||||
sRunQueue->Remove(nextThread);
|
|
||||||
|
|
||||||
TRACE("reschedule(): cpu %ld, next thread = %ld\n", thisCPU,
|
TRACE("reschedule(): cpu %ld, next thread = %ld\n", thisCPU,
|
||||||
nextThread->id);
|
nextThread->id);
|
||||||
@@ -676,6 +745,20 @@ scheduler_simple_init()
|
|||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
return result;
|
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;
|
gScheduler = &kSimpleOps;
|
||||||
|
|
||||||
add_debugger_command_etc("run_queue", &dump_run_queue,
|
add_debugger_command_etc("run_queue", &dump_run_queue,
|
||||||
@@ -687,5 +770,6 @@ scheduler_simple_init()
|
|||||||
cpuHeapDeleter.Detach();
|
cpuHeapDeleter.Detach();
|
||||||
cpuEntriesDeleter.Detach();
|
cpuEntriesDeleter.Detach();
|
||||||
runQueueDeleter.Detach();
|
runQueueDeleter.Detach();
|
||||||
|
cpuRunQueuesDeleter.Detach();
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user