feat(kernel/sched): scheduler + task subsystem

This commit is contained in:
Fábio Coutada 2026-07-12 21:06:40 +01:00
parent e8e2f06b0a
commit 9c19e1a69f
4 changed files with 1641 additions and 0 deletions

452
kernel/src/core/sched.cpp Normal file
View file

@ -0,0 +1,452 @@
/* -------------------------- FILE PROLOGUE -------------------------------- */
/**
* @file
* uos_sched.cpp
*
* @purpose
* Implementation of scheduler for UniversalisOS.
* Based on PikeOS sched.h architecture.
*/
/* ------------------------- FILE INCLUSION -------------------------------- */
#include "sched.h"
/* ------------------------ STATIC VARIABLES ------------------------------- */
/** Per-CPU scheduler state */
static uos_sched_cpu_t sched_cpu[UOS_MAX_CPUS];
/** Time partitions */
static uos_timepart_t* sched_taudir[UOS_MAX_TIMEPARTS];
/** Number of time partitions */
static uint32_t sched_num_timepart = 0;
/** Number of priorities */
static uos_prio_t sched_num_prio = 0;
/** Current CPU ID */
static uos_cpuid_t sched_current_cpu = 0;
/* ----------------------- FUNCTION IMPLEMENTATIONS ------------------------ */
/**
* @purpose
* Initialize the scheduling module.
*/
void uos_sched_init(uint32_t num_timepart, uos_prio_t num_prio) {
/* Validate parameters */
if (num_timepart == 0 || num_timepart > UOS_MAX_TIMEPARTS) {
/* TODO: Panic */
return;
}
if (num_prio == 0 || num_prio > UOS_MAX_PRIORITIES) {
/* TODO: Panic */
return;
}
sched_num_timepart = num_timepart;
sched_num_prio = num_prio;
/* Initialize per-CPU data structures */
for (uos_cpuid_t cpu = 0; cpu < UOS_MAX_CPUS; cpu++) {
sched_cpu[cpu].current = NULL;
sched_cpu[cpu].idle = NULL;
sched_cpu[cpu].switcher = NULL;
sched_cpu[cpu].active_tau = NULL;
sched_cpu[cpu].lock = 0;
sched_cpu[cpu].preempt_pending = false;
}
/* Allocate time partition data structures */
for (uint32_t i = 0; i < num_timepart; i++) {
/* TODO: Allocate from boot allocator */
sched_taudir[i] = (uos_timepart_t*)0; /* Placeholder */
if (sched_taudir[i] != NULL) {
sched_taudir[i]->id = i;
sched_taudir[i]->overall_exec_time = 0;
sched_taudir[i]->lock = 0;
/* Initialize ready queue */
for (uos_prio_t prio = 0; prio < num_prio; prio++) {
sched_taudir[i]->readyq.queues[prio].head.next =
&sched_taudir[i]->readyq.queues[prio].head;
sched_taudir[i]->readyq.queues[prio].head.prev =
&sched_taudir[i]->readyq.queues[prio].head;
}
/* Initialize priority bitmap */
for (uint32_t j = 0; j < UOS_MAX_PRIORITIES / 32; j++) {
sched_taudir[i]->readyq.prio_bitmap[j] = 0;
}
sched_taudir[i]->readyq.maxprio = 0;
}
}
/* Set time partition 0 as active for all CPUs */
for (uos_cpuid_t cpu = 0; cpu < UOS_MAX_CPUS; cpu++) {
sched_cpu[cpu].active_tau = sched_taudir[0];
}
}
/**
* @purpose
* Return pointer to thread object of currently running thread.
*/
uos_thrinfo_t* uos_sched_current(void) {
/* TODO: Get current thread from architecture-specific code */
return sched_cpu[sched_current_cpu].current;
}
/**
* @purpose
* Registers the current thread as idle thread.
*/
void uos_sched_register_idle(uos_cpuid_t cpuid) {
/* Validate CPU ID */
if (cpuid >= UOS_MAX_CPUS) {
return;
}
/* Get current thread */
uos_thrinfo_t* thr = uos_sched_current();
if (thr == NULL) {
return;
}
/* Register as idle thread */
sched_cpu[cpuid].idle = thr;
sched_cpu[cpuid].current = thr;
/* Set idle flag */
thr->flags |= UOS_SCHEDFLAG_IDLE;
}
/**
* @purpose
* Register a kernel thread with entry point.
*/
void uos_sched_register_kthread(uos_thrinfo_t* thr, void (*kentry)(void*)) {
/* Validate thread */
if (thr == NULL) {
return;
}
/* Set preemption level to kernel */
/* TODO: Set preemption level */
/* Register kernel entry point */
thr->entry = kentry;
/* TODO: Create context for kernel thread */
}
/**
* @purpose
* Make a thread ready.
*/
void uos_sched_make_ready(uos_thrinfo_t* thr) {
/* Validate thread */
if (thr == NULL) {
return;
}
/* Get time partition */
uos_timepart_t* tau = thr->sched.boost_tau;
if (tau == NULL) {
tau = thr->sched.base_tau;
}
if (tau == NULL) {
return;
}
/* Get priority */
uos_prio_t prio = thr->sched.boost_prio;
if (prio == 0) {
prio = thr->sched.base_prio;
}
/* Enqueue at tail of ready queue */
uos_list_node_t* node = &thr->sched.readyql;
uos_list_t* queue = &tau->readyq.queues[prio];
node->next = &queue->head;
node->prev = queue->head.prev;
queue->head.prev->next = node;
queue->head.prev = node;
/* Update priority bitmap */
uint32_t bitmap_idx = prio / 32;
uint32_t bitmap_bit = prio % 32;
tau->readyq.prio_bitmap[bitmap_idx] |= (1 << bitmap_bit);
/* Update maxprio */
if (prio > tau->readyq.maxprio) {
tau->readyq.maxprio = prio;
}
/* Set thread state to ready */
thr->state = UOS_THR_STATE_READY;
/* TODO: Check preemption */
}
/**
* @purpose
* Schedule the next thread.
*/
void uos_sched_schedule(void) {
uos_sched_cpu_t* cpu = &sched_cpu[sched_current_cpu];
uos_timepart_t* tau = cpu->active_tau;
if (tau == NULL) {
return;
}
/* Find highest priority non-empty queue */
uos_prio_t maxprio = tau->readyq.maxprio;
uos_list_t* queue = &tau->readyq.queues[maxprio];
/* Check if queue is empty */
if (queue->head.next == &queue->head) {
/* No threads ready - schedule idle thread */
if (cpu->idle != NULL) {
cpu->current = cpu->idle;
cpu->idle->state = UOS_THR_STATE_RUNNING;
}
return;
}
/* Get first thread from queue */
uos_list_node_t* node = queue->head.next;
uos_thrinfo_t* next = (uos_thrinfo_t*)((char*)node - offsetof(uos_thrinfo_t, sched.readyql));
/* Remove from queue */
node->prev->next = node->next;
node->next->prev = node->prev;
/* Update priority bitmap if queue is now empty */
if (queue->head.next == &queue->head) {
uint32_t bitmap_idx = maxprio / 32;
uint32_t bitmap_bit = maxprio % 32;
tau->readyq.prio_bitmap[bitmap_idx] &= ~(1 << bitmap_bit);
/* Find new maxprio */
for (uos_prio_t prio = maxprio; prio > 0; prio--) {
bitmap_idx = prio / 32;
bitmap_bit = prio % 32;
if (tau->readyq.prio_bitmap[bitmap_idx] & (1 << bitmap_bit)) {
tau->readyq.maxprio = prio;
break;
}
}
}
/* Switch to next thread */
uos_thrinfo_t* last = cpu->current;
cpu->current = next;
next->state = UOS_THR_STATE_RUNNING;
/* Update last thread state */
if (last != NULL && last->state == UOS_THR_STATE_RUNNING) {
last->state = UOS_THR_STATE_READY;
}
/* TODO: Perform context switch */
}
/**
* @purpose
* Yield the current thread.
*/
void uos_sched_yield(void) {
uos_thrinfo_t* thr = uos_sched_current();
if (thr == NULL) {
return;
}
/* Set yield flag */
thr->flags |= UOS_SCHEDFLAG_YIELD;
/* Make thread ready */
uos_sched_make_ready(thr);
/* Schedule next thread */
uos_sched_schedule();
}
/**
* @purpose
* Block the current thread.
*/
void uos_sched_block(void) {
uos_thrinfo_t* thr = uos_sched_current();
if (thr == NULL) {
return;
}
/* Set thread state to blocked */
thr->state = UOS_THR_STATE_BLOCKED;
/* Schedule next thread */
uos_sched_schedule();
}
/**
* @purpose
* Wake up a thread.
*/
void uos_sched_wakeup(uos_thrinfo_t* thr) {
/* Validate thread */
if (thr == NULL) {
return;
}
/* Check if thread is blocked */
if (thr->state != UOS_THR_STATE_BLOCKED &&
thr->state != UOS_THR_STATE_WAITING) {
return;
}
/* Make thread ready */
uos_sched_make_ready(thr);
}
/**
* @purpose
* Set timeout for the current thread.
*/
void uos_sched_timeout_set(uos_time_t timeout) {
uos_thrinfo_t* thr = uos_sched_current();
if (thr == NULL) {
return;
}
/* Set timeout expiration time */
/* TODO: Get current time and add timeout */
thr->sched.expiry_time = timeout;
/* Set timeout flag */
thr->sched.tpflags |= UOS_SCHEDFLAG_TIMEOUT;
}
/**
* @purpose
* Set infinite timeout for the current thread.
*/
void uos_sched_timeout_set_infinite(void) {
uos_thrinfo_t* thr = uos_sched_current();
if (thr == NULL) {
return;
}
/* Clear timeout flag */
thr->sched.tpflags &= ~UOS_SCHEDFLAG_TIMEOUT;
}
/**
* @purpose
* Start waiting in the scheduler.
*/
void uos_sched_wait_start(uos_thr_state_t state) {
uos_thrinfo_t* thr = uos_sched_current();
if (thr == NULL) {
return;
}
/* Set wait indicated state */
thr->sched.wait_indicated = state;
}
/**
* @purpose
* Wait in the scheduler.
*/
uint32_t uos_sched_wait(void) {
uos_thrinfo_t* thr = uos_sched_current();
if (thr == NULL) {
return 0;
}
/* Set thread state to waiting */
thr->state = UOS_THR_STATE_WAITING;
/* Schedule next thread */
uos_sched_schedule();
/* Return wakeup cause */
return thr->sched.wakeup_cause;
}
/**
* @purpose
* Complete waiting in the scheduler.
*/
uint32_t uos_sched_wait_complete(void) {
uos_thrinfo_t* thr = uos_sched_current();
if (thr == NULL) {
return 0;
}
/* Clear wait indicated state */
thr->sched.wait_indicated = 0;
/* Return wakeup cause */
return thr->sched.wakeup_cause;
}
/**
* @purpose
* Start wakeup of a thread.
*/
void uos_sched_wakeup_start(uos_thrinfo_t* thr, uint32_t cause) {
/* Validate thread */
if (thr == NULL) {
return;
}
/* Set wakeup cause */
thr->sched.wakeup_cause = cause;
}
/**
* @purpose
* Complete wakeup of a thread.
*/
void uos_sched_wakeup_complete(uos_thrinfo_t* thr) {
/* Validate thread */
if (thr == NULL) {
return;
}
/* Set wakeup completed flag */
thr->sched.wakeup_completed = true;
/* Wake up thread */
uos_sched_wakeup(thr);
}
/**
* @purpose
* Check if preemption is pending.
*/
bool uos_sched_preempt_pending(void) {
return sched_cpu[sched_current_cpu].preempt_pending;
}
/**
* @purpose
* Preemption point.
*/
void uos_sched_preempt_point(void) {
/* Check if preemption is pending */
if (uos_sched_preempt_pending()) {
/* Schedule next thread */
uos_sched_schedule();
}
}

369
kernel/src/core/sched.h Normal file
View file

@ -0,0 +1,369 @@
#ifndef UOS_SCHED_H
#define UOS_SCHED_H
/* -------------------------- FILE PROLOGUE -------------------------------- */
/**
* @file
* uos_sched.h
*
* @purpose
* The scheduler module implements the scheduling concepts time partitioning
* and preemptive priority scheduling.
*
* Based on PikeOS sched.h architecture.
*/
/* ------------------------- FILE INCLUSION -------------------------------- */
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
/* ------------------- MACRO / CONSTANT DEFINITIONS ------------------------ */
/** Maximum number of CPUs */
#define UOS_MAX_CPUS 4
/** Maximum number of time partitions */
#define UOS_MAX_TIMEPARTS 8
/** Maximum number of priorities */
#define UOS_MAX_PRIORITIES 256
/** Thread states */
#define UOS_THR_STATE_READY 0
#define UOS_THR_STATE_RUNNING 1
#define UOS_THR_STATE_BLOCKED 2
#define UOS_THR_STATE_WAITING 3
#define UOS_THR_STATE_ZOMBIE 4
/** Scheduler flags */
#define UOS_SCHEDFLAG_YIELD (1<<0)
#define UOS_SCHEDFLAG_TIMEOUT (1<<1)
#define UOS_SCHEDFLAG_TP_ALL (1<<2)
#define UOS_SCHEDFLAG_TP_PERIOD (1<<3)
#define UOS_SCHEDFLAG_TP_MAJOR (1<<4)
#define UOS_SCHEDFLAG_TP_CHANGE (1<<5)
#define UOS_SCHEDFLAG_DEADLINE (1<<8)
#define UOS_SCHEDFLAG_OVERDUE (1<<9)
#define UOS_SCHEDFLAG_IDLE (1<<11)
#define UOS_SCHEDFLAG_FREE_THREAD (1<<12)
#define UOS_SCHEDFLAG_BOOST (1<<13)
/* ------------------------ TYPE DECLARATIONS ------------------------------ */
/**
* @brief Priority type
*/
typedef uint32_t uos_prio_t;
/**
* @brief CPU ID type
*/
typedef uint32_t uos_cpuid_t;
/**
* @brief Time type
*/
typedef uint64_t uos_time_t;
/**
* @brief CPU mask type
*/
typedef uint32_t uos_cpumask_t;
/**
* @brief Thread state type
*/
typedef uint32_t uos_thr_state_t;
/**
* @brief List node structure
*/
typedef struct uos_list_node_str {
struct uos_list_node_str* next;
struct uos_list_node_str* prev;
} uos_list_node_t;
/**
* @brief List head structure
*/
typedef struct uos_list_str {
uos_list_node_t head;
} uos_list_t;
/**
* @brief Thread scheduling state
*
* This structure is part of the thread descriptor.
*/
typedef struct uos_sched_state_str {
/** Priority of the thread */
uos_prio_t base_prio;
/** Boosted priority of the thread */
uos_prio_t boost_prio;
/** Assigned CPU */
uos_cpuid_t cpu;
/** MCP */
uos_prio_t mcprio;
/** Preemption threshold priority */
uos_prio_t preempt_prio;
/** Thread's associated time partition */
struct uos_timepart_str* base_tau;
/** Thread's boosted time partition */
struct uos_timepart_str* boost_tau;
/** List link into the ready queue */
uos_list_node_t readyql;
/** Time the thread was selected by the scheduler */
uos_time_t last_start_time;
/** Accumulated execution time */
uos_time_t overall_exec_time;
/** Timeout expiration time */
uos_time_t expiry_time;
/** Timeout related flags */
uint32_t tpflags;
/** List link into the normal timeout tree */
uos_list_node_t timeql_time;
/** List link into the time partition timeout queue */
uos_list_node_t timeql_tp;
/** Absolute deadline expiration time */
uos_time_t deadline;
/** Node link in the deadline tree */
uos_list_node_t deadline_node;
/** Wake up cause */
uint32_t wakeup_cause;
/** Indicator that a wait operation is going to start */
uos_thr_state_t wait_indicated;
/** Indicator that the wakeup operation is completed */
bool wakeup_completed;
/** Bitmask of CPUs on which thread may be scheduled */
uos_cpumask_t affinity_mask;
/** CPU to migrate to */
uos_cpuid_t migrate_cpu;
} uos_sched_state_t;
/**
* @brief Thread information structure
*/
typedef struct uos_thrinfo_str {
/** Thread ID */
uint32_t tid;
/** Thread state */
uos_thr_state_t state;
/** Scheduling state */
uos_sched_state_t sched;
/** Thread entry point */
void (*entry)(void* arg);
/** Thread argument */
void* arg;
/** Thread stack */
void* stack;
/** Thread stack size */
uint32_t stack_size;
/** Thread flags */
uint32_t flags;
/** Thread lock */
uint32_t lock;
} uos_thrinfo_t;
/**
* @brief Ready queue structure
*/
typedef struct uos_readyq_str {
/** Ready queues for each priority */
uos_list_t queues[UOS_MAX_PRIORITIES];
/** Priority tracking bitmap */
uint32_t prio_bitmap[UOS_MAX_PRIORITIES / 32];
/** Highest priority with non-empty queue */
uos_prio_t maxprio;
} uos_readyq_t;
/**
* @brief Time partition structure
*/
typedef struct uos_timepart_str {
/** Time partition ID */
uint32_t id;
/** Ready queue */
uos_readyq_t readyq;
/** Overall execution time */
uos_time_t overall_exec_time;
/** Time partition lock */
uint32_t lock;
} uos_timepart_t;
/**
* @brief Per-CPU scheduler state
*/
typedef struct uos_sched_cpu_str {
/** Current thread */
uos_thrinfo_t* current;
/** Idle thread */
uos_thrinfo_t* idle;
/** Switcher thread */
uos_thrinfo_t* switcher;
/** Active time partition */
uos_timepart_t* active_tau;
/** Scheduler lock */
uint32_t lock;
/** Preemption pending flag */
bool preempt_pending;
} uos_sched_cpu_t;
/* ----------------------- FUNCTION DECLARATIONS --------------------------- */
/**
* @purpose
* Initialize the scheduling module.
*
* @param num_timepart
* IN: number of time partitions
* @param num_prio
* IN: number of priorities
*/
void uos_sched_init(uint32_t num_timepart, uos_prio_t num_prio);
/**
* @purpose
* Return pointer to thread object of currently running thread.
*
* @returns
* Pointer to thread object, always succeeds.
*/
uos_thrinfo_t* uos_sched_current(void);
/**
* @purpose
* Registers the current thread as idle thread.
*
* @param cpuid
* IN: current CPU
*/
void uos_sched_register_idle(uos_cpuid_t cpuid);
/**
* @purpose
* Register a kernel thread with entry point.
*
* @param thr
* IN: thread to register
* @param kentry
* IN: kernel entry point
*/
void uos_sched_register_kthread(uos_thrinfo_t* thr, void (*kentry)(void*));
/**
* @purpose
* Make a thread ready.
*
* @param thr
* IN: thread to make ready
*/
void uos_sched_make_ready(uos_thrinfo_t* thr);
/**
* @purpose
* Schedule the next thread.
*/
void uos_sched_schedule(void);
/**
* @purpose
* Yield the current thread.
*/
void uos_sched_yield(void);
/**
* @purpose
* Block the current thread.
*/
void uos_sched_block(void);
/**
* @purpose
* Wake up a thread.
*
* @param thr
* IN: thread to wake up
*/
void uos_sched_wakeup(uos_thrinfo_t* thr);
/**
* @purpose
* Set timeout for the current thread.
*
* @param timeout
* IN: timeout in milliseconds
*/
void uos_sched_timeout_set(uos_time_t timeout);
/**
* @purpose
* Set infinite timeout for the current thread.
*/
void uos_sched_timeout_set_infinite(void);
/**
* @purpose
* Start waiting in the scheduler.
*
* @param state
* IN: state to wait in
*/
void uos_sched_wait_start(uos_thr_state_t state);
/**
* @purpose
* Wait in the scheduler.
*
* @returns
* Wakeup cause
*/
uint32_t uos_sched_wait(void);
/**
* @purpose
* Complete waiting in the scheduler.
*
* @returns
* Wakeup cause
*/
uint32_t uos_sched_wait_complete(void);
/**
* @purpose
* Start wakeup of a thread.
*
* @param thr
* IN: thread to wake up
* @param cause
* IN: wakeup cause
*/
void uos_sched_wakeup_start(uos_thrinfo_t* thr, uint32_t cause);
/**
* @purpose
* Complete wakeup of a thread.
*
* @param thr
* IN: thread to wake up
*/
void uos_sched_wakeup_complete(uos_thrinfo_t* thr);
/**
* @purpose
* Check if preemption is pending.
*
* @returns
* true if preemption is pending, false otherwise
*/
bool uos_sched_preempt_pending(void);
/**
* @purpose
* Preemption point.
*/
void uos_sched_preempt_point(void);
#endif /* UOS_SCHED_H */

490
kernel/src/core/task.cpp Normal file
View file

@ -0,0 +1,490 @@
/* -------------------------- FILE PROLOGUE -------------------------------- */
/**
* @file
* uos_task.cpp
*
* @purpose
* Implementation of task management for UniversalisOS.
* Based on PikeOS task.h and thread.h architecture.
*/
/* ------------------------- FILE INCLUSION -------------------------------- */
#include "task.h"
/* ------------------------ STATIC VARIABLES ------------------------------- */
/** Task directory */
static uos_task_desc_t task_dir[UOS_TASK_MAX];
/** Thread directory */
static uos_thread_desc_t thread_dir[UOS_TASK_MAX * UOS_THREAD_MAX];
/** Current task ID */
static uos_task_id_t current_task = 0;
/** Current thread ID */
static uos_thread_id_t current_thread = 0;
/** Next task ID */
static uos_task_id_t next_task_id = 1;
/** Next thread ID */
static uos_thread_id_t next_thread_id = 1;
/** Task statistics */
static uos_task_stats_t task_stats;
/* ----------------------- FUNCTION IMPLEMENTATIONS ------------------------ */
/**
* @purpose
* Initialize task management.
*/
void uos_task_init(void) {
/* Initialize task directory */
for (uint32_t i = 0; i < UOS_TASK_MAX; i++) {
task_dir[i].id = 0;
task_dir[i].name[0] = '\0';
task_dir[i].state = UOS_TASK_STATE_DEAD;
task_dir[i].flags = 0;
task_dir[i].priority = 0;
task_dir[i].num_threads = 0;
task_dir[i].parent = 0;
task_dir[i].child = 0;
task_dir[i].sibling = 0;
task_dir[i].address_space = NULL;
task_dir[i].exit_status = 0;
task_dir[i].in_use = false;
}
/* Initialize thread directory */
for (uint32_t i = 0; i < UOS_TASK_MAX * UOS_THREAD_MAX; i++) {
thread_dir[i].id = 0;
thread_dir[i].task = 0;
thread_dir[i].state = UOS_THREAD_STATE_ZOMBIE;
thread_dir[i].flags = 0;
thread_dir[i].priority = 0;
thread_dir[i].entry = NULL;
thread_dir[i].arg = NULL;
thread_dir[i].stack = NULL;
thread_dir[i].stack_size = 0;
thread_dir[i].context = NULL;
thread_dir[i].exit_status = 0;
thread_dir[i].in_use = false;
}
/* Initialize statistics */
task_stats.forks = 0;
task_stats.execs = 0;
task_stats.exits = 0;
task_stats.waits = 0;
task_stats.signals = 0;
/* Create idle task */
uos_task_id_t idle_task = uos_task_create("idle", 0, UOS_TASK_FLAG_IDLE | UOS_TASK_FLAG_SYSTEM);
if (idle_task > 0) {
current_task = idle_task;
}
}
/**
* @purpose
* Create a new task.
*/
uos_task_id_t uos_task_create(const char* name, uos_task_prio_t priority, uint32_t flags) {
/* Validate parameters */
if (name == NULL) {
return UOS_TASK_E_INVAL;
}
/* Find free task slot */
uos_task_id_t task_id = 0;
for (uint32_t i = 0; i < UOS_TASK_MAX; i++) {
if (!task_dir[i].in_use) {
task_id = i;
break;
}
}
if (task_id == 0 && task_dir[0].in_use) {
return UOS_TASK_E_NOSPC;
}
/* Initialize task descriptor */
task_dir[task_id].id = next_task_id++;
/* Copy name */
uint32_t i = 0;
while (name[i] != '\0' && i < UOS_TASK_NAME_MAX - 1) {
task_dir[task_id].name[i] = name[i];
i++;
}
task_dir[task_id].name[i] = '\0';
task_dir[task_id].state = UOS_TASK_STATE_READY;
task_dir[task_id].flags = flags;
task_dir[task_id].priority = priority;
task_dir[task_id].num_threads = 0;
task_dir[task_id].parent = current_task;
task_dir[task_id].child = 0;
task_dir[task_id].sibling = 0;
task_dir[task_id].address_space = NULL;
task_dir[task_id].exit_status = 0;
task_dir[task_id].in_use = true;
/* Add to parent's child list */
if (current_task > 0 && task_dir[current_task].in_use) {
task_dir[task_id].sibling = task_dir[current_task].child;
task_dir[current_task].child = task_id;
}
return task_id;
}
/**
* @purpose
* Delete a task.
*/
int uos_task_delete(uos_task_id_t task_id) {
/* Validate task ID */
if (task_id >= UOS_TASK_MAX) {
return UOS_TASK_E_INVAL;
}
if (!task_dir[task_id].in_use) {
return UOS_TASK_E_NOENT;
}
/* Check if task has threads */
if (task_dir[task_id].num_threads > 0) {
return UOS_TASK_E_PERM;
}
/* Remove from parent's child list */
uos_task_id_t parent = task_dir[task_id].parent;
if (parent > 0 && task_dir[parent].in_use) {
if (task_dir[parent].child == task_id) {
task_dir[parent].child = task_dir[task_id].sibling;
} else {
uos_task_id_t child = task_dir[parent].child;
while (child > 0 && task_dir[child].sibling != task_id) {
child = task_dir[child].sibling;
}
if (child > 0) {
task_dir[child].sibling = task_dir[task_id].sibling;
}
}
}
/* Mark as unused */
task_dir[task_id].in_use = false;
task_dir[task_id].state = UOS_TASK_STATE_DEAD;
return UOS_TASK_E_OK;
}
/**
* @purpose
* Get task descriptor.
*/
uos_task_desc_t* uos_task_get(uos_task_id_t task_id) {
/* Validate task ID */
if (task_id >= UOS_TASK_MAX) {
return NULL;
}
if (!task_dir[task_id].in_use) {
return NULL;
}
return &task_dir[task_id];
}
/**
* @purpose
* Get current task.
*/
uos_task_desc_t* uos_task_current(void) {
return uos_task_get(current_task);
}
/**
* @purpose
* Fork a task.
*/
uos_task_id_t uos_task_fork(void) {
/* Get current task */
uos_task_desc_t* parent = uos_task_current();
if (parent == NULL) {
return UOS_TASK_E_NOENT;
}
/* Create child task */
uos_task_id_t child_id = uos_task_create(parent->name, parent->priority, parent->flags);
if (child_id == 0 || child_id >= UOS_TASK_MAX) {
return UOS_TASK_E_NOSPC;
}
/* Copy address space (COW) */
/* TODO: Implement COW address space copying */
/* Update statistics */
task_stats.forks++;
/* Return child task ID in parent, 0 in child */
return child_id;
}
/**
* @purpose
* Execute a program in a task.
*/
int uos_task_exec(uos_task_id_t task_id, const char* path, char* const argv[]) {
/* Validate parameters */
if (path == NULL) {
return UOS_TASK_E_INVAL;
}
/* Validate task ID */
if (task_id >= UOS_TASK_MAX) {
return UOS_TASK_E_INVAL;
}
if (!task_dir[task_id].in_use) {
return UOS_TASK_E_NOENT;
}
/* TODO: Implement program loading and execution */
/* Update statistics */
task_stats.execs++;
return UOS_TASK_E_OK;
}
/**
* @purpose
* Exit a task.
*/
int uos_task_exit(uos_task_id_t task_id, int status) {
/* Validate task ID */
if (task_id >= UOS_TASK_MAX) {
return UOS_TASK_E_INVAL;
}
if (!task_dir[task_id].in_use) {
return UOS_TASK_E_NOENT;
}
/* Set exit status */
task_dir[task_id].exit_status = status;
task_dir[task_id].state = UOS_TASK_STATE_ZOMBIE;
/* TODO: Clean up task resources */
/* Update statistics */
task_stats.exits++;
return UOS_TASK_E_OK;
}
/**
* @purpose
* Wait for a task to exit.
*/
uos_task_id_t uos_task_wait(uos_task_id_t task_id, int* status, uint32_t options) {
/* Validate task ID */
if (task_id >= UOS_TASK_MAX) {
return UOS_TASK_E_INVAL;
}
if (!task_dir[task_id].in_use) {
return UOS_TASK_E_NOENT;
}
/* Check if task is zombie */
if (task_dir[task_id].state == UOS_TASK_STATE_ZOMBIE) {
/* Return exit status */
if (status != NULL) {
*status = task_dir[task_id].exit_status;
}
/* Clean up task */
uos_task_delete(task_id);
/* Update statistics */
task_stats.waits++;
return task_id;
}
/* TODO: Implement blocking wait */
return UOS_TASK_E_NOTIMPL;
}
/**
* @purpose
* Send a signal to a task.
*/
int uos_task_kill(uos_task_id_t task_id, int signal) {
/* Validate task ID */
if (task_id >= UOS_TASK_MAX) {
return UOS_TASK_E_INVAL;
}
if (!task_dir[task_id].in_use) {
return UOS_TASK_E_NOENT;
}
/* TODO: Implement signal handling */
/* Update statistics */
task_stats.signals++;
return UOS_TASK_E_OK;
}
/**
* @purpose
* Create a new thread.
*/
uos_thread_id_t uos_thread_create(uos_task_id_t task_id, void (*entry)(void*), void* arg, uos_task_prio_t priority) {
/* Validate parameters */
if (entry == NULL) {
return UOS_TASK_E_INVAL;
}
/* Validate task ID */
if (task_id >= UOS_TASK_MAX) {
return UOS_TASK_E_INVAL;
}
if (!task_dir[task_id].in_use) {
return UOS_TASK_E_NOENT;
}
/* Check if task has too many threads */
if (task_dir[task_id].num_threads >= UOS_THREAD_MAX) {
return UOS_TASK_E_NOSPC;
}
/* Find free thread slot */
uos_thread_id_t thread_id = 0;
for (uint32_t i = 0; i < UOS_TASK_MAX * UOS_THREAD_MAX; i++) {
if (!thread_dir[i].in_use) {
thread_id = i;
break;
}
}
if (thread_id == 0 && thread_dir[0].in_use) {
return UOS_TASK_E_NOSPC;
}
/* Initialize thread descriptor */
thread_dir[thread_id].id = next_thread_id++;
thread_dir[thread_id].task = task_id;
thread_dir[thread_id].state = UOS_THREAD_STATE_READY;
thread_dir[thread_id].flags = 0;
thread_dir[thread_id].priority = priority;
thread_dir[thread_id].entry = entry;
thread_dir[thread_id].arg = arg;
thread_dir[thread_id].stack = NULL;
thread_dir[thread_id].stack_size = 0;
thread_dir[thread_id].context = NULL;
thread_dir[thread_id].exit_status = 0;
thread_dir[thread_id].in_use = true;
/* Update task thread count */
task_dir[task_id].num_threads++;
return thread_id;
}
/**
* @purpose
* Delete a thread.
*/
int uos_thread_delete(uos_thread_id_t thread_id) {
/* Validate thread ID */
if (thread_id >= UOS_TASK_MAX * UOS_THREAD_MAX) {
return UOS_TASK_E_INVAL;
}
if (!thread_dir[thread_id].in_use) {
return UOS_TASK_E_NOENT;
}
/* Update task thread count */
uos_task_id_t task_id = thread_dir[thread_id].task;
if (task_id < UOS_TASK_MAX && task_dir[task_id].in_use) {
task_dir[task_id].num_threads--;
}
/* Mark as unused */
thread_dir[thread_id].in_use = false;
thread_dir[thread_id].state = UOS_THREAD_STATE_ZOMBIE;
return UOS_TASK_E_OK;
}
/**
* @purpose
* Get thread descriptor.
*/
uos_thread_desc_t* uos_thread_get(uos_thread_id_t thread_id) {
/* Validate thread ID */
if (thread_id >= UOS_TASK_MAX * UOS_THREAD_MAX) {
return NULL;
}
if (!thread_dir[thread_id].in_use) {
return NULL;
}
return &thread_dir[thread_id];
}
/**
* @purpose
* Get current thread.
*/
uos_thread_desc_t* uos_thread_current(void) {
return uos_thread_get(current_thread);
}
/**
* @purpose
* Exit a thread.
*/
int uos_thread_exit(uos_thread_id_t thread_id, int status) {
/* Validate thread ID */
if (thread_id >= UOS_TASK_MAX * UOS_THREAD_MAX) {
return UOS_TASK_E_INVAL;
}
if (!thread_dir[thread_id].in_use) {
return UOS_TASK_E_NOENT;
}
/* Set exit status */
thread_dir[thread_id].exit_status = status;
thread_dir[thread_id].state = UOS_THREAD_STATE_ZOMBIE;
/* TODO: Clean up thread resources */
return UOS_TASK_E_OK;
}
/**
* @purpose
* Get task statistics.
*/
void uos_task_get_stats(uos_task_stats_t* stats) {
if (stats != NULL) {
*stats = task_stats;
}
}

330
kernel/src/core/task.h Normal file
View file

@ -0,0 +1,330 @@
#ifndef UOS_TASK_H
#define UOS_TASK_H
/* -------------------------- FILE PROLOGUE -------------------------------- */
/**
* @file
* uos_task.h
*
* @purpose
* Task management interface for UniversalisOS.
* Based on PikeOS task.h and thread.h architecture.
*/
/* ------------------------- FILE INCLUSION -------------------------------- */
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
/* ------------------- MACRO / CONSTANT DEFINITIONS ------------------------ */
/** Maximum number of tasks */
#define UOS_TASK_MAX 64
/** Maximum number of threads per task */
#define UOS_THREAD_MAX 16
/** Maximum task name length */
#define UOS_TASK_NAME_MAX 32
/** Task states */
#define UOS_TASK_STATE_READY 0
#define UOS_TASK_STATE_RUNNING 1
#define UOS_TASK_STATE_BLOCKED 2
#define UOS_TASK_STATE_ZOMBIE 3
#define UOS_TASK_STATE_DEAD 4
/** Thread states */
#define UOS_THREAD_STATE_READY 0
#define UOS_THREAD_STATE_RUNNING 1
#define UOS_THREAD_STATE_BLOCKED 2
#define UOS_THREAD_STATE_WAITING 3
#define UOS_THREAD_STATE_ZOMBIE 4
/** Task flags */
#define UOS_TASK_FLAG_SYSTEM (1<<0)
#define UOS_TASK_FLAG_USER (1<<1)
#define UOS_TASK_FLAG_IDLE (1<<2)
/** Thread flags */
#define UOS_THREAD_FLAG_EXIT_CLEANUP (1<<0)
#define UOS_THREAD_FLAG_EXIT_OPS (1<<1)
#define UOS_THREAD_FLAG_MIGRATE (1<<2)
/** Error codes */
#define UOS_TASK_E_OK 0
#define UOS_TASK_E_PERM -1
#define UOS_TASK_E_NOENT -2
#define UOS_TASK_E_INVAL -3
#define UOS_TASK_E_NOMEM -4
#define UOS_TASK_E_NOSPC -5
#define UOS_TASK_E_EXIST -6
#define UOS_TASK_E_NOTIMPL -7
/* ------------------------ TYPE DECLARATIONS ------------------------------ */
/**
* @brief Task ID type
*/
typedef uint32_t uos_task_id_t;
/**
* @brief Thread ID type
*/
typedef uint32_t uos_thread_id_t;
/**
* @brief Task priority type
*/
typedef uint32_t uos_task_prio_t;
/**
* @brief Task descriptor structure
*/
typedef struct uos_task_desc_str {
uos_task_id_t id; /**< Task ID */
char name[UOS_TASK_NAME_MAX]; /**< Task name */
uint32_t state; /**< Task state */
uint32_t flags; /**< Task flags */
uos_task_prio_t priority; /**< Task priority */
uint32_t num_threads; /**< Number of threads */
uos_task_id_t parent; /**< Parent task ID */
uos_task_id_t child; /**< First child task ID */
uos_task_id_t sibling; /**< Next sibling task ID */
void* address_space; /**< Address space */
uint32_t exit_status; /**< Exit status */
bool in_use; /**< In use flag */
} uos_task_desc_t;
/**
* @brief Thread descriptor structure
*/
typedef struct uos_thread_desc_str {
uos_thread_id_t id; /**< Thread ID */
uos_task_id_t task; /**< Task ID */
uint32_t state; /**< Thread state */
uint32_t flags; /**< Thread flags */
uos_task_prio_t priority; /**< Thread priority */
void (*entry)(void* arg); /**< Thread entry point */
void* arg; /**< Thread argument */
void* stack; /**< Thread stack */
uint32_t stack_size; /**< Thread stack size */
void* context; /**< Thread context */
uint32_t exit_status; /**< Exit status */
bool in_use; /**< In use flag */
} uos_thread_desc_t;
/**
* @brief Task statistics structure
*/
typedef struct uos_task_stats_str {
uint64_t forks; /**< Number of forks */
uint64_t execs; /**< Number of execs */
uint64_t exits; /**< Number of exits */
uint64_t waits; /**< Number of waits */
uint64_t signals; /**< Number of signals */
} uos_task_stats_t;
/* ----------------------- FUNCTION DECLARATIONS --------------------------- */
/**
* @purpose
* Initialize task management.
*/
void uos_task_init(void);
/**
* @purpose
* Create a new task.
*
* @param name
* IN: Task name
* @param priority
* IN: Task priority
* @param flags
* IN: Task flags
*
* @returns
* Task ID on success, error code otherwise
*/
uos_task_id_t uos_task_create(const char* name, uos_task_prio_t priority, uint32_t flags);
/**
* @purpose
* Delete a task.
*
* @param task_id
* IN: Task ID
*
* @returns
* UOS_TASK_E_OK on success, error code otherwise
*/
int uos_task_delete(uos_task_id_t task_id);
/**
* @purpose
* Get task descriptor.
*
* @param task_id
* IN: Task ID
*
* @returns
* Task descriptor on success, NULL otherwise
*/
uos_task_desc_t* uos_task_get(uos_task_id_t task_id);
/**
* @purpose
* Get current task.
*
* @returns
* Current task descriptor
*/
uos_task_desc_t* uos_task_current(void);
/**
* @purpose
* Fork a task.
*
* @returns
* Child task ID in parent, 0 in child, error code otherwise
*/
uos_task_id_t uos_task_fork(void);
/**
* @purpose
* Execute a program in a task.
*
* @param task_id
* IN: Task ID
* @param path
* IN: Program path
* @param argv
* IN: Program arguments
*
* @returns
* UOS_TASK_E_OK on success, error code otherwise
*/
int uos_task_exec(uos_task_id_t task_id, const char* path, char* const argv[]);
/**
* @purpose
* Exit a task.
*
* @param task_id
* IN: Task ID
* @param status
* IN: Exit status
*
* @returns
* UOS_TASK_E_OK on success, error code otherwise
*/
int uos_task_exit(uos_task_id_t task_id, int status);
/**
* @purpose
* Wait for a task to exit.
*
* @param task_id
* IN: Task ID
* @param status
* OUT: Exit status
* @param options
* IN: Wait options
*
* @returns
* Task ID on success, error code otherwise
*/
uos_task_id_t uos_task_wait(uos_task_id_t task_id, int* status, uint32_t options);
/**
* @purpose
* Send a signal to a task.
*
* @param task_id
* IN: Task ID
* @param signal
* IN: Signal number
*
* @returns
* UOS_TASK_E_OK on success, error code otherwise
*/
int uos_task_kill(uos_task_id_t task_id, int signal);
/**
* @purpose
* Create a new thread.
*
* @param task_id
* IN: Task ID
* @param entry
* IN: Thread entry point
* @param arg
* IN: Thread argument
* @param priority
* IN: Thread priority
*
* @returns
* Thread ID on success, error code otherwise
*/
uos_thread_id_t uos_thread_create(uos_task_id_t task_id, void (*entry)(void*), void* arg, uos_task_prio_t priority);
/**
* @purpose
* Delete a thread.
*
* @param thread_id
* IN: Thread ID
*
* @returns
* UOS_TASK_E_OK on success, error code otherwise
*/
int uos_thread_delete(uos_thread_id_t thread_id);
/**
* @purpose
* Get thread descriptor.
*
* @param thread_id
* IN: Thread ID
*
* @returns
* Thread descriptor on success, NULL otherwise
*/
uos_thread_desc_t* uos_thread_get(uos_thread_id_t thread_id);
/**
* @purpose
* Get current thread.
*
* @returns
* Current thread descriptor
*/
uos_thread_desc_t* uos_thread_current(void);
/**
* @purpose
* Exit a thread.
*
* @param thread_id
* IN: Thread ID
* @param status
* IN: Exit status
*
* @returns
* UOS_TASK_E_OK on success, error code otherwise
*/
int uos_thread_exit(uos_thread_id_t thread_id, int status);
/**
* @purpose
* Get task statistics.
*
* @param stats
* OUT: Task statistics
*/
void uos_task_get_stats(uos_task_stats_t* stats);
#endif /* UOS_TASK_H */