Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <AK/HashTable.h>
28#include <AK/StdLibExtras.h>
29#include <AK/StringView.h>
30#include <Kernel/FileSystem/FIFO.h>
31#include <Kernel/FileSystem/FileDescription.h>
32#include <Kernel/Lock.h>
33#include <Kernel/Process.h>
34#include <Kernel/Thread.h>
35
36//#define FIFO_DEBUG
37
38namespace Kernel {
39
40Lockable<HashTable<FIFO*>>& all_fifos()
41{
42 static Lockable<HashTable<FIFO*>>* s_table;
43 if (!s_table)
44 s_table = new Lockable<HashTable<FIFO*>>;
45 return *s_table;
46}
47
48static int s_next_fifo_id = 1;
49
50NonnullRefPtr<FIFO> FIFO::create(uid_t uid)
51{
52 return adopt(*new FIFO(uid));
53}
54
55NonnullRefPtr<FileDescription> FIFO::open_direction(FIFO::Direction direction)
56{
57 auto description = FileDescription::create(*this);
58 attach(direction);
59 description->set_fifo_direction({}, direction);
60 return description;
61}
62
63FIFO::FIFO(uid_t uid)
64 : m_uid(uid)
65{
66 LOCKER(all_fifos().lock());
67 all_fifos().resource().set(this);
68 m_fifo_id = ++s_next_fifo_id;
69}
70
71FIFO::~FIFO()
72{
73 LOCKER(all_fifos().lock());
74 all_fifos().resource().remove(this);
75}
76
77void FIFO::attach(Direction direction)
78{
79 if (direction == Direction::Reader) {
80 ++m_readers;
81#ifdef FIFO_DEBUG
82 klog() << "open reader (" << m_readers << ")";
83#endif
84 } else if (direction == Direction::Writer) {
85 ++m_writers;
86#ifdef FIFO_DEBUG
87 klog() << "open writer (" << m_writers << ")";
88#endif
89 }
90}
91
92void FIFO::detach(Direction direction)
93{
94 if (direction == Direction::Reader) {
95#ifdef FIFO_DEBUG
96 klog() << "close reader (" << m_readers << " - 1)";
97#endif
98 ASSERT(m_readers);
99 --m_readers;
100 } else if (direction == Direction::Writer) {
101#ifdef FIFO_DEBUG
102 klog() << "close writer (" << m_writers << " - 1)";
103#endif
104 ASSERT(m_writers);
105 --m_writers;
106 }
107}
108
109bool FIFO::can_read(const FileDescription&) const
110{
111 return !m_buffer.is_empty() || !m_writers;
112}
113
114bool FIFO::can_write(const FileDescription&) const
115{
116 return m_buffer.space_for_writing() || !m_readers;
117}
118
119ssize_t FIFO::read(FileDescription&, u8* buffer, ssize_t size)
120{
121 if (!m_writers && m_buffer.is_empty())
122 return 0;
123#ifdef FIFO_DEBUG
124 dbg() << "fifo: read(" << size << ")\n";
125#endif
126 ssize_t nread = m_buffer.read(buffer, size);
127#ifdef FIFO_DEBUG
128 dbg() << " -> read (" << String::format("%c", buffer[0]) << ") " << nread;
129#endif
130 return nread;
131}
132
133ssize_t FIFO::write(FileDescription&, const u8* buffer, ssize_t size)
134{
135 if (!m_readers) {
136 Thread::current->send_signal(SIGPIPE, Process::current);
137 return -EPIPE;
138 }
139#ifdef FIFO_DEBUG
140 dbg() << "fifo: write(" << (const void*)buffer << ", " << size << ")";
141#endif
142 return m_buffer.write(buffer, size);
143}
144
145String FIFO::absolute_path(const FileDescription&) const
146{
147 return String::format("fifo:%u", m_fifo_id);
148}
149
150}