mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 07:02:44 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									ba56f4afde
								
							
						
					
					
						commit
						c6f2890d8e
					
				
					 18 changed files with 86 additions and 17 deletions
				
			
		|  | @ -21,6 +21,11 @@ Console::~Console() | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool Console::hasDataAvailableForRead() const | ||||||
|  | { | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ssize_t Console::read(byte* buffer, size_t bufferSize) | ssize_t Console::read(byte* buffer, size_t bufferSize) | ||||||
| { | { | ||||||
|     // FIXME: Implement reading from the console.
 |     // FIXME: Implement reading from the console.
 | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ public: | ||||||
|     Console(); |     Console(); | ||||||
|     virtual ~Console() override; |     virtual ~Console() override; | ||||||
| 
 | 
 | ||||||
|  |     virtual bool hasDataAvailableForRead() const override; | ||||||
|     virtual ssize_t read(byte* buffer, size_t size) override; |     virtual ssize_t read(byte* buffer, size_t size) override; | ||||||
|     virtual ssize_t write(const byte* data, size_t size) override; |     virtual ssize_t write(const byte* data, size_t size) override; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -86,6 +86,11 @@ Keyboard::~Keyboard() | ||||||
|     ASSERT_NOT_REACHED(); |     ASSERT_NOT_REACHED(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool Keyboard::hasDataAvailableForRead() const | ||||||
|  | { | ||||||
|  |     return !m_queue.isEmpty(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ssize_t Keyboard::read(byte* buffer, size_t size) | ssize_t Keyboard::read(byte* buffer, size_t size) | ||||||
| { | { | ||||||
|     ssize_t nread = 0; |     ssize_t nread = 0; | ||||||
|  |  | ||||||
|  | @ -18,6 +18,7 @@ private: | ||||||
|     // ^CharacterDevice
 |     // ^CharacterDevice
 | ||||||
|     virtual ssize_t read(byte* buffer, size_t) override; |     virtual ssize_t read(byte* buffer, size_t) override; | ||||||
|     virtual ssize_t write(const byte* buffer, size_t) override; |     virtual ssize_t write(const byte* buffer, size_t) override; | ||||||
|  |     virtual bool hasDataAvailableForRead() const override; | ||||||
| 
 | 
 | ||||||
|     CircularQueue<byte, 16> m_queue; |     CircularQueue<byte, 16> m_queue; | ||||||
|     byte m_modifiers { 0 }; |     byte m_modifiers { 0 }; | ||||||
|  |  | ||||||
|  | @ -466,6 +466,14 @@ bool scheduleNewTask() | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         if (task->state() == Task::BlockedRead) { | ||||||
|  |             ASSERT(task->m_fdBlockedOnRead != -1); | ||||||
|  |             if (task->m_fileHandles[task->m_fdBlockedOnRead]->hasDataAvailableForRead()) { | ||||||
|  |                 task->unblock(); | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| #if 0 | #if 0 | ||||||
|  | @ -619,6 +627,13 @@ ssize_t Task::sys$read(int fd, void* outbuf, size_t nread) | ||||||
| #ifdef DEBUG_IO | #ifdef DEBUG_IO | ||||||
|     kprintf("call read on handle=%p\n", handle); |     kprintf("call read on handle=%p\n", handle); | ||||||
| #endif | #endif | ||||||
|  |     if (handle->isBlocking()) { | ||||||
|  |         if (!handle->hasDataAvailableForRead()) { | ||||||
|  |             m_fdBlockedOnRead = fd; | ||||||
|  |             block(BlockedRead); | ||||||
|  |             yield(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|     nread = handle->read((byte*)outbuf, nread); |     nread = handle->read((byte*)outbuf, nread); | ||||||
| #ifdef DEBUG_IO | #ifdef DEBUG_IO | ||||||
|     kprintf("Task::sys$read: nread=%u\n", nread); |     kprintf("Task::sys$read: nread=%u\n", nread); | ||||||
|  |  | ||||||
|  | @ -31,11 +31,12 @@ public: | ||||||
|         Invalid = 0, |         Invalid = 0, | ||||||
|         Runnable = 1, |         Runnable = 1, | ||||||
|         Running = 2, |         Running = 2, | ||||||
|         BlockedSleep = 3, |         Terminated = 3, | ||||||
|         BlockedWait = 4, |         Crashing = 4, | ||||||
|         Terminated = 5, |         Exiting = 5, | ||||||
|         Crashing = 6, |         BlockedSleep = 6, | ||||||
|         Exiting = 7, |         BlockedWait = 7, | ||||||
|  |         BlockedRead = 8, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     enum RingLevel { |     enum RingLevel { | ||||||
|  | @ -114,6 +115,7 @@ public: | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     friend class MemoryManager; |     friend class MemoryManager; | ||||||
|  |     friend bool scheduleNewTask(); | ||||||
| 
 | 
 | ||||||
|     Task(String&& name, uid_t, gid_t, pid_t parentPID, RingLevel); |     Task(String&& name, uid_t, gid_t, pid_t parentPID, RingLevel); | ||||||
| 
 | 
 | ||||||
|  | @ -143,6 +145,7 @@ private: | ||||||
|     void* m_kernelStack { nullptr }; |     void* m_kernelStack { nullptr }; | ||||||
|     dword m_timesScheduled { 0 }; |     dword m_timesScheduled { 0 }; | ||||||
|     pid_t m_waitee { -1 }; |     pid_t m_waitee { -1 }; | ||||||
|  |     int m_fdBlockedOnRead { -1 }; | ||||||
| 
 | 
 | ||||||
|     String m_cwd; |     String m_cwd; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -165,7 +165,7 @@ static void init_stage2() | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     for (;;) { |     for (;;) { | ||||||
|         sleep(3600 * TICKS_PER_SECOND); |         //sleep(3600 * TICKS_PER_SECOND);
 | ||||||
|         asm("hlt"); |         asm("hlt"); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -7,6 +7,8 @@ class CharacterDevice { | ||||||
| public: | public: | ||||||
|     virtual ~CharacterDevice(); |     virtual ~CharacterDevice(); | ||||||
| 
 | 
 | ||||||
|  |     virtual bool hasDataAvailableForRead() const = 0; | ||||||
|  | 
 | ||||||
|     virtual Unix::ssize_t read(byte* buffer, Unix::size_t bufferSize) = 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; |     virtual Unix::ssize_t write(const byte* buffer, Unix::size_t bufferSize) = 0; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -107,6 +107,13 @@ Unix::ssize_t FileHandle::read(byte* buffer, Unix::size_t count) | ||||||
|     return nread; |     return nread; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool FileHandle::hasDataAvailableForRead() | ||||||
|  | { | ||||||
|  |     if (m_vnode->isCharacterDevice()) | ||||||
|  |         return m_vnode->characterDevice()->hasDataAvailableForRead(); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ByteBuffer FileHandle::readEntireFile() | ByteBuffer FileHandle::readEntireFile() | ||||||
| { | { | ||||||
|     Locker locker(VirtualFileSystem::lock()); |     Locker locker(VirtualFileSystem::lock()); | ||||||
|  |  | ||||||
|  | @ -12,6 +12,8 @@ public: | ||||||
|     Unix::ssize_t read(byte* buffer, Unix::size_t count); |     Unix::ssize_t read(byte* buffer, Unix::size_t count); | ||||||
|     int stat(Unix::stat*); |     int stat(Unix::stat*); | ||||||
| 
 | 
 | ||||||
|  |     bool hasDataAvailableForRead(); | ||||||
|  | 
 | ||||||
|     ssize_t get_dir_entries(byte* buffer, Unix::size_t); |     ssize_t get_dir_entries(byte* buffer, Unix::size_t); | ||||||
| 
 | 
 | ||||||
|     ByteBuffer readEntireFile(); |     ByteBuffer readEntireFile(); | ||||||
|  | @ -21,6 +23,9 @@ public: | ||||||
| #ifdef SERENITY | #ifdef SERENITY | ||||||
|     int fd() const { return m_fd; } |     int fd() const { return m_fd; } | ||||||
|     void setFD(int fd) { m_fd = fd; } |     void setFD(int fd) { m_fd = fd; } | ||||||
|  | 
 | ||||||
|  |     bool isBlocking() const { return m_isBlocking; } | ||||||
|  |     void setBlocking(bool b) { m_isBlocking = b; } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  | @ -32,6 +37,7 @@ private: | ||||||
| 
 | 
 | ||||||
| #ifdef SERENITY | #ifdef SERENITY | ||||||
|     int m_fd { -1 }; |     int m_fd { -1 }; | ||||||
|  |     bool m_isBlocking { true }; | ||||||
| #endif | #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -12,6 +12,11 @@ FullDevice::~FullDevice() | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool FullDevice::hasDataAvailableForRead() const | ||||||
|  | { | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| Unix::ssize_t FullDevice::read(byte* buffer, Unix::size_t bufferSize) | Unix::ssize_t FullDevice::read(byte* buffer, Unix::size_t bufferSize) | ||||||
| { | { | ||||||
|     kprintf("FullDevice: read from full\n"); |     kprintf("FullDevice: read from full\n"); | ||||||
|  |  | ||||||
|  | @ -7,7 +7,8 @@ public: | ||||||
|     FullDevice(); |     FullDevice(); | ||||||
|     virtual ~FullDevice(); |     virtual ~FullDevice(); | ||||||
| 
 | 
 | ||||||
|     Unix::ssize_t read(byte* buffer, Unix::size_t bufferSize) override; |     virtual 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 write(const byte* buffer, Unix::size_t bufferSize) override; | ||||||
|  |     virtual bool hasDataAvailableForRead() const override; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -11,6 +11,11 @@ NullDevice::~NullDevice() | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool NullDevice::hasDataAvailableForRead() const | ||||||
|  | { | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| Unix::ssize_t NullDevice::read(byte*, Unix::size_t) | Unix::ssize_t NullDevice::read(byte*, Unix::size_t) | ||||||
| { | { | ||||||
|     kprintf("NullDevice: read from null\n"); |     kprintf("NullDevice: read from null\n"); | ||||||
|  |  | ||||||
|  | @ -5,9 +5,10 @@ | ||||||
| class NullDevice final : public CharacterDevice { | class NullDevice final : public CharacterDevice { | ||||||
| public: | public: | ||||||
|     NullDevice(); |     NullDevice(); | ||||||
|     virtual ~NullDevice(); |     virtual ~NullDevice() override; | ||||||
| 
 | 
 | ||||||
|     Unix::ssize_t read(byte* buffer, Unix::size_t bufferSize) override; |     virtual 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 write(const byte* buffer, Unix::size_t bufferSize) override; | ||||||
|  |     virtual bool hasDataAvailableForRead() const override; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -28,6 +28,11 @@ static void mysrand(unsigned seed) | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | bool RandomDevice::hasDataAvailableForRead() const | ||||||
|  | { | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| Unix::ssize_t RandomDevice::read(byte* buffer, Unix::size_t bufferSize) | Unix::ssize_t RandomDevice::read(byte* buffer, Unix::size_t bufferSize) | ||||||
| { | { | ||||||
|     const int range = 'z' - 'a'; |     const int range = 'z' - 'a'; | ||||||
|  |  | ||||||
|  | @ -5,9 +5,10 @@ | ||||||
| class RandomDevice final : public CharacterDevice { | class RandomDevice final : public CharacterDevice { | ||||||
| public: | public: | ||||||
|     RandomDevice(); |     RandomDevice(); | ||||||
|     virtual ~RandomDevice(); |     virtual ~RandomDevice() override; | ||||||
| 
 | 
 | ||||||
|     Unix::ssize_t read(byte* buffer, Unix::size_t bufferSize) override; |     virtual 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 write(const byte* buffer, Unix::size_t bufferSize) override; | ||||||
|  |     virtual bool hasDataAvailableForRead() const override; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -11,6 +11,11 @@ ZeroDevice::~ZeroDevice() | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool ZeroDevice::hasDataAvailableForRead() const | ||||||
|  | { | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| Unix::ssize_t ZeroDevice::read(byte* buffer, Unix::size_t bufferSize) | Unix::ssize_t ZeroDevice::read(byte* buffer, Unix::size_t bufferSize) | ||||||
| { | { | ||||||
|     kprintf("ZeroDevice: read from zero\n"); |     kprintf("ZeroDevice: read from zero\n"); | ||||||
|  |  | ||||||
|  | @ -5,9 +5,10 @@ | ||||||
| class ZeroDevice final : public CharacterDevice { | class ZeroDevice final : public CharacterDevice { | ||||||
| public: | public: | ||||||
|     ZeroDevice(); |     ZeroDevice(); | ||||||
|     virtual ~ZeroDevice(); |     virtual ~ZeroDevice() override; | ||||||
| 
 | 
 | ||||||
|     Unix::ssize_t read(byte* buffer, Unix::size_t bufferSize) override; |     virtual 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 write(const byte* buffer, Unix::size_t bufferSize) override; | ||||||
|  |     virtual bool hasDataAvailableForRead() const override; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling