mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 14:28:12 +00:00

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 :^)
109 lines
2.5 KiB
C++
109 lines
2.5 KiB
C++
#include "MasterPTY.h"
|
|
#include "PTYMultiplexer.h"
|
|
#include "SlavePTY.h"
|
|
#include <Kernel/Process.h>
|
|
#include <LibC/errno_numbers.h>
|
|
#include <LibC/signal_numbers.h>
|
|
#include <LibC/sys/ioctl_numbers.h>
|
|
|
|
//#define MASTERPTY_DEBUG
|
|
|
|
MasterPTY::MasterPTY(unsigned index)
|
|
: CharacterDevice(10, index)
|
|
, m_slave(adopt(*new SlavePTY(*this, index)))
|
|
, m_index(index)
|
|
{
|
|
m_pts_name = String::format("/dev/pts/%u", m_index);
|
|
set_uid(current->process().uid());
|
|
set_gid(current->process().gid());
|
|
}
|
|
|
|
MasterPTY::~MasterPTY()
|
|
{
|
|
#ifdef MASTERPTY_DEBUG
|
|
dbgprintf("~MasterPTY(%u)\n", m_index);
|
|
#endif
|
|
PTYMultiplexer::the().notify_master_destroyed({}, m_index);
|
|
}
|
|
|
|
String MasterPTY::pts_name() const
|
|
{
|
|
return m_pts_name;
|
|
}
|
|
|
|
ssize_t MasterPTY::read(FileDescription&, u8* buffer, ssize_t size)
|
|
{
|
|
if (!m_slave && m_buffer.is_empty())
|
|
return 0;
|
|
return m_buffer.read(buffer, size);
|
|
}
|
|
|
|
ssize_t MasterPTY::write(FileDescription&, const u8* buffer, ssize_t size)
|
|
{
|
|
if (!m_slave)
|
|
return -EIO;
|
|
m_slave->on_master_write(buffer, size);
|
|
return size;
|
|
}
|
|
|
|
bool MasterPTY::can_read(FileDescription&) const
|
|
{
|
|
if (!m_slave)
|
|
return true;
|
|
return !m_buffer.is_empty();
|
|
}
|
|
|
|
bool MasterPTY::can_write(FileDescription&) const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void MasterPTY::notify_slave_closed(Badge<SlavePTY>)
|
|
{
|
|
#ifdef MASTERPTY_DEBUG
|
|
dbgprintf("MasterPTY(%u): slave closed, my retains: %u, slave retains: %u\n", m_index, ref_count(), m_slave->ref_count());
|
|
#endif
|
|
// +1 ref for my MasterPTY::m_slave
|
|
// +1 ref for FileDescription::m_device
|
|
if (m_slave->ref_count() == 2)
|
|
m_slave = nullptr;
|
|
}
|
|
|
|
ssize_t MasterPTY::on_slave_write(const u8* data, ssize_t size)
|
|
{
|
|
if (m_closed)
|
|
return -EIO;
|
|
m_buffer.write(data, size);
|
|
return size;
|
|
}
|
|
|
|
bool MasterPTY::can_write_from_slave() const
|
|
{
|
|
if (m_closed)
|
|
return true;
|
|
return m_buffer.space_for_writing();
|
|
}
|
|
|
|
void MasterPTY::close()
|
|
{
|
|
if (ref_count() == 2) {
|
|
InterruptDisabler disabler;
|
|
// After the closing FileDescription dies, slave is the only thing keeping me alive.
|
|
// From this point, let's consider ourselves closed.
|
|
m_closed = true;
|
|
|
|
m_slave->hang_up();
|
|
}
|
|
}
|
|
|
|
int MasterPTY::ioctl(FileDescription& description, unsigned request, unsigned arg)
|
|
{
|
|
if (request == TIOCSWINSZ)
|
|
return m_slave->ioctl(description, request, arg);
|
|
return -EINVAL;
|
|
}
|
|
|
|
String MasterPTY::absolute_path(const FileDescription&) const
|
|
{
|
|
return String::format("ptm:%s", m_pts_name.characters());
|
|
}
|