diff --git a/Kernel/FileSystem/FIFO.cpp b/Kernel/FileSystem/FIFO.cpp index 610b580ada0..43a34412087 100644 --- a/Kernel/FileSystem/FIFO.cpp +++ b/Kernel/FileSystem/FIFO.cpp @@ -60,6 +60,35 @@ NonnullRefPtr FIFO::open_direction(FIFO::Direction direction) return description; } +NonnullRefPtr FIFO::open_direction_blocking(FIFO::Direction direction) +{ + Locker locker(m_open_lock); + + auto description = open_direction(direction); + + if (direction == Direction::Reader) { + m_read_open_queue.wake_all(); + + if (m_writers == 0) { + locker.unlock(); + Thread::current()->wait_on(m_write_open_queue, "FIFO"); + locker.lock(); + } + } + + if (direction == Direction::Writer) { + m_write_open_queue.wake_all(); + + if (m_readers == 0) { + locker.unlock(); + Thread::current()->wait_on(m_read_open_queue, "FIFO"); + locker.lock(); + } + } + + return description; +} + FIFO::FIFO(uid_t uid) : m_uid(uid) { diff --git a/Kernel/FileSystem/FIFO.h b/Kernel/FileSystem/FIFO.h index 81a65d8caef..81a48680967 100644 --- a/Kernel/FileSystem/FIFO.h +++ b/Kernel/FileSystem/FIFO.h @@ -28,7 +28,9 @@ #include #include +#include #include +#include namespace Kernel { @@ -48,6 +50,7 @@ public: uid_t uid() const { return m_uid; } NonnullRefPtr open_direction(Direction); + NonnullRefPtr open_direction_blocking(Direction); void attach(Direction); void detach(Direction); @@ -71,6 +74,10 @@ private: uid_t m_uid { 0 }; int m_fifo_id { 0 }; + + WaitQueue m_read_open_queue; + WaitQueue m_write_open_queue; + Lock m_open_lock; }; } diff --git a/Kernel/FileSystem/Inode.cpp b/Kernel/FileSystem/Inode.cpp index ec410bcac34..8d4f76a6ad9 100644 --- a/Kernel/FileSystem/Inode.cpp +++ b/Kernel/FileSystem/Inode.cpp @@ -205,6 +205,18 @@ void Inode::unregister_watcher(Badge, InodeWatcher& watcher) m_watchers.remove(&watcher); } +FIFO& Inode::fifo() +{ + ASSERT(metadata().is_fifo()); + + // FIXME: Release m_fifo when it is closed by all readers and writers + if (!m_fifo) + m_fifo = FIFO::create(metadata().uid); + + ASSERT(m_fifo); + return *m_fifo; +} + void Inode::set_metadata_dirty(bool metadata_dirty) { if (m_metadata_dirty == metadata_dirty) diff --git a/Kernel/FileSystem/Inode.h b/Kernel/FileSystem/Inode.h index ff15682fbcc..d6a13f01fb4 100644 --- a/Kernel/FileSystem/Inode.h +++ b/Kernel/FileSystem/Inode.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -111,6 +112,8 @@ public: void register_watcher(Badge, InodeWatcher&); void unregister_watcher(Badge, InodeWatcher&); + FIFO& fifo(); + // For InlineLinkedListNode. Inode* m_next { nullptr }; Inode* m_prev { nullptr }; @@ -134,6 +137,7 @@ private: RefPtr m_socket; HashTable m_watchers; bool m_metadata_dirty { false }; + RefPtr m_fifo; }; } diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp index ef8fd319004..d6aec7a730a 100644 --- a/Kernel/FileSystem/VirtualFileSystem.cpp +++ b/Kernel/FileSystem/VirtualFileSystem.cpp @@ -292,6 +292,23 @@ KResultOr> VFS::open(StringView path, int options if (auto preopen_fd = inode.preopen_fd()) return *preopen_fd; + if (metadata.is_fifo()) { + if (options & O_WRONLY) { + auto description = inode.fifo().open_direction_blocking(FIFO::Direction::Writer); + description->set_rw_mode(options); + description->set_file_flags(options); + description->set_original_inode({}, inode); + return description; + } else if (options & O_RDONLY) { + auto description = inode.fifo().open_direction_blocking(FIFO::Direction::Reader); + description->set_rw_mode(options); + description->set_file_flags(options); + description->set_original_inode({}, inode); + return description; + } + return KResult(-EINVAL); + } + if (metadata.is_device()) { if (custody.mount_flags() & MS_NODEV) return KResult(-EACCES);