/* * This file contains the scheduler. It implements a basic task switching * routine, as well as the schedule() function. The scheduler can be called * from anywhere, and will switch to the next task decided by the scheduler * rules. If it cannot find a task to schedule, it just idles until one becomes * available. This avoids the need for an idle task. */ #include #include #define PRIORITY_COUNT 6 ObjectList *readyQueue[PRIORITY_COUNT]; /* Switch to a task */ static void switch_to_task(Task *task) { /* Save current task state */ if (__builtin_expect(!!current, 1)) { lock(current); asm volatile("mov %%esp, %0" : "=r" (current->esp)); asm volatile("mov %%ebp, %0" : "=r" (current->ebp)); current->eip = (uintptr_t) &&end; unlock(current); put(current); } /* Switch to new context */ current = task; /* Use the passed reference */ asm volatile ( "cli;" "movl %0, %%ecx;" "movl %1, %%esp;" "movl %2, %%ebp;" "movl %3, %%cr3;" "sti;" "jmp *%%ecx" :: "g" (current->eip), "g" (current->esp), "g" (current->ebp), "g" (current->pageDir) ); end: /* This prevents GCC from optimising the jump to be after the return */ asm volatile("":::"memory"); } /* Find the next schedulable ready queue */ static ObjectList * highest_priority_queue(void) { enum Priority p; for (p = PRIORITY_COUNT - 1; p > 0; p--) { if (count(readyQueue[p])) return readyQueue[p]; } return NULL; } /* Schedule the next task */ void schedule(void) { if (current && current->inCriticalSection) return; Task *task = current; ObjectList *queue = highest_priority_queue(); /* Idle if necessary */ if (!queue) { if (current && current->state == RUNNING) return; current = NULL; asm volatile("sti"); while (!(queue = highest_priority_queue())) asm volatile("hlt"); asm volatile("cli"); current = task; } /* Schedule next task */ task = pop_from_start(queue); task->state = RUNNING; if (current && current->state == RUNNING) { current->state = READY; add(readyQueue[current->priority], current); } switch_to_task(task); } /* Initialise the scheduler */ void init_scheduler(void) { enum Priority p; for (p = 0; p < PRIORITY_COUNT; p++) readyQueue[p] = create_list(&taskType); }