multitasking.h:
Code: Select all
#ifndef MULTITASKING_H
#define MULTITASKING_H
#include <stdint.h>
enum task_priority {
PRIORITY_IDLE = 1, //Only for idle process.
PRIORITY_LOW = 5,
PRIORITY_NORMAL = 10, //Recommended for use by all regular processes.
PRIORITY_HIGH = 20,
PRIORITY_MAXIMAL = 40, //It will slow down all processes with other priorities, but will work maximally fast.
};
/*
* Reserved PIDs:
*
* - 0 is idle process.
* - 1 is init process. This is every process' parent.
*/
struct task
{
struct task *prev;
//We need to check if the process is dead, so on next PIT tick it will be removed from process list.
uint8_t alive; //On new process, it's set to 1.
uint16_t time_out; //Time before task switch
int8_t exit_status; //Contains 0 when the process is alive. kill_process() sets it to provided value, nulls all register data, frees stack memory and makes alive field == 1.
enum task_priority priority;
void *stack; //Stack needs to be separated from kernel and other processes' stack.
uint32_t eax, ebx, ecx, edx, eip, esi, edi, ebp, cr3;
struct task *next;
};
extern struct task *process_list;
extern struct task *running_task;
void init_multitasking();
void switch_task(struct task*);
#endif
Code: Select all
#include <arch/i686/multitasking.h>
#include <arch/i686/regs.h>
#include <memory.h>
#include <stdio.h>
#include <tty_old.h>
#include <stddef.h>
struct task *process_list=NULL;
struct task *running_task;
void insertTaskAfter(struct task* a, struct task* b)
{
b->prev = a;
b->next = a->next;
a->next = b;
b->next->prev = b;
}
//What do you want?
//Arguments. Lots of arguments.
struct task *create_task(void *page_directory,
void *start_address,
enum task_priority priority)
{
struct task *t = malloc(sizeof(struct task));
printf("creating task, structure address=0x%x, code address=0x%x\n", t, start_address);
t->eax = 0;
t->ebx = 0;
t->ecx = 0;
t->edx = 0;
t->esi = 0;
t->edi = 0;
t->stack = malloc(4096) + 4096; //4kb will be enough
t->eip = (uint32_t) start_address;
t->cr3 = (uint32_t) page_directory;
t->priority = priority;
t->alive = 1;
t->exit_status = 0;
t->time_out = priority;
t->next = t; //It will point to start of process list.
//Now we will put it into our process list.
if(process_list)
insertTaskAfter(process_list->prev, t);
else
{
t->prev = t;
process_list = t;
}
//process_list->prev = t;
return t;
}
static uint32_t task_eip_address; //VERY bad code, but everything crashes without this
void __attribute__((noreturn)) switch_task(struct task *task)
{
//We will change stack there, so we want to save EIP to jump.
task_eip_address = task->eip;
asm volatile("mov %0, %%eax;"
"mov %1, %%ebx;"
"mov %2, %%ecx;"
"mov %3, %%edx;"
"mov %4, %%esi;"
"mov %5, %%edi;"
"mov %6, %%ebp;"
"mov %7, %%esp;" :
"=g" (task->eax),
"=g" (task->ebx),
"=g" (task->ecx),
"=g" (task->edx),
"=g" (task->esi),
"=g" (task->edi),
"=g" (task->ebp),
"=g" (task->stack) : : "memory");
asm volatile("jmp *%0" : "=g" (task_eip_address) : : "memory");
//If something happened, halt the system.
while(1);
}
void idle_process()
{
while(1)
asm("sti; hlt");
}
void test_process()
{
while(1)
tty_putchar('a');
}
void test2_process()
{
while(1)
tty_putchar('b');
}
void test3_process()
{
while(1)
//tty_putchar('c');
;
}
void init_multitasking()
{
create_task(0, (void*) idle_process, PRIORITY_IDLE);
create_task(0, (void*) test_process, PRIORITY_NORMAL);
create_task(0, (void*) test2_process, PRIORITY_NORMAL);
create_task(0, (void*) test3_process, PRIORITY_NORMAL);
struct task *t;
for(t = process_list; t->next!=process_list; t=t->next)
printf("struct: 0x%x, code: 0x%x, priority: %d -> ", t, t->eip, t->priority);
printf("struct: 0x%x, code: 0x%x, priority: %d", t, t->eip, t->priority);
running_task = process_list; //Idle process enters the scene! Woo-hoo!
}
Code: Select all
void timer_handler(regs* r)
{
tty_wrstr("Timer interrupt!\n");
timer_ticks++; //Just increment timer_ticks.
if(running_task->time_out) //Yes, it can be zero.
running_task->time_out--;
if(running_task->time_out == 0) //Our task's time is out, so we need to switch task.
{
running_task->time_out = running_task->priority;
//Save current task state and switch to next task.
running_task->eax = r->eax ;
running_task->ebx = r->ebx ;
running_task->ecx = r->ecx ;
running_task->edx = r->edx ;
running_task->esi = r->esi ;
running_task->edi = r->edi ;
running_task->eip = r->eip ;
running_task = running_task->next ;
//Current task state saved. We will call switch_task to actually switch.
printf("Interrupting current task! New EIP is 0x%x\n", running_task->eip);
switch_task(running_task);
}
}