From c6f2890d8e4620e85d6320a9ed121b640dded80e Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 25 Oct 2018 13:07:59 +0200 Subject: [PATCH] Implement a basic way for read() to block. FileHandle gets a hasDataAvailableForRead() getter. If this returns true in sys$read(), the task will block(BlockedRead) + yield. The fd blocked on is stored in Task::m_fdBlockedOnRead. The scheduler then looks at the state of that fd during the unblock phase. This makes "sh" restful. :^) There's still some problem with the kernel not surviving the colonel task getting scheduled. I need to figure that out and fix it. --- Kernel/Console.cpp | 5 +++++ Kernel/Console.h | 1 + Kernel/Keyboard.cpp | 5 +++++ Kernel/Keyboard.h | 1 + Kernel/Task.cpp | 15 +++++++++++++++ Kernel/Task.h | 13 ++++++++----- Kernel/init.cpp | 2 +- VirtualFileSystem/CharacterDevice.h | 2 ++ VirtualFileSystem/FileHandle.cpp | 7 +++++++ VirtualFileSystem/FileHandle.h | 6 ++++++ VirtualFileSystem/FullDevice.cpp | 5 +++++ VirtualFileSystem/FullDevice.h | 5 +++-- VirtualFileSystem/NullDevice.cpp | 5 +++++ VirtualFileSystem/NullDevice.h | 7 ++++--- VirtualFileSystem/RandomDevice.cpp | 5 +++++ VirtualFileSystem/RandomDevice.h | 7 ++++--- VirtualFileSystem/ZeroDevice.cpp | 5 +++++ VirtualFileSystem/ZeroDevice.h | 7 ++++--- 18 files changed, 86 insertions(+), 17 deletions(-) diff --git a/Kernel/Console.cpp b/Kernel/Console.cpp index ecd10acffc..02154010b7 100644 --- a/Kernel/Console.cpp +++ b/Kernel/Console.cpp @@ -21,6 +21,11 @@ Console::~Console() { } +bool Console::hasDataAvailableForRead() const +{ + return false; +} + ssize_t Console::read(byte* buffer, size_t bufferSize) { // FIXME: Implement reading from the console. diff --git a/Kernel/Console.h b/Kernel/Console.h index 742ed68074..18f3882924 100644 --- a/Kernel/Console.h +++ b/Kernel/Console.h @@ -9,6 +9,7 @@ public: Console(); virtual ~Console() override; + virtual bool hasDataAvailableForRead() const override; virtual ssize_t read(byte* buffer, size_t size) override; virtual ssize_t write(const byte* data, size_t size) override; diff --git a/Kernel/Keyboard.cpp b/Kernel/Keyboard.cpp index 60edc829f3..f23f5bbbd5 100644 --- a/Kernel/Keyboard.cpp +++ b/Kernel/Keyboard.cpp @@ -86,6 +86,11 @@ Keyboard::~Keyboard() ASSERT_NOT_REACHED(); } +bool Keyboard::hasDataAvailableForRead() const +{ + return !m_queue.isEmpty(); +} + ssize_t Keyboard::read(byte* buffer, size_t size) { ssize_t nread = 0; diff --git a/Kernel/Keyboard.h b/Kernel/Keyboard.h index 21da8eb573..d5554c77ac 100644 --- a/Kernel/Keyboard.h +++ b/Kernel/Keyboard.h @@ -18,6 +18,7 @@ private: // ^CharacterDevice virtual ssize_t read(byte* buffer, size_t) override; virtual ssize_t write(const byte* buffer, size_t) override; + virtual bool hasDataAvailableForRead() const override; CircularQueue m_queue; byte m_modifiers { 0 }; diff --git a/Kernel/Task.cpp b/Kernel/Task.cpp index 4f8a22b089..44240a77e5 100644 --- a/Kernel/Task.cpp +++ b/Kernel/Task.cpp @@ -466,6 +466,14 @@ bool scheduleNewTask() continue; } } + + if (task->state() == Task::BlockedRead) { + ASSERT(task->m_fdBlockedOnRead != -1); + if (task->m_fileHandles[task->m_fdBlockedOnRead]->hasDataAvailableForRead()) { + task->unblock(); + continue; + } + } } #if 0 @@ -619,6 +627,13 @@ ssize_t Task::sys$read(int fd, void* outbuf, size_t nread) #ifdef DEBUG_IO kprintf("call read on handle=%p\n", handle); #endif + if (handle->isBlocking()) { + if (!handle->hasDataAvailableForRead()) { + m_fdBlockedOnRead = fd; + block(BlockedRead); + yield(); + } + } nread = handle->read((byte*)outbuf, nread); #ifdef DEBUG_IO kprintf("Task::sys$read: nread=%u\n", nread); diff --git a/Kernel/Task.h b/Kernel/Task.h index f166df8c9b..9d84877f89 100644 --- a/Kernel/Task.h +++ b/Kernel/Task.h @@ -31,11 +31,12 @@ public: Invalid = 0, Runnable = 1, Running = 2, - BlockedSleep = 3, - BlockedWait = 4, - Terminated = 5, - Crashing = 6, - Exiting = 7, + Terminated = 3, + Crashing = 4, + Exiting = 5, + BlockedSleep = 6, + BlockedWait = 7, + BlockedRead = 8, }; enum RingLevel { @@ -114,6 +115,7 @@ public: private: friend class MemoryManager; + friend bool scheduleNewTask(); Task(String&& name, uid_t, gid_t, pid_t parentPID, RingLevel); @@ -143,6 +145,7 @@ private: void* m_kernelStack { nullptr }; dword m_timesScheduled { 0 }; pid_t m_waitee { -1 }; + int m_fdBlockedOnRead { -1 }; String m_cwd; diff --git a/Kernel/init.cpp b/Kernel/init.cpp index 66109f8475..92026a036c 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -165,7 +165,7 @@ static void init_stage2() #endif for (;;) { - sleep(3600 * TICKS_PER_SECOND); + //sleep(3600 * TICKS_PER_SECOND); asm("hlt"); } } diff --git a/VirtualFileSystem/CharacterDevice.h b/VirtualFileSystem/CharacterDevice.h index 41c12e7e37..6d017a1eed 100644 --- a/VirtualFileSystem/CharacterDevice.h +++ b/VirtualFileSystem/CharacterDevice.h @@ -7,6 +7,8 @@ class CharacterDevice { public: virtual ~CharacterDevice(); + virtual bool hasDataAvailableForRead() const = 0; + virtual Unix::ssize_t read(byte* buffer, Unix::size_t bufferSize) = 0; virtual Unix::ssize_t write(const byte* buffer, Unix::size_t bufferSize) = 0; diff --git a/VirtualFileSystem/FileHandle.cpp b/VirtualFileSystem/FileHandle.cpp index 172fe74cf5..f7cb6aeb67 100644 --- a/VirtualFileSystem/FileHandle.cpp +++ b/VirtualFileSystem/FileHandle.cpp @@ -107,6 +107,13 @@ Unix::ssize_t FileHandle::read(byte* buffer, Unix::size_t count) return nread; } +bool FileHandle::hasDataAvailableForRead() +{ + if (m_vnode->isCharacterDevice()) + return m_vnode->characterDevice()->hasDataAvailableForRead(); + return true; +} + ByteBuffer FileHandle::readEntireFile() { Locker locker(VirtualFileSystem::lock()); diff --git a/VirtualFileSystem/FileHandle.h b/VirtualFileSystem/FileHandle.h index 0aa23b93dd..23c584df25 100644 --- a/VirtualFileSystem/FileHandle.h +++ b/VirtualFileSystem/FileHandle.h @@ -12,6 +12,8 @@ public: Unix::ssize_t read(byte* buffer, Unix::size_t count); int stat(Unix::stat*); + bool hasDataAvailableForRead(); + ssize_t get_dir_entries(byte* buffer, Unix::size_t); ByteBuffer readEntireFile(); @@ -21,6 +23,9 @@ public: #ifdef SERENITY int fd() const { return m_fd; } void setFD(int fd) { m_fd = fd; } + + bool isBlocking() const { return m_isBlocking; } + void setBlocking(bool b) { m_isBlocking = b; } #endif private: @@ -32,6 +37,7 @@ private: #ifdef SERENITY int m_fd { -1 }; + bool m_isBlocking { true }; #endif }; diff --git a/VirtualFileSystem/FullDevice.cpp b/VirtualFileSystem/FullDevice.cpp index aa0a4a55ed..795fe5b0c5 100644 --- a/VirtualFileSystem/FullDevice.cpp +++ b/VirtualFileSystem/FullDevice.cpp @@ -12,6 +12,11 @@ FullDevice::~FullDevice() { } +bool FullDevice::hasDataAvailableForRead() const +{ + return true; +} + Unix::ssize_t FullDevice::read(byte* buffer, Unix::size_t bufferSize) { kprintf("FullDevice: read from full\n"); diff --git a/VirtualFileSystem/FullDevice.h b/VirtualFileSystem/FullDevice.h index d13aed013f..f52dc5b8cb 100644 --- a/VirtualFileSystem/FullDevice.h +++ b/VirtualFileSystem/FullDevice.h @@ -7,7 +7,8 @@ public: FullDevice(); virtual ~FullDevice(); - Unix::ssize_t read(byte* buffer, Unix::size_t bufferSize) override; - Unix::ssize_t write(const byte* buffer, Unix::size_t bufferSize) override; + virtual Unix::ssize_t read(byte* buffer, Unix::size_t bufferSize) override; + virtual Unix::ssize_t write(const byte* buffer, Unix::size_t bufferSize) override; + virtual bool hasDataAvailableForRead() const override; }; diff --git a/VirtualFileSystem/NullDevice.cpp b/VirtualFileSystem/NullDevice.cpp index 4636c8cfdc..b8ec74513e 100644 --- a/VirtualFileSystem/NullDevice.cpp +++ b/VirtualFileSystem/NullDevice.cpp @@ -11,6 +11,11 @@ NullDevice::~NullDevice() { } +bool NullDevice::hasDataAvailableForRead() const +{ + return true; +} + Unix::ssize_t NullDevice::read(byte*, Unix::size_t) { kprintf("NullDevice: read from null\n"); diff --git a/VirtualFileSystem/NullDevice.h b/VirtualFileSystem/NullDevice.h index 98b309f4d4..74cffee686 100644 --- a/VirtualFileSystem/NullDevice.h +++ b/VirtualFileSystem/NullDevice.h @@ -5,9 +5,10 @@ class NullDevice final : public CharacterDevice { public: NullDevice(); - virtual ~NullDevice(); + virtual ~NullDevice() override; - Unix::ssize_t read(byte* buffer, Unix::size_t bufferSize) override; - Unix::ssize_t write(const byte* buffer, Unix::size_t bufferSize) override; + virtual Unix::ssize_t read(byte* buffer, Unix::size_t bufferSize) override; + virtual Unix::ssize_t write(const byte* buffer, Unix::size_t bufferSize) override; + virtual bool hasDataAvailableForRead() const override; }; diff --git a/VirtualFileSystem/RandomDevice.cpp b/VirtualFileSystem/RandomDevice.cpp index 3bc9eaeb7a..d34ac8400b 100644 --- a/VirtualFileSystem/RandomDevice.cpp +++ b/VirtualFileSystem/RandomDevice.cpp @@ -28,6 +28,11 @@ static void mysrand(unsigned seed) } #endif +bool RandomDevice::hasDataAvailableForRead() const +{ + return true; +} + Unix::ssize_t RandomDevice::read(byte* buffer, Unix::size_t bufferSize) { const int range = 'z' - 'a'; diff --git a/VirtualFileSystem/RandomDevice.h b/VirtualFileSystem/RandomDevice.h index 4a30c259fc..eaa91c223d 100644 --- a/VirtualFileSystem/RandomDevice.h +++ b/VirtualFileSystem/RandomDevice.h @@ -5,9 +5,10 @@ class RandomDevice final : public CharacterDevice { public: RandomDevice(); - virtual ~RandomDevice(); + virtual ~RandomDevice() override; - Unix::ssize_t read(byte* buffer, Unix::size_t bufferSize) override; - Unix::ssize_t write(const byte* buffer, Unix::size_t bufferSize) override; + virtual Unix::ssize_t read(byte* buffer, Unix::size_t bufferSize) override; + virtual Unix::ssize_t write(const byte* buffer, Unix::size_t bufferSize) override; + virtual bool hasDataAvailableForRead() const override; }; diff --git a/VirtualFileSystem/ZeroDevice.cpp b/VirtualFileSystem/ZeroDevice.cpp index cdb168a763..5747c82d86 100644 --- a/VirtualFileSystem/ZeroDevice.cpp +++ b/VirtualFileSystem/ZeroDevice.cpp @@ -11,6 +11,11 @@ ZeroDevice::~ZeroDevice() { } +bool ZeroDevice::hasDataAvailableForRead() const +{ + return true; +} + Unix::ssize_t ZeroDevice::read(byte* buffer, Unix::size_t bufferSize) { kprintf("ZeroDevice: read from zero\n"); diff --git a/VirtualFileSystem/ZeroDevice.h b/VirtualFileSystem/ZeroDevice.h index cdbda79bfa..f83cae7d47 100644 --- a/VirtualFileSystem/ZeroDevice.h +++ b/VirtualFileSystem/ZeroDevice.h @@ -5,9 +5,10 @@ class ZeroDevice final : public CharacterDevice { public: ZeroDevice(); - virtual ~ZeroDevice(); + virtual ~ZeroDevice() override; - Unix::ssize_t read(byte* buffer, Unix::size_t bufferSize) override; - Unix::ssize_t write(const byte* buffer, Unix::size_t bufferSize) override; + virtual Unix::ssize_t read(byte* buffer, Unix::size_t bufferSize) override; + virtual Unix::ssize_t write(const byte* buffer, Unix::size_t bufferSize) override; + virtual bool hasDataAvailableForRead() const override; };