Task scheduler

This commit is contained in:
2026-02-26 21:08:06 +00:00
parent 6658e4314b
commit d449150169
9 changed files with 836 additions and 62 deletions

View File

@@ -2,6 +2,7 @@
#include "commands.h"
#include "string_utils.h"
#include "memory.h"
#include "task.h"
#define SAFE_PRINT(Boot, ...) \
do { \
@@ -17,6 +18,10 @@ static void cmd_man(BootInfo *Boot, CHAR16 *Args);
static void cmd_clear(BootInfo *Boot, CHAR16 *Args);
static void cmd_about(BootInfo *Boot, CHAR16 *Args);
static void cmd_mem(BootInfo *Boot, CHAR16 *Args);
static void cmd_ps(BootInfo *Boot, CHAR16 *Args);
static void cmd_spawn(BootInfo *Boot, CHAR16 *Args);
static void cmd_memtest(BootInfo *Boot, CHAR16 *Args);
static void cmd_tasktest(BootInfo *Boot, CHAR16 *Args);
// Command registry
static Command commands[] = {
@@ -56,6 +61,30 @@ static Command commands[] = {
L"Usage: mem\n\r Shows physical memory, heap, and paging information.",
cmd_mem
},
{
L"ps",
L"List running tasks",
L"Usage: ps\n\r Displays all active tasks with PID, state, and name.",
cmd_ps
},
{
L"spawn",
L"Spawn a demo background task",
L"Usage: spawn [name]\n\r Creates a cooperative demo task.\n\r Optional argument sets the task name.",
cmd_spawn
},
{
L"memtest",
L"Test memory allocation and deallocation",
L"Usage: memtest\n\r Allocates and frees heap and page memory to verify\n\r the memory manager is working correctly.",
cmd_memtest
},
{
L"tasktest",
L"Test task scheduler with multiple tasks",
L"Usage: tasktest\n\r Spawns several concurrent tasks that run cooperatively\n\r and report their progress, demonstrating context switching.",
cmd_tasktest
},
{NULL, NULL, NULL, NULL} // Sentinel
};
@@ -153,6 +182,7 @@ static void cmd_about(BootInfo *Boot, CHAR16 *Args)
SAFE_PRINT(Boot, L" - Console I/O\n\r");
SAFE_PRINT(Boot, L" - ELF64 Kernel Loader\n\r");
SAFE_PRINT(Boot, L" - Memory Management (PMM + Heap)\n\r");
SAFE_PRINT(Boot, L" - Cooperative Multitasking\n\r");
SAFE_PRINT(Boot, L" - Interactive Command Interface\n\r");
SAFE_PRINT(Boot, L"\n\r");
SAFE_PRINT(Boot, L"Type 'help' for available commands.\n\r");
@@ -165,6 +195,189 @@ static void cmd_mem(BootInfo *Boot, CHAR16 *Args)
memory_print_stats(Boot);
}
/* ----------------------------------------------------------------
* Demo task runs cooperatively, prints progress, then exits
* ---------------------------------------------------------------- */
static void demo_task_fn(void *arg)
{
BootInfo *Boot = (BootInfo *)arg;
Task *self = task_current();
UINTN i;
SAFE_PRINT(Boot, L"[%s:%d] started\n\r", self->name, self->pid);
for (i = 0; i < 5; i++) {
SAFE_PRINT(Boot, L"[%s:%d] tick %d/5\n\r",
self->name, self->pid, i + 1);
task_yield();
}
SAFE_PRINT(Boot, L"[%s:%d] finished\n\r", self->name, self->pid);
}
static void cmd_ps(BootInfo *Boot, CHAR16 *Args)
{
(void)Args;
task_print_list(Boot);
}
static void cmd_spawn(BootInfo *Boot, CHAR16 *Args)
{
Task *t;
const CHAR16 *name;
if (Args != NULL && Args[0] != L'\0') {
trim_spaces_inplace(Args);
name = Args;
} else {
name = L"demo";
}
t = task_create(name, demo_task_fn, Boot);
if (t == NULL) {
SAFE_PRINT(Boot, L"Failed to create task (out of slots or memory).\n\r");
return;
}
SAFE_PRINT(Boot, L"Created task '%s' (PID %d)\n\r", t->name, t->pid);
}
/* ----------------------------------------------------------------
* memtest exercise the heap and PMM allocators
* ---------------------------------------------------------------- */
static void cmd_memtest(BootInfo *Boot, CHAR16 *Args)
{
void *ptrs[8];
UINTN sizes[] = { 16, 64, 128, 256, 512, 1024, 2048, 4096 };
UINTN i;
UINT64 page;
UINTN h_total, h_used, h_free, h_blocks;
(void)Args;
SAFE_PRINT(Boot, L"\n\r");
SAFE_PRINT(Boot, L"Memory Test\n\r");
SAFE_PRINT(Boot, L"================================================\n\r");
SAFE_PRINT(Boot, L"\n\r");
/* --- Heap allocation test --- */
SAFE_PRINT(Boot, L"[1] Heap allocation test\n\r");
for (i = 0; i < 8; i++) {
ptrs[i] = kmalloc(sizes[i]);
if (ptrs[i] != NULL) {
SAFE_PRINT(Boot, L" kmalloc(%4d) = 0x%lx OK\n\r",
sizes[i], (UINT64)(UINTN)ptrs[i]);
} else {
SAFE_PRINT(Boot, L" kmalloc(%4d) = NULL FAIL\n\r", sizes[i]);
}
}
heap_get_stats(&h_total, &h_used, &h_free, &h_blocks);
SAFE_PRINT(Boot, L" Heap after alloc: used=%d free=%d blocks=%d\n\r",
h_used, h_free, h_blocks);
/* --- Heap free test --- */
SAFE_PRINT(Boot, L"\n\r[2] Heap free test\n\r");
for (i = 0; i < 8; i++) {
if (ptrs[i] != NULL) {
kfree(ptrs[i]);
SAFE_PRINT(Boot, L" kfree(0x%lx) OK\n\r",
(UINT64)(UINTN)ptrs[i]);
}
}
heap_get_stats(&h_total, &h_used, &h_free, &h_blocks);
SAFE_PRINT(Boot, L" Heap after free: used=%d free=%d blocks=%d\n\r",
h_used, h_free, h_blocks);
/* --- PMM page allocation test --- */
SAFE_PRINT(Boot, L"\n\r[3] PMM page allocation test\n\r");
SAFE_PRINT(Boot, L" Free pages before: %d\n\r", pmm_get_free_pages());
page = pmm_alloc_page();
if (page != 0) {
SAFE_PRINT(Boot, L" pmm_alloc_page() = 0x%lx OK\n\r", page);
SAFE_PRINT(Boot, L" Free pages after alloc: %d\n\r", pmm_get_free_pages());
pmm_free_page(page);
SAFE_PRINT(Boot, L" pmm_free_page() OK\n\r");
SAFE_PRINT(Boot, L" Free pages after free: %d\n\r", pmm_get_free_pages());
} else {
SAFE_PRINT(Boot, L" pmm_alloc_page() = 0 FAIL (out of pages)\n\r");
}
/* --- Multi-page allocation test --- */
SAFE_PRINT(Boot, L"\n\r[4] PMM multi-page allocation test (4 pages)\n\r");
page = pmm_alloc_pages(4);
if (page != 0) {
SAFE_PRINT(Boot, L" pmm_alloc_pages(4) = 0x%lx OK\n\r", page);
SAFE_PRINT(Boot, L" Free pages after alloc: %d\n\r", pmm_get_free_pages());
pmm_free_pages(page, 4);
SAFE_PRINT(Boot, L" pmm_free_pages() OK\n\r");
SAFE_PRINT(Boot, L" Free pages after free: %d\n\r", pmm_get_free_pages());
} else {
SAFE_PRINT(Boot, L" pmm_alloc_pages(4) = 0 FAIL\n\r");
}
SAFE_PRINT(Boot, L"\n\rAll memory tests completed.\n\r\n\r");
}
/* ----------------------------------------------------------------
* tasktest spawn multiple concurrent tasks to exercise scheduler
* ---------------------------------------------------------------- */
static void worker_task_fn(void *arg)
{
BootInfo *Boot = (BootInfo *)arg;
Task *self = task_current();
UINTN i;
for (i = 0; i < 3; i++) {
SAFE_PRINT(Boot, L" [%s:%d] working... step %d/3\n\r",
self->name, self->pid, i + 1);
task_yield();
}
SAFE_PRINT(Boot, L" [%s:%d] done\n\r", self->name, self->pid);
}
static void cmd_tasktest(BootInfo *Boot, CHAR16 *Args)
{
Task *t1, *t2, *t3;
UINTN i;
(void)Args;
SAFE_PRINT(Boot, L"\n\r");
SAFE_PRINT(Boot, L"Task Scheduler Test\n\r");
SAFE_PRINT(Boot, L"================================================\n\r");
SAFE_PRINT(Boot, L"\n\r");
SAFE_PRINT(Boot, L"Spawning 3 worker tasks...\n\r\n\r");
t1 = task_create(L"worker-A", worker_task_fn, Boot);
t2 = task_create(L"worker-B", worker_task_fn, Boot);
t3 = task_create(L"worker-C", worker_task_fn, Boot);
if (t1 == NULL || t2 == NULL || t3 == NULL) {
SAFE_PRINT(Boot, L"Failed to create one or more tasks.\n\r");
return;
}
SAFE_PRINT(Boot, L"Created: %s (PID %d), %s (PID %d), %s (PID %d)\n\r",
t1->name, t1->pid, t2->name, t2->pid, t3->name, t3->pid);
SAFE_PRINT(Boot, L"\n\rYielding to let workers run:\n\r\n\r");
/* Yield enough times for all workers to complete (3 tasks x 3 steps) */
for (i = 0; i < 12; i++) {
task_yield();
}
SAFE_PRINT(Boot, L"\n\rTask list after test:\n\r");
task_print_list(Boot);
SAFE_PRINT(Boot, L"Task scheduler test completed.\n\r\n\r");
}
void show_help(BootInfo *Boot)
{
UINTN i = 0;