wip: thread and processes handle

This commit is contained in:
0x35c
2025-11-05 16:19:21 +01:00
parent 56cfe9f2be
commit 374ea13173
25 changed files with 243 additions and 340 deletions

11
headers/assert.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "kpanic.h"
#define assert(X) \
do { \
if (!(X)) { \
kpanic("ASSERT_FAIL %s:%u %s\n", __FILE__, __LINE__, \
#X); \
} \
} while (0)

View File

@ -9,13 +9,6 @@
#define PRINT_STR(X) kprintf("%s:%u %s: %s\n", __FILE__, __LINE__, #X, X) #define PRINT_STR(X) kprintf("%s:%u %s: %s\n", __FILE__, __LINE__, #X, X)
#define PRINT_UINT(X) kprintf("%s:%u %s: %u\n", __FILE__, __LINE__, #X, X) #define PRINT_UINT(X) kprintf("%s:%u %s: %u\n", __FILE__, __LINE__, #X, X)
#define PRINT_INT(X) kprintf("%s:%u %s: %d\n", __FILE__, __LINE__, #X, X) #define PRINT_INT(X) kprintf("%s:%u %s: %d\n", __FILE__, __LINE__, #X, X)
#define assert(X) \
do { \
if (!(X)) { \
kpanic("ASSERT_FAIL %s:%u %s\n", __FILE__, __LINE__, \
#X); \
} \
} while (0)
struct function_entry { struct function_entry {
uint32_t addr; uint32_t addr;

25
headers/process.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include "signal.h"
#include <stdint.h>
extern struct pcb *current_pcb;
enum owner { OWNER_KERNEL, OWNER_USER };
struct pcb {
void *cr3;
uint32_t *heap;
uint16_t pid;
uint8_t uid;
struct signal_data signals;
struct pcb *next;
struct pcb *prev;
struct tcb *thread_list;
};
void switch_process(struct pcb *next_pcb);
struct pcb *create_process(uint8_t uid);
int8_t create_kernel_process(void);
void remove_process(struct pcb *pcb);

3
headers/scheduler.h Normal file
View File

@ -0,0 +1,3 @@
#pragma once
void scheduler(void);

View File

@ -1,44 +0,0 @@
#pragma once
#include "list.h"
#include "memory.h"
#include "signal.h"
#include <stdint.h>
extern struct task *current_task;
enum status { ZOMBIE, THREAD, RUN, WAIT, SLEEP, STOPPED, FORKED };
enum owner { OWNER_KERNEL, OWNER_USER };
#define STACK_SIZE PAGE_SIZE * 4
struct task {
uint8_t *esp;
uint8_t *esp0;
uint32_t *cr3; // physical
uint32_t *heap; // virtual
uint32_t *eip;
uint16_t pid;
uint8_t status;
uint8_t uid;
struct task *daddy;
struct task *child;
struct signal_data signals;
struct task *next;
struct task *prev;
};
void scheduler(void);
void switch_to_task(struct task *next_task);
struct task *create_task(uint8_t uid);
int8_t create_kernel_task(void);
void remove_task(struct task *task);
struct task *copy_task(const struct task *task);
void kfork(struct task *daddy);
void zombify_task(struct task *task);
// utils
void exec_fn(void (*fn)(void));
uint16_t fork(void);
uint16_t wait(void);

27
headers/thread.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include "process.h"
#include <stdint.h>
#define STACK_SIZE PAGE_SIZE * 4
typedef enum {
NEW,
RUNNING,
WAITING,
STOPPED,
} state_t;
struct tcb {
uint8_t *esp;
uint8_t *esp0;
uint16_t tid;
state_t state;
struct pcb *process;
struct tcb *next;
};
struct tcb *create_thread(struct pcb *process, void (*routine)(void));
void delete_thread(struct tcb *thread);
void switch_thread(struct tcb *thread_to_switch);

View File

@ -5,8 +5,9 @@
#include "interrupts.h" #include "interrupts.h"
#include "kprintf.h" #include "kprintf.h"
#include "memory.h" #include "memory.h"
#include "process.h"
#include "scheduler.h"
#include "sys/io.h" #include "sys/io.h"
#include "task.h"
#define PIT_CHANNEL0 0x40 #define PIT_CHANNEL0 0x40
#define PIT_FREQUENCY 1193182 #define PIT_FREQUENCY 1193182

View File

@ -38,7 +38,6 @@ irq_common_stub:
iret iret
irq0: irq0:
mov [esp_backup], esp
push 0 push 0
push 32 push 32
jmp irq_common_stub jmp irq_common_stub

View File

@ -8,9 +8,9 @@
#include "memory.h" #include "memory.h"
#include "multiboot.h" #include "multiboot.h"
#include "power.h" #include "power.h"
#include "process.h"
#include "shell.h" #include "shell.h"
#include "string.h" #include "string.h"
#include "task.h"
#include "terminal.h" #include "terminal.h"
#include "time.h" #include "time.h"
#include "vbe.h" #include "vbe.h"
@ -43,9 +43,9 @@ void kernel_main(multiboot_info_t *mbd, uint32_t magic)
init_memory(mbd, magic); init_memory(mbd, magic);
load_drivers(); load_drivers();
terminal_initialize(); terminal_initialize();
create_kernel_task(); create_kernel_process();
signal(4, bozo); signal(4, bozo);
kill(0, 4); kill(0, 4);
create_task(42); // create_process(42);
shell_init(); shell_init();
} }

View File

@ -2,7 +2,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "debug.h" #include "assert.h"
#include "kprintf.h" #include "kprintf.h"
#include "memory.h" #include "memory.h"
#include "string.h" #include "string.h"

View File

@ -2,11 +2,11 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "debug.h" #include "assert.h"
#include "kprintf.h" #include "kprintf.h"
#include "memory.h" #include "memory.h"
#include "string.h" #include "string.h"
#include "task.h" #include "process.h"
#include "utils.h" #include "utils.h"
static int16_t find_next_block(size_t nb_pages, uint16_t *pd_index_ptr, static int16_t find_next_block(size_t nb_pages, uint16_t *pd_index_ptr,

View File

@ -1,4 +1,4 @@
#include "debug.h" #include "assert.h"
#include "kprintf.h" #include "kprintf.h"
#include "memory.h" #include "memory.h"
void init_page_table(uint32_t page_table[1024], uint16_t start) void init_page_table(uint32_t page_table[1024], uint16_t start)

View File

@ -1,9 +1,9 @@
#include "alloc.h" #include "alloc.h"
#include "debug.h" #include "assert.h"
#include "kpanic.h" #include "kpanic.h"
#include "kprintf.h" #include "kprintf.h"
#include "memory.h" #include "memory.h"
#include "task.h" #include "process.h"
Zone *kzones[3]; Zone *kzones[3];

View File

@ -1,5 +1,5 @@
#include "alloc.h" #include "alloc.h"
#include "debug.h" #include "assert.h"
#include "kprintf.h" #include "kprintf.h"
#include "terminal.h" #include "terminal.h"
#include <stdint.h> #include <stdint.h>

View File

@ -1,9 +1,9 @@
#include "alloc.h" #include "alloc.h"
#include "debug.h" #include "assert.h"
#include "kpanic.h" #include "kpanic.h"
#include "kprintf.h" #include "kprintf.h"
#include "memory.h" #include "memory.h"
#include "task.h" #include "process.h"
Zone *vzones[3]; Zone *vzones[3];

View File

@ -1,5 +1,5 @@
#include "alloc.h" #include "alloc.h"
#include "debug.h" #include "assert.h"
#include "kprintf.h" #include "kprintf.h"
#include "terminal.h" #include "terminal.h"
#include <stdint.h> #include <stdint.h>

View File

@ -1,26 +0,0 @@
#include "interrupts.h"
#include "kprintf.h"
#include "task.h"
uint16_t fork(void)
{
current_task->status = FORKED;
scheduler();
return current_task->child ? current_task->child->pid : 0;
}
void kfork(struct task *daddy)
{
cli();
struct task *child = copy_task(daddy);
if (!child) {
kprintf(KERN_ALERT "Fork failed ! retry at the next loop");
toris();
return;
}
child->daddy = daddy;
daddy->child = child;
daddy->status = RUN;
child->status = RUN;
toris();
}

View File

@ -0,0 +1,57 @@
#include "process.h"
#include "alloc.h"
#include "interrupts.h"
#include "memory.h"
#include "string.h"
int8_t create_kernel_process(void)
{
struct pcb *new_pcb = vmalloc(sizeof(struct pcb));
if (!new_pcb)
return -1;
new_pcb->pid = 0;
new_pcb->uid = 0;
new_pcb->heap = kernel_pd;
new_pcb->cr3 = (uint32_t *)((uint32_t)kernel_pd - HEAP_END);
new_pcb->next = new_pcb;
new_pcb->prev = new_pcb;
return 0;
}
struct pcb *create_process(uint8_t uid)
{
static uint32_t pid = 1;
struct pcb *new_pcb = vmalloc(sizeof(struct pcb));
if (!new_pcb)
return NULL;
new_pcb->uid = uid;
new_pcb->pid = pid++;
new_pcb->heap = alloc_pages(4096, &new_pcb->cr3);
if (!new_pcb->heap) {
vfree(new_pcb);
return NULL;
}
memcpy(new_pcb->heap, current_pcb->heap, 4096);
new_pcb->next = current_pcb->next;
new_pcb->prev = current_pcb;
current_pcb->next = new_pcb;
if (current_pcb->prev == current_pcb)
current_pcb->prev = new_pcb;
new_pcb->signals.pending = SIG_IGN;
return new_pcb;
}
void remove_pcb(struct pcb *pcb)
{
struct pcb *left = pcb->prev;
struct pcb *right = pcb->next;
if (pcb->heap)
free_pages(pcb->heap, 4096);
left->next = right;
right->prev = left;
vfree(pcb);
}

View File

@ -2,34 +2,28 @@
#include "debug.h" #include "debug.h"
#include "interrupts.h" #include "interrupts.h"
#include "kprintf.h" #include "kprintf.h"
#include "task.h" #include "process.h"
#include "thread.h"
#include "time.h" #include "time.h"
#include <stddef.h> #include <stddef.h>
struct task *current_task; struct pcb *current_pcb;
struct tcb *current_tcb;
void scheduler(void) void scheduler(void)
{ {
// ZOMBIE, THREAD, RUN, WAIT, SLEEP, STOPPED, FORKED struct tcb *thread_to_switch;
void (*func[])(struct task *) = { if (!current_tcb) {
zombify_task, NULL, NULL, NULL, NULL, remove_task, kfork, thread_to_switch = current_pcb->thread_list;
}; } else {
if (!current_tcb->next) {
if (!current_task) // || current_task->next == current_task) current_pcb = current_pcb->next;
return; // TODO switch context
cli(); thread_to_switch = current_pcb->thread_list;
switch_pd(kernel_pd, (uint32_t *)((uint32_t)kernel_pd - HEAP_END)); } else {
struct task *it = current_task->next; thread_to_switch = current_tcb->next;
while (it && it->status != RUN) {
if (it != current_task && func[it->status]) {
struct task *new_it = it->prev;
func[it->status](it);
it = new_it;
} }
it = it->next;
} }
switch_to_task(it); switch_thread(thread_to_switch);
exec_signal_pending();
toris();
} }

View File

@ -1,58 +0,0 @@
.intel_syntax noprefix
.section .text
.global switch_to_task
switch_to_task:
push ebx
push ebp
push edi
push esi
mov eax, [current_task]
// save the current stack pointer to the old stack
mov [eax+0], esp
// stack pointer + the 4 regs pushed
// and + 1 to get the argument (next task)
mov esi, [esp+(4+1)*4]
mov [current_task], esi
mov eax, [current_task]
mov esp, [eax+0] // get esp
mov ecx, [eax+12] // get task's pd
mov [current_pd], ecx
mov ecx, [eax+8]
mov cr3, ecx
pop esi
pop edi
pop ebp
pop ebx
mov ecx, 0
cmp [eax+16], ecx
je .END
sti
push [eax+16] // store func_ptr
mov [eax+16], ecx // clear eip in current_task
push 0
call pic_send_eoi
pop edx // remove pic_send_eoi argument
pop edx // get func_ptr
call edx
call exit_task
.END:
ret

View File

@ -0,0 +1,31 @@
.intel_syntax noprefix
.section .text
.global switch_thread
switch_thread:
push ebx
push ebp
push edi
push esi
mov eax, [current_tcb]
// save the current stack pointer to the old stack
mov [eax+0], esp
// stack pointer + the 4 regs pushed
// and + 1 to get the argument (next thread)
mov esi, [esp+(4+1)*4]
mov [current_tcb], esi
mov eax, [current_tcb]
mov esp, [eax+0] // get esp
pop esi
pop edi
pop ebp
pop ebx
iret

View File

@ -1,140 +0,0 @@
#include "task.h"
#include "alloc.h"
#include "debug.h"
#include "interrupts.h"
#include "kpanic.h"
#include "kprintf.h"
#include "memory.h"
#include "string.h"
#include <stdbool.h>
#include <stdint.h>
uint32_t esp_backup;
struct task *create_task(uint8_t uid)
{
static uint32_t pid = 1;
switch_pd(kernel_pd, (uint32_t *)((uint32_t)kernel_pd - HEAP_END));
struct task *new_task = vmalloc(sizeof(struct task));
if (!new_task) {
switch_pd(current_task->heap, current_task->cr3);
return NULL;
}
switch_pd(current_task->heap, current_task->cr3);
new_task->status = RUN;
new_task->uid = uid;
new_task->esp = new_task->esp0 + STACK_SIZE;
new_task->pid = pid++;
// Allocate new pd
new_task->heap = alloc_pages(4096, (void **)&new_task->cr3);
if (!new_task->heap) {
vfree(new_task);
return NULL;
}
new_task->heap[768] = ((uint32_t)boot_page_table1 - HEAP_END) | 0x03;
// memcpy(new_task->heap, current_task->heap, 4096);
current_pd = new_task->heap;
// switch_pd(new_task->heap, new_task->cr3);
// Allocate new stack on the newly allocated pd
new_task->esp0 = alloc_pages(STACK_SIZE, NULL);
current_pd = kernel_pd;
// switch_pd(current_task->heap, current_task->cr3);
if (!new_task->esp0) {
vfree(new_task);
free_pages(new_task->heap, 4096);
return NULL;
}
new_task->next = current_task->next;
new_task->prev = current_task;
current_task->next = new_task;
if (current_task->prev == current_task)
current_task->prev = new_task;
new_task->signals.pending = SIG_IGN;
return new_task;
}
int8_t create_kernel_task(void)
{
struct task *new_task = vmalloc(sizeof(struct task));
if (!new_task)
return -1;
new_task->status = RUN;
new_task->uid = 0;
new_task->pid = 0;
new_task->heap = kernel_pd;
new_task->cr3 = (uint32_t *)((uint32_t)kernel_pd - HEAP_END);
new_task->prev = new_task;
new_task->next = new_task;
new_task->signals.pending = SIG_IGN;
current_task = new_task;
return 0;
}
void exec_fn(void (*fn)(void))
{
struct task *new_task = create_task(OWNER_KERNEL);
if (!new_task)
kpanic("failed to create new task");
new_task->eip = (uint32_t *)fn;
}
void zombify_task(struct task *task)
{
cli(); // Technically useless
free_pages(task->heap, 4096);
free_pages(task->esp0, STACK_SIZE);
task->esp0 = NULL;
task->heap = NULL;
toris();
}
void remove_task(struct task *task)
{
cli();
struct task *left = task->prev;
struct task *right = task->next;
if (task->child) {
remove_task(task->child);
task->child = NULL;
}
if (task->heap)
free_pages(task->heap, 4096);
if (task->esp0)
free_pages(task->esp0, STACK_SIZE);
left->next = right;
right->prev = left;
vfree(task);
toris();
}
struct task *copy_task(const struct task *task)
{
struct task *new_task = create_task(task->uid);
if (!new_task)
return NULL;
memcpy(new_task->esp0, task->esp0, STACK_SIZE);
new_task->esp = new_task->esp0 + (task->esp - task->esp0);
new_task->status = task->status;
return new_task;
}
void exit_task(void)
{
cli();
if (current_task->daddy && current_task->daddy->status != WAIT)
current_task->status = ZOMBIE;
else {
if (current_task->daddy->status == WAIT)
current_task->daddy->status = RUN;
current_task->status = STOPPED;
}
toris();
scheduler();
}

47
src/multitasking/thread.c Normal file
View File

@ -0,0 +1,47 @@
#include "thread.h"
#include "alloc.h"
#include "assert.h"
#include "interrupts.h"
#include "memory.h"
#include "string.h"
#include "thread.h"
struct tcb *create_thread(struct pcb *process, void (*routine)(void))
{
static uint32_t tid = 1;
struct tcb *new_tcb = vmalloc(sizeof(struct tcb));
if (!new_tcb)
return NULL;
new_tcb->tid = tid++;
new_tcb->esp0 = alloc_pages(STACK_SIZE, NULL);
if (!new_tcb->esp0) {
vfree(new_tcb);
return NULL;
}
// set esp to "skip" the 4 GPRs and eip later to be used as the context
// of the thread
new_tcb->esp = new_tcb->esp0 + STACK_SIZE - 5 * 4;
memcpy(new_tcb->esp + 4, routine, 4);
new_tcb->process = process;
new_tcb->next = NULL;
new_tcb->state = NEW;
struct tcb *it = process->thread_list;
while (it)
it = it->next;
it = new_tcb;
return new_tcb;
}
void delete_thread(struct tcb *thread)
{
vfree(thread->esp0);
struct tcb *it = thread->process->thread_list;
assert(it);
while (it->next != thread)
it = it->next;
it->next = it->next->next;
vfree(thread);
}

View File

@ -1,17 +0,0 @@
#include "interrupts.h"
#include "task.h"
uint16_t wait(void)
{
if (current_task->child == NULL)
return -1;
cli();
if (current_task->child->status == ZOMBIE)
current_task->child->status = STOPPED;
else
current_task->status = WAIT;
uint16_t child_pid = current_task->child->pid;
toris();
scheduler();
return child_pid;
}

View File

@ -1,21 +1,21 @@
#include "signal.h" #include "signal.h"
#include "kprintf.h" #include "kprintf.h"
#include "task.h" #include "process.h"
#include <stdint.h> #include <stdint.h>
void signal(SIGNAL_CODE sig_num, void *handler) void signal(SIGNAL_CODE sig_num, void *handler)
{ {
current_task->signals.handlers[sig_num] = handler; current_pcb->signals.handlers[sig_num] = handler;
} }
void kill(int pid, SIGNAL_CODE sig_num) void kill(int pid, SIGNAL_CODE sig_num)
{ {
struct task *task = current_task; struct pcb *pcb = current_pcb;
while (task->pid != pid) while (pcb->pid != pid)
task = task->next; pcb = pcb->next;
task->signals.pending = sig_num; pcb->signals.pending = sig_num;
} }
static void display_signal(SIGNAL_CODE sig_num) static void display_signal(SIGNAL_CODE sig_num)
@ -25,12 +25,12 @@ static void display_signal(SIGNAL_CODE sig_num)
static void exec_signal(SIGNAL_CODE sig_num) static void exec_signal(SIGNAL_CODE sig_num)
{ {
void *handler = current_task->signals.handlers[sig_num]; void *handler = current_pcb->signals.handlers[sig_num];
if (handler == SIG_IGN) if ((int32_t)handler == SIG_IGN)
return; return;
if (handler == SIG_DFL) { if ((int32_t)handler == SIG_DFL) {
display_signal(sig_num); display_signal(sig_num);
return; return;
} }
@ -41,9 +41,9 @@ static void exec_signal(SIGNAL_CODE sig_num)
void exec_signal_pending(void) void exec_signal_pending(void)
{ {
uint32_t signal_code = current_task->signals.pending; int32_t signal_code = current_pcb->signals.pending;
if (signal_code != SIG_IGN) { if (signal_code != SIG_IGN) {
exec_signal(signal_code); exec_signal(signal_code);
current_task->signals.pending = SIG_IGN; current_pcb->signals.pending = SIG_IGN;
} }
} }