diff --git a/kernel/include/kernel/FS/Pipe.h b/kernel/include/kernel/FS/Pipe.h index d8bd0372..972b22f3 100644 --- a/kernel/include/kernel/FS/Pipe.h +++ b/kernel/include/kernel/FS/Pipe.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -33,7 +34,7 @@ namespace Kernel virtual BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) override; virtual BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan) override; - virtual bool can_read_impl() const override { return !m_buffer.empty(); } + virtual bool can_read_impl() const override { return m_buffer_size == 0; } virtual bool can_write_impl() const override { return true; } virtual bool has_error_impl() const override { return false; } @@ -46,10 +47,13 @@ namespace Kernel timespec m_atime {}; timespec m_mtime {}; timespec m_ctime {}; - BAN::Vector m_buffer; ThreadBlocker m_thread_blocker; - uint32_t m_writing_count { 1 }; + BAN::Array m_buffer; + BAN::Atomic m_buffer_size { 0 }; + size_t m_buffer_tail { 0 }; + + BAN::Atomic m_writing_count { 1 }; }; } diff --git a/kernel/kernel/FS/Pipe.cpp b/kernel/kernel/FS/Pipe.cpp index 4afe645f..d12ece83 100644 --- a/kernel/kernel/FS/Pipe.cpp +++ b/kernel/kernel/FS/Pipe.cpp @@ -3,6 +3,8 @@ #include #include +#include + namespace Kernel { @@ -26,24 +28,23 @@ namespace Kernel void Pipe::clone_writing() { - LockGuard _(m_mutex); - ASSERT(m_writing_count > 0); - m_writing_count++; + [[maybe_unused]] auto old_writing_count = m_writing_count.fetch_add(1); + ASSERT(old_writing_count > 0); } void Pipe::close_writing() { - LockGuard _(m_mutex); - ASSERT(m_writing_count > 0); - m_writing_count--; - if (m_writing_count == 0) + auto old_writing_count = m_writing_count.fetch_sub(1); + ASSERT(old_writing_count > 0); + if (old_writing_count == 1) m_thread_blocker.unblock(); } BAN::ErrorOr Pipe::read_impl(off_t, BAN::ByteSpan buffer) { LockGuard _(m_mutex); - while (m_buffer.empty()) + + while (m_buffer_size == 0) { if (m_writing_count == 0) return 0; @@ -51,11 +52,20 @@ namespace Kernel TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker)); } - size_t to_copy = BAN::Math::min(buffer.size(), m_buffer.size()); - memcpy(buffer.data(), m_buffer.data(), to_copy); + const size_t to_copy = BAN::Math::min(buffer.size(), m_buffer_size); - memmove(m_buffer.data(), m_buffer.data() + to_copy, m_buffer.size() - to_copy); - MUST(m_buffer.resize(m_buffer.size() - to_copy)); + if (m_buffer_tail + to_copy <= m_buffer.size()) + memcpy(buffer.data(), m_buffer.data() + m_buffer_tail, to_copy); + else + { + const size_t before_wrap = m_buffer.size() - m_buffer_tail; + const size_t after_wrap = to_copy - before_wrap; + memcpy(buffer.data(), m_buffer.data() + m_buffer_tail, before_wrap); + memcpy(buffer.data() + before_wrap, m_buffer.data(), after_wrap); + } + + m_buffer_tail = (m_buffer_tail + to_copy) % m_buffer.size(); + m_buffer_size -= to_copy; m_atime = SystemTimer::get().real_time(); @@ -68,10 +78,29 @@ namespace Kernel { LockGuard _(m_mutex); - size_t old_size = m_buffer.size(); + if (buffer.size() > m_buffer.size()) + buffer = buffer.slice(0, m_buffer.size()); - TRY(m_buffer.resize(old_size + buffer.size())); - memcpy(m_buffer.data() + old_size, buffer.data(), buffer.size()); + while (m_buffer.size() - m_buffer_size < buffer.size()) + { + LockFreeGuard lock_free(m_mutex); + TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker)); + } + + const size_t to_copy = buffer.size(); + const size_t buffer_head = (m_buffer_tail + m_buffer_size) % m_buffer.size(); + + if (buffer_head + to_copy <= m_buffer.size()) + memcpy(m_buffer.data() + buffer_head, buffer.data(), to_copy); + else + { + const size_t before_wrap = m_buffer.size() - buffer_head; + const size_t after_wrap = to_copy - before_wrap; + memcpy(m_buffer.data() + buffer_head, buffer.data(), before_wrap); + memcpy(m_buffer.data(), buffer.data() + before_wrap, after_wrap); + } + + m_buffer_size += to_copy; timespec current_time = SystemTimer::get().real_time(); m_mtime = current_time; @@ -79,7 +108,7 @@ namespace Kernel m_thread_blocker.unblock(); - return buffer.size(); + return to_copy; } } diff --git a/kernel/kernel/OpenFileDescriptorSet.cpp b/kernel/kernel/OpenFileDescriptorSet.cpp index e3a9e388..58b0dbf4 100644 --- a/kernel/kernel/OpenFileDescriptorSet.cpp +++ b/kernel/kernel/OpenFileDescriptorSet.cpp @@ -48,8 +48,11 @@ namespace Kernel m_open_files[fd] = result.release_value(); - if (m_open_files[fd]->flags & O_WRONLY && m_open_files[fd]->inode->is_pipe()) - ((Pipe*)m_open_files[fd]->inode.ptr())->clone_writing(); + if (m_open_files[fd]->path == ""_sv) + { + ASSERT(m_open_files[fd]->inode->is_pipe()); + static_cast(m_open_files[fd]->inode.ptr())->clone_writing(); + } } return {}; @@ -59,7 +62,7 @@ namespace Kernel { ASSERT(file.inode); - if (flags & ~(O_ACCMODE | O_NOFOLLOW | O_APPEND | O_TRUNC | O_CLOEXEC | O_TTY_INIT | O_DIRECTORY | O_CREAT | O_EXCL | O_NONBLOCK)) + if (flags & ~(O_ACCMODE | O_NOFOLLOW | O_APPEND | O_TRUNC | O_CLOEXEC | O_TTY_INIT | O_NOCTTY | O_DIRECTORY | O_CREAT | O_EXCL | O_NONBLOCK)) return BAN::Error::from_errno(ENOTSUP); if ((flags & O_ACCMODE) != O_RDWR && __builtin_popcount(flags & O_ACCMODE) != 1) @@ -139,8 +142,8 @@ namespace Kernel TRY(get_free_fd_pair(fds)); auto pipe = TRY(Pipe::create(m_credentials)); - m_open_files[fds[0]] = TRY(BAN::RefPtr::create(pipe, ""_sv, 0, O_RDONLY)); - m_open_files[fds[1]] = TRY(BAN::RefPtr::create(pipe, ""_sv, 0, O_WRONLY)); + m_open_files[fds[0]] = TRY(BAN::RefPtr::create(pipe, ""_sv, 0, O_RDONLY)); + m_open_files[fds[1]] = TRY(BAN::RefPtr::create(pipe, ""_sv, 0, O_WRONLY)); return {}; } @@ -152,8 +155,11 @@ namespace Kernel int result = TRY(get_free_fd()); m_open_files[result] = m_open_files[fildes]; - if (m_open_files[result]->flags & O_WRONLY && m_open_files[result]->inode->is_pipe()) - ((Pipe*)m_open_files[result]->inode.ptr())->clone_writing(); + if (m_open_files[result]->path == ""_sv) + { + ASSERT(m_open_files[result]->inode->is_pipe()); + static_cast(m_open_files[result]->inode.ptr())->clone_writing(); + } return result; } @@ -172,8 +178,11 @@ namespace Kernel m_open_files[fildes2] = m_open_files[fildes]; m_open_files[fildes2]->flags &= ~O_CLOEXEC; - if (m_open_files[fildes]->flags & O_WRONLY && m_open_files[fildes]->inode->is_pipe()) - ((Pipe*)m_open_files[fildes]->inode.ptr())->clone_writing(); + if (m_open_files[fildes2]->path == ""_sv) + { + ASSERT(m_open_files[fildes2]->inode->is_pipe()); + static_cast(m_open_files[fildes2]->inode.ptr())->clone_writing(); + } return fildes; } @@ -303,8 +312,11 @@ namespace Kernel { TRY(validate_fd(fd)); - if (m_open_files[fd]->flags & O_WRONLY && m_open_files[fd]->inode->is_pipe()) - ((Pipe*)m_open_files[fd]->inode.ptr())->close_writing(); + if (m_open_files[fd]->path == ""_sv) + { + ASSERT(m_open_files[fd]->inode->is_pipe()); + static_cast(m_open_files[fd]->inode.ptr())->close_writing(); + } m_open_files[fd].clear();