From ba2f957dd39a44e0828ab4efd809d36d704fd537 Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Tue, 24 Jan 2023 13:53:44 +0100
Subject: kernel/procfs: allow interrupting processes

---
 src/kernel/proc.c       |  4 +--
 src/kernel/vfs/procfs.c | 72 +++++++++++++++++++++++++++++++++++++------------
 2 files changed, 57 insertions(+), 19 deletions(-)

(limited to 'src')

diff --git a/src/kernel/proc.c b/src/kernel/proc.c
index d8c7e57..b49b645 100755
--- a/src/kernel/proc.c
+++ b/src/kernel/proc.c
@@ -196,8 +196,8 @@ void process_kill(struct process *p, int ret) {
 			process_transition(p, PS_TOMBSTONE);
 		}
 	}
-	if (p == process_first) {
-		assert(!p->child);
+	if (p == process_first && p->child) {
+		_panic("init killed prematurely");
 	}
 	process_tryreap(p);
 
diff --git a/src/kernel/vfs/procfs.c b/src/kernel/vfs/procfs.c
index 5837012..7ca8c14 100644
--- a/src/kernel/vfs/procfs.c
+++ b/src/kernel/vfs/procfs.c
@@ -6,40 +6,65 @@
 #include <kernel/vfs/request.h>
 #include <shared/mem.h>
 
-static uint32_t openpath(const char *path, size_t len, struct process *root);
+enum phandle_type {
+	PhDir,
+	PhIntr,
+};
+
+struct phandle {
+	uint32_t gid;
+	enum phandle_type type;
+};
+
+static struct phandle *openpath(const char *path, size_t len, struct process *root);
 static struct process *findgid(uint32_t gid, struct process *root);
 static void procfs_accept(struct vfs_request *req);
 static void procfs_cleanup(struct vfs_backend *be);
+static int isdigit(int c);
 
-static uint32_t
+static struct phandle *
 openpath(const char *path, size_t len, struct process *p)
 {
-	if (len == 0) return 0;
+	struct phandle *h;
+	enum phandle_type type;
+	if (len == 0) return NULL;
 	path++, len--;
 
-	while (len) {
+	while (len && isdigit(*path)) {
+		/* parse numerical segment / "directory" name */
 		uint32_t cid = 0;
 		for (; 0 < len && *path != '/'; path++, len--) {
 			char c = *path;
-			if (!('0' <= c && c <= '9')) {
-				return 0;
+			if (!isdigit(c)) {
+				return NULL;
 			}
 			cid = cid * 10 + *path - '0';
 		}
-		if (len == 0) {
-			return 0;
-		}
+		if (len == 0) return NULL;
 		assert(*path == '/');
 		path++, len--;
 
 		p = p->child;
-		if (!p) return 0;
+		if (!p) return NULL;
 		while (p->cid != cid) {
 			p = p->sibling;
-			if (!p) return 0;
+			if (!p) return NULL;
 		}
 	}
-	return p->globalid;
+
+	/* parse the per-process part */
+	if (len == 0) {
+		type = PhDir;
+	} else if (len == 4 && memcmp(path, "intr", 4) == 0) {
+		type = PhIntr;
+	} else {
+		return NULL;
+	}
+
+	h = kmalloc(sizeof *h);
+	h->gid = p->globalid;
+	h->type = type;
+	return h;
 }
 
 static struct process *
@@ -55,29 +80,31 @@ static void
 procfs_accept(struct vfs_request *req)
 {
 	struct process *root = req->backend->kern.data;
+	struct phandle *h = (__force void*)req->id;
 	struct process *p;
 	char buf[512];
 	assert(root);
 	if (req->type == VFSOP_OPEN) {
-		int gid;
 		assert(req->input.kern);
-		gid = openpath(req->input.buf_kern, req->input.len, root);
-		vfsreq_finish_short(req, gid == 0 ? -ENOENT : gid);
+		h = openpath(req->input.buf_kern, req->input.len, root);
+		vfsreq_finish_short(req, h ? (long)h : -ENOENT);
 		return;
 	}
-	p = findgid((uintptr_t)req->id, root);
+	assert(h);
+	p = findgid(h->gid, root);
 	if (!p) {
 		vfsreq_finish_short(req, -EGENERIC);
 		return;
 	}
 
-	if (req->type == VFSOP_READ) {
+	if (req->type == VFSOP_READ && h->type == PhDir) {
 		// TODO port dirbuild to kernel
 		int pos = 0;
 		if (req->offset != 0) {
 			vfsreq_finish_short(req, -ENOSYS);
 			return;
 		}
+		pos += snprintf(buf + pos, 512 - pos, "intr")+1;
 		for (struct process *iter = p->child; iter; iter = iter->sibling) {
 			assert(pos < 512);
 			// processes could possibly be identified by unique identifiers instead
@@ -91,6 +118,12 @@ procfs_accept(struct vfs_request *req)
 		assert(0 <= pos && (size_t)pos <= sizeof buf);
 		virt_cpy_to(req->caller->pages, req->output.buf, buf, pos);
 		vfsreq_finish_short(req, pos);
+	} else if (req->type == VFSOP_WRITE && h->type == PhIntr) {
+		process_intr(p);
+		vfsreq_finish_short(req, req->input.len);
+	} else if (req->type == VFSOP_CLOSE) {
+		kfree(h);
+		vfsreq_finish_short(req, 0);
 	} else {
 		vfsreq_finish_short(req, -ENOSYS);
 	}
@@ -104,6 +137,11 @@ procfs_cleanup(struct vfs_backend *be)
 	p->refcount--;
 }
 
+static int
+isdigit(int c) {
+	return '0' <= c && c <= '9';
+}
+
 struct vfs_backend *
 procfs_backend(struct process *proc)
 {
-- 
cgit v1.2.3