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.
This commit is contained in:
@@ -0,0 +1,312 @@
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
Reference in New Issue
Block a user