mirror of
https://github.com/RGBCube/serenity
synced 2025-05-29 06:35:06 +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:
parent
b46ae2bf09
commit
9dd29f9aa9
13 changed files with 75 additions and 37 deletions
|
@ -19,6 +19,7 @@ KERNEL_OBJS = \
|
||||||
ProcFileSystem.o \
|
ProcFileSystem.o \
|
||||||
RTC.o \
|
RTC.o \
|
||||||
TTY.o \
|
TTY.o \
|
||||||
|
PTYMultiplexer.o \
|
||||||
MasterPTY.o \
|
MasterPTY.o \
|
||||||
SlavePTY.o \
|
SlavePTY.o \
|
||||||
VirtualConsole.o \
|
VirtualConsole.o \
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
class SlavePTY;
|
class SlavePTY;
|
||||||
|
|
||||||
class MasterPTY final : public CharacterDevice {
|
class MasterPTY final : public CharacterDevice {
|
||||||
AK_MAKE_ETERNAL
|
|
||||||
public:
|
public:
|
||||||
explicit MasterPTY(unsigned index);
|
explicit MasterPTY(unsigned index);
|
||||||
virtual ~MasterPTY() override;
|
virtual ~MasterPTY() override;
|
||||||
|
@ -17,6 +16,7 @@ public:
|
||||||
virtual bool can_write(Process&) const override;
|
virtual bool can_write(Process&) const override;
|
||||||
virtual bool is_master_pty() const override { return true; }
|
virtual bool is_master_pty() const override { return true; }
|
||||||
|
|
||||||
|
unsigned index() const { return m_index; }
|
||||||
String pts_name() const;
|
String pts_name() const;
|
||||||
void on_slave_write(const byte*, size_t);
|
void on_slave_write(const byte*, size_t);
|
||||||
|
|
||||||
|
|
27
Kernel/PTYMultiplexer.cpp
Normal file
27
Kernel/PTYMultiplexer.cpp
Normal 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
24
Kernel/PTYMultiplexer.h
Normal 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;
|
||||||
|
};
|
|
@ -617,9 +617,10 @@ Process::Process(String&& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel ring
|
||||||
} else {
|
} else {
|
||||||
m_fds.resize(m_max_open_file_descriptors);
|
m_fds.resize(m_max_open_file_descriptors);
|
||||||
if (tty) {
|
if (tty) {
|
||||||
m_fds[0].set(tty->open(O_RDONLY));
|
int error;
|
||||||
m_fds[1].set(tty->open(O_WRONLY));
|
m_fds[0].set(tty->open(error, O_RDONLY));
|
||||||
m_fds[2].set(tty->open(O_WRONLY));
|
m_fds[1].set(tty->open(error, O_WRONLY));
|
||||||
|
m_fds[2].set(tty->open(error, O_WRONLY));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
class MasterPTY;
|
class MasterPTY;
|
||||||
|
|
||||||
class SlavePTY final : public TTY {
|
class SlavePTY final : public TTY {
|
||||||
AK_MAKE_ETERNAL
|
|
||||||
public:
|
public:
|
||||||
virtual ~SlavePTY() override;
|
virtual ~SlavePTY() override;
|
||||||
|
|
||||||
virtual String tty_name() const override;
|
virtual String tty_name() const override;
|
||||||
|
|
||||||
void on_master_write(const byte*, size_t);
|
void on_master_write(const byte*, size_t);
|
||||||
|
unsigned index() const { return m_index; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void on_tty_write(const byte*, size_t) override;
|
virtual void on_tty_write(const byte*, size_t) override;
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "VirtualConsole.h"
|
#include "VirtualConsole.h"
|
||||||
#include "Scheduler.h"
|
#include "Scheduler.h"
|
||||||
#include "PS2MouseDevice.h"
|
#include "PS2MouseDevice.h"
|
||||||
#include "MasterPTY.h"
|
#include "PTYMultiplexer.h"
|
||||||
|
|
||||||
#define SPAWN_GUI_TEST_APP
|
#define SPAWN_GUI_TEST_APP
|
||||||
//#define SPAWN_MULTIPLE_SHELLS
|
//#define SPAWN_MULTIPLE_SHELLS
|
||||||
|
@ -37,10 +37,6 @@ VirtualConsole* tty3;
|
||||||
Keyboard* keyboard;
|
Keyboard* keyboard;
|
||||||
PS2MouseDevice* ps2mouse;
|
PS2MouseDevice* ps2mouse;
|
||||||
GUIEventDevice* gui_event_device;
|
GUIEventDevice* gui_event_device;
|
||||||
MasterPTY* ptm0;
|
|
||||||
MasterPTY* ptm1;
|
|
||||||
MasterPTY* ptm2;
|
|
||||||
MasterPTY* ptm3;
|
|
||||||
|
|
||||||
#ifdef STRESS_TEST_SPAWNING
|
#ifdef STRESS_TEST_SPAWNING
|
||||||
static void spawn_stress() NORETURN;
|
static void spawn_stress() NORETURN;
|
||||||
|
@ -80,10 +76,8 @@ static void init_stage2()
|
||||||
auto dev_random = make<RandomDevice>();
|
auto dev_random = make<RandomDevice>();
|
||||||
vfs->register_character_device(*dev_random);
|
vfs->register_character_device(*dev_random);
|
||||||
|
|
||||||
VFS::the().register_character_device(*new MasterPTY(0));
|
auto dev_ptmx = make<PTYMultiplexer>();
|
||||||
VFS::the().register_character_device(*new MasterPTY(1));
|
vfs->register_character_device(*dev_ptmx);
|
||||||
VFS::the().register_character_device(*new MasterPTY(2));
|
|
||||||
VFS::the().register_character_device(*new MasterPTY(3));
|
|
||||||
|
|
||||||
vfs->register_character_device(*keyboard);
|
vfs->register_character_device(*keyboard);
|
||||||
vfs->register_character_device(*ps2mouse);
|
vfs->register_character_device(*ps2mouse);
|
||||||
|
|
|
@ -9,6 +9,7 @@ mknod mnt/dev/tty1 c 4 1
|
||||||
mknod mnt/dev/tty2 c 4 2
|
mknod mnt/dev/tty2 c 4 2
|
||||||
mknod mnt/dev/tty3 c 4 3
|
mknod mnt/dev/tty3 c 4 3
|
||||||
mknod mnt/dev/psaux c 10 1
|
mknod mnt/dev/psaux c 10 1
|
||||||
|
mknod mnt/dev/ptmx c 5 2
|
||||||
mknod mnt/dev/ptm0 c 10 0
|
mknod mnt/dev/ptm0 c 10 0
|
||||||
mknod mnt/dev/ptm1 c 10 1
|
mknod mnt/dev/ptm1 c 10 1
|
||||||
mknod mnt/dev/ptm2 c 10 2
|
mknod mnt/dev/ptm2 c 10 2
|
||||||
|
|
|
@ -59,23 +59,13 @@ static int max(int a, int b)
|
||||||
return a > b ? a : b;
|
return a > b ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int open_ptm()
|
|
||||||
{
|
|
||||||
char buf[32];
|
|
||||||
for (unsigned i = 0; i < 4; ++i) {
|
|
||||||
sprintf(buf, "/dev/ptm%u", i);
|
|
||||||
int fd = open(buf, O_RDWR);
|
|
||||||
if (fd)
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
dbgprintf("No master PTY available :(\n");
|
|
||||||
exit(1);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int, char**)
|
int main(int, char**)
|
||||||
{
|
{
|
||||||
int ptm_fd = open_ptm();
|
int ptm_fd = open("/dev/ptmx", O_RDWR);
|
||||||
|
if (ptm_fd < 0) {
|
||||||
|
perror("open(ptmx)");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
make_shell(ptm_fd);
|
make_shell(ptm_fd);
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,11 @@
|
||||||
|
|
||||||
CharacterDevice::~CharacterDevice()
|
CharacterDevice::~CharacterDevice()
|
||||||
{
|
{
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RetainPtr<FileDescriptor> CharacterDevice::open(int options)
|
RetainPtr<FileDescriptor> CharacterDevice::open(int& error, int options)
|
||||||
{
|
{
|
||||||
return VFS::the().open(*this, options);
|
return VFS::the().open(*this, error, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CharacterDevice::ioctl(Process&, unsigned, unsigned)
|
int CharacterDevice::ioctl(Process&, unsigned, unsigned)
|
||||||
|
|
|
@ -13,7 +13,7 @@ public:
|
||||||
|
|
||||||
InodeMetadata metadata() const { return { }; }
|
InodeMetadata metadata() const { return { }; }
|
||||||
|
|
||||||
RetainPtr<FileDescriptor> open(int options);
|
virtual RetainPtr<FileDescriptor> open(int& error, int options);
|
||||||
|
|
||||||
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;
|
||||||
|
|
|
@ -128,11 +128,12 @@ void VFS::traverse_directory_inode(Inode& dir_inode, Function<bool(const FS::Dir
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
RetainPtr<FileDescriptor> VFS::open(CharacterDevice& device, int options)
|
RetainPtr<FileDescriptor> VFS::open(RetainPtr<CharacterDevice>&& device, int& error, int options)
|
||||||
{
|
{
|
||||||
// FIXME: Respect options.
|
// FIXME: Respect options.
|
||||||
(void) options;
|
(void) options;
|
||||||
return FileDescriptor::create(device);
|
(void) error;
|
||||||
|
return FileDescriptor::create(move(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
RetainPtr<FileDescriptor> VFS::open(const String& path, int& error, int options, InodeIdentifier base)
|
RetainPtr<FileDescriptor> VFS::open(const String& path, int& error, int options, InodeIdentifier base)
|
||||||
|
@ -148,7 +149,7 @@ RetainPtr<FileDescriptor> VFS::open(const String& path, int& error, int options,
|
||||||
kprintf("VFS::open: no such character device %u,%u\n", metadata.majorDevice, metadata.minorDevice);
|
kprintf("VFS::open: no such character device %u,%u\n", metadata.majorDevice, metadata.minorDevice);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return FileDescriptor::create((*it).value);
|
return (*it).value->open(error, options);
|
||||||
}
|
}
|
||||||
return FileDescriptor::create(move(inode));
|
return FileDescriptor::create(move(inode));
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ public:
|
||||||
bool mount_root(RetainPtr<FS>&&);
|
bool mount_root(RetainPtr<FS>&&);
|
||||||
bool mount(RetainPtr<FS>&&, const String& path);
|
bool mount(RetainPtr<FS>&&, const String& path);
|
||||||
|
|
||||||
RetainPtr<FileDescriptor> open(CharacterDevice&, int options);
|
RetainPtr<FileDescriptor> open(RetainPtr<CharacterDevice>&&, int& error, int options);
|
||||||
RetainPtr<FileDescriptor> open(const String& path, int& error, int options = 0, InodeIdentifier base = InodeIdentifier());
|
RetainPtr<FileDescriptor> open(const String& path, int& error, int options = 0, InodeIdentifier base = InodeIdentifier());
|
||||||
RetainPtr<FileDescriptor> create(const String& path, InodeIdentifier base, int& error);
|
RetainPtr<FileDescriptor> create(const String& path, InodeIdentifier base, int& error);
|
||||||
bool mkdir(const String& path, mode_t mode, InodeIdentifier base, int& error);
|
bool mkdir(const String& path, mode_t mode, InodeIdentifier base, int& error);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue