wip: fork()
This commit is contained in:
@ -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);
|
||||||
|
|||||||
@ -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));
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
10
libbozo/src/list/lst_add_back.c
Normal file
10
libbozo/src/list/lst_add_back.c
Normal 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;
|
||||||
|
}
|
||||||
12
libbozo/src/list/lst_last.c
Normal file
12
libbozo/src/list/lst_last.c
Normal 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
40
src/multitasking/fork.c
Normal 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;
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user