From 2d7da42acbf2782636e481ebd79f30700fb7dc9e Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Wed, 19 Jul 2023 21:27:15 +0200
Subject: user /keyboard: handle open()s instantly even if waiting for kb

fixes e.g. `echo */*` in dash
---
 src/shared/include/camellia/errno.h |  1 +
 src/user/app/init/driver/ps2.c      | 66 ++++++++++++++++++++++++++++---------
 src/user/app/shell/builtins.c       |  4 +++
 src/user/lib/include/__errno.h      |  1 +
 4 files changed, 56 insertions(+), 16 deletions(-)

(limited to 'src')

diff --git a/src/shared/include/camellia/errno.h b/src/shared/include/camellia/errno.h
index e29f3d7..1177f54 100644
--- a/src/shared/include/camellia/errno.h
+++ b/src/shared/include/camellia/errno.h
@@ -25,3 +25,4 @@
 #define EINTR 205
 #define EWOULDBLOCK 206
 #define EEXIST 207
+#define EAGAIN 208
diff --git a/src/user/app/init/driver/ps2.c b/src/user/app/init/driver/ps2.c
index 2752238..5470249 100644
--- a/src/user/app/init/driver/ps2.c
+++ b/src/user/app/init/driver/ps2.c
@@ -1,10 +1,12 @@
 #include "driver.h"
+#include <assert.h>
 #include <camellia/compat.h>
 #include <camellia/syscalls.h>
 #include <errno.h>
 #include <shared/ring.h>
 #include <stdbool.h>
 #include <stdlib.h>
+#include <thread.h>
 
 
 static const char keymap_lower[] = {
@@ -51,36 +53,68 @@ static void parse_scancode(uint8_t s) {
 	if (down && c) ring_put1b((void*)&backlog, c);
 }
 
-static void main_loop(void) {
+
+/** Is a thread waiting for /kdev/ps2/kb? */
+static volatile bool blocked = false;
+/* for use in read_thread */
+static hid_t rt_reqh;
+static size_t rt_cap;
+
+static void read_thread(void *unused) {
+	char buf[512];
+	(void)unused;
+
+	assert(blocked);
+	while (ring_used((void*)&backlog) == 0) {
+		/* read raw input until we have something to output */
+		int len = _sys_read(fd, buf, sizeof buf, 0);
+		if (len == 0) break;
+		for (int i = 0; i < len; i++)
+			parse_scancode(buf[i]);
+	}
+	if (ring_used((void*)&backlog) > 0) {
+		int ret = ring_get((void*)&backlog, buf, rt_cap);
+		_sys_fs_respond(rt_reqh, buf, ret, 0);
+	} else {
+		_sys_fs_respond(rt_reqh, 0, -EGENERIC, 0);
+	}
+	blocked = false;
+}
+
+static void fs_loop(void) {
 	static char buf[512];
-	struct ufs_request res;
 	int ret;
-	while (!c0_fs_wait(buf, sizeof buf, &res)) {
-		// TODO don't hang on ps2 reads
+	for (;;) {
+		struct ufs_request res;
+		hid_t reqh = _sys_fs_wait(buf, sizeof buf, &res);
+		if (reqh < 0) return;
 
 		switch (res.op) {
 			case VFSOP_OPEN:
 				if (res.len == 0) {
-					c0_fs_respond(NULL, 1, 0);
+					_sys_fs_respond(reqh, NULL, 1, 0);
 				} else {
-					c0_fs_respond(NULL, -ENOENT, 0);
+					_sys_fs_respond(reqh, NULL, -ENOENT, 0);
 				}
 				break;
 
 			case VFSOP_READ:
-				while (ring_used((void*)&backlog) == 0) {
-					/* read raw input until we have something to output */
-					int len = _sys_read(fd, buf, sizeof buf, 0);
-					if (len == 0) break;
-					for (int i = 0; i < len; i++)
-						parse_scancode(buf[i]);
+				if (blocked) {
+					_sys_fs_respond(reqh, NULL, -EAGAIN, 0);
+					break;
+				} else if (ring_used((void*)&backlog) > 0) {
+					ret = ring_get((void*)&backlog, buf, res.capacity);
+					_sys_fs_respond(reqh, buf, ret, 0);
+				} else {
+					blocked = true;
+					rt_reqh = reqh;
+					rt_cap = res.capacity;
+					thread_create(0, read_thread, 0);
 				}
-				ret = ring_get((void*)&backlog, buf, res.capacity);
-				c0_fs_respond(buf, ret, 0);
 				break;
 
 			default:
-				c0_fs_respond(NULL, -1, 0);
+				_sys_fs_respond(reqh, NULL, -1, 0);
 				break;
 		}
 	}
@@ -90,6 +124,6 @@ void ps2_drv(void) {
 	fd = _sys_open("/kdev/ps2/kb", 12, 0);
 	if (fd < 0) exit(1);
 
-	main_loop();
+	fs_loop();
 	exit(0);
 }
diff --git a/src/user/app/shell/builtins.c b/src/user/app/shell/builtins.c
index 734370b..9c294b2 100644
--- a/src/user/app/shell/builtins.c
+++ b/src/user/app/shell/builtins.c
@@ -35,6 +35,10 @@ static void cmd_cat(int argc, char **argv) {
 			if (len <= 0) break;
 			fwrite(buf, 1, len, stdout);
 		}
+		if (ferror(file)) {
+			perror(argv[i]);
+			return;
+		}
 		fclose(file);
 	}
 }
diff --git a/src/user/lib/include/__errno.h b/src/user/lib/include/__errno.h
index 0808ac6..7551ce0 100644
--- a/src/user/lib/include/__errno.h
+++ b/src/user/lib/include/__errno.h
@@ -22,4 +22,5 @@ E(204, "ENOEXEC")
 E(205, "EINTR")
 E(206, "EWOULDBLOCK")
 E(207, "EEXIST")
+E(208, "EAGAIN")
 #endif
-- 
cgit v1.2.3