1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 20:17:44 +00:00

Add a PTY multiplexer (/dev/ptmx) device.

When you open /dev/ptmx, you get a file descriptor pointing to one of the
available MasterPTY's. If none are available, you get an EBUSY.

This makes it possible to open multiple (up to 4) Terminals. :^)

To support this, I also added a CharacterDevice::open() that gets control
when VFS is opening a CharacterDevice. This is useful when we want to return
a custom FileDescriptor like we do here.
This commit is contained in:
Andreas Kling 2019-01-16 13:36:10 +01:00
parent b46ae2bf09
commit 9dd29f9aa9
13 changed files with 75 additions and 37 deletions

View file

@ -19,6 +19,7 @@ KERNEL_OBJS = \
ProcFileSystem.o \
RTC.o \
TTY.o \
PTYMultiplexer.o \
MasterPTY.o \
SlavePTY.o \
VirtualConsole.o \

View file

@ -6,7 +6,6 @@
class SlavePTY;
class MasterPTY final : public CharacterDevice {
AK_MAKE_ETERNAL
public:
explicit MasterPTY(unsigned index);
virtual ~MasterPTY() override;
@ -17,6 +16,7 @@ public:
virtual bool can_write(Process&) const override;
virtual bool is_master_pty() const override { return true; }
unsigned index() const { return m_index; }
String pts_name() const;
void on_slave_write(const byte*, size_t);

27
Kernel/PTYMultiplexer.cpp Normal file
View file

@ -0,0 +1,27 @@
#include "PTYMultiplexer.h"
#include "MasterPTY.h"
#include <LibC/errno_numbers.h>
PTYMultiplexer::PTYMultiplexer()
: CharacterDevice(5, 2)
{
m_freelist.ensureCapacity(4);
for (int i = 4; i > 0; --i)
m_freelist.unchecked_append(adopt(*new MasterPTY(i - 1)));
}
PTYMultiplexer::~PTYMultiplexer()
{
}
RetainPtr<FileDescriptor> PTYMultiplexer::open(int& error, int options)
{
LOCKER(m_lock);
if (m_freelist.is_empty()) {
error = -EBUSY;
return nullptr;
}
auto master = m_freelist.takeLast();
dbgprintf("PTYMultiplexer::open: Vending master %u\n", master->index());
return VFS::the().open(move(master), error, options);
}

24
Kernel/PTYMultiplexer.h Normal file
View file

@ -0,0 +1,24 @@
#pragma once
#include <VirtualFileSystem/CharacterDevice.h>
#include <AK/Lock.h>
class MasterPTY;
class PTYMultiplexer final : public CharacterDevice {
AK_MAKE_ETERNAL
public:
PTYMultiplexer();
virtual ~PTYMultiplexer() override;
// ^CharacterDevice
virtual RetainPtr<FileDescriptor> open(int& error, int options) override;
virtual ssize_t read(Process&, byte*, size_t) override { return 0; }
virtual ssize_t write(Process&, const byte*, size_t) override { return 0; }
virtual bool can_read(Process&) const override { return true; }
virtual bool can_write(Process&) const override { return true; }
private:
SpinLock m_lock;
Vector<RetainPtr<MasterPTY>> m_freelist;
};

View file

@ -617,9 +617,10 @@ Process::Process(String&& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel ring
} else {
m_fds.resize(m_max_open_file_descriptors);
if (tty) {
m_fds[0].set(tty->open(O_RDONLY));
m_fds[1].set(tty->open(O_WRONLY));
m_fds[2].set(tty->open(O_WRONLY));
int error;
m_fds[0].set(tty->open(error, O_RDONLY));
m_fds[1].set(tty->open(error, O_WRONLY));
m_fds[2].set(tty->open(error, O_WRONLY));
}
}

View file

@ -5,13 +5,13 @@
class MasterPTY;
class SlavePTY final : public TTY {
AK_MAKE_ETERNAL
public:
virtual ~SlavePTY() override;
virtual String tty_name() const override;
void on_master_write(const byte*, size_t);
unsigned index() const { return m_index; }
protected:
virtual void on_tty_write(const byte*, size_t) override;

View file

@ -22,7 +22,7 @@
#include "VirtualConsole.h"
#include "Scheduler.h"
#include "PS2MouseDevice.h"
#include "MasterPTY.h"
#include "PTYMultiplexer.h"
#define SPAWN_GUI_TEST_APP
//#define SPAWN_MULTIPLE_SHELLS
@ -37,10 +37,6 @@ VirtualConsole* tty3;
Keyboard* keyboard;
PS2MouseDevice* ps2mouse;
GUIEventDevice* gui_event_device;
MasterPTY* ptm0;
MasterPTY* ptm1;
MasterPTY* ptm2;
MasterPTY* ptm3;
#ifdef STRESS_TEST_SPAWNING
static void spawn_stress() NORETURN;
@ -80,10 +76,8 @@ static void init_stage2()
auto dev_random = make<RandomDevice>();
vfs->register_character_device(*dev_random);
VFS::the().register_character_device(*new MasterPTY(0));
VFS::the().register_character_device(*new MasterPTY(1));
VFS::the().register_character_device(*new MasterPTY(2));
VFS::the().register_character_device(*new MasterPTY(3));
auto dev_ptmx = make<PTYMultiplexer>();
vfs->register_character_device(*dev_ptmx);
vfs->register_character_device(*keyboard);
vfs->register_character_device(*ps2mouse);

View file

@ -9,6 +9,7 @@ mknod mnt/dev/tty1 c 4 1
mknod mnt/dev/tty2 c 4 2
mknod mnt/dev/tty3 c 4 3
mknod mnt/dev/psaux c 10 1
mknod mnt/dev/ptmx c 5 2
mknod mnt/dev/ptm0 c 10 0
mknod mnt/dev/ptm1 c 10 1
mknod mnt/dev/ptm2 c 10 2