mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-22 04:25:13 +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
Notes:
sideshowbarker
2024-07-19 16:01:34 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/9dd29f9aa97
13 changed files with 75 additions and 37 deletions
|
@ -19,6 +19,7 @@ KERNEL_OBJS = \
|
|||
ProcFileSystem.o \
|
||||
RTC.o \
|
||||
TTY.o \
|
||||
PTYMultiplexer.o \
|
||||
MasterPTY.o \
|
||||
SlavePTY.o \
|
||||
VirtualConsole.o \
|
||||
|
|
|
@ -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
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 {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -59,23 +59,13 @@ static int max(int a, int 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 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);
|
||||
|
||||
|
|
|
@ -3,12 +3,11 @@
|
|||
|
||||
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)
|
||||
|
|
|
@ -13,7 +13,7 @@ public:
|
|||
|
||||
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_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.
|
||||
(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)
|
||||
|
@ -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);
|
||||
return nullptr;
|
||||
}
|
||||
return FileDescriptor::create((*it).value);
|
||||
return (*it).value->open(error, options);
|
||||
}
|
||||
return FileDescriptor::create(move(inode));
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ public:
|
|||
bool mount_root(RetainPtr<FS>&&);
|
||||
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> create(const String& path, InodeIdentifier base, int& error);
|
||||
bool mkdir(const String& path, mode_t mode, InodeIdentifier base, int& error);
|
||||
|
|
Loading…
Add table
Reference in a new issue