Enhance command execution with improved concurrency and documentation updates. Refined the CommandTaskContext structure for better task management and clarified usage instructions for 'memtest' and 'tasktest' commands in README.md.

This commit is contained in:
2026-02-27 20:14:24 +00:00
parent 7ecf26cbd9
commit 9b1a70e3a5
4 changed files with 199 additions and 61 deletions

220
kernel.c
View File

@@ -1,12 +1,13 @@
/*
* kernel.c Kernel entry point and interactive shell loop.
* kernel.c Kernel entry point and Starling Terminal task.
*
* kmain() is called by the loader (main.c) after the ELF kernel has been
* mapped into memory. It initialises subsystems (IDT, memory, tasks),
* prints a welcome banner, and enters an interactive read-eval-print
* prints a welcome banner, and then spawns the Starling Terminal as a
* dedicated task. The terminal task runs the interactive read-eval-print
* loop that dispatches typed commands via commands.c.
*
* While waiting for keyboard input, the shell yields to the cooperative
* While the terminal waits for keyboard input it yields to the cooperative
* scheduler so that background tasks can make progress.
*/
@@ -16,6 +17,7 @@
#include "idt.h"
#include "memory.h"
#include "task.h"
#include "string_utils.h"
/* Null-safe print helper used throughout the kernel. */
#define SAFE_PRINT(Boot, ...) \
@@ -32,15 +34,143 @@
#define COLOR_BLACK 0x0
#define COLOR_LIGHTGREEN 0xA
/* Simple context passed to each Starling Terminal instance. */
typedef struct {
BootInfo *Boot;
UINTN depth; /* 0 = top-level, 1+ = nested shells */
} StarlingContext;
/* ================================================================
* Starling Terminal task interactive command loop
* ================================================================ */
static void starling_terminal_task(void *arg)
{
StarlingContext *ctx = (StarlingContext *)arg;
BootInfo *Boot = NULL;
KeyEvent Key;
KSTATUS Status;
UINTN read_errors = 0;
CHAR16 line[128];
UINTN len = 0;
UINTN depth = 0;
if (ctx == NULL || ctx->Boot == NULL) {
return;
}
Boot = ctx->Boot;
depth = ctx->depth;
SAFE_PRINT(Boot, L"\n\r[Starling Terminal depth %d] ready.\n\r\n\r", depth);
SAFE_PRINT(Boot, L"starling> ");
while (TRUE) {
/* Try non-blocking read first; yield to other tasks while idle */
if (Boot->try_read_key != NULL) {
Status = Boot->try_read_key(&Key);
if (Status != 0) {
task_yield();
continue;
}
} else if (Boot->read_key != NULL) {
Status = Boot->read_key(&Key);
} else {
SAFE_PRINT(Boot, L"Console input unavailable.\n\r");
break;
}
if (Status != 0) {
read_errors++;
if (read_errors == 1 || (read_errors % 64) == 0) {
SAFE_PRINT(Boot, L"read_key failed (status=%ld)\n\r",
(UINT64)Status);
}
continue;
}
read_errors = 0;
if (Key.unicode_char == L'\r' || Key.unicode_char == L'\n') {
/* Enter pressed: execute the buffered command */
line[len] = L'\0';
SAFE_PRINT(Boot, L"\n\r");
trim_spaces_inplace(line);
/* Built-in terminal controls: exit / spawn nested Starling. */
if (ascii_streq_ci(line, L"exit")) {
if (depth == 0) {
SAFE_PRINT(Boot, L"Starling: cannot exit top-level terminal.\n\r");
SAFE_PRINT(Boot, L"starling> ");
} else {
SAFE_PRINT(Boot, L"Exiting Starling Terminal depth %d...\n\r", depth);
break;
}
} else if (ascii_streq_ci(line, L"starling")) {
StarlingContext *child_ctx;
Task *child_task;
child_ctx = (StarlingContext *)kmalloc(sizeof(StarlingContext));
if (child_ctx == NULL) {
SAFE_PRINT(Boot, L"Starling: failed to allocate nested terminal context.\n\r");
SAFE_PRINT(Boot, L"starling> ");
} else {
child_ctx->Boot = Boot;
child_ctx->depth = depth + 1;
child_task = task_create(L"starling-term", starling_terminal_task, child_ctx);
if (child_task == NULL) {
SAFE_PRINT(Boot, L"Starling: failed to spawn nested terminal.\n\r");
kfree(child_ctx);
SAFE_PRINT(Boot, L"starling> ");
} else {
SAFE_PRINT(Boot, L"[starling] spawned nested terminal (PID %d, depth %d)\n\r",
child_task->pid, child_ctx->depth);
/* Block this shell until the child terminal exits. */
task_wait(child_task);
SAFE_PRINT(Boot, L"[starling] returned from nested terminal (depth %d)\n\r", depth);
SAFE_PRINT(Boot, L"starling> ");
}
}
} else {
Task *cmd_task = execute_command(Boot, line);
/* If a command task was spawned, wait for it to finish. */
if (cmd_task != NULL) {
task_wait(cmd_task);
}
/* Reset for next command */
len = 0;
SAFE_PRINT(Boot, L"starling> ");
}
} else if (Key.scan_code == 0x08 || Key.unicode_char == L'\b' || Key.unicode_char == 0x7F) {
/* Backspace */
if (len > 0) {
len--;
SAFE_PRINT(Boot, L"\b \b");
}
} else if (Key.unicode_char >= 32 && Key.unicode_char < 127) {
/* Printable ASCII */
if (len < (sizeof(line) / sizeof(line[0]) - 1)) {
line[len++] = Key.unicode_char;
SAFE_PRINT(Boot, L"%c", Key.unicode_char);
}
}
}
/* Free our context on exit (allocated by the spawner). */
kfree(ctx);
}
/* ================================================================
* Kernel entry point
* ================================================================ */
void kmain(BootInfo *Boot)
{
KeyEvent Key;
KSTATUS Status;
UINTN read_errors = 0;
Task *terminal_task = NULL;
StarlingContext *ctx = NULL;
if (Boot == NULL) {
return;
@@ -84,61 +214,41 @@ void kmain(BootInfo *Boot)
SAFE_PRINT(Boot, L"Available Services:\n\r");
SAFE_PRINT(Boot, L" - Console Input/Output: %s\n\r",
(Boot->read_key != NULL && Boot->print != NULL) ? L"Active" : L"Unavailable");
SAFE_PRINT(Boot, L" - Terminal: Starling Terminal\n\r");
SAFE_PRINT(Boot, L"\n\r");
SAFE_PRINT(Boot, L"Type 'help' for a list of commands.\n\r\n\r");
/* ---- Interactive shell loop ---- */
CHAR16 line[128];
UINTN len = 0;
/* ---- Spawn Starling Terminal as its own task ---- */
ctx = (StarlingContext *)kmalloc(sizeof(StarlingContext));
if (ctx == NULL) {
SAFE_PRINT(Boot, L"Failed to allocate Starling Terminal context; starting inline.\n\r");
StarlingContext inline_ctx;
inline_ctx.Boot = Boot;
inline_ctx.depth = 0;
starling_terminal_task(&inline_ctx);
return;
}
SAFE_PRINT(Boot, L"-> ");
ctx->Boot = Boot;
ctx->depth = 0;
terminal_task = task_create(L"starling-term", starling_terminal_task, ctx);
if (terminal_task == NULL) {
SAFE_PRINT(Boot, L"Failed to start Starling Terminal task; falling back to kernel loop.\n\r");
/*
* Fall back to running the terminal loop directly in the core
* thread so the system remains usable even if task creation
* fails for some reason.
*/
starling_terminal_task(Boot);
return;
}
SAFE_PRINT(Boot, L"[core] Started Starling Terminal (PID %d).\n\r", terminal_task->pid);
/* Core thread becomes an idle loop, yielding to the terminal and others. */
while (TRUE) {
/* Try non-blocking read first; yield to other tasks while idle */
if (Boot->try_read_key != NULL) {
Status = Boot->try_read_key(&Key);
if (Status != 0) {
task_yield();
continue;
}
} else if (Boot->read_key != NULL) {
Status = Boot->read_key(&Key);
} else {
SAFE_PRINT(Boot, L"Console input unavailable.\n\r");
break;
}
if (Status != 0) {
read_errors++;
if (read_errors == 1 || (read_errors % 64) == 0) {
SAFE_PRINT(Boot, L"read_key failed (status=%ld)\n\r",
(UINT64)Status);
}
continue;
}
read_errors = 0;
if (Key.unicode_char == L'\r' || Key.unicode_char == L'\n') {
/* Enter pressed: execute the buffered command */
line[len] = L'\0';
SAFE_PRINT(Boot, L"\n\r");
execute_command(Boot, line);
/* Reset for next command */
len = 0;
SAFE_PRINT(Boot, L"-> ");
} else if (Key.scan_code == 0x08 || Key.unicode_char == L'\b' || Key.unicode_char == 0x7F) {
/* Backspace */
if (len > 0) {
len--;
SAFE_PRINT(Boot, L"\b \b");
}
} else if (Key.unicode_char >= 32 && Key.unicode_char < 127) {
/* Printable ASCII */
if (len < (sizeof(line) / sizeof(line[0]) - 1)) {
line[len++] = Key.unicode_char;
SAFE_PRINT(Boot, L"%c", Key.unicode_char);
}
}
task_yield();
}
}