From c50398ab4cb09658b3b3fff74804d2f26df785e7 Mon Sep 17 00:00:00 2001 From: Minep Date: Tue, 30 Aug 2022 13:20:39 +0100 Subject: [PATCH] feat: support ioctl() syscall for direct control to devices 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. --- README.md | 5 +- lunaix-os/includes/lunaix/device.h | 4 + lunaix-os/includes/lunaix/ds/fifo.h | 3 + lunaix-os/includes/lunaix/fs.h | 6 ++ lunaix-os/includes/lunaix/ioctl.h | 19 ++++ lunaix-os/includes/lunaix/lunistd.h | 4 + lunaix-os/includes/lunaix/lxconsole.h | 7 ++ lunaix-os/includes/lunaix/syscall.h | 12 +++ lunaix-os/kernel/asm/x86/syscall.S | 3 + lunaix-os/kernel/demos/simple_sh.c | 124 ++++++++++++++++++-------- lunaix-os/kernel/device/device.c | 29 ++++++ lunaix-os/kernel/ds/fifo.c | 10 +++ lunaix-os/kernel/fs/twimap.c | 4 +- lunaix-os/kernel/fs/vfs.c | 72 ++++++++++----- lunaix-os/kernel/peripheral/ps2kbd.c | 10 +-- lunaix-os/kernel/process/process.c | 7 +- lunaix-os/kernel/process/sched.c | 7 ++ lunaix-os/kernel/process/signal.c | 1 - lunaix-os/kernel/process/task_attr.c | 13 +-- lunaix-os/kernel/process/taskfs.c | 3 +- lunaix-os/kernel/tty/lxconsole.c | 114 +++++++++++++++++++---- 21 files changed, 368 insertions(+), 89 deletions(-) create mode 100644 lunaix-os/includes/lunaix/ioctl.h diff --git a/README.md b/README.md index 35db086..77920e7 100644 --- 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自有** diff --git a/lunaix-os/includes/lunaix/device.h b/lunaix-os/includes/lunaix/device.h index be6dc26..c456df4 100644 --- a/lunaix-os/includes/lunaix/device.h +++ b/lunaix-os/includes/lunaix/device.h @@ -7,6 +7,8 @@ #include #include +#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* diff --git a/lunaix-os/includes/lunaix/ds/fifo.h b/lunaix-os/includes/lunaix/ds/fifo.h index a7ac90b..b6c0dec 100644 --- a/lunaix-os/includes/lunaix/ds/fifo.h +++ b/lunaix-os/includes/lunaix/ds/fifo.h @@ -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 */ diff --git a/lunaix-os/includes/lunaix/fs.h b/lunaix-os/includes/lunaix/fs.h index 94c6e6b..2fee2f2 100644 --- a/lunaix-os/includes/lunaix/fs.h +++ b/lunaix-os/includes/lunaix/fs.h @@ -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 index 0000000..e074bba --- /dev/null +++ b/lunaix-os/includes/lunaix/ioctl.h @@ -0,0 +1,19 @@ +#ifndef __LUNAIX_IOCTL_H +#define __LUNAIX_IOCTL_H + +#include + +#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 */ diff --git a/lunaix-os/includes/lunaix/lunistd.h b/lunaix-os/includes/lunaix/lunistd.h index d964428..9f2ef9e 100644 --- a/lunaix-os/includes/lunaix/lunistd.h +++ b/lunaix-os/includes/lunaix/lunistd.h @@ -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) diff --git a/lunaix-os/includes/lunaix/lxconsole.h b/lunaix-os/includes/lunaix/lxconsole.h index 02e2198..fbf59a4 100644 --- a/lunaix-os/includes/lunaix/lxconsole.h +++ b/lunaix-os/includes/lunaix/lxconsole.h @@ -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(); diff --git a/lunaix-os/includes/lunaix/syscall.h b/lunaix-os/includes/lunaix/syscall.h index 98f5585..8a523ad 100644 --- a/lunaix-os/includes/lunaix/syscall.h +++ b/lunaix-os/includes/lunaix/syscall.h @@ -54,6 +54,10 @@ #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 */ diff --git a/lunaix-os/kernel/asm/x86/syscall.S b/lunaix-os/kernel/asm/x86/syscall.S index b8d0219..34b4330 100644 --- a/lunaix-os/kernel/asm/x86/syscall.S +++ b/lunaix-os/kernel/asm/x86/syscall.S @@ -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 diff --git a/lunaix-os/kernel/demos/simple_sh.c b/lunaix-os/kernel/demos/simple_sh.c index 693bb75..5e89194 100644 --- a/lunaix-os/kernel/demos/simple_sh.c +++ b/lunaix-os/kernel/demos/simple_sh.c @@ -1,7 +1,9 @@ #include #include +#include #include #include +#include #include #include @@ -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 or 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 or to scroll.\n\n"); + if (!fork()) { + sh_loop(); + _exit(0); + } + wait(NULL); } \ No newline at end of file diff --git a/lunaix-os/kernel/device/device.c b/lunaix-os/kernel/device/device.c index beb1f18..6b901a6 100644 --- a/lunaix-os/kernel/device/device.c +++ b/lunaix-os/kernel/device/device.c @@ -1,8 +1,11 @@ #include #include +#include #include +#include #include #include +#include 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 diff --git a/lunaix-os/kernel/ds/fifo.c b/lunaix-os/kernel/ds/fifo.c index 7f34bf6..252cd2d 100644 --- a/lunaix-os/kernel/ds/fifo.c +++ b/lunaix-os/kernel/ds/fifo.c @@ -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) { diff --git a/lunaix-os/kernel/fs/twimap.c b/lunaix-os/kernel/fs/twimap.c index e32ec33..009cdf3 100644 --- a/lunaix-os/kernel/fs/twimap.c +++ b/lunaix-os/kernel/fs/twimap.c @@ -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; } diff --git a/lunaix-os/kernel/fs/vfs.c b/lunaix-os/kernel/fs/vfs.c index 3592dc8..476b00b 100644 --- a/lunaix-os/kernel/fs/vfs.c +++ b/lunaix-os/kernel/fs/vfs.c @@ -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); diff --git a/lunaix-os/kernel/peripheral/ps2kbd.c b/lunaix-os/kernel/peripheral/ps2kbd.c index 04debc8..6f17176 100644 --- a/lunaix-os/kernel/peripheral/ps2kbd.c +++ b/lunaix-os/kernel/peripheral/ps2kbd.c @@ -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); diff --git a/lunaix-os/kernel/process/process.c b/lunaix-os/kernel/process/process.c index e30e461..82f1ffa 100644 --- a/lunaix-os/kernel/process/process.c +++ b/lunaix-os/kernel/process/process.c @@ -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); diff --git a/lunaix-os/kernel/process/sched.c b/lunaix-os/kernel/process/sched.c index f58710e..c48de8e 100644 --- a/lunaix-os/kernel/process/sched.c +++ b/lunaix-os/kernel/process/sched.c @@ -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]; diff --git a/lunaix-os/kernel/process/signal.c b/lunaix-os/kernel/process/signal.c index 5f0c868..5d09d9b 100644 --- a/lunaix-os/kernel/process/signal.c +++ b/lunaix-os/kernel/process/signal.c @@ -126,7 +126,6 @@ send_grp: { __SIGSET(pos->sig_pending, signum); } - return 0; send_single: if (PROC_TERMINATED(proc->state)) { diff --git a/lunaix-os/kernel/process/task_attr.c b/lunaix-os/kernel/process/task_attr.c index f90ed35..4610acf 100644 --- a/lunaix-os/kernel/process/task_attr.c +++ b/lunaix-os/kernel/process/task_attr.c @@ -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 == ¤t->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 diff --git a/lunaix-os/kernel/process/taskfs.c b/lunaix-os/kernel/process/taskfs.c index 1e4ad2d..14ca61c 100644 --- a/lunaix-os/kernel/process/taskfs.c +++ b/lunaix-os/kernel/process/taskfs.c @@ -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; diff --git a/lunaix-os/kernel/tty/lxconsole.c b/lunaix-os/kernel/tty/lxconsole.c index a226e42..ad3fc42 100644 --- a/lunaix-os/kernel/tty/lxconsole.c +++ b/lunaix-os/kernel/tty/lxconsole.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -10,6 +11,8 @@ #include #include +#include + 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; } } -- 2.27.0