Files
RTOS/kernel/src/task.c
T
root ca13734bf0 Add full automotive RTOS project
Add kernel (Cortex-M0/M3/M4, Tricore, S32K, RISC-V ports), drivers,
middleware (CAN stack, diagnostics, safety), applications, board
support, build/test tooling, and documentation.
2026-08-23 03:35:29 -04:00

313 lines
8.0 KiB
C

/**
* @file task.c
* @brief Task management implementation
*/
#include "kernel.h"
#include "task.h"
#include "scheduler.h"
#include "isr.h"
/* Task List Head */
static TaskHandle_t task_list_head = NULL;
static TaskHandle_t task_list_tail = NULL;
static uint32_t next_task_id = 0;
static TaskHandle_t current_task = NULL;
/* Stack Overflow Pattern */
#define STACK_FILL_PATTERN 0xA5A5A5A5
#define STACK_CHECK_PATTERN 0xDEADBEEF
/* Initialize Task Management */
void task_init(void) {
task_list_head = NULL;
task_list_tail = NULL;
next_task_id = 1;
current_task = NULL;
}
/* Create Task */
TaskHandle_t task_create(const TaskConfig_t* config) {
if (config == NULL || config->function == NULL) {
return NULL;
}
if (config->priority >= MAX_PRIORITY_LEVELS) {
return NULL;
}
/* Allocate task control block */
TaskHandle_t task = (TaskHandle_t)malloc(sizeof(struct TaskControlBlock));
if (task == NULL) {
return NULL;
}
/* Initialize task control block */
memset(task, 0, sizeof(struct TaskControlBlock));
/* Set task name */
if (config->name != NULL) {
strncpy(task->name, config->name, MAX_TASK_NAME_LENGTH - 1);
} else {
snprintf(task->name, MAX_TASK_NAME_LENGTH, "task_%u", next_task_id);
}
/* Initialize task fields */
task->task_id = next_task_id++;
task->function = config->function;
task->parameters = config->parameters;
task->priority = config->priority;
task->state = TASK_SUSPENDED;
task->period_ticks = config->period_ticks;
task->last_wake_time = 0;
/* Allocate stack */
task->stack_size = config->stack_size;
task->stack_base = (uint32_t*)malloc(task->stack_size);
if (task->stack_base == NULL) {
free(task);
return NULL;
}
/* Initialize stack with pattern for overflow detection */
memset(task->stack_base, STACK_FILL_PATTERN, task->stack_size);
/* Set initial stack pointer (grows downward on ARM) */
task->stack_pointer = task->stack_base + (task->stack_size / sizeof(uint32_t)) - 16;
/* Initialize task context for first run */
task->context[0] = (uint32_t)task->function; /* PC */
task->context[1] = 0x01000000; /* xPSR */
task->context[2] = (uint32_t)task->parameters; /* R0 */
task->context[3] = 0; /* R1 */
task->context[4] = 0; /* R2 */
task->context[5] = 0; /* R3 */
task->context[6] = 0; /* R12 */
task->context[7] = 0; /* LR */
task->context[8] = (uint32_t)task->stack_pointer; /* PSP */
/* Add to task list */
critical_section_enter();
if (task_list_head == NULL) {
task_list_head = task;
task_list_tail = task;
} else {
task_list_tail->next = task;
task->prev = task_list_tail;
task_list_tail = task;
}
/* Make task ready */
task->state = TASK_READY;
scheduler_add_task(task);
critical_section_exit();
return task;
}
/* Delete Task */
KernelStatus_t task_delete(TaskHandle_t task) {
if (task == NULL || task == current_task) {
return KERNEL_INVALID_PARAMETER;
}
critical_section_enter();
/* Remove from scheduler */
scheduler_remove_task(task);
/* Remove from task list */
if (task->prev != NULL) {
task->prev->next = task->next;
} else {
task_list_head = task->next;
}
if (task->next != NULL) {
task->next->prev = task->prev;
} else {
task_list_tail = task->prev;
}
/* Free stack and task control block */
free(task->stack_base);
free(task);
critical_section_exit();
return KERNEL_OK;
}
/* Suspend Task */
KernelStatus_t task_suspend(TaskHandle_t task) {
if (task == NULL) {
return KERNEL_INVALID_PARAMETER;
}
critical_section_enter();
if (task->state != TASK_SUSPENDED) {
task->state = TASK_SUSPENDED;
scheduler_update_task_state(task, TASK_SUSPENDED);
}
critical_section_exit();
if (task == current_task) {
scheduler_yield();
}
return KERNEL_OK;
}
/* Resume Task */
KernelStatus_t task_resume(TaskHandle_t task) {
if (task == NULL) {
return KERNEL_INVALID_PARAMETER;
}
critical_section_enter();
if (task->state == TASK_SUSPENDED) {
task->state = TASK_READY;
scheduler_update_task_state(task, TASK_READY);
}
critical_section_exit();
return KERNEL_OK;
}
/* Set Task Priority */
KernelStatus_t task_set_priority(TaskHandle_t task, TaskPriority_t new_priority) {
if (task == NULL || new_priority >= MAX_PRIORITY_LEVELS) {
return KERNEL_INVALID_PARAMETER;
}
critical_section_enter();
task->priority = new_priority;
critical_section_exit();
/* Reschedule if needed */
scheduler_yield();
return KERNEL_OK;
}
/* Get Task Priority */
TaskPriority_t task_get_priority(TaskHandle_t task) {
if (task == NULL) {
return MAX_PRIORITY_LEVELS;
}
return task->priority;
}
/* Get Task State */
TaskState_t task_get_state(TaskHandle_t task) {
if (task == NULL) {
return TASK_TERMINATED;
}
return task->state;
}
/* Get Task Statistics */
KernelStatus_t task_get_statistics(TaskHandle_t task, TaskStatistics_t* stats) {
if (task == NULL || stats == NULL) {
return KERNEL_INVALID_PARAMETER;
}
critical_section_enter();
memcpy(stats, &task->statistics, sizeof(TaskStatistics_t));
/* Update stack high water mark */
task_check_stack_overflow();
stats->stack_high_water_mark = task->stack_high_water_mark;
critical_section_exit();
return KERNEL_OK;
}
/* Switch Context to Next Task */
void task_switch_context(TaskHandle_t next_task) {
if (next_task == NULL || next_task == current_task) {
return;
}
TaskHandle_t previous_task = current_task;
current_task = next_task;
/* Update task states */
if (previous_task != NULL && previous_task->state == TASK_RUNNING) {
previous_task->state = TASK_READY;
}
next_task->state = TASK_RUNNING;
/* Perform architecture-specific context switch */
// This is implemented in port_asm.s
port_context_switch(&previous_task->context, &next_task->context);
}
/* Get Idle Task */
TaskHandle_t task_get_idle_task(void) {
/* Return the idle task (stored in kernel state) */
extern TaskHandle_t kernel_get_idle_task(void);
return kernel_get_idle_task();
}
/* Update Task Statistics */
void task_update_statistics(void) {
if (current_task == NULL) {
return;
}
TickType_t current_time = kernel_get_tick_count();
current_task->statistics.execution_count++;
current_task->statistics.last_execution_time = current_time;
/* Check for deadline miss */
if (current_task->deadline_ticks > 0 &&
current_time > current_task->deadline_ticks) {
current_task->statistics.deadline_misses++;
}
}
/* Check Stack Overflow */
void task_check_stack_overflow(void) {
if (current_task == NULL || current_task->stack_base == NULL) {
return;
}
/* Check stack guard pattern */
uint32_t* stack_bottom = current_task->stack_base;
uint32_t guard_size = 16; /* Number of guard words */
for (uint32_t i = 0; i < guard_size; i++) {
if (stack_bottom[i] != STACK_FILL_PATTERN) {
/* Stack overflow detected! */
fault_handler_stack_overflow(current_task);
break;
}
}
/* Calculate stack usage */
uint32_t* stack_ptr = current_task->stack_base;
uint32_t* stack_top = current_task->stack_base +
(current_task->stack_size / sizeof(uint32_t));
uint32_t used_words = 0;
while (stack_ptr < stack_top && *stack_ptr != STACK_FILL_PATTERN) {
used_words++;
stack_ptr++;
}
current_task->stack_high_water_mark = used_words * sizeof(uint32_t);
}
/* Check if Task is Ready */
bool task_is_ready(TaskHandle_t task) {
return (task != NULL && task->state == TASK_READY);
}