From 81425929f5844e07fec4bf849a0f7bb483ce876a Mon Sep 17 00:00:00 2001 From: Leonmmcoset Date: Tue, 14 Apr 2026 18:28:29 +0800 Subject: [PATCH] Stage 29B --- clks/include/clks/exec.h | 1 + clks/include/clks/keyboard.h | 1 + clks/kernel/exec.c | 35 ++++++++++++- clks/kernel/keyboard.c | 96 +++++++++++++++++++++++++++--------- clks/kernel/kmain.c | 2 +- clks/kernel/syscall.c | 3 +- docs/README.md | 1 + docs/stage29.md | 39 +++++++++++++++ ramdisk/shell/init.cmd | 4 +- 9 files changed, 154 insertions(+), 28 deletions(-) create mode 100644 docs/stage29.md diff --git a/clks/include/clks/exec.h b/clks/include/clks/exec.h index b4704f9..71846f7 100644 --- a/clks/include/clks/exec.h +++ b/clks/include/clks/exec.h @@ -9,6 +9,7 @@ clks_bool clks_exec_spawn_path(const char *path, u64 *out_pid); u64 clks_exec_wait_pid(u64 pid, u64 *out_status); clks_bool clks_exec_request_exit(u64 status); u64 clks_exec_current_pid(void); +u32 clks_exec_current_tty(void); u64 clks_exec_sleep_ticks(u64 ticks); u64 clks_exec_yield(void); void clks_exec_tick(u64 tick); diff --git a/clks/include/clks/keyboard.h b/clks/include/clks/keyboard.h index b4f9cbe..2a62508 100644 --- a/clks/include/clks/keyboard.h +++ b/clks/include/clks/keyboard.h @@ -15,6 +15,7 @@ void clks_keyboard_init(void); void clks_keyboard_handle_scancode(u8 scancode); u64 clks_keyboard_hotkey_switch_count(void); clks_bool clks_keyboard_pop_char(char *out_ch); +clks_bool clks_keyboard_pop_char_for_tty(u32 tty_index, char *out_ch); u64 clks_keyboard_buffered_count(void); u64 clks_keyboard_drop_count(void); u64 clks_keyboard_push_count(void); diff --git a/clks/kernel/exec.c b/clks/kernel/exec.c index 0bf8a0c..de6abf8 100644 --- a/clks/kernel/exec.c +++ b/clks/kernel/exec.c @@ -7,6 +7,7 @@ #include #include #include +#include typedef u64 (*clks_exec_entry_fn)(void); @@ -30,6 +31,7 @@ struct clks_exec_proc_record { u64 started_tick; u64 exited_tick; u64 exit_status; + u32 tty_index; char path[CLKS_EXEC_PATH_MAX]; }; @@ -206,6 +208,7 @@ static struct clks_exec_proc_record *clks_exec_prepare_proc_record(i32 slot, proc->started_tick = 0ULL; proc->exited_tick = 0ULL; proc->exit_status = (u64)-1; + proc->tty_index = clks_tty_active(); clks_exec_copy_path(proc->path, sizeof(proc->path), path); return proc; } @@ -583,6 +586,36 @@ u64 clks_exec_current_pid(void) { return clks_exec_pid_stack[(u32)depth_index]; } +u32 clks_exec_current_tty(void) { + i32 depth_index = clks_exec_current_depth_index(); + u32 tty_count = clks_tty_count(); + i32 slot; + const struct clks_exec_proc_record *proc; + + if (tty_count == 0U) { + return 0U; + } + + if (depth_index < 0) { + u32 active = clks_tty_active(); + return (active < tty_count) ? active : 0U; + } + + slot = clks_exec_proc_find_slot_by_pid(clks_exec_pid_stack[(u32)depth_index]); + + if (slot < 0) { + return 0U; + } + + proc = &clks_exec_proc_table[(u32)slot]; + + if (proc->used == CLKS_FALSE || proc->tty_index >= tty_count) { + return 0U; + } + + return proc->tty_index; +} + u64 clks_exec_sleep_ticks(u64 ticks) { u64 start = clks_interrupts_timer_ticks(); @@ -649,4 +682,4 @@ clks_bool clks_exec_current_path_is_user(void) { proc = &clks_exec_proc_table[(u32)slot]; return clks_exec_path_is_user_program(proc->path); -} \ No newline at end of file +} diff --git a/clks/kernel/keyboard.c b/clks/kernel/keyboard.c index babf011..bb4b7b2 100644 --- a/clks/kernel/keyboard.c +++ b/clks/kernel/keyboard.c @@ -23,6 +23,7 @@ #define CLKS_SC_EXT_DELETE 0x53U #define CLKS_KBD_INPUT_CAP 256U +#define CLKS_KBD_TTY_MAX 8U #define CLKS_KBD_DROP_LOG_EVERY 64ULL static const char clks_kbd_map[128] = { @@ -47,10 +48,10 @@ static const char clks_kbd_shift_map[128] = { [51] = '<', [52] = '>', [53] = '?', [57] = ' ' }; -static char clks_kbd_input_queue[CLKS_KBD_INPUT_CAP]; -static u16 clks_kbd_input_head = 0U; -static u16 clks_kbd_input_tail = 0U; -static u16 clks_kbd_input_count = 0U; +static char clks_kbd_input_queue[CLKS_KBD_TTY_MAX][CLKS_KBD_INPUT_CAP]; +static u16 clks_kbd_input_head[CLKS_KBD_TTY_MAX]; +static u16 clks_kbd_input_tail[CLKS_KBD_TTY_MAX]; +static u16 clks_kbd_input_count[CLKS_KBD_TTY_MAX]; static clks_bool clks_kbd_alt_down = CLKS_FALSE; static clks_bool clks_kbd_lshift_down = CLKS_FALSE; @@ -62,6 +63,30 @@ static u64 clks_kbd_push_count = 0ULL; static u64 clks_kbd_pop_count = 0ULL; static u64 clks_kbd_drop_count = 0ULL; +static u32 clks_keyboard_effective_tty_count(void) { + u32 tty_count = clks_tty_count(); + + if (tty_count == 0U) { + return 1U; + } + + if (tty_count > CLKS_KBD_TTY_MAX) { + return CLKS_KBD_TTY_MAX; + } + + return tty_count; +} + +static u32 clks_keyboard_clamp_tty_index(u32 tty_index) { + u32 tty_count = clks_keyboard_effective_tty_count(); + + if (tty_index >= tty_count) { + return 0U; + } + + return tty_index; +} + static char clks_keyboard_translate_ext_scancode(u8 code) { switch (code) { case CLKS_SC_EXT_LEFT: @@ -83,21 +108,24 @@ static char clks_keyboard_translate_ext_scancode(u8 code) { } } -static clks_bool clks_keyboard_queue_push(char ch) { - if (clks_kbd_input_count >= CLKS_KBD_INPUT_CAP) { +static clks_bool clks_keyboard_queue_push_for_tty(u32 tty_index, char ch) { + u32 tty = clks_keyboard_clamp_tty_index(tty_index); + + if (clks_kbd_input_count[tty] >= CLKS_KBD_INPUT_CAP) { clks_kbd_drop_count++; if ((clks_kbd_drop_count % CLKS_KBD_DROP_LOG_EVERY) == 1ULL) { clks_log(CLKS_LOG_WARN, "KBD", "INPUT QUEUE OVERFLOW"); + clks_log_hex(CLKS_LOG_WARN, "KBD", "TTY", (u64)tty); clks_log_hex(CLKS_LOG_WARN, "KBD", "DROPPED", clks_kbd_drop_count); } return CLKS_FALSE; } - clks_kbd_input_queue[clks_kbd_input_head] = ch; - clks_kbd_input_head = (u16)((clks_kbd_input_head + 1U) % CLKS_KBD_INPUT_CAP); - clks_kbd_input_count++; + clks_kbd_input_queue[tty][clks_kbd_input_head[tty]] = ch; + clks_kbd_input_head[tty] = (u16)((clks_kbd_input_head[tty] + 1U) % CLKS_KBD_INPUT_CAP); + clks_kbd_input_count[tty]++; clks_kbd_push_count++; return CLKS_TRUE; } @@ -131,9 +159,14 @@ static char clks_keyboard_translate_scancode(u8 code) { } void clks_keyboard_init(void) { - clks_kbd_input_head = 0U; - clks_kbd_input_tail = 0U; - clks_kbd_input_count = 0U; + u32 tty; + + for (tty = 0U; tty < CLKS_KBD_TTY_MAX; tty++) { + clks_kbd_input_head[tty] = 0U; + clks_kbd_input_tail[tty] = 0U; + clks_kbd_input_count[tty] = 0U; + } + clks_kbd_alt_down = CLKS_FALSE; clks_kbd_lshift_down = CLKS_FALSE; clks_kbd_rshift_down = CLKS_FALSE; @@ -184,10 +217,13 @@ void clks_keyboard_handle_scancode(u8 scancode) { if (clks_kbd_e0_prefix == CLKS_TRUE) { char ext = clks_keyboard_translate_ext_scancode(code); + u32 active_tty = clks_tty_active(); + clks_kbd_e0_prefix = CLKS_FALSE; - if (ext != '\0' && clks_keyboard_shell_input_enabled() == CLKS_TRUE) { - if (clks_keyboard_queue_push(ext) == CLKS_TRUE && clks_keyboard_should_pump_shell_now() == CLKS_TRUE) { + if (ext != '\0') { + if (clks_keyboard_queue_push_for_tty(active_tty, ext) == CLKS_TRUE && + clks_keyboard_should_pump_shell_now() == CLKS_TRUE) { clks_shell_pump_input(1U); } } @@ -215,9 +251,11 @@ void clks_keyboard_handle_scancode(u8 scancode) { { char translated = clks_keyboard_translate_scancode(code); + u32 active_tty = clks_tty_active(); - if (translated != '\0' && clks_keyboard_shell_input_enabled() == CLKS_TRUE) { - if (clks_keyboard_queue_push(translated) == CLKS_TRUE && clks_keyboard_should_pump_shell_now() == CLKS_TRUE) { + if (translated != '\0') { + if (clks_keyboard_queue_push_for_tty(active_tty, translated) == CLKS_TRUE && + clks_keyboard_should_pump_shell_now() == CLKS_TRUE) { clks_shell_pump_input(1U); } } @@ -228,20 +266,33 @@ u64 clks_keyboard_hotkey_switch_count(void) { return clks_kbd_hotkey_switches; } -clks_bool clks_keyboard_pop_char(char *out_ch) { - if (out_ch == CLKS_NULL || clks_kbd_input_count == 0U) { +clks_bool clks_keyboard_pop_char_for_tty(u32 tty_index, char *out_ch) { + u32 tty = clks_keyboard_clamp_tty_index(tty_index); + + if (out_ch == CLKS_NULL || clks_kbd_input_count[tty] == 0U) { return CLKS_FALSE; } - *out_ch = clks_kbd_input_queue[clks_kbd_input_tail]; - clks_kbd_input_tail = (u16)((clks_kbd_input_tail + 1U) % CLKS_KBD_INPUT_CAP); - clks_kbd_input_count--; + *out_ch = clks_kbd_input_queue[tty][clks_kbd_input_tail[tty]]; + clks_kbd_input_tail[tty] = (u16)((clks_kbd_input_tail[tty] + 1U) % CLKS_KBD_INPUT_CAP); + clks_kbd_input_count[tty]--; clks_kbd_pop_count++; return CLKS_TRUE; } +clks_bool clks_keyboard_pop_char(char *out_ch) { + return clks_keyboard_pop_char_for_tty(clks_tty_active(), out_ch); +} + u64 clks_keyboard_buffered_count(void) { - return (u64)clks_kbd_input_count; + u64 total = 0ULL; + u32 tty; + + for (tty = 0U; tty < CLKS_KBD_TTY_MAX; tty++) { + total += (u64)clks_kbd_input_count[tty]; + } + + return total; } u64 clks_keyboard_drop_count(void) { @@ -255,4 +306,3 @@ u64 clks_keyboard_push_count(void) { u64 clks_keyboard_pop_count(void) { return clks_kbd_pop_count; } - diff --git a/clks/kernel/kmain.c b/clks/kernel/kmain.c index b5b3d52..a17de87 100644 --- a/clks/kernel/kmain.c +++ b/clks/kernel/kmain.c @@ -100,7 +100,7 @@ void clks_kernel_main(void) { clks_tty_init(); } - clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS Stage28 START"); + clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS Stage29 START"); if (boot_fb == CLKS_NULL) { clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE"); diff --git a/clks/kernel/syscall.c b/clks/kernel/syscall.c index b267a8a..4bb91d0 100644 --- a/clks/kernel/syscall.c +++ b/clks/kernel/syscall.c @@ -128,8 +128,9 @@ static u64 clks_syscall_tty_write_char(u64 arg0) { static u64 clks_syscall_kbd_get_char(void) { char ch; + u32 tty_index = clks_exec_current_tty(); - if (clks_keyboard_pop_char(&ch) == CLKS_FALSE) { + if (clks_keyboard_pop_char_for_tty(tty_index, &ch) == CLKS_FALSE) { return (u64)-1; } diff --git a/docs/README.md b/docs/README.md index 9ae51c1..d5bf84e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -25,6 +25,7 @@ - `stage26.md` - `stage27.md` - `stage28.md` +- `stage29.md` - `syscall.md` (syscall ABI reference) diff --git a/docs/stage29.md b/docs/stage29.md new file mode 100644 index 0000000..0eaf2c8 --- /dev/null +++ b/docs/stage29.md @@ -0,0 +1,39 @@ +# Stage 29 - Async Exec Dispatch + TTY-Bound Input Ownership + +## Goal +- Make process launch lifecycle explicit (`pending -> running -> exited`) and tick-driven. +- Bind user input to the process TTY context to avoid cross-TTY input stealing. +- Keep kernel shell input compatibility while preparing cleaner multi-TTY user-shell behavior. + +## Implementation +- Exec lifecycle (Stage 29A): + - Added process states: `CLKS_EXEC_PROC_PENDING`, `CLKS_EXEC_PROC_RUNNING`, `CLKS_EXEC_PROC_EXITED`. + - `clks_exec_spawn_path()` now queues process records as pending. + - Added `clks_exec_tick()` to dispatch pending processes from scheduler tick context. + - `waitpid` now understands pending/running/exited transitions. +- TTY ownership (Stage 29B): + - Added `tty_index` to exec process record and capture active TTY when process is created. + - Added `clks_exec_current_tty()` to resolve the current execution TTY safely. + - Refactored keyboard input buffer to per-TTY ring queues. + - Added `clks_keyboard_pop_char_for_tty()` API. + - Updated syscall keyboard read path to pop from `clks_exec_current_tty()` queue. + +## Acceptance Criteria +- `spawn` no longer blocks immediate caller flow and enters pending lifecycle. +- Tick loop dispatches pending processes without recursive launch storm. +- Keyboard input on one TTY is not consumed by process context on another TTY. +- Kernel shell input remains functional through existing `clks_keyboard_pop_char()` API. + +## Build Targets +- `make userapps` +- `make ramdisk` +- `make iso` +- `make run` + +## QEMU Command +- `make run` + +## Debug Notes +- If user shell appears to miss input, log `clks_exec_current_tty()` and active TTY during syscall `KBD_GET_CHAR`. +- If input is delayed, inspect queue depth via `kbdstat` and verify per-TTY counters move. +- If `waitpid` stalls forever, check whether `clks_exec_tick()` is called in scheduler/user service tick. diff --git a/ramdisk/shell/init.cmd b/ramdisk/shell/init.cmd index 20f505f..f678fbf 100644 --- a/ramdisk/shell/init.cmd +++ b/ramdisk/shell/init.cmd @@ -1,5 +1,5 @@ # Stage13 shell init script for CLeonOS # Lines starting with # are comments. -help -stats \ No newline at end of file +# help +# stats