1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-28 13:45:07 +00:00
serenity/Kernel/FileSystem/FIFO.cpp
Andreas Kling 1cca5142af Kernel: Make DoubleBuffer use a KBuffer instead of kmalloc()ing
Background: DoubleBuffer is a handy buffer class in the kernel that
allows you to keep writing to it from the "outside" while the "inside"
reads from it. It's used for things like LocalSocket and PTY's.
Internally, it has a read buffer and a write buffer, but the two will
swap places when the read buffer is exhausted (by reading from it.)

Before this patch, it was internally implemented as two Vector<u8>
that we would swap between when the reader side had exhausted the data
in the read buffer. Now instead we preallocate a large KBuffer (64KB*2)
on DoubleBuffer construction and use that throughout its lifetime.

This removes all the kmalloc heap traffic caused by DoubleBuffers :^)
2019-10-18 14:55:04 +02:00

125 lines
2.8 KiB
C++

#include <AK/HashTable.h>
#include <AK/StdLibExtras.h>
#include <Kernel/FileSystem/FIFO.h>
#include <Kernel/FileSystem/FileDescription.h>
#include <Kernel/Lock.h>
#include <Kernel/Process.h>
#include <Kernel/Thread.h>
//#define FIFO_DEBUG
Lockable<HashTable<FIFO*>>& all_fifos()
{
static Lockable<HashTable<FIFO*>>* s_table;
if (!s_table)
s_table = new Lockable<HashTable<FIFO*>>;
return *s_table;
}
RefPtr<FIFO> FIFO::from_fifo_id(u32 id)
{
auto* ptr = reinterpret_cast<FIFO*>(id);
LOCKER(all_fifos().lock());
if (auto it = all_fifos().resource().find(ptr); it == all_fifos().resource().end())
return nullptr;
return ptr;
}
NonnullRefPtr<FIFO> FIFO::create(uid_t uid)
{
return adopt(*new FIFO(uid));
}
NonnullRefPtr<FileDescription> FIFO::open_direction(FIFO::Direction direction)
{
auto description = FileDescription::create(*this);
attach(direction);
description->set_fifo_direction({}, direction);
return description;
}
FIFO::FIFO(uid_t uid)
: m_uid(uid)
{
LOCKER(all_fifos().lock());
all_fifos().resource().set(this);
}
FIFO::~FIFO()
{
LOCKER(all_fifos().lock());
all_fifos().resource().remove(this);
}
void FIFO::attach(Direction direction)
{
if (direction == Direction::Reader) {
++m_readers;
#ifdef FIFO_DEBUG
kprintf("open reader (%u)\n", m_readers);
#endif
} else if (direction == Direction::Writer) {
++m_writers;
#ifdef FIFO_DEBUG
kprintf("open writer (%u)\n", m_writers);
#endif
}
}
void FIFO::detach(Direction direction)
{
if (direction == Direction::Reader) {
#ifdef FIFO_DEBUG
kprintf("close reader (%u - 1)\n", m_readers);
#endif
ASSERT(m_readers);
--m_readers;
} else if (direction == Direction::Writer) {
#ifdef FIFO_DEBUG
kprintf("close writer (%u - 1)\n", m_writers);
#endif
ASSERT(m_writers);
--m_writers;
}
}
bool FIFO::can_read(FileDescription&) const
{
return !m_buffer.is_empty() || !m_writers;
}
bool FIFO::can_write(FileDescription&) const
{
return m_buffer.space_for_writing() || !m_readers;
}
ssize_t FIFO::read(FileDescription&, u8* buffer, ssize_t size)
{
if (!m_writers && m_buffer.is_empty())
return 0;
#ifdef FIFO_DEBUG
dbgprintf("fifo: read(%u)\n", size);
#endif
ssize_t nread = m_buffer.read(buffer, size);
#ifdef FIFO_DEBUG
dbgprintf(" -> read (%c) %u\n", buffer[0], nread);
#endif
return nread;
}
ssize_t FIFO::write(FileDescription&, const u8* buffer, ssize_t size)
{
if (!m_readers) {
current->process().send_signal(SIGPIPE, &current->process());
return -EPIPE;
}
#ifdef FIFO_DEBUG
dbgprintf("fifo: write(%p, %u)\n", buffer, size);
#endif
return m_buffer.write(buffer, size);
}
String FIFO::absolute_path(const FileDescription&) const
{
return String::format("fifo:%u", this);
}