]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
feat: multiple PTY pairs (up to 8 dynamic /dev/pts/N)
authorTulio A M Mendes <[email protected]>
Tue, 10 Feb 2026 12:55:26 +0000 (09:55 -0300)
committerTulio A M Mendes <[email protected]>
Fri, 13 Feb 2026 02:20:50 +0000 (23:20 -0300)
Refactored PTY subsystem from single global pair to array of up to 8 pairs:
- New pty_pair struct with per-pair buffers, waitqueues, session/pgrp
- pty_alloc_pair() allocates new pairs dynamically
- Inode encoding: masters=100+N, slaves=200+N
- pty_get_master_node()/pty_get_slave_node() return per-pair fs_node_t
- All _idx() variants for indexed pair access
- Old single-pair API preserved as wrappers around pair 0
- devfs /dev/pts/ now lists all active pairs dynamically
- syscall.c poll/nonblock/ioctl updated to use pty_is_master_ino/pty_is_slave_ino
- cppcheck clean, 19/19 smoke tests pass

include/pty.h
src/kernel/devfs.c
src/kernel/pty.c
src/kernel/syscall.c

index cde5919c8200eab64c98b629274063cc5eda3670..8289f722c43d459595762c12038e81a7c9b03193 100644 (file)
@@ -2,21 +2,51 @@
 #define PTY_H
 
 #include <stdint.h>
+#include "fs.h"
+
+#define PTY_MAX_PAIRS    8
+#define PTY_MASTER_INO_BASE 100
+#define PTY_SLAVE_INO_BASE  200
 
 void pty_init(void);
 
+int pty_alloc_pair(void);
+int pty_pair_count(void);
+int pty_pair_active(int idx);
+
 int pty_master_read_kbuf(void* kbuf, uint32_t len);
 int pty_master_write_kbuf(const void* kbuf, uint32_t len);
-
 int pty_slave_read_kbuf(void* kbuf, uint32_t len);
 int pty_slave_write_kbuf(const void* kbuf, uint32_t len);
-
 int pty_master_can_read(void);
 int pty_master_can_write(void);
-
 int pty_slave_can_read(void);
 int pty_slave_can_write(void);
-
 int pty_slave_ioctl(uint32_t cmd, void* user_arg);
 
+int pty_master_read_idx(int idx, void* kbuf, uint32_t len);
+int pty_master_write_idx(int idx, const void* kbuf, uint32_t len);
+int pty_slave_read_idx(int idx, void* kbuf, uint32_t len);
+int pty_slave_write_idx(int idx, const void* kbuf, uint32_t len);
+int pty_master_can_read_idx(int idx);
+int pty_master_can_write_idx(int idx);
+int pty_slave_can_read_idx(int idx);
+int pty_slave_can_write_idx(int idx);
+int pty_slave_ioctl_idx(int idx, uint32_t cmd, void* user_arg);
+
+fs_node_t* pty_get_master_node(int idx);
+fs_node_t* pty_get_slave_node(int idx);
+
+static inline int pty_is_master_ino(uint32_t ino) {
+    return (ino >= PTY_MASTER_INO_BASE && ino < PTY_MASTER_INO_BASE + PTY_MAX_PAIRS);
+}
+static inline int pty_is_slave_ino(uint32_t ino) {
+    return (ino >= PTY_SLAVE_INO_BASE && ino < PTY_SLAVE_INO_BASE + PTY_MAX_PAIRS);
+}
+static inline int pty_ino_to_idx(uint32_t ino) {
+    if (pty_is_master_ino(ino)) return (int)(ino - PTY_MASTER_INO_BASE);
+    if (pty_is_slave_ino(ino)) return (int)(ino - PTY_SLAVE_INO_BASE);
+    return -1;
+}
+
 #endif
index eec1583a1098f6febcf2ff8a528287083e4e513e..444f17663178cb0c3649c5225afd99021a5f6b56 100644 (file)
@@ -20,7 +20,6 @@ static fs_node_t g_dev_console;
 static fs_node_t g_dev_tty;
 static fs_node_t g_dev_ptmx;
 static fs_node_t g_dev_pts_dir;
-static fs_node_t g_dev_pts0;
 static uint32_t g_devfs_inited = 0;
 
 static uint32_t prng_state = 0x12345678;
@@ -124,33 +123,19 @@ static uint32_t dev_tty_write(fs_node_t* node, uint32_t offset, uint32_t size, c
 }
 
 static uint32_t dev_ptmx_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
-    (void)node;
     (void)offset;
-    int rc = pty_master_read_kbuf(buffer, size);
+    int idx = pty_ino_to_idx(node->inode);
+    if (idx < 0) idx = 0;
+    int rc = pty_master_read_idx(idx, buffer, size);
     if (rc < 0) return 0;
     return (uint32_t)rc;
 }
 
 static uint32_t dev_ptmx_write(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) {
-    (void)node;
-    (void)offset;
-    int rc = pty_master_write_kbuf(buffer, size);
-    if (rc < 0) return 0;
-    return (uint32_t)rc;
-}
-
-static uint32_t dev_pts0_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
-    (void)node;
     (void)offset;
-    int rc = pty_slave_read_kbuf(buffer, size);
-    if (rc < 0) return 0;
-    return (uint32_t)rc;
-}
-
-static uint32_t dev_pts0_write(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) {
-    (void)node;
-    (void)offset;
-    int rc = pty_slave_write_kbuf(buffer, size);
+    int idx = pty_ino_to_idx(node->inode);
+    if (idx < 0) idx = 0;
+    int rc = pty_master_write_idx(idx, buffer, size);
     if (rc < 0) return 0;
     return (uint32_t)rc;
 }
@@ -173,7 +158,15 @@ static struct fs_node* devfs_finddir_impl(struct fs_node* node, const char* name
 static struct fs_node* devfs_pts_finddir_impl(struct fs_node* node, const char* name) {
     (void)node;
     if (!name || name[0] == 0) return 0;
-    if (strcmp(name, "0") == 0) return &g_dev_pts0;
+    int count = pty_pair_count();
+    for (int i = 0; i < count; i++) {
+        char num[4];
+        num[0] = '0' + (char)i;
+        num[1] = '\0';
+        if (strcmp(name, num) == 0) {
+            return pty_get_slave_node(i);
+        }
+    }
     return 0;
 }
 
@@ -230,6 +223,7 @@ static int devfs_pts_readdir_impl(struct fs_node* node, uint32_t* inout_index, v
     if (!inout_index || !buf) return -1;
     if (buf_len < sizeof(struct vfs_dirent)) return -1;
 
+    int count = pty_pair_count();
     uint32_t idx = *inout_index;
     uint32_t cap = buf_len / (uint32_t)sizeof(struct vfs_dirent);
     struct vfs_dirent* ents = (struct vfs_dirent*)buf;
@@ -243,10 +237,13 @@ static int devfs_pts_readdir_impl(struct fs_node* node, uint32_t* inout_index, v
             e.d_ino = 5; e.d_type = FS_DIRECTORY; strcpy(e.d_name, ".");
         } else if (idx == 1) {
             e.d_ino = 1; e.d_type = FS_DIRECTORY; strcpy(e.d_name, "..");
-        } else if (idx == 2) {
-            e.d_ino = 6; e.d_type = FS_CHARDEVICE; strcpy(e.d_name, "0");
         } else {
-            break;
+            int pi = (int)(idx - 2);
+            if (pi >= count) break;
+            e.d_ino = PTY_SLAVE_INO_BASE + (uint32_t)pi;
+            e.d_type = FS_CHARDEVICE;
+            e.d_name[0] = '0' + (char)pi;
+            e.d_name[1] = '\0';
         }
 
         e.d_reclen = (uint16_t)sizeof(e);
@@ -328,13 +325,9 @@ static void devfs_init_once(void) {
     memset(&g_dev_ptmx, 0, sizeof(g_dev_ptmx));
     strcpy(g_dev_ptmx.name, "ptmx");
     g_dev_ptmx.flags = FS_CHARDEVICE;
-    g_dev_ptmx.inode = 4;
-    g_dev_ptmx.length = 0;
+    g_dev_ptmx.inode = PTY_MASTER_INO_BASE;
     g_dev_ptmx.read = &dev_ptmx_read;
     g_dev_ptmx.write = &dev_ptmx_write;
-    g_dev_ptmx.open = 0;
-    g_dev_ptmx.close = 0;
-    g_dev_ptmx.finddir = 0;
 
     memset(&g_dev_pts_dir, 0, sizeof(g_dev_pts_dir));
     strcpy(g_dev_pts_dir.name, "pts");
@@ -348,16 +341,6 @@ static void devfs_init_once(void) {
     g_dev_pts_dir.finddir = &devfs_pts_finddir_impl;
     g_dev_pts_dir.readdir = &devfs_pts_readdir_impl;
 
-    memset(&g_dev_pts0, 0, sizeof(g_dev_pts0));
-    strcpy(g_dev_pts0.name, "0");
-    g_dev_pts0.flags = FS_CHARDEVICE;
-    g_dev_pts0.inode = 6;
-    g_dev_pts0.length = 0;
-    g_dev_pts0.read = &dev_pts0_read;
-    g_dev_pts0.write = &dev_pts0_write;
-    g_dev_pts0.open = 0;
-    g_dev_pts0.close = 0;
-    g_dev_pts0.finddir = 0;
 }
 
 fs_node_t* devfs_create_root(void) {
index 5a4d6c28643a79434550f0a1065d190010065a24..14e1d019d417dcec9fd13b53d41fae3142771fad 100644 (file)
@@ -4,6 +4,7 @@
 #include "process.h"
 #include "spinlock.h"
 #include "uaccess.h"
+#include "utils.h"
 
 #include "hal/cpu.h"
 
 #define PTY_BUF_CAP 1024
 #define PTY_WAITQ_MAX 16
 
-static spinlock_t pty_lock = {0};
-
-static uint8_t m2s_buf[PTY_BUF_CAP];
-static uint32_t m2s_head = 0;
-static uint32_t m2s_tail = 0;
-
-static uint8_t s2m_buf[PTY_BUF_CAP];
-static uint32_t s2m_head = 0;
-static uint32_t s2m_tail = 0;
-
-static struct process* m2s_waitq[PTY_WAITQ_MAX];
-static uint32_t m2s_wq_head = 0;
-static uint32_t m2s_wq_tail = 0;
-
-static struct process* s2m_waitq[PTY_WAITQ_MAX];
-static uint32_t s2m_wq_head = 0;
-static uint32_t s2m_wq_tail = 0;
-
-static uint32_t pty_session_id = 0;
-static uint32_t pty_fg_pgrp = 0;
-
 enum {
     SIGTTIN = 21,
     SIGTTOU = 22,
@@ -43,6 +23,35 @@ enum {
     TTY_TIOCSPGRP = 0x5410,
 };
 
+struct pty_pair {
+    uint8_t  m2s_buf[PTY_BUF_CAP];
+    uint32_t m2s_head;
+    uint32_t m2s_tail;
+
+    uint8_t  s2m_buf[PTY_BUF_CAP];
+    uint32_t s2m_head;
+    uint32_t s2m_tail;
+
+    struct process* m2s_waitq[PTY_WAITQ_MAX];
+    uint32_t m2s_wq_head;
+    uint32_t m2s_wq_tail;
+
+    struct process* s2m_waitq[PTY_WAITQ_MAX];
+    uint32_t s2m_wq_head;
+    uint32_t s2m_wq_tail;
+
+    uint32_t session_id;
+    uint32_t fg_pgrp;
+    int      active;
+
+    fs_node_t master_node;
+    fs_node_t slave_node;
+};
+
+static spinlock_t pty_lock = {0};
+static struct pty_pair g_ptys[PTY_MAX_PAIRS];
+static int g_pty_count = 0;
+
 static uint32_t rb_count(uint32_t head, uint32_t tail) {
     if (head >= tail) return head - tail;
     return (PTY_BUF_CAP - tail) + head;
@@ -91,79 +100,147 @@ static void waitq_wake_one(struct process** q, uint32_t* head, uint32_t* tail) {
     }
 }
 
+static uint32_t pty_master_read_fn(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer);
+static uint32_t pty_master_write_fn(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer);
+static uint32_t pty_slave_read_fn(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer);
+static uint32_t pty_slave_write_fn(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer);
+
+static void pty_init_pair(int idx) {
+    struct pty_pair* p = &g_ptys[idx];
+    memset(p, 0, sizeof(*p));
+    p->active = 1;
+
+    char name[8];
+    memset(&p->master_node, 0, sizeof(p->master_node));
+    strcpy(p->master_node.name, "ptmx");
+    p->master_node.flags = FS_CHARDEVICE;
+    p->master_node.inode = PTY_MASTER_INO_BASE + (uint32_t)idx;
+    p->master_node.read = &pty_master_read_fn;
+    p->master_node.write = &pty_master_write_fn;
+
+    memset(&p->slave_node, 0, sizeof(p->slave_node));
+    name[0] = '0' + (char)idx;
+    name[1] = '\0';
+    strcpy(p->slave_node.name, name);
+    p->slave_node.flags = FS_CHARDEVICE;
+    p->slave_node.inode = PTY_SLAVE_INO_BASE + (uint32_t)idx;
+    p->slave_node.read = &pty_slave_read_fn;
+    p->slave_node.write = &pty_slave_write_fn;
+}
+
 void pty_init(void) {
     spinlock_init(&pty_lock);
-    m2s_head = m2s_tail = 0;
-    s2m_head = s2m_tail = 0;
-    m2s_wq_head = m2s_wq_tail = 0;
-    s2m_wq_head = s2m_wq_tail = 0;
-    pty_session_id = 0;
-    pty_fg_pgrp = 0;
+    memset(g_ptys, 0, sizeof(g_ptys));
+    g_pty_count = 0;
+    pty_init_pair(0);
+    g_pty_count = 1;
+}
+
+int pty_alloc_pair(void) {
+    uintptr_t flags = spin_lock_irqsave(&pty_lock);
+    if (g_pty_count >= PTY_MAX_PAIRS) {
+        spin_unlock_irqrestore(&pty_lock, flags);
+        return -ENOMEM;
+    }
+    int idx = g_pty_count;
+    g_pty_count++;
+    spin_unlock_irqrestore(&pty_lock, flags);
+    pty_init_pair(idx);
+    return idx;
+}
+
+int pty_pair_count(void) {
+    return g_pty_count;
+}
+
+int pty_pair_active(int idx) {
+    if (idx < 0 || idx >= g_pty_count) return 0;
+    return g_ptys[idx].active;
+}
+
+fs_node_t* pty_get_master_node(int idx) {
+    if (idx < 0 || idx >= g_pty_count) return NULL;
+    return &g_ptys[idx].master_node;
+}
+
+fs_node_t* pty_get_slave_node(int idx) {
+    if (idx < 0 || idx >= g_pty_count) return NULL;
+    return &g_ptys[idx].slave_node;
 }
 
-static int pty_jobctl_write_check(void) {
-    if (current_process && pty_session_id != 0 && current_process->session_id == pty_session_id &&
-        pty_fg_pgrp != 0 && current_process->pgrp_id != pty_fg_pgrp) {
+static int pty_jobctl_write_check(struct pty_pair* p) {
+    if (current_process && p->session_id != 0 && current_process->session_id == p->session_id &&
+        p->fg_pgrp != 0 && current_process->pgrp_id != p->fg_pgrp) {
         (void)process_kill(current_process->pid, SIGTTOU);
         return -EINTR;
     }
     return 0;
 }
 
-static int pty_jobctl_read_check(void) {
+static int pty_jobctl_read_check(struct pty_pair* p) {
     if (!current_process) return -ECHILD;
-    if (pty_session_id != 0 && current_process->session_id == pty_session_id &&
-        pty_fg_pgrp != 0 && current_process->pgrp_id != pty_fg_pgrp) {
+    if (p->session_id != 0 && current_process->session_id == p->session_id &&
+        p->fg_pgrp != 0 && current_process->pgrp_id != p->fg_pgrp) {
         (void)process_kill(current_process->pid, SIGTTIN);
         return -EINTR;
     }
     return 0;
 }
 
-int pty_master_can_read(void) {
+int pty_master_can_read_idx(int idx) {
+    if (idx < 0 || idx >= g_pty_count) return 0;
+    struct pty_pair* p = &g_ptys[idx];
     uintptr_t flags = spin_lock_irqsave(&pty_lock);
-    int ready = (rb_count(s2m_head, s2m_tail) != 0U) ? 1 : 0;
+    int ready = (rb_count(p->s2m_head, p->s2m_tail) != 0U) ? 1 : 0;
     spin_unlock_irqrestore(&pty_lock, flags);
     return ready;
 }
 
-int pty_master_can_write(void) {
+int pty_master_can_write_idx(int idx) {
+    if (idx < 0 || idx >= g_pty_count) return 0;
+    struct pty_pair* p = &g_ptys[idx];
     uintptr_t flags = spin_lock_irqsave(&pty_lock);
-    int ready = (rb_free(m2s_head, m2s_tail) != 0U) ? 1 : 0;
+    int ready = (rb_free(p->m2s_head, p->m2s_tail) != 0U) ? 1 : 0;
     spin_unlock_irqrestore(&pty_lock, flags);
     return ready;
 }
 
-int pty_slave_can_read(void) {
+int pty_slave_can_read_idx(int idx) {
+    if (idx < 0 || idx >= g_pty_count) return 0;
+    struct pty_pair* p = &g_ptys[idx];
     uintptr_t flags = spin_lock_irqsave(&pty_lock);
-    int ready = (rb_count(m2s_head, m2s_tail) != 0U) ? 1 : 0;
+    int ready = (rb_count(p->m2s_head, p->m2s_tail) != 0U) ? 1 : 0;
     spin_unlock_irqrestore(&pty_lock, flags);
     return ready;
 }
 
-int pty_slave_can_write(void) {
+int pty_slave_can_write_idx(int idx) {
+    if (idx < 0 || idx >= g_pty_count) return 0;
+    struct pty_pair* p = &g_ptys[idx];
     uintptr_t flags = spin_lock_irqsave(&pty_lock);
-    int ready = (rb_free(s2m_head, s2m_tail) != 0U) ? 1 : 0;
+    int ready = (rb_free(p->s2m_head, p->s2m_tail) != 0U) ? 1 : 0;
     spin_unlock_irqrestore(&pty_lock, flags);
     return ready;
 }
 
-int pty_master_read_kbuf(void* kbuf, uint32_t len) {
+int pty_master_read_idx(int idx, void* kbuf, uint32_t len) {
+    if (idx < 0 || idx >= g_pty_count) return -ENODEV;
+    struct pty_pair* p = &g_ptys[idx];
     if (!kbuf) return -EFAULT;
     if (len > 1024 * 1024) return -EINVAL;
 
-    int jc = pty_jobctl_read_check();
+    int jc = pty_jobctl_read_check(p);
     if (jc < 0) return jc;
 
     while (1) {
         uintptr_t flags = spin_lock_irqsave(&pty_lock);
-        uint32_t avail = rb_count(s2m_head, s2m_tail);
+        uint32_t avail = rb_count(p->s2m_head, p->s2m_tail);
         if (avail != 0U) {
             uint32_t to_read = len;
             if (to_read > avail) to_read = avail;
             for (uint32_t i = 0; i < to_read; i++) {
                 uint8_t c = 0;
-                (void)rb_pop(s2m_buf, &s2m_head, &s2m_tail, &c);
+                (void)rb_pop(p->s2m_buf, &p->s2m_head, &p->s2m_tail, &c);
                 ((uint8_t*)kbuf)[i] = c;
             }
             spin_unlock_irqrestore(&pty_lock, flags);
@@ -171,7 +248,7 @@ int pty_master_read_kbuf(void* kbuf, uint32_t len) {
         }
 
         if (current_process) {
-            if (waitq_push(s2m_waitq, &s2m_wq_head, &s2m_wq_tail, current_process) == 0) {
+            if (waitq_push(p->s2m_waitq, &p->s2m_wq_head, &p->s2m_wq_tail, current_process) == 0) {
                 current_process->state = PROCESS_BLOCKED;
             }
         }
@@ -182,11 +259,13 @@ int pty_master_read_kbuf(void* kbuf, uint32_t len) {
     }
 }
 
-int pty_master_write_kbuf(const void* kbuf, uint32_t len) {
+int pty_master_write_idx(int idx, const void* kbuf, uint32_t len) {
+    if (idx < 0 || idx >= g_pty_count) return -ENODEV;
+    struct pty_pair* p = &g_ptys[idx];
     if (!kbuf) return -EFAULT;
     if (len > 1024 * 1024) return -EINVAL;
 
-    int jc = pty_jobctl_write_check();
+    int jc = pty_jobctl_write_check(p);
     if (jc < 0) return jc;
 
     enum { SIGINT_NUM = 2, SIGQUIT_NUM = 3, SIGTSTP_NUM = 20 };
@@ -198,44 +277,46 @@ int pty_master_write_kbuf(const void* kbuf, uint32_t len) {
         if (ch == 0x03) sig = SIGINT_NUM;
         else if (ch == 0x1C) sig = SIGQUIT_NUM;
         else if (ch == 0x1A) sig = SIGTSTP_NUM;
-        if (sig && pty_fg_pgrp != 0) {
-            process_kill_pgrp(pty_fg_pgrp, sig);
+        if (sig && p->fg_pgrp != 0) {
+            process_kill_pgrp(p->fg_pgrp, sig);
         }
     }
 
     uintptr_t flags = spin_lock_irqsave(&pty_lock);
-    uint32_t free = rb_free(m2s_head, m2s_tail);
+    uint32_t free_space = rb_free(p->m2s_head, p->m2s_tail);
     uint32_t to_write = len;
-    if (to_write > free) to_write = free;
+    if (to_write > free_space) to_write = free_space;
 
     for (uint32_t i = 0; i < to_write; i++) {
-        rb_push(m2s_buf, &m2s_head, &m2s_tail, ((const uint8_t*)kbuf)[i]);
+        rb_push(p->m2s_buf, &p->m2s_head, &p->m2s_tail, ((const uint8_t*)kbuf)[i]);
     }
 
     if (to_write) {
-        waitq_wake_one(m2s_waitq, &m2s_wq_head, &m2s_wq_tail);
+        waitq_wake_one(p->m2s_waitq, &p->m2s_wq_head, &p->m2s_wq_tail);
     }
 
     spin_unlock_irqrestore(&pty_lock, flags);
     return (int)to_write;
 }
 
-int pty_slave_read_kbuf(void* kbuf, uint32_t len) {
+int pty_slave_read_idx(int idx, void* kbuf, uint32_t len) {
+    if (idx < 0 || idx >= g_pty_count) return -ENODEV;
+    struct pty_pair* p = &g_ptys[idx];
     if (!kbuf) return -EFAULT;
     if (len > 1024 * 1024) return -EINVAL;
 
-    int jc = pty_jobctl_read_check();
+    int jc = pty_jobctl_read_check(p);
     if (jc < 0) return jc;
 
     while (1) {
         uintptr_t flags = spin_lock_irqsave(&pty_lock);
-        uint32_t avail = rb_count(m2s_head, m2s_tail);
+        uint32_t avail = rb_count(p->m2s_head, p->m2s_tail);
         if (avail != 0U) {
             uint32_t to_read = len;
             if (to_read > avail) to_read = avail;
             for (uint32_t i = 0; i < to_read; i++) {
                 uint8_t c = 0;
-                (void)rb_pop(m2s_buf, &m2s_head, &m2s_tail, &c);
+                (void)rb_pop(p->m2s_buf, &p->m2s_head, &p->m2s_tail, &c);
                 ((uint8_t*)kbuf)[i] = c;
             }
             spin_unlock_irqrestore(&pty_lock, flags);
@@ -243,7 +324,7 @@ int pty_slave_read_kbuf(void* kbuf, uint32_t len) {
         }
 
         if (current_process) {
-            if (waitq_push(m2s_waitq, &m2s_wq_head, &m2s_wq_tail, current_process) == 0) {
+            if (waitq_push(p->m2s_waitq, &p->m2s_wq_head, &p->m2s_wq_tail, current_process) == 0) {
                 current_process->state = PROCESS_BLOCKED;
             }
         }
@@ -254,41 +335,45 @@ int pty_slave_read_kbuf(void* kbuf, uint32_t len) {
     }
 }
 
-int pty_slave_write_kbuf(const void* kbuf, uint32_t len) {
+int pty_slave_write_idx(int idx, const void* kbuf, uint32_t len) {
+    if (idx < 0 || idx >= g_pty_count) return -ENODEV;
+    struct pty_pair* p = &g_ptys[idx];
     if (!kbuf) return -EFAULT;
     if (len > 1024 * 1024) return -EINVAL;
 
-    int jc = pty_jobctl_write_check();
+    int jc = pty_jobctl_write_check(p);
     if (jc < 0) return jc;
 
     uintptr_t flags = spin_lock_irqsave(&pty_lock);
-    uint32_t free = rb_free(s2m_head, s2m_tail);
+    uint32_t free_space = rb_free(p->s2m_head, p->s2m_tail);
     uint32_t to_write = len;
-    if (to_write > free) to_write = free;
+    if (to_write > free_space) to_write = free_space;
 
     for (uint32_t i = 0; i < to_write; i++) {
-        rb_push(s2m_buf, &s2m_head, &s2m_tail, ((const uint8_t*)kbuf)[i]);
+        rb_push(p->s2m_buf, &p->s2m_head, &p->s2m_tail, ((const uint8_t*)kbuf)[i]);
     }
 
     if (to_write) {
-        waitq_wake_one(s2m_waitq, &s2m_wq_head, &s2m_wq_tail);
+        waitq_wake_one(p->s2m_waitq, &p->s2m_wq_head, &p->s2m_wq_tail);
     }
 
     spin_unlock_irqrestore(&pty_lock, flags);
     return (int)to_write;
 }
 
-int pty_slave_ioctl(uint32_t cmd, void* user_arg) {
+int pty_slave_ioctl_idx(int idx, uint32_t cmd, void* user_arg) {
+    if (idx < 0 || idx >= g_pty_count) return -ENODEV;
+    struct pty_pair* p = &g_ptys[idx];
     if (!user_arg) return -EFAULT;
 
-    if (current_process && pty_session_id == 0 && current_process->session_id != 0) {
-        pty_session_id = current_process->session_id;
-        pty_fg_pgrp = current_process->pgrp_id;
+    if (current_process && p->session_id == 0 && current_process->session_id != 0) {
+        p->session_id = current_process->session_id;
+        p->fg_pgrp = current_process->pgrp_id;
     }
 
     if (cmd == TTY_TIOCGPGRP) {
         if (user_range_ok(user_arg, sizeof(int)) == 0) return -EFAULT;
-        int fg = (int)pty_fg_pgrp;
+        int fg = (int)p->fg_pgrp;
         if (copy_to_user(user_arg, &fg, sizeof(fg)) < 0) return -EFAULT;
         return 0;
     }
@@ -299,17 +384,60 @@ int pty_slave_ioctl(uint32_t cmd, void* user_arg) {
         if (copy_from_user(&fg, user_arg, sizeof(fg)) < 0) return -EFAULT;
         if (!current_process) return -EINVAL;
 
-        if (pty_session_id == 0) {
+        if (p->session_id == 0) {
             if (fg != 0) return -EPERM;
-            pty_fg_pgrp = 0;
+            p->fg_pgrp = 0;
             return 0;
         }
 
-        if (current_process->session_id != pty_session_id) return -EPERM;
+        if (current_process->session_id != p->session_id) return -EPERM;
         if (fg < 0) return -EINVAL;
-        pty_fg_pgrp = (uint32_t)fg;
+        p->fg_pgrp = (uint32_t)fg;
         return 0;
     }
 
     return -EINVAL;
 }
+
+static uint32_t pty_master_read_fn(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
+    (void)offset;
+    int idx = pty_ino_to_idx(node->inode);
+    int rc = pty_master_read_idx(idx, buffer, size);
+    if (rc < 0) return 0;
+    return (uint32_t)rc;
+}
+
+static uint32_t pty_master_write_fn(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) {
+    (void)offset;
+    int idx = pty_ino_to_idx(node->inode);
+    int rc = pty_master_write_idx(idx, buffer, size);
+    if (rc < 0) return 0;
+    return (uint32_t)rc;
+}
+
+static uint32_t pty_slave_read_fn(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
+    (void)offset;
+    int idx = pty_ino_to_idx(node->inode);
+    int rc = pty_slave_read_idx(idx, buffer, size);
+    if (rc < 0) return 0;
+    return (uint32_t)rc;
+}
+
+static uint32_t pty_slave_write_fn(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) {
+    (void)offset;
+    int idx = pty_ino_to_idx(node->inode);
+    int rc = pty_slave_write_idx(idx, buffer, size);
+    if (rc < 0) return 0;
+    return (uint32_t)rc;
+}
+
+int pty_master_can_read(void)  { return pty_master_can_read_idx(0); }
+int pty_master_can_write(void) { return pty_master_can_write_idx(0); }
+int pty_slave_can_read(void)   { return pty_slave_can_read_idx(0); }
+int pty_slave_can_write(void)  { return pty_slave_can_write_idx(0); }
+
+int pty_master_read_kbuf(void* kbuf, uint32_t len)        { return pty_master_read_idx(0, kbuf, len); }
+int pty_master_write_kbuf(const void* kbuf, uint32_t len)  { return pty_master_write_idx(0, kbuf, len); }
+int pty_slave_read_kbuf(void* kbuf, uint32_t len)         { return pty_slave_read_idx(0, kbuf, len); }
+int pty_slave_write_kbuf(const void* kbuf, uint32_t len)   { return pty_slave_write_idx(0, kbuf, len); }
+int pty_slave_ioctl(uint32_t cmd, void* user_arg)          { return pty_slave_ioctl_idx(0, cmd, user_arg); }
index 486dbf30b68346e375be76ad2c777577adb29722..263cdc900c9b5a5b8a43a061b7002644d074e8d1 100644 (file)
@@ -273,12 +273,14 @@ static int poll_wait_kfds(struct pollfd* kfds, uint32_t nfds, int32_t timeout) {
                 } else if (n->inode == 3) {
                     if ((kfds[i].events & POLLIN) && tty_can_read()) kfds[i].revents |= POLLIN;
                     if ((kfds[i].events & POLLOUT) && tty_can_write()) kfds[i].revents |= POLLOUT;
-                } else if (n->inode == 4) {
-                    if ((kfds[i].events & POLLIN) && pty_master_can_read()) kfds[i].revents |= POLLIN;
-                    if ((kfds[i].events & POLLOUT) && pty_master_can_write()) kfds[i].revents |= POLLOUT;
-                } else if (n->inode == 6) {
-                    if ((kfds[i].events & POLLIN) && pty_slave_can_read()) kfds[i].revents |= POLLIN;
-                    if ((kfds[i].events & POLLOUT) && pty_slave_can_write()) kfds[i].revents |= POLLOUT;
+                } else if (pty_is_master_ino(n->inode)) {
+                    int pi = pty_ino_to_idx(n->inode);
+                    if ((kfds[i].events & POLLIN) && pty_master_can_read_idx(pi)) kfds[i].revents |= POLLIN;
+                    if ((kfds[i].events & POLLOUT) && pty_master_can_write_idx(pi)) kfds[i].revents |= POLLOUT;
+                } else if (pty_is_slave_ino(n->inode)) {
+                    int pi = pty_ino_to_idx(n->inode);
+                    if ((kfds[i].events & POLLIN) && pty_slave_can_read_idx(pi)) kfds[i].revents |= POLLIN;
+                    if ((kfds[i].events & POLLOUT) && pty_slave_can_write_idx(pi)) kfds[i].revents |= POLLOUT;
                 }
             } else {
                 // Regular files are always readable/writable (best-effort).
@@ -1197,10 +1199,10 @@ static int syscall_read_impl(int fd, void* user_buf, uint32_t len) {
         if (f->node->flags == FS_CHARDEVICE) {
             if (f->node->inode == 3) {
                 if (!tty_can_read()) return -EAGAIN;
-            } else if (f->node->inode == 4) {
-                if (!pty_master_can_read()) return -EAGAIN;
-            } else if (f->node->inode == 6) {
-                if (!pty_slave_can_read()) return -EAGAIN;
+            } else if (pty_is_master_ino(f->node->inode)) {
+                if (!pty_master_can_read_idx(pty_ino_to_idx(f->node->inode))) return -EAGAIN;
+            } else if (pty_is_slave_ino(f->node->inode)) {
+                if (!pty_slave_can_read_idx(pty_ino_to_idx(f->node->inode))) return -EAGAIN;
             }
         }
     }
@@ -1306,7 +1308,8 @@ static int syscall_ioctl_impl(int fd, uint32_t cmd, void* user_arg) {
     fs_node_t* n = f->node;
     if (n->flags != FS_CHARDEVICE) return -ENOTTY;
     if (n->inode == 3) return tty_ioctl(cmd, user_arg);
-    if (n->inode == 6) return pty_slave_ioctl(cmd, user_arg);
+    if (pty_is_slave_ino(n->inode)) return pty_slave_ioctl_idx(pty_ino_to_idx(n->inode), cmd, user_arg);
+    if (pty_is_master_ino(n->inode)) return -ENOTTY;
     return -ENOTTY;
 }