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

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

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;
}