mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 06:58:11 +00:00
Deallocate PTY's when they close.
This required a fair bit of plumbing. The CharacterDevice::close() virtual will now be closed by ~FileDescriptor(), allowing device implementations to do custom cleanup at that point. One big problem remains: if the master PTY is closed before the slave PTY, we go into crashy land.
This commit is contained in:
parent
027d26cd5d
commit
b4e478aa50
19 changed files with 104 additions and 12 deletions
7
AK/Badge.h
Normal file
7
AK/Badge.h
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Badge {
|
||||||
|
friend T;
|
||||||
|
Badge() { }
|
||||||
|
};
|
|
@ -10,6 +10,10 @@ RetainPtr<FileDescriptor> CharacterDevice::open(int& error, int options)
|
||||||
return VFS::the().open(*this, error, options);
|
return VFS::the().open(*this, error, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CharacterDevice::close()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
int CharacterDevice::ioctl(Process&, unsigned, unsigned)
|
int CharacterDevice::ioctl(Process&, unsigned, unsigned)
|
||||||
{
|
{
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
|
|
|
@ -14,6 +14,7 @@ public:
|
||||||
InodeMetadata metadata() const { return { }; }
|
InodeMetadata metadata() const { return { }; }
|
||||||
|
|
||||||
virtual RetainPtr<FileDescriptor> open(int& error, int options);
|
virtual RetainPtr<FileDescriptor> open(int& error, int options);
|
||||||
|
virtual void close();
|
||||||
|
|
||||||
virtual bool can_read(Process&) const = 0;
|
virtual bool can_read(Process&) const = 0;
|
||||||
virtual bool can_write(Process&) const = 0;
|
virtual bool can_write(Process&) const = 0;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "DevPtsFS.h"
|
#include <Kernel/DevPtsFS.h>
|
||||||
|
#include <Kernel/SlavePTY.h>
|
||||||
#include <Kernel/VirtualFileSystem.h>
|
#include <Kernel/VirtualFileSystem.h>
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "SlavePTY.h"
|
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <Kernel/SyntheticFileSystem.h>
|
#include <Kernel/SyntheticFileSystem.h>
|
||||||
|
|
||||||
class Process;
|
class Process;
|
||||||
|
class SlavePTY;
|
||||||
|
|
||||||
class DevPtsFS final : public SynthFS {
|
class DevPtsFS final : public SynthFS {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -40,8 +40,15 @@ FileDescriptor::FileDescriptor(RetainPtr<CharacterDevice>&& device)
|
||||||
|
|
||||||
FileDescriptor::~FileDescriptor()
|
FileDescriptor::~FileDescriptor()
|
||||||
{
|
{
|
||||||
if (m_fifo)
|
if (m_device) {
|
||||||
|
m_device->close();
|
||||||
|
m_device = nullptr;
|
||||||
|
}
|
||||||
|
if (m_fifo) {
|
||||||
m_fifo->close(fifo_direction());
|
m_fifo->close(fifo_direction());
|
||||||
|
m_fifo = nullptr;
|
||||||
|
}
|
||||||
|
m_inode = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
RetainPtr<FileDescriptor> FileDescriptor::clone()
|
RetainPtr<FileDescriptor> FileDescriptor::clone()
|
||||||
|
|
|
@ -86,5 +86,7 @@ private:
|
||||||
|
|
||||||
RetainPtr<FIFO> m_fifo;
|
RetainPtr<FIFO> m_fifo;
|
||||||
FIFO::Direction m_fifo_direction { FIFO::Neither };
|
FIFO::Direction m_fifo_direction { FIFO::Neither };
|
||||||
|
|
||||||
|
bool m_closed { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
#include "MasterPTY.h"
|
#include "MasterPTY.h"
|
||||||
#include "SlavePTY.h"
|
#include "SlavePTY.h"
|
||||||
|
#include "PTYMultiplexer.h"
|
||||||
|
#include <LibC/errno_numbers.h>
|
||||||
|
|
||||||
MasterPTY::MasterPTY(unsigned index)
|
MasterPTY::MasterPTY(unsigned index)
|
||||||
: CharacterDevice(10, index)
|
: CharacterDevice(10, index)
|
||||||
, m_slave(*new SlavePTY(*this, index))
|
, m_slave(adopt(*new SlavePTY(*this, index)))
|
||||||
, m_index(index)
|
, m_index(index)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MasterPTY::~MasterPTY()
|
MasterPTY::~MasterPTY()
|
||||||
{
|
{
|
||||||
|
PTYMultiplexer::the().notify_master_destroyed(Badge<MasterPTY>(), m_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
String MasterPTY::pts_name() const
|
String MasterPTY::pts_name() const
|
||||||
|
@ -19,17 +22,23 @@ String MasterPTY::pts_name() const
|
||||||
|
|
||||||
ssize_t MasterPTY::read(Process&, byte* buffer, size_t size)
|
ssize_t MasterPTY::read(Process&, byte* buffer, size_t size)
|
||||||
{
|
{
|
||||||
|
if (!m_slave && m_buffer.is_empty())
|
||||||
|
return 0;
|
||||||
return m_buffer.read(buffer, size);
|
return m_buffer.read(buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t MasterPTY::write(Process&, const byte* buffer, size_t size)
|
ssize_t MasterPTY::write(Process&, const byte* buffer, size_t size)
|
||||||
{
|
{
|
||||||
m_slave.on_master_write(buffer, size);
|
if (!m_slave)
|
||||||
|
return -EIO;
|
||||||
|
m_slave->on_master_write(buffer, size);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MasterPTY::can_read(Process&) const
|
bool MasterPTY::can_read(Process&) const
|
||||||
{
|
{
|
||||||
|
if (!m_slave)
|
||||||
|
return true;
|
||||||
return !m_buffer.is_empty();
|
return !m_buffer.is_empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +47,15 @@ bool MasterPTY::can_write(Process&) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MasterPTY::notify_slave_closed(Badge<SlavePTY>)
|
||||||
|
{
|
||||||
|
dbgprintf("MasterPTY(%u): slave closed, my retains: %u, slave retains: %u\n", m_index, retain_count(), m_slave->retain_count());
|
||||||
|
// +1 retain for my MasterPTY::m_slave
|
||||||
|
// +1 retain for FileDescriptor::m_device
|
||||||
|
if (m_slave->retain_count() == 2)
|
||||||
|
m_slave = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void MasterPTY::on_slave_write(const byte* data, size_t size)
|
void MasterPTY::on_slave_write(const byte* data, size_t size)
|
||||||
{
|
{
|
||||||
m_buffer.write(data, size);
|
m_buffer.write(data, size);
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Badge.h>
|
||||||
#include <Kernel/CharacterDevice.h>
|
#include <Kernel/CharacterDevice.h>
|
||||||
#include "DoubleBuffer.h"
|
#include <Kernel/DoubleBuffer.h>
|
||||||
|
|
||||||
class SlavePTY;
|
class SlavePTY;
|
||||||
|
|
||||||
|
@ -21,12 +22,13 @@ public:
|
||||||
String pts_name() const;
|
String pts_name() const;
|
||||||
void on_slave_write(const byte*, size_t);
|
void on_slave_write(const byte*, size_t);
|
||||||
bool can_write_from_slave() const;
|
bool can_write_from_slave() const;
|
||||||
|
void notify_slave_closed(Badge<SlavePTY>);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// ^CharacterDevice
|
// ^CharacterDevice
|
||||||
virtual const char* class_name() const override { return "MasterPTY"; }
|
virtual const char* class_name() const override { return "MasterPTY"; }
|
||||||
|
|
||||||
SlavePTY& m_slave;
|
RetainPtr<SlavePTY> m_slave;
|
||||||
unsigned m_index;
|
unsigned m_index;
|
||||||
DoubleBuffer m_buffer;
|
DoubleBuffer m_buffer;
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,10 +3,23 @@
|
||||||
#include <LibC/errno_numbers.h>
|
#include <LibC/errno_numbers.h>
|
||||||
|
|
||||||
static const unsigned s_max_pty_pairs = 8;
|
static const unsigned s_max_pty_pairs = 8;
|
||||||
|
static PTYMultiplexer* s_the;
|
||||||
|
|
||||||
|
PTYMultiplexer& PTYMultiplexer::the()
|
||||||
|
{
|
||||||
|
ASSERT(s_the);
|
||||||
|
return *s_the;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PTYMultiplexer::initialize_statics()
|
||||||
|
{
|
||||||
|
s_the = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
PTYMultiplexer::PTYMultiplexer()
|
PTYMultiplexer::PTYMultiplexer()
|
||||||
: CharacterDevice(5, 2)
|
: CharacterDevice(5, 2)
|
||||||
{
|
{
|
||||||
|
s_the = this;
|
||||||
m_freelist.ensure_capacity(s_max_pty_pairs);
|
m_freelist.ensure_capacity(s_max_pty_pairs);
|
||||||
for (int i = s_max_pty_pairs; i > 0; --i)
|
for (int i = s_max_pty_pairs; i > 0; --i)
|
||||||
m_freelist.unchecked_append(i - 1);
|
m_freelist.unchecked_append(i - 1);
|
||||||
|
@ -28,3 +41,10 @@ RetainPtr<FileDescriptor> PTYMultiplexer::open(int& error, int options)
|
||||||
dbgprintf("PTYMultiplexer::open: Vending master %u\n", master->index());
|
dbgprintf("PTYMultiplexer::open: Vending master %u\n", master->index());
|
||||||
return VFS::the().open(move(master), error, options);
|
return VFS::the().open(move(master), error, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PTYMultiplexer::notify_master_destroyed(Badge<MasterPTY>, unsigned index)
|
||||||
|
{
|
||||||
|
LOCKER(m_lock);
|
||||||
|
m_freelist.append(index);
|
||||||
|
dbgprintf("PTYMultiplexer: %u added to freelist\n", index);
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Kernel/CharacterDevice.h>
|
#include <Kernel/CharacterDevice.h>
|
||||||
|
#include <AK/Badge.h>
|
||||||
#include <AK/Lock.h>
|
#include <AK/Lock.h>
|
||||||
|
|
||||||
class MasterPTY;
|
class MasterPTY;
|
||||||
|
@ -11,6 +12,9 @@ public:
|
||||||
PTYMultiplexer();
|
PTYMultiplexer();
|
||||||
virtual ~PTYMultiplexer() override;
|
virtual ~PTYMultiplexer() override;
|
||||||
|
|
||||||
|
static PTYMultiplexer& the();
|
||||||
|
static void initialize_statics();
|
||||||
|
|
||||||
// ^CharacterDevice
|
// ^CharacterDevice
|
||||||
virtual RetainPtr<FileDescriptor> open(int& error, int options) override;
|
virtual RetainPtr<FileDescriptor> open(int& error, int options) override;
|
||||||
virtual ssize_t read(Process&, byte*, size_t) override { return 0; }
|
virtual ssize_t read(Process&, byte*, size_t) override { return 0; }
|
||||||
|
@ -18,6 +22,8 @@ public:
|
||||||
virtual bool can_read(Process&) const override { return true; }
|
virtual bool can_read(Process&) const override { return true; }
|
||||||
virtual bool can_write(Process&) const override { return true; }
|
virtual bool can_write(Process&) const override { return true; }
|
||||||
|
|
||||||
|
void notify_master_destroyed(Badge<MasterPTY>, unsigned index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// ^CharacterDevice
|
// ^CharacterDevice
|
||||||
virtual const char* class_name() const override { return "PTYMultiplexer"; }
|
virtual const char* class_name() const override { return "PTYMultiplexer"; }
|
||||||
|
|
|
@ -735,7 +735,7 @@ void Process::sys$exit(int status)
|
||||||
kprintf("sys$exit: %s(%u) exit with status %d\n", name().characters(), pid(), status);
|
kprintf("sys$exit: %s(%u) exit with status %d\n", name().characters(), pid(), status);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
set_state(Dead);
|
die();
|
||||||
m_termination_status = status;
|
m_termination_status = status;
|
||||||
m_termination_signal = 0;
|
m_termination_signal = 0;
|
||||||
|
|
||||||
|
@ -750,7 +750,7 @@ void Process::terminate_due_to_signal(byte signal)
|
||||||
dbgprintf("terminate_due_to_signal %s(%u) <- %u\n", name().characters(), pid(), signal);
|
dbgprintf("terminate_due_to_signal %s(%u) <- %u\n", name().characters(), pid(), signal);
|
||||||
m_termination_status = 0;
|
m_termination_status = 0;
|
||||||
m_termination_signal = signal;
|
m_termination_signal = signal;
|
||||||
set_state(Dead);
|
die();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process::send_signal(byte signal, Process* sender)
|
void Process::send_signal(byte signal, Process* sender)
|
||||||
|
@ -935,8 +935,8 @@ void Process::crash()
|
||||||
ASSERT_INTERRUPTS_DISABLED();
|
ASSERT_INTERRUPTS_DISABLED();
|
||||||
ASSERT(state() != Dead);
|
ASSERT(state() != Dead);
|
||||||
m_termination_signal = SIGSEGV;
|
m_termination_signal = SIGSEGV;
|
||||||
set_state(Dead);
|
|
||||||
dumpRegions();
|
dumpRegions();
|
||||||
|
die();
|
||||||
Scheduler::pick_next_and_switch_now();
|
Scheduler::pick_next_and_switch_now();
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
@ -2130,3 +2130,9 @@ int Process::sys$chmod(const char* pathname, mode_t mode)
|
||||||
return error;
|
return error;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Process::die()
|
||||||
|
{
|
||||||
|
set_state(Dead);
|
||||||
|
m_fds.clear();
|
||||||
|
}
|
||||||
|
|
|
@ -128,6 +128,7 @@ public:
|
||||||
|
|
||||||
void setSelector(word s) { m_farPtr.selector = s; }
|
void setSelector(word s) { m_farPtr.selector = s; }
|
||||||
void set_state(State s) { m_state = s; }
|
void set_state(State s) { m_state = s; }
|
||||||
|
void die();
|
||||||
|
|
||||||
pid_t sys$setsid();
|
pid_t sys$setsid();
|
||||||
pid_t sys$getsid(pid_t);
|
pid_t sys$getsid(pid_t);
|
||||||
|
@ -315,7 +316,7 @@ private:
|
||||||
struct FileDescriptorAndFlags {
|
struct FileDescriptorAndFlags {
|
||||||
operator bool() const { return !!descriptor; }
|
operator bool() const { return !!descriptor; }
|
||||||
void clear() { descriptor = nullptr; flags = 0; }
|
void clear() { descriptor = nullptr; flags = 0; }
|
||||||
void set(RetainPtr<FileDescriptor>&& d, dword f = 0) { descriptor = move(d), flags = f; }
|
void set(RetainPtr<FileDescriptor>&& d, dword f = 0) { descriptor = move(d); flags = f; }
|
||||||
RetainPtr<FileDescriptor> descriptor;
|
RetainPtr<FileDescriptor> descriptor;
|
||||||
dword flags { 0 };
|
dword flags { 0 };
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,6 +15,7 @@ SlavePTY::SlavePTY(MasterPTY& master, unsigned index)
|
||||||
SlavePTY::~SlavePTY()
|
SlavePTY::~SlavePTY()
|
||||||
{
|
{
|
||||||
DevPtsFS::the().unregister_slave_pty(*this);
|
DevPtsFS::the().unregister_slave_pty(*this);
|
||||||
|
VFS::the().unregister_character_device(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
String SlavePTY::tty_name() const
|
String SlavePTY::tty_name() const
|
||||||
|
@ -37,3 +38,8 @@ bool SlavePTY::can_write(Process&) const
|
||||||
{
|
{
|
||||||
return m_master.can_write_from_slave();
|
return m_master.can_write_from_slave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SlavePTY::close()
|
||||||
|
{
|
||||||
|
m_master.notify_slave_closed(Badge<SlavePTY>());
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ private:
|
||||||
// ^CharacterDevice
|
// ^CharacterDevice
|
||||||
virtual bool can_write(Process&) const override;
|
virtual bool can_write(Process&) const override;
|
||||||
virtual const char* class_name() const override { return "SlavePTY"; }
|
virtual const char* class_name() const override { return "SlavePTY"; }
|
||||||
|
virtual void close() override;
|
||||||
|
|
||||||
friend class MasterPTY;
|
friend class MasterPTY;
|
||||||
SlavePTY(MasterPTY&, unsigned index);
|
SlavePTY(MasterPTY&, unsigned index);
|
||||||
|
|
|
@ -510,6 +510,11 @@ void VFS::register_character_device(CharacterDevice& device)
|
||||||
m_character_devices.set(encodedDevice(device.major(), device.minor()), &device);
|
m_character_devices.set(encodedDevice(device.major(), device.minor()), &device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VFS::unregister_character_device(CharacterDevice& device)
|
||||||
|
{
|
||||||
|
m_character_devices.remove(encodedDevice(device.major(), device.minor()));
|
||||||
|
}
|
||||||
|
|
||||||
void VFS::for_each_mount(Function<void(const Mount&)> callback) const
|
void VFS::for_each_mount(Function<void(const Mount&)> callback) const
|
||||||
{
|
{
|
||||||
for (auto& mount : m_mounts) {
|
for (auto& mount : m_mounts) {
|
||||||
|
|
|
@ -72,6 +72,7 @@ public:
|
||||||
bool chmod(const String& path, mode_t, Inode& base, int& error);
|
bool chmod(const String& path, mode_t, Inode& base, int& error);
|
||||||
|
|
||||||
void register_character_device(CharacterDevice&);
|
void register_character_device(CharacterDevice&);
|
||||||
|
void unregister_character_device(CharacterDevice&);
|
||||||
|
|
||||||
size_t mount_count() const { return m_mounts.size(); }
|
size_t mount_count() const { return m_mounts.size(); }
|
||||||
void for_each_mount(Function<void(const Mount&)>) const;
|
void for_each_mount(Function<void(const Mount&)>) const;
|
||||||
|
|
|
@ -142,6 +142,7 @@ void init()
|
||||||
gdt_init();
|
gdt_init();
|
||||||
idt_init();
|
idt_init();
|
||||||
|
|
||||||
|
PTYMultiplexer::initialize_statics();
|
||||||
VFS::initialize_globals();
|
VFS::initialize_globals();
|
||||||
vfs = new VFS;
|
vfs = new VFS;
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,10 @@ int main(int, char**)
|
||||||
perror("read(ptm)");
|
perror("read(ptm)");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
assert(nread != 0);
|
if (nread == 0) {
|
||||||
|
dbgprintf("Terminal: EOF on master pty, closing.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
for (ssize_t i = 0; i < nread; ++i)
|
for (ssize_t i = 0; i < nread; ++i)
|
||||||
terminal.on_char(buffer[i]);
|
terminal.on_char(buffer[i]);
|
||||||
terminal.update();
|
terminal.update();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue