From 6fe8073de975ad7722043f9173fec068178e2eac Mon Sep 17 00:00:00 2001 From: dzwdz Date: Sun, 14 Jul 2024 19:19:35 +0200 Subject: kernel: rework postqueue Keeping its old name for now to make things easier for myself. This might just be replaced by sys/queue.h soon. --- src/kernel/arch/amd64/driver/ps2.c | 7 ++-- src/kernel/arch/amd64/driver/rtl8139.c | 9 ++++-- src/kernel/arch/amd64/driver/serial.c | 3 +- src/kernel/arch/amd64/driver/util.c | 44 ------------------------- src/kernel/arch/amd64/driver/util.h | 7 ---- src/kernel/types.h | 1 + src/kernel/vfs/request.c | 59 ++++++++++++++++++++++++++++++++++ src/kernel/vfs/request.h | 12 +++++++ 8 files changed, 86 insertions(+), 56 deletions(-) (limited to 'src') diff --git a/src/kernel/arch/amd64/driver/ps2.c b/src/kernel/arch/amd64/driver/ps2.c index f0c5f2c..86fcffd 100644 --- a/src/kernel/arch/amd64/driver/ps2.c +++ b/src/kernel/arch/amd64/driver/ps2.c @@ -19,8 +19,8 @@ static volatile ring_t mouse_backlog = {(void*)mouse_buf, sizeof mouse_buf, 0, 0 static void accept(VfsReq *req); static void ps2_irq(void); -static VfsReq *kb_queue = NULL; -static VfsReq *mouse_queue = NULL; +static ReqQueue kb_queue; +static ReqQueue mouse_queue; static void wait_out(void) { while ((port_in8(PS2 + 4) & 2) != 0); @@ -58,6 +58,9 @@ void ps2_init(void) { irq_fn[IRQ_PS2KB] = ps2_irq; irq_fn[IRQ_PS2MOUSE] = ps2_irq; + postqueue_init(&kb_queue); + postqueue_init(&mouse_queue); + vfs_root_register("/dev/ps2/", accept); } diff --git a/src/kernel/arch/amd64/driver/rtl8139.c b/src/kernel/arch/amd64/driver/rtl8139.c index a005df5..bce1071 100644 --- a/src/kernel/arch/amd64/driver/rtl8139.c +++ b/src/kernel/arch/amd64/driver/rtl8139.c @@ -13,7 +13,7 @@ static void accept(VfsReq *req); static void rtl8139_irq(void); -static VfsReq *blocked_on = NULL; +static ReqQueue blocked_on; enum { @@ -86,6 +86,8 @@ void rtl8139_init(uint32_t bdf) { mac[i] = port_in8(iobase + Mac + i); } + postqueue_init(&blocked_on); + vfs_root_register("/dev/eth/", accept); } @@ -100,7 +102,10 @@ static void rtl8139_irq(void) { /* bit 0 of cmd - Rx Buffer Empty * not a do while() because sometimes the bit is empty on IRQ. no clue why. */ while (!(port_in8(iobase + Cmd) & 1)) { - if (!postqueue_pop(&blocked_on, accept)) { + VfsReq *req = postqueue_pop(&blocked_on); + if (req) { + accept(req); + } else { rx_irq_enable(false); break; } diff --git a/src/kernel/arch/amd64/driver/serial.c b/src/kernel/arch/amd64/driver/serial.c index 6f383a3..eb347d0 100644 --- a/src/kernel/arch/amd64/driver/serial.c +++ b/src/kernel/arch/amd64/driver/serial.c @@ -16,12 +16,13 @@ static bool COM1_exists = false; static void accept(VfsReq *req); static void serial_irq(void); -static VfsReq *hung_reads = NULL; +static ReqQueue hung_reads; void serial_init(void) { if (COM1_exists) { vfs_root_register("/dev/com1", accept); } + postqueue_init(&hung_reads); } static bool serial_selftest(void) { diff --git a/src/kernel/arch/amd64/driver/util.c b/src/kernel/arch/amd64/driver/util.c index 2b33849..f02c4e2 100644 --- a/src/kernel/arch/amd64/driver/util.c +++ b/src/kernel/arch/amd64/driver/util.c @@ -13,50 +13,6 @@ int req_readcopy(VfsReq *req, const void *buf, size_t len) { return req->output.len; } -void postqueue_join(VfsReq **queue, VfsReq *req) { - if (req->postqueue_next) - panic_invalid_state(); - - while (*queue) - queue = &(*queue)->postqueue_next; - *queue = req; -} - -bool postqueue_pop(VfsReq **queue, void (*accept)(VfsReq *)) { - VfsReq *req = *queue; - if (req == NULL) return false; - *queue = req->postqueue_next; - req->postqueue_next = NULL; - accept(req); - return true; -} - -void postqueue_ringreadall(VfsReq **queue, ring_t *r) { - VfsReq *req; - char tmp[64]; - size_t mlen = 0; - if (ring_used(r) == 0) return; - - /* read as much as the biggest request wants */ - for (req = *queue; req; req = req->postqueue_next) - mlen = max(mlen, req->output.len); - mlen = min(mlen, sizeof tmp); - mlen = ring_get(r, tmp, mlen); - - while (*queue) { - req = *queue; - *queue = req->postqueue_next; - req->postqueue_next = NULL; - - size_t ret = min(mlen, req->output.len); - assert(req->type == VFSOP_READ); - if (req->caller) { - pcpy_to(req->caller, req->output.buf, tmp, ret); - } - vfsreq_finish_short(req, ret); - } -} - size_t ring_to_virt(ring_t *r, Proc *proc, void __user *ubuf, size_t max) { char tmp[32]; if (max > sizeof tmp) max = sizeof tmp; diff --git a/src/kernel/arch/amd64/driver/util.h b/src/kernel/arch/amd64/driver/util.h index 6fae977..898875a 100644 --- a/src/kernel/arch/amd64/driver/util.h +++ b/src/kernel/arch/amd64/driver/util.h @@ -15,11 +15,4 @@ int req_readcopy(VfsReq *req, const void *buf, size_t len); req->input.len == plen && \ memcmp(req->input.buf_kern, path, plen) == 0) -void postqueue_join(VfsReq **queue, VfsReq *req); -bool postqueue_pop(VfsReq **queue, void (*accept)(VfsReq *)); - -/** If there are any pending read requests, and the ring buffer isn't empty, fulfill them - * all with a single read. */ -void postqueue_ringreadall(VfsReq **queue, ring_t *r); - size_t ring_to_virt(ring_t *r, Proc *proc, void __user *ubuf, size_t max); diff --git a/src/kernel/types.h b/src/kernel/types.h index e186479..b8308a5 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -10,6 +10,7 @@ FORWARD_STRUCT(Proc) FORWARD_STRUCT(VfsBackend) FORWARD_STRUCT(VfsMount) FORWARD_STRUCT(VfsReq) +FORWARD_STRUCT(ReqQueue) /* arch-specific stuff */ FORWARD_STRUCT(GfxInfo) diff --git a/src/kernel/vfs/request.c b/src/kernel/vfs/request.c index d4ea16c..8f44afb 100644 --- a/src/kernel/vfs/request.c +++ b/src/kernel/vfs/request.c @@ -242,3 +242,62 @@ vfsback_provdown(VfsBackend *b) } vfsback_checkfree(b); } + +void +postqueue_init(ReqQueue *q) +{ + q->head = NULL; +} + +void +postqueue_join(ReqQueue *q, VfsReq *req) +{ + if (req->postqueue_next) + panic_invalid_state(); + + VfsReq **it = &q->head; + while (*it != NULL) { + it = &(*it)->postqueue_next; + } + *it = req; +} + +VfsReq * +postqueue_pop(ReqQueue *q) +{ + VfsReq *req = q->head; + if (req) { + q->head = req->postqueue_next; + req->postqueue_next = NULL; + } + return req; +} + +void +postqueue_ringreadall(ReqQueue *q, ring_t *r) +{ + VfsReq **queue = &q->head; /* whatever */ + VfsReq *req; + char tmp[64]; + size_t mlen = 0; + if (ring_used(r) == 0) return; + + /* read as much as the biggest request wants */ + for (req = *queue; req; req = req->postqueue_next) + mlen = max(mlen, req->output.len); + mlen = min(mlen, sizeof tmp); + mlen = ring_get(r, tmp, mlen); + + while (*queue) { + req = *queue; + *queue = req->postqueue_next; + req->postqueue_next = NULL; + + size_t ret = min(mlen, req->output.len); + assert(req->type == VFSOP_READ); + if (req->caller) { + pcpy_to(req->caller, req->output.buf, tmp, ret); + } + vfsreq_finish_short(req, ret); + } +} diff --git a/src/kernel/vfs/request.h b/src/kernel/vfs/request.h index 06c46e7..616c044 100644 --- a/src/kernel/vfs/request.h +++ b/src/kernel/vfs/request.h @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include @@ -77,3 +78,14 @@ void vfsback_userdown(VfsBackend *); /** Decrements the "provider" reference count. */ void vfsback_provdown(VfsBackend *); + +struct ReqQueue { + VfsReq *head; +}; +void postqueue_init(ReqQueue *q); +void postqueue_join(ReqQueue *q, VfsReq *req); +VfsReq *postqueue_pop(ReqQueue *q); + +/** If there are any pending read requests, and the ring buffer isn't empty, fulfill them + * all with a single read. */ +void postqueue_ringreadall(ReqQueue *q, ring_t *r); -- cgit v1.2.3