Orion
Barry Moving signal handlers into separate namespace 7ae31b0 (3 years, 3 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();
}