]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
tty: make stdin (fd 0) blocking via keyboard waiter
authorTulio A M Mendes <[email protected]>
Sat, 7 Feb 2026 19:22:30 +0000 (16:22 -0300)
committerTulio A M Mendes <[email protected]>
Sat, 7 Feb 2026 19:22:30 +0000 (16:22 -0300)
include/keyboard.h
src/drivers/keyboard.c
src/kernel/syscall.c

index 9542aeb641a3debe9a42d87dc5c433a6722edfcc..31cc0418b6eeebc54e82df31758fac25d1a9ea6b 100644 (file)
@@ -11,4 +11,6 @@ void keyboard_set_callback(keyboard_callback_t callback);
 
 int keyboard_read_nonblock(char* out, uint32_t max_len);
 
+int keyboard_read_blocking(char* out, uint32_t max_len);
+
 #endif
index 4011f91ca36842e1cdf0327f4e0c9cab219c321b..f986ff2f0e4091baf05d541ff100ee22290e8cdc 100644 (file)
@@ -4,6 +4,9 @@
 
 #include "hal/keyboard.h"
 
+#include "process.h"
+#include "spinlock.h"
+
 static keyboard_callback_t active_callback = NULL;
 
 #define KBD_BUF_SIZE 256
@@ -11,6 +14,9 @@ static volatile uint32_t kbd_head = 0;
 static volatile uint32_t kbd_tail = 0;
 static char kbd_buf[KBD_BUF_SIZE];
 
+static spinlock_t kbd_lock = {0};
+static struct process* kbd_waiter = NULL;
+
 static void kbd_push_char(char c) {
     uint32_t next = (kbd_head + 1U) % KBD_BUF_SIZE;
     if (next == kbd_tail) {
@@ -21,7 +27,19 @@ static void kbd_push_char(char c) {
 }
 
 static void hal_kbd_bridge(char c) {
+    // IRQ context: push to buffer and wake a single blocked waiter (if any)
+    uintptr_t flags = spin_lock_irqsave(&kbd_lock);
     kbd_push_char(c);
+
+    if (kbd_waiter) {
+        if (kbd_waiter->state == PROCESS_BLOCKED) {
+            kbd_waiter->state = PROCESS_READY;
+        }
+        kbd_waiter = NULL;
+    }
+
+    spin_unlock_irqrestore(&kbd_lock, flags);
+
     if (active_callback) {
         active_callback(c);
     }
@@ -29,8 +47,10 @@ static void hal_kbd_bridge(char c) {
 
 void keyboard_init(void) {
     uart_print("[KBD] Initializing Keyboard Driver...\n");
+    spinlock_init(&kbd_lock);
     kbd_head = 0;
     kbd_tail = 0;
+    kbd_waiter = NULL;
     hal_keyboard_init(hal_kbd_bridge);
 }
 
@@ -41,11 +61,34 @@ void keyboard_set_callback(keyboard_callback_t callback) {
 int keyboard_read_nonblock(char* out, uint32_t max_len) {
     if (!out || max_len == 0) return 0;
 
+    uintptr_t flags = spin_lock_irqsave(&kbd_lock);
+
     uint32_t count = 0;
     while (count < max_len) {
         if (kbd_tail == kbd_head) break;
         out[count++] = kbd_buf[kbd_tail];
         kbd_tail = (kbd_tail + 1U) % KBD_BUF_SIZE;
     }
+
+    spin_unlock_irqrestore(&kbd_lock, flags);
     return (int)count;
 }
+
+int keyboard_read_blocking(char* out, uint32_t max_len) {
+    if (!out || max_len == 0) return 0;
+    if (!current_process) return 0;
+
+    while (1) {
+        int rd = keyboard_read_nonblock(out, max_len);
+        if (rd > 0) return rd;
+
+        uintptr_t flags = spin_lock_irqsave(&kbd_lock);
+        if (kbd_waiter == NULL) {
+            kbd_waiter = current_process;
+            current_process->state = PROCESS_BLOCKED;
+        }
+        spin_unlock_irqrestore(&kbd_lock, flags);
+
+        schedule();
+    }
+}
index fc18743ef94ece45a2c577ada969356623ff1dfd..2b228c5a113170464ad3dc82d286ab74ca546f6c 100644 (file)
@@ -87,8 +87,8 @@ static int syscall_read_impl(int fd, void* user_buf, uint32_t len) {
         char kbuf[256];
         uint32_t chunk = len;
         if (chunk > sizeof(kbuf)) chunk = (uint32_t)sizeof(kbuf);
-        int rd = keyboard_read_nonblock(kbuf, chunk);
-        if (rd <= 0) return 0;
+        int rd = keyboard_read_blocking(kbuf, chunk);
+        if (rd <= 0) return -1;
         if (copy_to_user(user_buf, kbuf, (size_t)rd) < 0) return -1;
         return rd;
     }