Serenity Operating System
at master 143 lines 3.4 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Atomic.h> 8#include <AK/StdLibExtras.h> 9#include <Kernel/FileSystem/FIFO.h> 10#include <Kernel/FileSystem/OpenFileDescription.h> 11#include <Kernel/Locking/Mutex.h> 12#include <Kernel/Process.h> 13#include <Kernel/Thread.h> 14 15namespace Kernel { 16 17static Atomic<int> s_next_fifo_id = 1; 18 19ErrorOr<NonnullRefPtr<FIFO>> FIFO::try_create(UserID uid) 20{ 21 auto buffer = TRY(DoubleBuffer::try_create("FIFO: Buffer"sv)); 22 return adopt_nonnull_ref_or_enomem(new (nothrow) FIFO(uid, move(buffer))); 23} 24 25ErrorOr<NonnullRefPtr<OpenFileDescription>> FIFO::open_direction(FIFO::Direction direction) 26{ 27 auto description = TRY(OpenFileDescription::try_create(*this)); 28 attach(direction); 29 description->set_fifo_direction({}, direction); 30 return description; 31} 32 33ErrorOr<NonnullRefPtr<OpenFileDescription>> FIFO::open_direction_blocking(FIFO::Direction direction) 34{ 35 MutexLocker locker(m_open_lock); 36 37 auto description = TRY(open_direction(direction)); 38 39 if (direction == Direction::Reader) { 40 m_read_open_queue.wake_all(); 41 42 if (m_writers == 0) { 43 locker.unlock(); 44 m_write_open_queue.wait_forever("FIFO"sv); 45 locker.lock(); 46 } 47 } 48 49 if (direction == Direction::Writer) { 50 m_write_open_queue.wake_all(); 51 52 if (m_readers == 0) { 53 locker.unlock(); 54 m_read_open_queue.wait_forever("FIFO"sv); 55 locker.lock(); 56 } 57 } 58 59 return description; 60} 61 62FIFO::FIFO(UserID uid, NonnullOwnPtr<DoubleBuffer> buffer) 63 : m_buffer(move(buffer)) 64 , m_uid(uid) 65{ 66 m_fifo_id = ++s_next_fifo_id; 67 68 // Use the same block condition for read and write 69 m_buffer->set_unblock_callback([this]() { 70 evaluate_block_conditions(); 71 }); 72} 73 74FIFO::~FIFO() = default; 75 76void FIFO::attach(Direction direction) 77{ 78 if (direction == Direction::Reader) { 79 ++m_readers; 80 } else if (direction == Direction::Writer) { 81 ++m_writers; 82 } 83 84 evaluate_block_conditions(); 85} 86 87void FIFO::detach(Direction direction) 88{ 89 if (direction == Direction::Reader) { 90 VERIFY(m_readers); 91 --m_readers; 92 } else if (direction == Direction::Writer) { 93 VERIFY(m_writers); 94 --m_writers; 95 } 96 97 evaluate_block_conditions(); 98} 99 100bool FIFO::can_read(OpenFileDescription const&, u64) const 101{ 102 return !m_buffer->is_empty() || !m_writers; 103} 104 105bool FIFO::can_write(OpenFileDescription const&, u64) const 106{ 107 return m_buffer->space_for_writing() || !m_readers; 108} 109 110ErrorOr<size_t> FIFO::read(OpenFileDescription& fd, u64, UserOrKernelBuffer& buffer, size_t size) 111{ 112 if (m_buffer->is_empty()) { 113 if (!m_writers) 114 return 0; 115 if (!fd.is_blocking()) 116 return EAGAIN; 117 } 118 return m_buffer->read(buffer, size); 119} 120 121ErrorOr<size_t> FIFO::write(OpenFileDescription& fd, u64, UserOrKernelBuffer const& buffer, size_t size) 122{ 123 if (!m_readers) 124 return EPIPE; 125 if (!fd.is_blocking() && m_buffer->space_for_writing() == 0) 126 return EAGAIN; 127 128 return m_buffer->write(buffer, size); 129} 130 131ErrorOr<NonnullOwnPtr<KString>> FIFO::pseudo_path(OpenFileDescription const&) const 132{ 133 return KString::formatted("fifo:{}", m_fifo_id); 134} 135 136ErrorOr<struct stat> FIFO::stat() const 137{ 138 struct stat st = {}; 139 st.st_mode = S_IFIFO; 140 return st; 141} 142 143}