From a7ef4f443662be39bc9f0b1bc2ac4d341d7ba920 Mon Sep 17 00:00:00 2001 From: phfr24 Date: Sat, 14 Mar 2026 15:08:31 -0300 Subject: [PATCH 1/1] tasks implementation (ongoing) --- ppos/kernel/task.c | 195 ++++++++++++++++++++++++++++++++++++++++++++- ppos/kernel/tcb.h | 22 +++-- 2 files changed, 210 insertions(+), 7 deletions(-) diff --git a/ppos/kernel/task.c b/ppos/kernel/task.c index a97fee7..4266c39 100644 --- a/ppos/kernel/task.c +++ b/ppos/kernel/task.c @@ -1,5 +1,198 @@ // PingPongOS - PingPong Operating System -void task_init() +/* PEDRO HENRIQUE FRIEDRICH RAMOS : GRR20243133 */ + +#include +#include +#include "tcb.h" +#include "ctx.h" + +/* ------------------------------------------------------------------------- */ +/* Constants -------------------------------------------------------------- */ + +/* 8 pages = 32 KiB */ +#define STACK_SIZE (8 * 4096) + +/* ------------------------------------------------------------------------- */ +/* Static variables ------------------------------------------------------- */ + +static struct task_t *task_current; +static struct task_t task_kernel; /* Is task_kernel like init for ppos? */ + +/* ------------------------------------------------------------------------- */ +/* Internal functions ----------------------------------------------------- */ + +/* Allocate memory for a task's stack. + * + * The size parameter must be page aligned! */ +static inline void * +alloc_stack (size_t size) { + + /* Using mmap () instead of malloc () makes a little bit more sense, since + * when a task ends the mapping can be immediately deleted. If we use malloc, + * we can't know for sure if the brk will be lowered. + * + * Also, it (probably) makes the stack allocations farther apart, so it's less + * likely that a task can corrupt another task's stack by accident, which is + * possible since ppos doesn't have virtual memory nor memory protection. */ + + return mmap (/* Let the kernel choose the address for the mapping. */ + NULL, + + /* Size of the mapping (must be page-aligned). */ + size, + + /* RW stack. */ + PROT_READ | PROT_WRITE, + + /* Not shared between (linux) processes. + * Not backed by a file. */ + MAP_PRIVATE | MAP_ANONYMOUS, + + /* No file descriptor. */ + -1, + + /* No offset. */ + 0); } + +/* ------------------------------------------------------------------------- */ + +/* Free allocated memory for a task's stack. */ +static inline int +free_stack (void *stack, size_t size) +{ + return munmap (stack, size); +} + +/* ------------------------------------------------------------------------- */ + +/* Get the next free task id. + * + * Stupid simple implementation, not thread safe! */ +static int +get_next_id (void) +{ + static int id = 0; + return ++id; /* id=0 is reserved for task_kernel */ +} + +/* ------------------------------------------------------------------------- */ +/* Exported functions ----------------------------------------------------- */ + +void +task_init (void) +{ + /* TODO */ +} + +/* ------------------------------------------------------------------------- */ + +struct task_t * +task_create (char *name, void (*entry) (void *), void *arg) +{ + struct task_t *task; + unsigned char *stack; + + if (!(task = malloc (sizeof *task))) + goto err_malloc_task; + + if (!(stack = alloc_stack (STACK_SIZE))) + goto err_malloc_stack; + + task->id = get_next_id (); + task->name = name; + task->status = STATUS_READY; + + /* Probably not the best way to do this but with this interface and the + * current implementation it's the best we can do right now. + * + * We need it for task_switch (). + * + * In a multiprocessor system this doesn't hold up. */ + + task->parent = task_current; + + if (ctx_create (&task->context, entry, arg, stack, STACK_SIZE)) + goto err_ctx_create; + + return task; + +err_ctx_create: + free_stack (stack, STACK_SIZE); +err_malloc_stack: + free (task); +err_malloc_task: + return NULL; +} + +/* ------------------------------------------------------------------------- */ + +int +task_destroy (struct task_t *task) +{ + if (task->status != STATUS_TERMINATED) + return ERROR; + + if (free_stack (task->context.stack, task->context.size)) + return ERROR; /* Probably EINVAL. */ + + free (task); + + return NOERROR; +} + +/* ------------------------------------------------------------------------- */ + +int +task_switch (struct task_t *task) +{ + if (!task) + return task_switch (task_current->parent); + + /* Instructions not clear... */ + switch (task->status) + { + case STATUS_TERMINATED: /* Switch to task_kernel or to parent? */ + return task_switch (task_kernel); + + case STATUS_RUNNING: /* Return ERROR or switch to another task? */ + return ERROR; + } + + task_current->status = STATUS_SUSPENDED; + task_current = task; + task_current->status = STATUS_RUNNING; + + /* task_current and task are not the same, because if they task->status would + * be STATUS_RUNNING, which is handled earlier. + * + * Since that's the only error case for ctx_swap (), we're fine ... */ + + return ctx_swap (&task_current->context, &task->context); +} + +/* ------------------------------------------------------------------------- */ + +int +task_id (struct task_t *task) +{ + if (!task) + return task_id (task->current); + + return task->id; +} + +/* ------------------------------------------------------------------------- */ + +char * +task_name (struct task_t *task) +{ + if (!task) + return task_id (task->current); + + return task->name; +} + +/* ------------------------------------------------------------------------- */ diff --git a/ppos/kernel/tcb.h b/ppos/kernel/tcb.h index d93897a..230bcdf 100644 --- a/ppos/kernel/tcb.h +++ b/ppos/kernel/tcb.h @@ -9,13 +9,23 @@ #include "ctx.h" -// Task Control Block (TCB), infos sobre uma tarefa -struct task_t +/* TODO */ +enum task_status { - int id; // identificador da tarefa - char *name; // nome da tarefa - struct ctx_t context; // contexto armazenado da tarefa - // ... + STATUS_READY, + STATUS_RUNNING, + STATUS_SUSPENDED, + STATUS_TERMINATED +}; + +/* Task Control Block. */ +struct task_t +{/* TODO comment fields. */ + int id; + char *name; + enum task_status status; + struct task_t *parent; + struct ctx_t context; }; #endif -- 2.52.0