feat: support ioctl() syscall for direct control to devices
authorMinep <zelong56@gmail.com>
Tue, 30 Aug 2022 12:20:39 +0000 (13:20 +0100)
committerMinep <zelong56@gmail.com>
Tue, 30 Aug 2022 12:20:39 +0000 (13:20 +0100)
feat: add ascii control code support to lunaix tty driver
feat: expose the syscall interface of getpgid() and setpgid()
fix: race condition when issuing SIGINT to process group.
fix: dead lock when a process get terminated while it is holding the inode lock
fix: double freeing the v_file object when terminating a process which it's fd is dup()ed from it's parent process.
todo: taskfs is still problematic..
chore: fixes and refactor.

21 files changed:
README.md
lunaix-os/includes/lunaix/device.h
lunaix-os/includes/lunaix/ds/fifo.h
lunaix-os/includes/lunaix/fs.h
lunaix-os/includes/lunaix/ioctl.h [new file with mode: 0644]
lunaix-os/includes/lunaix/lunistd.h
lunaix-os/includes/lunaix/lxconsole.h
lunaix-os/includes/lunaix/syscall.h
lunaix-os/kernel/asm/x86/syscall.S
lunaix-os/kernel/demos/simple_sh.c
lunaix-os/kernel/device/device.c
lunaix-os/kernel/ds/fifo.c
lunaix-os/kernel/fs/twimap.c
lunaix-os/kernel/fs/vfs.c
lunaix-os/kernel/peripheral/ps2kbd.c
lunaix-os/kernel/process/process.c
lunaix-os/kernel/process/sched.c
lunaix-os/kernel/process/signal.c
lunaix-os/kernel/process/task_attr.c
lunaix-os/kernel/process/taskfs.c
lunaix-os/kernel/tty/lxconsole.c

index 35db0861698924676755b8b6bfdcee12ee1bb9ed..77920e7a3a539c5bd0d97d7b0bedf8f466b58def 100644 (file)
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@ LunaixOS - 一个简单的,详细的,POSIX兼容的(但愿!),带有
 + 内存管理与按需分页(Demand Paging)
 + 键盘输入
 + 多进程
-+ 44个常见的Linux/POSIX系统调用([附录1](#appendix1))
++ 47个常见的Linux/POSIX系统调用([附录1](#appendix1))
 + 用户模式
 + 信号机制
 + PCI 3.0
@@ -189,6 +189,9 @@ qemu-img create -f vdi machine/disk0.vdi 128M
 2. `setxattr(2)`※
 2. `fgetxattr(2)`※
 2. `fsetxattr(2)`※
+2. `ioctl(2)`※
+2. `getpgid(2)`
+2. `setpgid(2)`
 
 **LunaixOS自有**
 
index be6dc26705d3228dba0f36ce0797cba048461834..c456df41bc6c08b960d66667a091e7ee54e0e859 100644 (file)
@@ -7,6 +7,8 @@
 #include <lunaix/ds/llist.h>
 #include <lunaix/types.h>
 
+#define DEV_STRUCT_MAGIC 0x5645444c
+
 #define DEV_MSKIF 0x00000003
 
 #define DEV_IFVOL 0x0 // volumetric (block) device
@@ -17,6 +19,7 @@ typedef unsigned int dev_t;
 
 struct device
 {
+    uint32_t magic;
     struct llist_header siblings;
     struct llist_header children;
     struct device* parent;
@@ -27,6 +30,7 @@ struct device
     void* underlay;
     int (*read)(struct device* dev, void* buf, size_t offset, size_t len);
     int (*write)(struct device* dev, void* buf, size_t offset, size_t len);
+    int (*exec_cmd)(struct device* dev, uint32_t req, va_list args);
 };
 
 struct device*
index a7ac90bb8260d971c2dc86f495d1094f862f959f..b6c0dec765a78055ead1a00465085b95c66d4388 100644 (file)
@@ -41,4 +41,7 @@ fifo_write(struct fifo_buf* fbuf, void* data, size_t count);
 size_t
 fifo_read(struct fifo_buf* fbuf, void* buf, size_t count);
 
+void
+fifo_clear(struct fifo_buf* fbuf);
+
 #endif /* __LUNAIX_FIFO_BUF_H */
index 94c6e6bbd918d112bb3d1761a810e2d2ceb8b3e9..2fee2f235f47d67d038e470f10b90600063653cf 100644 (file)
@@ -372,6 +372,12 @@ vfs_getfd(int fd, struct v_fd** fd_s);
 int
 vfs_get_dtype(int itype);
 
+void
+vfs_ref_dnode(struct v_dnode* dnode);
+
+void
+vfs_unref_dnode(struct v_dnode* dnode);
+
 void
 pcache_init(struct pcache* pcache);
 
diff --git a/lunaix-os/includes/lunaix/ioctl.h b/lunaix-os/includes/lunaix/ioctl.h
new file mode 100644 (file)
index 0000000..e074bba
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __LUNAIX_IOCTL_H
+#define __LUNAIX_IOCTL_H
+
+#include <lunaix/syscall.h>
+
+#define IOREQ(cmd, arg_num) ((((cmd)&0xffff) << 8) | ((arg_num)&0xff))
+
+#define IOCMD(req) ((req) >> 8)
+
+#define IOARGNUM(req) ((req)&0xff)
+
+#define TIOCGPGRP IOREQ(1, 0)
+#define TIOCSPGRP IOREQ(1, 1)
+#define TIOCCLSBUF IOREQ(2, 0)
+#define TIOCFLUSH IOREQ(3, 0)
+
+__LXSYSCALL2_VARG(int, ioctl, int, fd, int, req);
+
+#endif /* __LUNAIX_IOCTL_H */
index d9644289087005b811496b2adf08048da86a37d3..9f2ef9ec75da987aa7e6d2b6222de50184f4dff7 100644 (file)
@@ -15,6 +15,10 @@ __LXSYSCALL(pid_t, getpid)
 
 __LXSYSCALL(pid_t, getppid)
 
+__LXSYSCALL(pid_t, getpgid)
+
+__LXSYSCALL2(pid_t, setpgid, pid_t, pid, pid_t, pgid)
+
 __LXSYSCALL1(void, _exit, int, status)
 
 __LXSYSCALL1(unsigned int, sleep, unsigned int, seconds)
index 02e21980db359d98b40b30806cb6a0ba93a463b6..fbf59a462d65568c71fa2708c74873a3d4b394fc 100644 (file)
@@ -1,6 +1,13 @@
 #ifndef __LUNAIX_LXCONSOLE_H
 #define __LUNAIX_LXCONSOLE_H
 
+#define TCINTR 0x03 // ETX
+#define TCEOF 0x04  // EOT
+#define TCBS 0x08   // BS
+#define TCLF 0x0A   // LF
+#define TCCR 0x0D   // CR
+#define TCSTOP 0x1A // SUB
+
 void
 lxconsole_init();
 
index 98f5585a16fb202a931765f5716d2773ef17071e..8a523ad2c4ea787a2b866b56dee567865643fabc 100644 (file)
 #define __SYSCALL_fgetxattr 46
 #define __SYSCALL_fsetxattr 47
 
+#define __SYSCALL_ioctl 48
+#define __SYSCALL_getpgid 49
+#define __SYSCALL_setpgid 50
+
 #define __SYSCALL_MAX 0x100
 
 #ifndef __ASM__
@@ -130,5 +134,13 @@ syscall_install();
         asm("\n" ::"b"(p1), "c"(p2), "d"(p3), "D"(p4));                        \
         ___DOINT33(__SYSCALL_##name, rettype)                                  \
     }
+
+#define __LXSYSCALL2_VARG(rettype, name, t1, p1, t2, p2)                       \
+    static rettype name(__PARAM_MAP2(t1, p1, t2, p2), ...)                     \
+    {                                                                          \
+        void* _last = (void*)&p2 + sizeof(void*);                              \
+        asm("\n" ::"b"(p1), "c"(p2), "d"(_last));                              \
+        ___DOINT33(__SYSCALL_##name, rettype)                                  \
+    }
 #endif
 #endif /* __LUNAIX_SYSCALL_H */
index b8d021973cbec4eda95d8daf7c78d6c53a86ad36..34b4330fbfdcf6bffbcad956584793f3e1f09fa8 100644 (file)
@@ -55,6 +55,9 @@
         .long __lxsys_setxattr      /* 45 */
         .long __lxsys_fgetxattr
         .long __lxsys_fsetxattr
+        .long __lxsys_ioctl
+        .long __lxsys_getpgid
+        .long __lxsys_setpgid       /* 50 */
         2:
         .rept __SYSCALL_MAX - (2b - 1b)/4
             .long 0
index 693bb75b63bec8ccfeae625834f2999fd4c7b061..5e8919442bda86e7fdd31340084885e1415cdbe3 100644 (file)
@@ -1,7 +1,9 @@
 #include <lunaix/fctrl.h>
 #include <lunaix/foptions.h>
+#include <lunaix/ioctl.h>
 #include <lunaix/lunistd.h>
 #include <lunaix/proc.h>
+#include <lunaix/signal.h>
 #include <lunaix/status.h>
 
 #include <klibc/string.h>
@@ -60,75 +62,123 @@ sh_printerr()
             printf("Error: This is a directory\n");
             break;
         default:
-            printf("Error: Fail to open (%d)\n", errno);
+            printf("Error: (%d)\n", errno);
             break;
     }
 }
 
 void
-sh_main()
+sigint_handle(int signum)
+{
+    return;
+}
+
+void
+do_cat(const char* file)
+{
+    int fd = open(file, 0);
+    if (fd < 0) {
+        sh_printerr();
+    } else {
+        int sz;
+        while ((sz = read(fd, cat_buf, 1024)) > 0) {
+            write(stdout, cat_buf, sz);
+        }
+        if (sz < 0) {
+            sh_printerr();
+        }
+        close(fd);
+        printf("\n");
+    }
+}
+
+void
+do_ls(const char* path)
+{
+    int fd = open(path, 0);
+    if (fd < 0) {
+        sh_printerr();
+    } else {
+        struct dirent ent = { .d_offset = 0 };
+        int status;
+        while ((status = readdir(fd, &ent)) == 1) {
+            if (ent.d_type == DT_DIR) {
+                printf(" \033[3m%s\033[39;49m\n", ent.d_name);
+            } else {
+                printf(" %s\n", ent.d_name);
+            }
+        }
+
+        if (status < 0)
+            sh_printerr();
+
+        close(fd);
+    }
+}
+
+void
+sh_loop()
 {
     char buf[512];
     char *cmd, *argpart;
+    pid_t p;
+    signal(_SIGINT, sigint_handle);
 
-    printf("\n Simple shell. Use <PG_UP> or <PG_DOWN> to scroll.\n\n");
+    // set our shell as foreground process (unistd.h:tcsetpgrp is wrapper of
+    // this)
+    // stdout (by default, unless user did smth) is the tty we are currently at
+    ioctl(stdout, TIOCSPGRP, getpgid());
 
     while (1) {
         getcwd(pwd, 512);
         printf("[\033[2m%s\033[39;49m]$ ", pwd);
-        size_t sz = read(stdin, buf, 512);
+        size_t sz = read(stdin, buf, 511);
         if (sz < 0) {
             printf("fail to read user input (%d)\n", geterrno());
             return;
         }
-        buf[sz - 1] = '\0';
+        buf[sz] = '\0';
         parse_cmdline(buf, &cmd, &argpart);
         if (cmd[0] == 0) {
+            printf("\n");
             goto cont;
         }
         if (streq(cmd, "cd")) {
             if (chdir(argpart) < 0) {
                 sh_printerr();
             }
+            goto cont;
+        } else if (streq(cmd, "clear")) {
+            ioctl(stdout, TIOCCLSBUF);
+            goto cont;
         } else if (streq(cmd, "ls")) {
-            int fd = open(argpart, 0);
-            if (fd < 0) {
-                sh_printerr();
-            } else {
-                struct dirent ent = { .d_offset = 0 };
-                int status;
-                while ((status = readdir(fd, &ent)) == 1) {
-                    if (ent.d_type == DT_DIR) {
-                        printf(" \033[3m%s\033[39;49m\n", ent.d_name);
-                    } else {
-                        printf(" %s\n", ent.d_name);
-                    }
-                }
-
-                if (status < 0)
-                    sh_printerr();
-
-                close(fd);
+            if (!(p = fork())) {
+                do_ls(argpart);
+                _exit(0);
             }
         } else if (streq(cmd, "cat")) {
-            int fd = open(argpart, 0);
-            if (fd < 0) {
-                sh_printerr();
-            } else {
-                int sz;
-                while ((sz = read(fd, cat_buf, 1024)) > 0) {
-                    write(stdout, cat_buf, sz);
-                }
-                if (sz < 0) {
-                    sh_printerr();
-                }
-                close(fd);
-                printf("\n");
+            if (!(p = fork())) {
+                do_cat(argpart);
+                _exit(0);
             }
         } else {
-            printf("unknow command");
+            printf("unknow command\n");
+            goto cont;
         }
+        setpgid(p, getpgid());
+        waitpid(p, NULL, 0);
     cont:
         printf("\n");
     }
+}
+
+void
+sh_main()
+{
+    printf("\n Simple shell. Use <PG_UP> or <PG_DOWN> to scroll.\n\n");
+    if (!fork()) {
+        sh_loop();
+        _exit(0);
+    }
+    wait(NULL);
 }
\ No newline at end of file
index beb1f18050b15097bb02d5696b037a8a8f32e5a6..6b901a6593958ac2a38fd4ea35009fd62d67c141 100644 (file)
@@ -1,8 +1,11 @@
 #include <klibc/stdio.h>
 #include <lunaix/device.h>
+#include <lunaix/fs.h>
 #include <lunaix/fs/twifs.h>
+#include <lunaix/ioctl.h>
 #include <lunaix/mm/valloc.h>
 #include <lunaix/spike.h>
+#include <lunaix/syscall.h>
 
 static DEFINE_LLIST(root_list);
 
@@ -27,6 +30,7 @@ device_add(struct device* parent,
     size_t strlen =
       __ksprintf_internal(dev->name_val, name_fmt, DEVICE_NAME_SIZE, args);
 
+    dev->magic = DEV_STRUCT_MAGIC;
     dev->dev_id = devid++;
     dev->name = HSTR(dev->name_val, strlen);
     dev->parent = parent;
@@ -136,4 +140,29 @@ device_getbyoffset(struct device* root_dev, int offset)
         }
     }
     return NULL;
+}
+
+__DEFINE_LXSYSCALL3(int, ioctl, int, fd, int, req, va_list, args)
+{
+    int errno;
+    struct v_fd* fd_s;
+    if ((errno = vfs_getfd(fd, &fd_s))) {
+        goto done;
+    }
+
+    struct device* dev = (struct device*)fd_s->file->inode->data;
+    if (dev->magic != DEV_STRUCT_MAGIC) {
+        errno = ENODEV;
+        goto done;
+    }
+
+    if (!dev->exec_cmd) {
+        errno = EINVAL;
+        goto done;
+    }
+
+    errno = dev->exec_cmd(dev, req, args);
+
+done:
+    return DO_STATUS_OR_RETURN(errno);
 }
\ No newline at end of file
index 7f34bf63132900953a890e1795c44050b478adf5..252cd2dd7df55d290aa8270b588145a13eb50273 100644 (file)
@@ -15,6 +15,16 @@ fifo_init(struct fifo_buf* buf, void* data_buffer, size_t buf_size, int flags)
     mutex_init(&buf->lock);
 }
 
+void
+fifo_clear(struct fifo_buf* fbuf)
+{
+    mutex_lock(&fbuf->lock);
+    fbuf->rd_pos = 0;
+    fbuf->wr_pos = 0;
+    fbuf->free_len = fbuf->size;
+    mutex_unlock(&fbuf->lock);
+}
+
 int
 fifo_backone(struct fifo_buf* fbuf)
 {
index e32ec333c3b7d1965b2d75dc95f303d1ff256077..009cdf319ef8fce97cc69e4ca5b3420a0096286d 100644 (file)
@@ -40,9 +40,9 @@ twimap_read(struct twimap* map, void* buffer, size_t len, size_t fpos)
         map->size_acc = 0;
         map->read(map);
         pos += map->size_acc;
-    } while (pos < fpos && map->go_next(map));
+    } while (pos <= fpos && map->go_next(map));
 
-    if (pos < fpos) {
+    if (pos <= fpos) {
         vfree(map->buffer);
         return 0;
     }
index 3592dc8e2fd9a43e43637b131d0929fca1fb4782..476b00bbc7e28c4426f9711464cbfeee2052cf31 100644 (file)
@@ -257,9 +257,33 @@ int
 vfs_close(struct v_file* file)
 {
     int errno = 0;
-    if (!(errno = file->ops->close(file))) {
+    if (file->ref_count > 1) {
+        atomic_fetch_sub(&file->ref_count, 1);
+    } else if (!(errno = file->ops->close(file))) {
         atomic_fetch_sub(&file->dnode->ref_count, 1);
         file->inode->open_count--;
+
+        // Remove dead lock.
+        // This happened when process is terminated while blocking on read.
+        // In that case, the process is still holding the inode lock and it will
+        // never get released.
+        // FIXME is this a good solution?
+        /*
+         * Consider two process both open the same file both with fd=x.
+         *      Process A: busy on reading x
+         *      Process B: do nothing with x
+         * Assume that, after a very short time, process B get terminated while
+         * process A is still busy in it's reading business. By this design, the
+         * inode lock of this file x is get released by B rather than A. And
+         * this will cause a probable race condition on A if other process is
+         * writing to this file later after B exit.
+         *
+         * A possible solution is to add a owner identification in the lock
+         * context, so only the lock holder can do the release.
+         */
+        if (mutex_on_hold(&file->inode->lock)) {
+            unlock_inode(file->inode);
+        }
         mnt_chillax(file->dnode->mnt);
 
         pcache_commit_all(file->inode);
@@ -561,9 +585,7 @@ __DEFINE_LXSYSCALL1(int, close, int, fd)
         goto done_err;
     }
 
-    if (fd_s->file->ref_count > 1) {
-        fd_s->file->ref_count--;
-    } else if ((errno = vfs_close(fd_s->file))) {
+    if ((errno = vfs_close(fd_s->file))) {
         goto done_err;
     }
 
@@ -687,13 +709,11 @@ __DEFINE_LXSYSCALL3(int, write, int, fd, void*, buf, size_t, count)
 
     file->inode->mtime = clock_unixtime();
 
-    __SYSCALL_INTERRUPTIBLE({
-        if ((file->inode->itype & VFS_IFSEQDEV) || (fd_s->flags & FO_DIRECT)) {
-            errno = file->ops->write(file->inode, buf, count, file->f_pos);
-        } else {
-            errno = pcache_write(file->inode, buf, count, file->f_pos);
-        }
-    })
+    if ((file->inode->itype & VFS_IFSEQDEV) || (fd_s->flags & FO_DIRECT)) {
+        errno = file->ops->write(file->inode, buf, count, file->f_pos);
+    } else {
+        errno = pcache_write(file->inode, buf, count, file->f_pos);
+    }
 
     if (errno > 0) {
         file->f_pos += errno;
@@ -1175,8 +1195,22 @@ done:
     return DO_STATUS(errno);
 }
 
+void
+vfs_ref_dnode(struct v_dnode* dnode)
+{
+    atomic_fetch_add(&dnode->ref_count, 1);
+    mnt_mkbusy(dnode->mnt);
+}
+
+void
+vfs_unref_dnode(struct v_dnode* dnode)
+{
+    atomic_fetch_sub(&dnode->ref_count, 1);
+    mnt_chillax(dnode->mnt);
+}
+
 int
-__vfs_do_chdir(struct v_dnode* dnode)
+vfs_do_chdir(struct proc_info* proc, struct v_dnode* dnode)
 {
     int errno = 0;
 
@@ -1187,14 +1221,12 @@ __vfs_do_chdir(struct v_dnode* dnode)
         goto done;
     }
 
-    if (__current->cwd) {
-        atomic_fetch_sub(&__current->cwd->ref_count, 1);
-        mnt_chillax(__current->cwd->mnt);
+    if (proc->cwd) {
+        vfs_unref_dnode(proc->cwd);
     }
 
-    atomic_fetch_add(&dnode->ref_count, 1);
-    mnt_mkbusy(dnode->mnt);
-    __current->cwd = dnode;
+    vfs_ref_dnode(dnode);
+    proc->cwd = dnode;
 
     unlock_dnode(dnode);
 
@@ -1211,7 +1243,7 @@ __DEFINE_LXSYSCALL1(int, chdir, const char*, path)
         goto done;
     }
 
-    errno = __vfs_do_chdir(dnode);
+    errno = vfs_do_chdir(__current, dnode);
 
 done:
     return DO_STATUS(errno);
@@ -1226,7 +1258,7 @@ __DEFINE_LXSYSCALL1(int, fchdir, int, fd)
         goto done;
     }
 
-    errno = __vfs_do_chdir(fd_s->file->dnode);
+    errno = vfs_do_chdir(__current, fd_s->file->dnode);
 
 done:
     return DO_STATUS(errno);
index 04debc8e6cdf1de575269f86e4d153ac78aa523d..6f17176c422a0f27c4b92b81b15f64997bd15f02 100644 (file)
@@ -274,11 +274,11 @@ kbd_buffer_key_event(kbd_keycode_t key, uint8_t scancode, kbd_kstate_t state)
         key = key & (0xffdf |
                      -('a' > key || key > 'z' || !(state & KBD_KEY_FCAPSLKED)));
 
-        struct input_evt_pkt ipkt = {
-            .pkt_type = (state & KBD_KEY_FPRESSED) ? PKT_PRESS : PKT_RELEASE,
-            .scan_code = scancode,
-            .sys_code = key,
-        };
+        struct input_evt_pkt ipkt = { .pkt_type = (state & KBD_KEY_FPRESSED)
+                                                    ? PKT_PRESS
+                                                    : PKT_RELEASE,
+                                      .scan_code = scancode,
+                                      .sys_code = (state << 16) | key };
 
         input_fire_event(kbd_idev, &ipkt);
 
index e30e46120a21b4e213c4087d10f158cc7352ca99..82f1ffa7dcec24bd10e15f09bae93f3e66b0d899 100644 (file)
@@ -123,7 +123,7 @@ __DEFINE_LXSYSCALL2(int, setpgid, pid_t, pid, pid_t, pgid)
 
     struct proc_info* gruppenfuhrer = get_process(pgid);
 
-    if (!gruppenfuhrer || proc->pgid == proc->pid) {
+    if (!gruppenfuhrer || proc->pgid == gruppenfuhrer->pid) {
         __current->k_status = EINVAL;
         return -1;
     }
@@ -196,6 +196,11 @@ dup_proc()
     pcb->intr_ctx = __current->intr_ctx;
     pcb->parent = __current;
 
+    if (__current->cwd) {
+        pcb->cwd = __current->cwd;
+        vfs_ref_dnode(pcb->cwd);
+    }
+
     __copy_fdtable(pcb);
     region_copy(&__current->mm.regions, &pcb->mm.regions);
 
index f58710ee347387eee1629214b8b3c270c25b1a62..c48de8e5f8274344bcaafc757667b670e1615853 100644 (file)
@@ -331,6 +331,13 @@ destroy_process(pid_t pid)
     sched_ctx._procs[index] = 0;
 
     llist_delete(&proc->siblings);
+    llist_delete(&proc->grp_member);
+    llist_delete(&proc->tasks);
+    llist_delete(&proc->sleep.sleepers);
+
+    if (proc->cwd) {
+        vfs_unref_dnode(proc->cwd);
+    }
 
     for (size_t i = 0; i < VFS_MAX_FD; i++) {
         struct v_fd* fd = proc->fdtable->fds[i];
index 5f0c868789d9af36d6286dfae989b9a385e28546..5d09d9b6efa59bb02df9faabb3d0c7111d5ce9d2 100644 (file)
@@ -126,7 +126,6 @@ send_grp:
     {
         __SIGSET(pos->sig_pending, signum);
     }
-    return 0;
 
 send_single:
     if (PROC_TERMINATED(proc->state)) {
index f90ed35941fdb6878f3ab353c017d652c8cb7dd5..4610acf2b9969d4ccfd77752e324a1f708bb8a9e 100644 (file)
@@ -38,7 +38,9 @@ __read_pgid(struct twimap* map)
 void
 __read_children(struct twimap* map)
 {
-    struct proc_info* proc = twimap_index(map, struct proc_info*);
+    struct llist_header* proc_list = twimap_index(map, struct llist_header*);
+    struct proc_info* proc =
+      container_of(proc_list, struct proc_info, siblings);
     if (!proc)
         return;
     twimap_printf(map, "%d ", proc->pid);
@@ -47,11 +49,12 @@ __read_children(struct twimap* map)
 int
 __next_children(struct twimap* map)
 {
-    struct proc_info* proc = twimap_index(map, struct proc_info*);
+    struct llist_header* proc = twimap_index(map, struct llist_header*);
+    struct proc_info* current = twimap_data(map, struct proc_info*);
     if (!proc)
         return 0;
-    map->index = container_of(proc->siblings.next, struct proc_info, siblings);
-    if (map->index == proc) {
+    map->index = proc->next;
+    if (map->index == &current->children) {
         return 0;
     }
     return 1;
@@ -65,7 +68,7 @@ __reset_children(struct twimap* map)
         map->index = 0;
         return;
     }
-    map->index = container_of(proc->children.next, struct proc_info, siblings);
+    map->index = proc->children.next;
 }
 
 void
index 1e4ad2d658ec143874b99d92888a1d2e33357001..14ca61c1c802cac01b2b1f8e382a18f019e645be 100644 (file)
@@ -111,7 +111,8 @@ taskfs_dirlookup(struct v_inode* this, struct v_dnode* dnode)
         if (!tattr || !(proc = get_process(pid)))
             return ENOENT;
 
-        int errno = taskfs_mknod(dnode, pid, taskfs_next_counter(), VFS_IFFILE);
+        int errno =
+          taskfs_mknod(dnode, pid, taskfs_next_counter(), VFS_IFSEQDEV);
         if (!errno) {
             tattr->map_file->data = proc;
             dnode->inode->data = tattr->map_file;
index a226e4221e8253336eb477c97ef114597d4c0460..ad3fc420af8520413ee46e1036b5e1daa62c7e77 100644 (file)
@@ -1,6 +1,7 @@
 #include <klibc/string.h>
 #include <lunaix/device.h>
 #include <lunaix/input.h>
+#include <lunaix/ioctl.h>
 #include <lunaix/keyboard.h>
 #include <lunaix/lxconsole.h>
 #include <lunaix/mm/pmm.h>
@@ -10,6 +11,8 @@
 #include <lunaix/tty/console.h>
 #include <lunaix/tty/tty.h>
 
+#include <lunaix/lxsignal.h>
+
 static struct console lx_console;
 
 int
@@ -18,34 +21,96 @@ __tty_write(struct device* dev, void* buf, size_t offset, size_t len);
 int
 __tty_read(struct device* dev, void* buf, size_t offset, size_t len);
 
+void
+console_flush();
+
 static waitq_t lx_reader;
-static volatile char key;
+static volatile char ttychr;
+
+static pid_t fg_pgid = 0;
+
+inline void
+print_control_code(const char cntrl)
+{
+    console_write_char('^');
+    console_write_char(cntrl + 64);
+}
 
 int
 __lxconsole_listener(struct input_device* dev)
 {
-    uint32_t keycode = dev->current_pkt.sys_code;
+    uint32_t key = dev->current_pkt.sys_code;
     uint32_t type = dev->current_pkt.pkt_type;
-    if (type == PKT_PRESS) {
-        if (keycode == KEY_PG_UP) {
-            console_view_up();
-        } else if (keycode == KEY_PG_DOWN) {
-            console_view_down();
-        }
+    kbd_kstate_t state = key >> 16;
+    ttychr = key & 0xff;
+    key = key & 0xffff;
+
+    if (type == PKT_RELEASE) {
         goto done;
     }
-    if ((keycode & 0xff00) > KEYPAD) {
+
+    if ((state & KBD_KEY_FLCTRL_HELD)) {
+        char cntrl = (char)(ttychr | 0x20);
+        if ('a' > cntrl || cntrl > 'z') {
+            goto done;
+        }
+        ttychr = cntrl - 'a' + 1;
+        switch (ttychr) {
+            case TCINTR:
+                signal_send(-fg_pgid, _SIGINT);
+                print_control_code(ttychr);
+                break;
+            case TCSTOP:
+                signal_send(-fg_pgid, _SIGSTOP);
+                print_control_code(ttychr);
+                break;
+            default:
+                break;
+        }
+    } else if (key == KEY_PG_UP) {
+        console_view_up();
+        goto done;
+    } else if (key == KEY_PG_DOWN) {
+        console_view_down();
+        goto done;
+    } else if ((key & 0xff00) <= KEYPAD) {
+        ttychr = key;
+    } else {
         goto done;
     }
 
-    key = (char)(keycode & 0x00ff);
-
     pwake_all(&lx_reader);
 
 done:
     return INPUT_EVT_NEXT;
 }
 
+int
+__tty_exec_cmd(struct device* dev, uint32_t req, va_list args)
+{
+    switch (req) {
+        case TIOCGPGRP:
+            return fg_pgid;
+        case TIOCSPGRP:
+            fg_pgid = va_arg(args, pid_t);
+            break;
+        case TIOCCLSBUF:
+            fifo_clear(&lx_console.output);
+            fifo_clear(&lx_console.input);
+            lx_console.wnd_start = 0;
+            lx_console.lines = 0;
+            lx_console.output.flags |= FIFO_DIRTY;
+            break;
+        case TIOCFLUSH:
+            lx_console.output.flags |= FIFO_DIRTY;
+            console_flush();
+            break;
+        default:
+            return EINVAL;
+    }
+    return 0;
+}
+
 void
 lxconsole_init()
 {
@@ -58,6 +123,7 @@ lxconsole_init()
     struct device* tty_dev = device_addseq(NULL, &lx_console, "tty");
     tty_dev->write = __tty_write;
     tty_dev->read = __tty_read;
+    tty_dev->exec_cmd = __tty_exec_cmd;
 
     waitq_init(&lx_reader);
     input_add_listener(__lxconsole_listener);
@@ -83,14 +149,30 @@ __tty_read(struct device* dev, void* buf, size_t offset, size_t len)
     while (count < len) {
         pwait(&lx_reader);
 
-        if (key == 0x08) {
-            if (fifo_backone(&console->input)) {
-                console_write_char(key);
+        if (ttychr < 0x1B) {
+            // ASCII control codes
+            switch (ttychr) {
+                case TCINTR:
+                    fifo_clear(&console->input);
+                    return 0;
+                case TCBS:
+                    if (fifo_backone(&console->input)) {
+                        console_write_char(ttychr);
+                    }
+                    continue;
+                case TCLF:
+                case TCCR:
+                    goto proceed;
+                default:
+                    break;
             }
+            print_control_code(ttychr);
             continue;
         }
-        console_write_char(key);
-        if (!fifo_putone(&console->input, key) || key == '\n') {
+
+    proceed:
+        console_write_char(ttychr);
+        if (!fifo_putone(&console->input, ttychr) || ttychr == '\n') {
             break;
         }
     }