feat(kernel/sched): scheduler + task subsystem
This commit is contained in:
parent
e8e2f06b0a
commit
9c19e1a69f
4 changed files with 1641 additions and 0 deletions
452
kernel/src/core/sched.cpp
Normal file
452
kernel/src/core/sched.cpp
Normal 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
369
kernel/src/core/sched.h
Normal 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
490
kernel/src/core/task.cpp
Normal 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
330
kernel/src/core/task.h
Normal 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 */
|
||||
Loading…
Reference in a new issue