From da61e3648f531a48822c4bd7d089fea4e4a23ca4 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 21 Oct 2022 21:26:19 +0200 Subject: [PATCH] Kernel: Implement blocking reads This is a huge step forward!! bc actually runs now, without echo or backspace, but it runs!! --- apps/src/sh.c | 7 +------ kernel/include/fs/VFS.h | 4 ++++ kernel/include/fs/devices/Keyboard.h | 2 ++ kernel/include/thread/Task.h | 12 ++++++++++++ kernel/src/fs/VFS.cpp | 7 +++++++ kernel/src/fs/devices/Keyboard.cpp | 6 ++++++ kernel/src/sys/stdio.cpp | 8 ++++++++ kernel/src/thread/Scheduler.cpp | 8 ++++++++ kernel/src/thread/Task.cpp | 17 +++++++++++++++++ 9 files changed, 65 insertions(+), 6 deletions(-) diff --git a/apps/src/sh.c b/apps/src/sh.c index c9904e76..422d2a28 100644 --- a/apps/src/sh.c +++ b/apps/src/sh.c @@ -187,12 +187,7 @@ int main() perror("fread"); return 1; } - if (feof(stdin)) - { - clearerr(stdin); - msleep(20); - continue; - } + if (feof(stdin)) { return 0; } buffer[nread] = 0; command_concat(&shell_command, buffer); } diff --git a/kernel/include/fs/VFS.h b/kernel/include/fs/VFS.h index c159fb11..b305efaa 100644 --- a/kernel/include/fs/VFS.h +++ b/kernel/include/fs/VFS.h @@ -18,6 +18,7 @@ namespace VFS typedef ssize_t (*node_write)(Node*, size_t, size_t, const char*); typedef Node* (*node_finddir)(Node*, const char*); typedef int (*node_mkdir)(Node*, const char*); + typedef int (*node_block)(Node*); struct Node { @@ -30,6 +31,7 @@ namespace VFS node_finddir find_func; node_mkdir mkdir_func; node_write write_func; + node_block block_func; int tty = 0; Node* link; }; @@ -39,6 +41,8 @@ namespace VFS int mkdir(const char* path, const char* name); int mkdir(const char* pathname); + int would_block(Node* node); + void mount_root(Node* root); Node* resolve_path(const char* filename, Node* root = nullptr); diff --git a/kernel/include/fs/devices/Keyboard.h b/kernel/include/fs/devices/Keyboard.h index f77c25b1..3dc30575 100644 --- a/kernel/include/fs/devices/Keyboard.h +++ b/kernel/include/fs/devices/Keyboard.h @@ -7,5 +7,7 @@ namespace KeyboardDevice ssize_t read(VFS::Node* node, size_t offset, size_t size, char* buffer); + int would_block(VFS::Node* node); + void append(char c); } \ No newline at end of file diff --git a/kernel/include/thread/Task.h b/kernel/include/thread/Task.h index 7405b9e8..ae2f109e 100644 --- a/kernel/include/thread/Task.h +++ b/kernel/include/thread/Task.h @@ -15,6 +15,7 @@ struct Task Running, Sleeping, Dying, + Blocking, Exited }; @@ -67,4 +68,15 @@ struct Task bool has_died(); char name[128]; + + struct + { + size_t size; + int fd; + char* buf; + } blocking_read_info; + + void resume_read(); + + bool is_still_blocking(); }; \ No newline at end of file diff --git a/kernel/src/fs/VFS.cpp b/kernel/src/fs/VFS.cpp index ee7518c5..29ca712b 100644 --- a/kernel/src/fs/VFS.cpp +++ b/kernel/src/fs/VFS.cpp @@ -9,6 +9,13 @@ static VFS::Node* vfs_root; +int VFS::would_block(Node* node) +{ + if (!node) { return 0; } + if (!node->block_func) { return 0; } + return node->block_func(node); +} + ssize_t VFS::read(Node* node, size_t offset, size_t length, char* buffer) { if (!node) diff --git a/kernel/src/fs/devices/Keyboard.cpp b/kernel/src/fs/devices/Keyboard.cpp index 6907042c..f844d1b9 100644 --- a/kernel/src/fs/devices/Keyboard.cpp +++ b/kernel/src/fs/devices/Keyboard.cpp @@ -11,10 +11,16 @@ char* kbd_buffer = nullptr; uint64_t kbd_bufsize = 0; +int KeyboardDevice::would_block(VFS::Node*) +{ + return kbd_bufsize == 0; +} + VFS::Node* KeyboardDevice::create_new(const char* devname) { VFS::Node* dev = new VFS::Node; dev->read_func = KeyboardDevice::read; + dev->block_func = KeyboardDevice::would_block; dev->inode = 0; dev->length = 0; dev->type = VFS_DEVICE; diff --git a/kernel/src/sys/stdio.cpp b/kernel/src/sys/stdio.cpp index a83c18d5..8be87515 100644 --- a/kernel/src/sys/stdio.cpp +++ b/kernel/src/sys/stdio.cpp @@ -209,6 +209,14 @@ void sys_read(Context* context, int fd, size_t size, char* buffer) context->rax = -EBADF; return; } + if (VFS::would_block(current_task->files[fd].node())) + { + current_task->state = current_task->Blocking; + current_task->blocking_read_info.fd = fd; + current_task->blocking_read_info.buf = (char*)VMM::get_physical((uint64_t)buffer); // FIXME: Handle errors. + current_task->blocking_read_info.size = size; + return Scheduler::task_yield(context); + } ssize_t result = current_task->files[fd].read(size, (char*)VMM::get_physical((uint64_t)buffer)); context->rax = (size_t)result; return; diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 097d9483..e6acc9dc 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -392,6 +392,14 @@ void Scheduler::task_yield(Context* context) Task* original_task = sched_current_task; do { sched_current_task = sched_current_task->next_task; + if (sched_current_task->state == sched_current_task->Blocking) + { + if (!sched_current_task->is_still_blocking()) + { + sched_current_task->resume_read(); + sched_current_task->state = sched_current_task->Running; + } + } if (sched_current_task->state == sched_current_task->Running) { if (sched_current_task->id != original_task->id || was_idle) diff --git a/kernel/src/thread/Task.cpp b/kernel/src/thread/Task.cpp index 0010e7d8..ec404f6f 100644 --- a/kernel/src/thread/Task.cpp +++ b/kernel/src/thread/Task.cpp @@ -1,4 +1,7 @@ +#define MODULE "sched" + #include "thread/Task.h" +#include "log/Log.h" #include "memory/VMM.h" #include "std/string.h" @@ -65,4 +68,18 @@ void Task::switch_to_address_space() bool Task::has_died() { return state == Exited; +} + +void Task::resume_read() +{ + VMM::switch_back_to_kernel_address_space(); + VMM::apply_address_space(); + VMM::switch_to_previous_user_address_space(); + regs.rax = files[blocking_read_info.fd].read(blocking_read_info.size, blocking_read_info.buf); + VMM::apply_address_space(); +} + +bool Task::is_still_blocking() +{ + return VFS::would_block(files[blocking_read_info.fd].node()); } \ No newline at end of file