[MULTITASKING] Processes
This commit is contained in:
parent
5e8fbcbb78
commit
5ca2b6994a
@ -4,12 +4,19 @@
|
||||
#include <mem.h>
|
||||
#include <gdt.h>
|
||||
#include <scheduler.h>
|
||||
#include <thread.h>
|
||||
#include <process.h>
|
||||
|
||||
void thread_function()
|
||||
{
|
||||
char *str = (char *)0x10000;
|
||||
str[0] = (char)((unsigned int)'0' + get_current_process()->pid);
|
||||
str[1] = (char)((unsigned int)'0' + get_current_thread()->tid);
|
||||
str[3] = '-';
|
||||
str[2] = '\0';
|
||||
while(1)
|
||||
{
|
||||
debug("%d", get_current_thread()->tid);
|
||||
debug((char *)0x10000);
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
@ -28,12 +35,23 @@ int kmain(uint64_t multiboot_magic, void *multiboot_data)
|
||||
gdt_init();
|
||||
scheduler_init();
|
||||
|
||||
process_t *p1 = process_spawn(0);
|
||||
process_t *p2 = process_spawn(p1);
|
||||
|
||||
scheduler_insert(new_thread(thread_function));
|
||||
scheduler_insert(new_thread(thread_function));
|
||||
scheduler_insert(new_thread(thread_function));
|
||||
scheduler_insert(new_thread(thread_function));
|
||||
scheduler_insert(new_thread(thread_function));
|
||||
thread_t *t1 = new_thread(thread_function);
|
||||
thread_t *t2 = new_thread(thread_function);
|
||||
thread_t *t3 = new_thread(thread_function);
|
||||
|
||||
process_attach(p1, t1);
|
||||
process_attach(p2, t2);
|
||||
process_attach(p1, t3);
|
||||
|
||||
vmm_set_page(p1->P4, 0x10000, pmm_alloc(), PAGE_PRESENT | PAGE_WRITE);
|
||||
vmm_set_page(p2->P4, 0x10000, pmm_alloc(), PAGE_PRESENT | PAGE_WRITE);
|
||||
|
||||
scheduler_insert(t1);
|
||||
scheduler_insert(t2);
|
||||
scheduler_insert(t3);
|
||||
|
||||
debug_info("BOOT COMPLETE\n");
|
||||
schedule();
|
||||
|
34
kernel/include/process.h
Normal file
34
kernel/include/process.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
typedef struct process_st process_t;
|
||||
#include <stdint.h>
|
||||
#include <thread.h>
|
||||
#include <mem.h>
|
||||
|
||||
typedef struct process_st
|
||||
{
|
||||
uint64_t pid;
|
||||
uint64_t state;
|
||||
uint64_t status;
|
||||
struct process_st *parent;
|
||||
page_table *P4;
|
||||
LIST(struct process_st, children);
|
||||
LIST(struct process_st, siblings);
|
||||
LIST(thread_t, threads);
|
||||
} process_t;
|
||||
|
||||
#define PROC_STATE_READY 1
|
||||
#define PROC_STATE_RUNNING 2
|
||||
#define PROC_STATE_ZOMBIE 3
|
||||
#define PROC_STATE_DONE 4
|
||||
|
||||
#define process_alive(proc) ((proc)->state == PROC_STATE_READY || (proc)->state == PROC_STATE_RUNNING)
|
||||
|
||||
process_t *current_process;
|
||||
#define get_current_process() (current_process)
|
||||
#define set_current_process(proc) (current_process = (proc))
|
||||
|
||||
process_t *process_spawn(process_t *parent);
|
||||
void process_attach(process_t *proc, thread_t *th);
|
||||
void switch_process(process_t *proc);
|
||||
void process_exit(process_t *proc, uint64_t status);
|
||||
void process_free(process_t *proc);
|
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
typedef struct thread_st thread_t;
|
||||
#include <stdint.h>
|
||||
#include <list.h>
|
||||
#include <process.h>
|
||||
|
||||
#define THREAD_STACK_SIZE 0x1000-sizeof(thread_t)
|
||||
|
||||
@ -9,6 +11,8 @@ typedef struct thread_st
|
||||
uint64_t stack_pointer; // Top of the kernel stack for thread
|
||||
uint64_t tid;
|
||||
uint64_t state;
|
||||
process_t *process;
|
||||
LIST(struct thread_st, process_threads);
|
||||
LIST(struct thread_st, ready_queue);
|
||||
} thread_t;
|
||||
|
||||
|
@ -63,6 +63,8 @@ registers_t *int_handler(registers_t *r)
|
||||
#ifndef NDEBUG
|
||||
thread_t *th = get_current_thread();
|
||||
(void)th;
|
||||
process_t *proc = get_current_process();
|
||||
(void)proc;
|
||||
asm("int_handler_breakpoint:");
|
||||
#endif
|
||||
|
||||
|
@ -22,7 +22,10 @@ page_table *vmm_new_P4()
|
||||
|
||||
void vmm_set_P4(page_table *P4)
|
||||
{
|
||||
write_cr3((uint64_t)P4);
|
||||
if(P4)
|
||||
write_cr3((uint64_t)P4);
|
||||
else
|
||||
write_cr3(V2P(&BootP4));
|
||||
}
|
||||
|
||||
void vmm_free_P4(page_table *P4)
|
||||
@ -145,6 +148,8 @@ registers_t *page_fault_handler(registers_t *r)
|
||||
#ifndef NDEBUG
|
||||
thread_t *th = get_current_thread();
|
||||
(void)th;
|
||||
process_t *proc = get_current_process();
|
||||
(void)proc;
|
||||
asm("page_fault_breakpoint:");
|
||||
#endif
|
||||
for(;;);
|
||||
|
91
kernel/proc/process.c
Normal file
91
kernel/proc/process.c
Normal file
@ -0,0 +1,91 @@
|
||||
#include <process.h>
|
||||
#include <thread.h>
|
||||
#include <debug.h>
|
||||
#include <scheduler.h>
|
||||
|
||||
uint64_t pid = 1;
|
||||
process_t *init_proc = 0;
|
||||
|
||||
process_t *process_spawn(process_t *parent)
|
||||
{
|
||||
process_t *proc = kcalloc(1, sizeof(process_t));
|
||||
proc->pid = pid++;
|
||||
proc->parent = parent;
|
||||
proc->P4 = vmm_new_P4();
|
||||
proc->state = PROC_STATE_READY;
|
||||
|
||||
LIST_INIT(proc, children);
|
||||
LIST_INIT(proc, siblings);
|
||||
LIST_INIT(proc, threads);
|
||||
|
||||
if(parent)
|
||||
{
|
||||
LIST_APPEND(parent->children, proc, siblings);
|
||||
}
|
||||
|
||||
if(proc->pid == 1)
|
||||
init_proc = proc;
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
void process_attach(process_t *proc, thread_t *th)
|
||||
{
|
||||
LIST_APPEND(proc->threads, th, process_threads);
|
||||
th->process = proc;
|
||||
}
|
||||
|
||||
void switch_process(process_t *proc)
|
||||
{
|
||||
process_t *old = get_current_process();
|
||||
if(old)
|
||||
{
|
||||
if(old == proc)
|
||||
return;
|
||||
if(old->state == PROC_STATE_RUNNING)
|
||||
old->state = PROC_STATE_READY;
|
||||
}
|
||||
set_current_process(proc);
|
||||
|
||||
if(proc)
|
||||
{
|
||||
proc->state = PROC_STATE_RUNNING;
|
||||
vmm_set_P4(proc->P4);
|
||||
}
|
||||
else
|
||||
{
|
||||
vmm_set_P4(0);
|
||||
}
|
||||
}
|
||||
|
||||
void process_exit(process_t *proc, uint64_t status)
|
||||
{
|
||||
proc->status = status;
|
||||
LIST_FOREACH(proc->children, process_t, c, siblings)
|
||||
{
|
||||
// Make init process adopt orphaned children
|
||||
LIST_REMOVE(proc->children, c, siblings);
|
||||
c->parent = init_proc;
|
||||
LIST_APPEND(init_proc->children, c, siblings);
|
||||
}
|
||||
proc->state = PROC_STATE_ZOMBIE;
|
||||
}
|
||||
|
||||
void process_free(process_t *proc)
|
||||
{
|
||||
if(proc->state != PROC_STATE_ZOMBIE)
|
||||
{
|
||||
debug_error("Trying to free an unfinished process!\n");
|
||||
for(;;);
|
||||
}
|
||||
LIST_FOREACH(proc->threads, thread_t, th, process_threads)
|
||||
{
|
||||
while(th->state == THREAD_STATE_RUNNING || th->state == THREAD_STATE_READY) schedule();
|
||||
free_thread(th);
|
||||
}
|
||||
LIST_REMOVE(proc->parent->children, proc, siblings);
|
||||
// Free page directory
|
||||
vmm_free_P4(proc->P4);
|
||||
// Free process structure
|
||||
kfree(proc);
|
||||
}
|
@ -41,15 +41,25 @@ void scheduler()
|
||||
thread_t *old = 0, *new = 0;
|
||||
if((old = get_last_thread()))
|
||||
{
|
||||
if(old->state == THREAD_STATE_RUNNING)
|
||||
if(old->state != THREAD_STATE_FINISHED && process_alive(old->process))
|
||||
{
|
||||
old->state = THREAD_STATE_READY;
|
||||
scheduler_insert(old);
|
||||
} else {
|
||||
old->state = THREAD_STATE_FINISHED;
|
||||
}
|
||||
}
|
||||
|
||||
while(!(new = scheduler_next()));
|
||||
|
||||
if(!process_alive(new->process))
|
||||
{
|
||||
new->state = THREAD_STATE_FINISHED;
|
||||
continue;
|
||||
}
|
||||
new->state = THREAD_STATE_RUNNING;
|
||||
set_last_thread(new);
|
||||
switch_process(new->process);
|
||||
switch_thread(scheduler_th, new);
|
||||
}
|
||||
}
|
||||
@ -60,6 +70,7 @@ void schedule()
|
||||
|
||||
thread_t *old = get_current_thread();
|
||||
|
||||
switch_process(0);
|
||||
switch_thread(old, scheduler_th);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <thread.h>
|
||||
#include <stdint.h>
|
||||
#include <process.h>
|
||||
#include <mem.h>
|
||||
#include <list.h>
|
||||
#include <debug.h>
|
||||
@ -23,6 +24,7 @@ thread_t *new_thread(void (*func)(void))
|
||||
th->stack_pointer = (uint64_t)&stack->RBP;
|
||||
|
||||
LIST_INIT(th, ready_queue);
|
||||
LIST_INIT(th, process_threads);
|
||||
|
||||
return th;
|
||||
}
|
||||
@ -42,6 +44,8 @@ void free_thread(thread_t *th)
|
||||
debug_error("Trying to free a live thread!\n");
|
||||
for(;;);
|
||||
}
|
||||
if(!LIST_EMPTY(th->process_threads))
|
||||
LIST_REMOVE(th->process->threads, th, process_threads);
|
||||
thread_stack_t *stack = incptr(th, -offsetof(thread_stack_t, tcb));
|
||||
kfree(stack);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user