wip: fork()

This commit is contained in:
0x35c
2025-11-12 15:07:36 +01:00
parent 02d196fab5
commit 34aa0f0eb4
9 changed files with 115 additions and 28 deletions

View File

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

View File

@ -1,10 +1,11 @@
#pragma once #pragma once
#include "process.h"
#include <stdint.h> #include <stdint.h>
#define STACK_SIZE PAGE_SIZE * 4 #define STACK_SIZE PAGE_SIZE * 4
#define CURRENT_TCB ((struct tcb *)current_tcb->content)
typedef uint16_t tid_t;
typedef enum { typedef enum {
NEW, NEW,
@ -16,10 +17,9 @@ typedef enum {
struct tcb { struct tcb {
uint32_t *esp; uint32_t *esp;
uint32_t *esp0; uint32_t *esp0;
uint16_t tid; tid_t tid;
state_t state; state_t state;
struct pcb *process; struct pcb *process;
struct tcb *next;
}; };
struct tcb *create_thread(struct pcb *process, void (*entry)(void)); struct tcb *create_thread(struct pcb *process, void (*entry)(void));

View File

@ -4,3 +4,6 @@ struct list {
void *content; void *content;
struct list *next; struct list *next;
}; };
struct list *lst_last(struct list *head);
void lst_add_back(struct list **head, struct list *e);

View File

@ -0,0 +1,10 @@
#include "list.h"
void lst_add_back(struct list **head, struct list *e)
{
struct list *last = lst_last(*head);
if (!last)
*head = e;
else
last->next = e;
}

View File

@ -0,0 +1,12 @@
#include "list.h"
#include <stddef.h>
struct list *lst_last(struct list *head)
{
if (!head)
return NULL;
struct list *it = head;
while (it->next)
it = it->next;
return it;
}

40
src/multitasking/fork.c Normal file
View File

@ -0,0 +1,40 @@
#include "alloc.h"
#include "memory.h"
#include "process.h"
#include "string.h"
#include "thread.h"
static struct tcb *thread_clone(struct tcb *thread)
{
struct tcb *new_tcb = vmalloc(sizeof(struct tcb));
if (!new_tcb)
return NULL;
new_tcb->tid = thread->tid;
new_tcb->esp0 = alloc_pages(STACK_SIZE, NULL);
if (!new_tcb->esp0) {
delete_thread(new_tcb);
return NULL;
}
memcpy(new_tcb->esp0, thread->esp0, STACK_SIZE);
return new_tcb;
}
pid_t fork(void)
{
struct pcb *new_pcb = create_process(current_pcb->uid);
if (!new_pcb)
return -1;
struct list *new_node = vmalloc(sizeof(struct list));
if (!new_node) {
remove_process(new_pcb);
return -1;
}
new_pcb->daddy = current_pcb;
lst_add_back(&new_pcb->children, new_node);
current_pd = new_pcb->cr3;
// loop on threads clone
thread_clone(current_pcb->thread_list->content);
current_pd = current_pcb->cr3;
return new_pcb->pid;
}

View File

@ -6,14 +6,15 @@
#include "string.h" #include "string.h"
struct pcb *create_process(uint8_t uid) struct pcb *create_process(uid_t uid)
{ {
static uint32_t pid = 1; static pid_t pid = 1;
struct pcb *new_pcb = vmalloc(sizeof(struct pcb)); struct pcb *new_pcb = vmalloc(sizeof(struct pcb));
if (!new_pcb) if (!new_pcb)
return NULL; return NULL;
new_pcb->uid = uid; new_pcb->uid = uid;
new_pcb->pid = pid++; new_pcb->pid = pid++;
new_pcb->tid = 1;
new_pcb->heap = alloc_pages(4096, &new_pcb->cr3); new_pcb->heap = alloc_pages(4096, &new_pcb->cr3);
if (!new_pcb->heap) { if (!new_pcb->heap) {
@ -22,6 +23,8 @@ struct pcb *create_process(uint8_t uid)
} }
memcpy(new_pcb->heap, current_pd, 4096); memcpy(new_pcb->heap, current_pd, 4096);
new_pcb->daddy = NULL;
new_pcb->children = NULL;
new_pcb->next = new_pcb; new_pcb->next = new_pcb;
new_pcb->prev = new_pcb; new_pcb->prev = new_pcb;
@ -40,7 +43,7 @@ struct pcb *create_process(uint8_t uid)
return new_pcb; return new_pcb;
} }
void remove_pcb(struct pcb *pcb) void remove_process(struct pcb *pcb)
{ {
struct pcb *left = pcb->prev; struct pcb *left = pcb->prev;
struct pcb *right = pcb->next; struct pcb *right = pcb->next;

View File

@ -9,18 +9,18 @@
#include <stddef.h> #include <stddef.h>
struct pcb *current_pcb; struct pcb *current_pcb;
struct tcb *current_tcb; struct list *current_tcb;
static struct tcb *get_thread_to_switch(void) static struct list *get_thread_to_switch(void)
{ {
struct pcb *it_p; struct pcb *it_p;
struct tcb *it_t; struct list *it_t;
it_p = current_pcb; it_p = current_pcb;
it_t = current_tcb == NULL ? NULL : current_tcb->next; it_t = current_tcb == NULL ? NULL : current_tcb->next;
while (it_p) { while (it_p) {
while (it_t != NULL) { while (it_t != NULL) {
if (it_t != NULL && it_t->state != WAITING) if (it_t != NULL && CURRENT_TCB->state != WAITING)
return it_t; return it_t;
it_t = it_t->next; it_t = it_t->next;
} }
@ -32,13 +32,14 @@ static struct tcb *get_thread_to_switch(void)
void scheduler(uint32_t *esp) void scheduler(uint32_t *esp)
{ {
struct tcb *thread_to_switch = get_thread_to_switch(); struct list *list_node = get_thread_to_switch();
if (!thread_to_switch) if (!list_node)
kpanic("No existing threads \n"); kpanic("No existing threads \n");
struct tcb *thread_to_switch = (struct tcb *)list_node->content;
if (current_tcb) if (current_tcb)
current_tcb->esp = esp; CURRENT_TCB->esp = esp;
if (thread_to_switch->process != current_pcb) if (thread_to_switch->process != current_pcb)
switch_process(thread_to_switch->process); switch_process(thread_to_switch->process);
current_tcb = thread_to_switch; current_tcb = list_node;
switch_thread(thread_to_switch->esp); switch_thread(thread_to_switch->esp);
} }

View File

@ -2,17 +2,18 @@
#include "alloc.h" #include "alloc.h"
#include "assert.h" #include "assert.h"
#include "interrupts.h" #include "interrupts.h"
#include "list.h"
#include "memory.h" #include "memory.h"
#include "process.h"
#include "string.h" #include "string.h"
#include "thread.h" #include "thread.h"
struct tcb *create_thread(struct pcb *process, void (*entry)(void)) struct tcb *create_thread(struct pcb *process, void (*entry)(void))
{ {
static uint32_t tid = 1;
struct tcb *new_tcb = vmalloc(sizeof(struct tcb)); struct tcb *new_tcb = vmalloc(sizeof(struct tcb));
if (!new_tcb) if (!new_tcb)
return NULL; return NULL;
new_tcb->tid = tid++; new_tcb->tid = process->tid++;
new_tcb->esp0 = alloc_pages(STACK_SIZE, NULL); new_tcb->esp0 = alloc_pages(STACK_SIZE, NULL);
if (!new_tcb->esp0) { if (!new_tcb->esp0) {
@ -40,18 +41,26 @@ struct tcb *create_thread(struct pcb *process, void (*entry)(void))
*(--stack) = 0; // ESI *(--stack) = 0; // ESI
*(--stack) = 0; // EDI *(--stack) = 0; // EDI
*(--stack) = 0x10; // kernel DS *(--stack) = 0x10; // kernel DS
new_tcb->esp = stack; new_tcb->esp = stack;
new_tcb->process = process; new_tcb->process = process;
new_tcb->next = NULL;
new_tcb->state = NEW; new_tcb->state = NEW;
struct list *new_node = vmalloc(sizeof(struct list));
if (!new_node) {
free_pages(new_tcb->esp0, STACK_SIZE);
vfree(new_tcb);
return NULL;
}
new_node->content = new_tcb;
new_node->next = NULL;
if (process->thread_list == NULL) { if (process->thread_list == NULL) {
process->thread_list = new_tcb; process->thread_list = new_node;
} else { } else {
struct tcb *it = process->thread_list; struct list *it = process->thread_list;
while (it->next) while (it->next)
it = it->next; it = it->next;
it->next = new_tcb; it->next = new_node;
} }
return new_tcb; return new_tcb;
@ -60,10 +69,12 @@ struct tcb *create_thread(struct pcb *process, void (*entry)(void))
void delete_thread(struct tcb *thread) void delete_thread(struct tcb *thread)
{ {
vfree(thread->esp0); vfree(thread->esp0);
struct tcb *it = thread->process->thread_list; struct list *it = thread->process->thread_list;
assert(it); assert(it);
while (it->next != thread) while (it->next && it->next->content != thread)
it = it->next; it = it->next;
struct list *to_free = it;
it->next = it->next->next; it->next = it->next->next;
vfree(to_free);
vfree(thread); vfree(thread);
} }