From 9c19e1a69fd0dedbfece798ab02994eb6cbe5e5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Coutada?= Date: Sun, 12 Jul 2026 21:06:40 +0100 Subject: [PATCH] feat(kernel/sched): scheduler + task subsystem --- kernel/src/core/sched.cpp | 452 +++++++++++++++++++++++++++++++++++ kernel/src/core/sched.h | 369 ++++++++++++++++++++++++++++ kernel/src/core/task.cpp | 490 ++++++++++++++++++++++++++++++++++++++ kernel/src/core/task.h | 330 +++++++++++++++++++++++++ 4 files changed, 1641 insertions(+) create mode 100644 kernel/src/core/sched.cpp create mode 100644 kernel/src/core/sched.h create mode 100644 kernel/src/core/task.cpp create mode 100644 kernel/src/core/task.h diff --git a/kernel/src/core/sched.cpp b/kernel/src/core/sched.cpp new file mode 100644 index 000000000..cb983b6e8 --- /dev/null +++ b/kernel/src/core/sched.cpp @@ -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(); + } +} diff --git a/kernel/src/core/sched.h b/kernel/src/core/sched.h new file mode 100644 index 000000000..db0658073 --- /dev/null +++ b/kernel/src/core/sched.h @@ -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 +#include +#include + +/* ------------------- 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 */ diff --git a/kernel/src/core/task.cpp b/kernel/src/core/task.cpp new file mode 100644 index 000000000..1d4d79716 --- /dev/null +++ b/kernel/src/core/task.cpp @@ -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; + } +} diff --git a/kernel/src/core/task.h b/kernel/src/core/task.h new file mode 100644 index 000000000..f2ee2c0ae --- /dev/null +++ b/kernel/src/core/task.h @@ -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 +#include +#include + +/* ------------------- 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 */