Orion
Barry Moving signal handlers into separate namespace 7ae31b0 (2 years, 4 months ago)/* * This file controls the Kernel's scheduler. It decides when a new task must * be scheduled, and which tasks can actually be scheduled. */ #include <stdint.h> #include "../proc/proc.h" #include "../mem/paging.h" #include "task.h" uintptr_t read_eip(void); void context_switch(uintptr_t eip, page_dir_t phys, uintptr_t ebp, uintptr_t esp); void handle_signals(void); TaskQueue readyQueue, tasks; Task *currentTask[MAX_CPUS]; /* Switch to a task */ static void switch_to_task(Task *task) { uintptr_t esp, ebp, eip; asm volatile("mov %%esp, %0" : "=r" (esp)); asm volatile("mov %%ebp, %0" : "=r" (ebp)); eip = read_eip(); if (eip == 0x10032004) /* Magic number */ return; acquire(¤t->lock); current->eip = eip; current->esp = esp; current->ebp = ebp; release(¤t->lock); current = task; eip = current->eip; esp = current->esp; ebp = current->ebp; context_switch(eip, current->pageDir, ebp, esp); /* UNREACHED */ /* * This code actually returns to the read_eip() call above. This is due * to how the call works. The context switch jumps to the address * stored in the eip variable. This address is the return address of * the read_eip() call. The context_switch() function sets the return * value before jumping, so it appears as though read_eip() returned * that value. The code uses the magic number 0x10032004 to tell when * this is occurring and just returns early. */ } /* Find task by ID */ Task * find_task(pid_t tid) { Task *task; for (task = tasks.start; task && task->tid != tid; task = task->tnext); return task; } /* Add a task to a task queue */ void add_to_queue(TaskQueue *queue, Task *task) { if (!queue->start) { queue->start = task; queue->end = task; } else { queue->end->next = task; queue->end = task; } task->next = NULL; } /* Remove a task from a task queue */ void remove_from_queue(TaskQueue *queue, Task *task) { /* Start of list */ if (queue->start == task) { queue->start = task->next; if (!queue->start) queue->end = NULL; return; } /* Search */ Task *prev; for (prev = queue->start; prev->next; prev = prev->next) if (prev->next == task) break; if (prev->next) { prev->next = task->next; if (queue->end == task) queue->end = prev; } } /* Remove the first task from a task queue */ Task * pop_from_queue(TaskQueue *queue) { Task *head = queue->start; if (!head) return NULL; queue->start = head->next; if (!queue->start) queue->end = NULL; return head; } /* Block a task */ void block_task(int reason) { acquire(¤t->lock); current->state = reason; release(¤t->lock); schedule(); } /* Unblock a task */ void unblock_task(Task *task) { if (task->state == READY || task->state == RUNNING) return; task->state = READY; if (!readyQueue.start || task->priority > current->priority) { acquire(&readyQueue.lock); task->next = readyQueue.start; readyQueue.start = task; if (!readyQueue.end) readyQueue.end = task; release(&readyQueue.lock); } else { add_to_queue(&readyQueue, task); } } /* Schedule next task */ void schedule(void) { Task *task = current; /* Next schedulable task */ if (readyQueue.start) { acquire(&readyQueue.lock); task = readyQueue.start; readyQueue.start = task->next; if (!readyQueue.start) readyQueue.end = NULL; task->state = RUNNING; task->next = NULL; if (current->state == RUNNING) { current->state = READY; add_to_queue(&readyQueue, current); } release(&readyQueue.lock); switch_to_task(task); /* Idle task */ } else if (current->state != RUNNING) { current = NULL; asm volatile("sti"); while (!readyQueue.start) asm volatile("hlt"); asm volatile("cli"); current = task; acquire(&readyQueue.lock); task = readyQueue.start; readyQueue.start = task->next; if (!readyQueue.start) readyQueue.end = NULL; task->state = RUNNING; task->next = NULL; release(&readyQueue.lock); switch_to_task(task); } handle_signals(); }