Browse Source

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.
Andreas Kling 6 years ago
parent
commit
9dd29f9aa9

+ 1 - 0
Kernel/Makefile

@@ -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 \

+ 1 - 1
Kernel/MasterPTY.h

@@ -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 - 0
Kernel/PTYMultiplexer.cpp

@@ -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 - 0
Kernel/PTYMultiplexer.h

@@ -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;
+};

+ 4 - 3
Kernel/Process.cpp

@@ -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));
-            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));
         }
         }
     }
     }
 
 

+ 1 - 1
Kernel/SlavePTY.h

@@ -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;

+ 3 - 9
Kernel/init.cpp

@@ -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));
-    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(*keyboard);
     vfs->register_character_device(*ps2mouse);
     vfs->register_character_device(*ps2mouse);

+ 1 - 0
Kernel/sync.sh

@@ -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

+ 5 - 15
Terminal/main.cpp

@@ -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);
 
 

+ 2 - 3
VirtualFileSystem/CharacterDevice.cpp

@@ -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)

+ 1 - 1
VirtualFileSystem/CharacterDevice.h

@@ -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;

+ 4 - 3
VirtualFileSystem/VirtualFileSystem.cpp

@@ -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));
 }
 }

+ 1 - 1
VirtualFileSystem/VirtualFileSystem.h

@@ -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);