diff --git a/kernel-src/arch/x86-64/syscall.asm b/kernel-src/arch/x86-64/syscall.asm index 43d38dbe..8eaf2393 100644 --- a/kernel-src/arch/x86-64/syscall.asm +++ b/kernel-src/arch/x86-64/syscall.asm @@ -52,6 +52,11 @@ extern syscall_newthread extern syscall_threadexit extern syscall_futex extern syscall_gettid +extern syscall_getppid +extern syscall_getpgid +extern syscall_getsid +extern syscall_setsid +extern syscall_setpgid syscalltab: dq syscall_print dq syscall_mmap @@ -106,7 +111,12 @@ dq syscall_newthread dq syscall_threadexit dq syscall_futex dq syscall_gettid -syscallcount equ 53 +dq syscall_getppid +dq syscall_getpgid +dq syscall_getsid +dq syscall_setsid +dq syscall_setpgid +syscallcount equ 58 section .text global arch_syscall_entry ; on entry: diff --git a/kernel-src/arch/x86-64/syscalllog.c b/kernel-src/arch/x86-64/syscalllog.c index 030c051c..733e8ba0 100644 --- a/kernel-src/arch/x86-64/syscalllog.c +++ b/kernel-src/arch/x86-64/syscalllog.c @@ -4,7 +4,7 @@ #ifdef SYSCALL_LOGGING -#define SYSCALL_COUNT 53 +#define SYSCALL_COUNT 58 #define LOGSTR(x) arch_e9_puts(x) static char *name[] = { @@ -60,7 +60,12 @@ static char *name[] = { "newthread", "threadexit", "futex", - "gettid" + "gettid", + "getppid", + "getpgid", + "getsid", + "setsid", + "setpgid" }; static char *args[] = { @@ -116,7 +121,12 @@ static char *args[] = { "entry %p stack %p", // newthread "N/A", // threadexit "futex %p op %d value %d timespec %p", // futex - "N/A" // gettid + "N/A", // gettid + "N/A", // getppid + "pid %d", // getpgid + "pid %d", // getsid + "N/A", // setsid + "pid %d pgid %d", // setpgid }; #endif @@ -129,7 +139,6 @@ __attribute__((no_caller_saved_registers)) void arch_syscall_log(int syscall, ui thread_t *thread = _cpu()->thread; proc_t *proc = thread->proc; - snprintf(argbuff, 768, syscall < SYSCALL_COUNT ? args[syscall] : "N/A", a1, a2, a3, a4, a5, a6); snprintf(printbuff, 1024, "\e[92msyscall: pid %d tid %d: %s: %s (%lu free pages)\n\e[0m", proc->pid, thread->tid, syscall < SYSCALL_COUNT ? name[syscall] : "invalid syscall", argbuff, freepagecount); diff --git a/kernel-src/include/kernel/jobctl.h b/kernel-src/include/kernel/jobctl.h new file mode 100644 index 00000000..0e39256c --- /dev/null +++ b/kernel-src/include/kernel/jobctl.h @@ -0,0 +1,17 @@ +#ifndef _JOBCTL_H +#define _JOBCTL_H + +#include + +int jobctl_newsession(proc_t *proc); +int jobctl_newgroup(proc_t *proc); +int jobctl_changegroup(proc_t *proc, proc_t *group); +void jobctl_detach(proc_t *); +void jobctl_addproc(proc_t *parent, proc_t *proc); +void jobctl_procremove(proc_t *proc); +pid_t jobctl_getpgid(proc_t *proc); +pid_t jobctl_getsid(proc_t *proc); +void jobctl_setctty(proc_t *proc, void *ctty); +void *jobctl_getctty(proc_t *proc); + +#endif diff --git a/kernel-src/include/kernel/scheduler.h b/kernel-src/include/kernel/scheduler.h index 45d58cec..521dcaf8 100644 --- a/kernel-src/include/kernel/scheduler.h +++ b/kernel-src/include/kernel/scheduler.h @@ -74,6 +74,29 @@ typedef struct proc_t { semaphore_t waitsem; spinlock_t exiting; bool nomorethreads; + + spinlock_t jobctllock; + struct { + // NULL if this process is leader + struct proc_t *leader; + + // these are only applicable if the process is leader + struct proc_t *foreground; // process group leader, NULL if self + void *controllingtty; + int processcount; // refcount + } session; + + struct { + // NULL if this process is leader + struct proc_t *leader; + // linked list + struct proc_t *nextmember; + struct proc_t *previousmember; + + // these are only applicable if the process is leader + spinlock_t lock; // protects the linked list + int processcount; // refcount + } pgrp; } proc_t; #include diff --git a/kernel-src/include/kernel/tty.h b/kernel-src/include/kernel/tty.h index 2d1b2485..b20021d0 100644 --- a/kernel-src/include/kernel/tty.h +++ b/kernel-src/include/kernel/tty.h @@ -5,6 +5,7 @@ #include #include #include +#include #define DEVICE_BUFFER_SIZE 512 #define READ_BUFFER_SIZE 4096 @@ -23,6 +24,7 @@ typedef struct { ttydevicewritefn_t writetodevice; int minor; winsize_t winsize; + vnode_t *mastervnode; } tty_t; void tty_init(); diff --git a/kernel-src/include/kernel/vfs.h b/kernel-src/include/kernel/vfs.h index b3fee378..7192a37b 100644 --- a/kernel-src/include/kernel/vfs.h +++ b/kernel-src/include/kernel/vfs.h @@ -55,6 +55,7 @@ typedef struct vfs_t { #define V_FFLAGS_NONBLOCKING 4 #define V_FFLAGS_SHARED 8 #define V_FFLAGS_EXEC 16 +#define V_FFLAGS_NOCTTY 32 typedef struct vnode_t { struct vops_t *ops; diff --git a/kernel-src/io/tty.c b/kernel-src/io/tty.c index 9f15451f..d1dfee31 100644 --- a/kernel-src/io/tty.c +++ b/kernel-src/io/tty.c @@ -2,6 +2,7 @@ #include #include #include +#include #define TTY_MAX_COUNT 4096 #define CONTROLLING_TTY_MINOR TTY_MAX_COUNT @@ -237,6 +238,29 @@ static int isatty(int minor) { return 0; } +static int open(int minor, vnode_t **vnode, int flags) { + tty_t *tty = ttyget(minor); + + if (minor == CONTROLLING_TTY_MINOR) { + // return controlling tty + tty_t *ctty = jobctl_getctty(_cpu()->thread->proc); + + if (ctty == NULL) { + return ENXIO; + } + + VOP_RELEASE(*vnode); + *vnode = (vnode_t *)(ctty->mastervnode); + } else if (tty == NULL) { + return ENODEV; + } else if ((flags & V_FFLAGS_NOCTTY) == 0) { + // set as controlling tty + jobctl_setctty(_cpu()->thread->proc, tty); + } + + return 0; +} + static int allocminor(tty_t *tty) { MUTEX_ACQUIRE(&listmutex, false); @@ -264,7 +288,8 @@ static devops_t devops = { .poll = poll, .read = read, .ioctl = ioctl, - .isatty = isatty + .isatty = isatty, + .open = open }; tty_t *tty_create(char *name, ttydevicewritefn_t fn) { @@ -310,6 +335,14 @@ tty_t *tty_create(char *name, ttydevicewritefn_t fn) { tty->writetodevice = fn; tty->minor = minor; + vnode_t *newnode; + __assert(devfs_getnode(NULL, DEV_MAJOR_TTY, minor, &newnode) == 0); + + tty->mastervnode = (vnode_t *)((devnode_t *)newnode)->master; + VOP_HOLD(tty->mastervnode); + + VOP_RELEASE(newnode); + return tty; error: if (tty->name) @@ -322,6 +355,10 @@ tty_t *tty_create(char *name, ttydevicewritefn_t fn) { return NULL; } +void tty_unregister(char *name, tty_t *tty) { + +} + void tty_destroy(char *name, tty_t *tty) { } diff --git a/kernel-src/sys/jobctl.c b/kernel-src/sys/jobctl.c new file mode 100644 index 00000000..20ee0d32 --- /dev/null +++ b/kernel-src/sys/jobctl.c @@ -0,0 +1,286 @@ +#include +#include +#include +#include +#include + +// assumes interrupts are disabled +static void addtolist(proc_t *pgrp, proc_t *proc) { + spinlock_acquire(&pgrp->pgrp.lock); + + proc->pgrp.nextmember = pgrp->pgrp.nextmember; + proc->pgrp.previousmember = NULL; + pgrp->pgrp.nextmember = proc; + + if (proc->pgrp.nextmember) + proc->pgrp.nextmember->pgrp.previousmember = proc; + + spinlock_release(&pgrp->pgrp.lock); +} + +// assumes interrupts are disabled +static void removefromlist(proc_t *pgrp, proc_t *proc) { + spinlock_acquire(&pgrp->pgrp.lock); + + if (proc->pgrp.previousmember) + proc->pgrp.previousmember->pgrp.nextmember = proc->pgrp.nextmember; + + if (proc->pgrp.nextmember) + proc->pgrp.nextmember->pgrp.previousmember = proc->pgrp.previousmember; + + spinlock_release(&pgrp->pgrp.lock); +} + +void jobctl_setctty(proc_t *proc, void *_ctty) { + tty_t *tty = _ctty; + __assert(tty); + + bool intstatus = interrupt_set(false); + spinlock_acquire(&proc->jobctllock); + + tty_t *unholdtty = NULL; + + // if not the session leader + if (proc->session.leader) + goto leave; + + if (tty == NULL && proc->session.controllingtty) { + unholdtty = proc->session.controllingtty; + proc->session.controllingtty = NULL; + } + + if (tty && proc->session.controllingtty == NULL) { + VOP_HOLD(tty->mastervnode); + proc->session.controllingtty = tty; + } + + leave: + spinlock_release(&proc->jobctllock); + interrupt_set(intstatus); + + if (unholdtty) { + VOP_RELEASE(unholdtty->mastervnode); + } +} + +void *jobctl_getctty(proc_t *proc) { + tty_t *tty = NULL; + + bool intstatus = interrupt_set(false); + spinlock_acquire(&proc->jobctllock); + + if (proc->session.leader) { + proc_t *session = proc->session.leader; + spinlock_acquire(&session->jobctllock); + + tty = session->session.controllingtty; + if (tty) { + VOP_HOLD(tty->mastervnode); + } + + spinlock_release(&session->jobctllock); + } else if (proc->session.controllingtty){ + // is the session leader + tty = proc->session.controllingtty; + VOP_HOLD(tty->mastervnode); + } + + spinlock_release(&proc->jobctllock); + interrupt_set(intstatus); + return tty; +} + +pid_t jobctl_getpgid(proc_t *proc) { + bool intstatus = interrupt_set(false); + spinlock_acquire(&proc->jobctllock); + + pid_t pid = proc->pgrp.leader ? proc->pgrp.leader->pid : proc->pid; + + spinlock_release(&proc->jobctllock); + interrupt_set(intstatus); + + return pid; +} + +pid_t jobctl_getsid(proc_t *proc) { + bool intstatus = interrupt_set(false); + spinlock_acquire(&proc->jobctllock); + + pid_t pid = proc->session.leader ? proc->session.leader->pid : proc->pid; + + spinlock_release(&proc->jobctllock); + interrupt_set(intstatus); + + return pid; +} + +int jobctl_newsession(proc_t *proc) { + // keep those saved so we don't unhold them with interrupts disabled, + // which would possibly call into the allocators without interrupts + proc_t *unholdpgrp = NULL; + proc_t *unholdsession = NULL; + + int error = 0; + bool intstatus = interrupt_set(false); + spinlock_acquire(&proc->jobctllock); + + // check if session/group leader + if (proc->pgrp.leader == NULL) { + error = EPERM; + goto leave; + } + + unholdpgrp = proc->pgrp.leader; + unholdsession = proc->session.leader; + + removefromlist(proc->pgrp.leader, proc); + + proc->session.leader = NULL; + proc->session.foreground = NULL; + proc->session.controllingtty = NULL; + + proc->pgrp.leader = NULL; + proc->pgrp.nextmember = NULL; + proc->pgrp.previousmember = NULL; + + leave: + spinlock_release(&proc->jobctllock); + interrupt_set(intstatus); + + if (unholdpgrp) { + PROC_RELEASE(unholdpgrp); + PROC_RELEASE(unholdsession); + } + + return error; +} + +int jobctl_newgroup(proc_t *proc) { + // keep it saved so we don't unhold it with interrupts disabled, + // which would possibly call into the allocators without interrupts + proc_t *unholdpgrp = NULL; + + int error = 0; + bool intstatus = interrupt_set(false); + spinlock_acquire(&proc->jobctllock); + + // check if session/group leader + if (proc->pgrp.leader == NULL) { + error = EPERM; + goto leave; + } + + unholdpgrp = proc->pgrp.leader; + + removefromlist(proc->pgrp.leader, proc); + + proc->pgrp.leader = NULL; + proc->pgrp.nextmember = NULL; + proc->pgrp.previousmember = NULL; + + leave: + spinlock_release(&proc->jobctllock); + interrupt_set(intstatus); + + if (unholdpgrp) { + PROC_RELEASE(unholdpgrp); + } + + return error; +} + +int jobctl_changegroup(proc_t *proc, proc_t *group) { + // keep it saved so we don't unhold it with interrupts disabled, + // which would possibly call into the allocators without interrupts + proc_t *unholdpgrp = NULL; + + int error = 0; + bool intstatus = interrupt_set(false); + spinlock_acquire(&proc->jobctllock); + + // check if session/group leader + if (proc->pgrp.leader == NULL) { + error = EPERM; + goto leave; + } + + removefromlist(proc->pgrp.leader, proc); + unholdpgrp = proc->pgrp.leader; + proc->pgrp.leader = group; + addtolist(group, proc); + + leave: + spinlock_release(&proc->jobctllock); + interrupt_set(intstatus); + + if (unholdpgrp) { + PROC_RELEASE(unholdpgrp); + } + + return error; +} + +void jobctl_detach(proc_t *proc) { + // called on process exit (when the last userland thread is exiting) + proc_t *unholdpgrp = NULL; + proc_t *unholdsession = NULL; + bool intstatus = interrupt_set(false); + spinlock_acquire(&proc->jobctllock); + + if (proc->pgrp.leader) { + unholdpgrp = proc->pgrp.leader; + removefromlist(proc->pgrp.leader, proc); + proc->pgrp.leader = NULL; + } + + if (proc->session.leader) { + unholdsession = proc->session.leader; + proc->session.leader = NULL; + } + + spinlock_release(&proc->jobctllock); + interrupt_set(intstatus); + + if (unholdpgrp) { + PROC_RELEASE(unholdpgrp); + } + + if (unholdsession) { + PROC_RELEASE(unholdsession); + } +} + +void jobctl_addproc(proc_t *parent, proc_t *proc) { + // called when a new process is being created (such as by fork) + + bool intstatus = interrupt_set(false); + spinlock_acquire(&parent->jobctllock); + spinlock_acquire(&proc->jobctllock); + + proc->session.leader = parent->session.leader ? parent->session.leader : parent; + proc->pgrp.leader = parent->pgrp.leader ? parent->pgrp.leader : parent; + + PROC_HOLD(proc->session.leader); + PROC_HOLD(proc->pgrp.leader); + + addtolist(proc->pgrp.leader, proc); + + spinlock_release(&proc->jobctllock); + spinlock_release(&parent->jobctllock); + interrupt_set(intstatus); +} + +void jobctl_procremove(proc_t *proc) { + // called after all refcounts to a proc are released + // cleans up session stuff + + if (proc->session.leader != NULL) + return; + + if (proc->session.foreground) { + PROC_RELEASE(proc->session.foreground); + } + + tty_t *tty = proc->session.controllingtty; + VOP_RELEASE(tty->mastervnode); +} diff --git a/kernel-src/sys/scheduler.c b/kernel-src/sys/scheduler.c index 7a536163..b753bc61 100644 --- a/kernel-src/sys/scheduler.c +++ b/kernel-src/sys/scheduler.c @@ -10,6 +10,7 @@ #include #include #include +#include #define QUANTUM_US 100000 #define SCHEDULER_STACK_SIZE PAGE_SIZE @@ -55,6 +56,8 @@ proc_t *sched_newproc() { proc->fdfirst = 3; SPINLOCK_INIT(proc->fdlock); SEMAPHORE_INIT(&proc->waitsem, 0); + SPINLOCK_INIT(proc->jobctllock); + SPINLOCK_INIT(proc->pgrp.lock); proc->fd = alloc(sizeof(fd_t) * 3); if (proc->fd == NULL) { @@ -242,6 +245,8 @@ void sched_procexit() { // which hold a reference. it won't now since its a zombie, which is why it will be held PROC_HOLD(proc); + jobctl_detach(proc); + // close fds for (int fd = 0; fd < proc->fdcount; ++fd) fd_close(fd); @@ -606,11 +611,11 @@ void sched_runinit() { vnode_t *consolenode; __assert(devfs_getbyname("console", &consolenode) == 0); - __assert(VOP_OPEN(&consolenode, V_FFLAGS_READ, &proc->cred) == 0) + __assert(VOP_OPEN(&consolenode, V_FFLAGS_READ | V_FFLAGS_NOCTTY, &proc->cred) == 0) VOP_HOLD(consolenode); - __assert(VOP_OPEN(&consolenode, V_FFLAGS_WRITE, &proc->cred) == 0) + __assert(VOP_OPEN(&consolenode, V_FFLAGS_WRITE | V_FFLAGS_NOCTTY, &proc->cred) == 0) VOP_HOLD(consolenode); - __assert(VOP_OPEN(&consolenode, V_FFLAGS_WRITE, &proc->cred) == 0) + __assert(VOP_OPEN(&consolenode, V_FFLAGS_WRITE | V_FFLAGS_NOCTTY, &proc->cred) == 0) file_t *stdin = fd_allocate(); file_t *stdout = fd_allocate(); diff --git a/kernel-src/sys/syscalls/fork.c b/kernel-src/sys/syscalls/fork.c index 12c384ad..780b269e 100644 --- a/kernel-src/sys/syscalls/fork.c +++ b/kernel-src/sys/syscalls/fork.c @@ -3,8 +3,8 @@ #include #include #include +#include -#include syscallret_t syscall_fork(context_t *ctx) { syscallret_t ret = { .ret = -1, @@ -53,6 +53,7 @@ syscallret_t syscall_fork(context_t *ctx) { CTX_RET(&nthread->context) = 0; CTX_ERRNO(&nthread->context) = 0; + jobctl_addproc(proc, nproc); ret.ret = nproc->pid; diff --git a/kernel-src/sys/syscalls/getpid.c b/kernel-src/sys/syscalls/getpid.c index c30d225c..78d7b65e 100644 --- a/kernel-src/sys/syscalls/getpid.c +++ b/kernel-src/sys/syscalls/getpid.c @@ -1,5 +1,7 @@ #include #include +#include +#include syscallret_t syscall_getpid(context_t *ctx) { syscallret_t ret = { @@ -8,3 +10,31 @@ syscallret_t syscall_getpid(context_t *ctx) { }; return ret; } + +syscallret_t syscall_getppid(context_t *ctx) { + syscallret_t ret = { + .ret = _cpu()->thread->proc->parent ? _cpu()->thread->proc->parent->pid : 1, + .errno = 0 + }; + return ret; +} + +syscallret_t syscall_getpgid(context_t *ctx, pid_t pid) { + syscallret_t ret = { + .errno = 0 + }; + + __assert(pid == 0); + ret.ret = jobctl_getpgid(_cpu()->thread->proc); + return ret; +} + +syscallret_t syscall_getsid(context_t *ctx, pid_t pid) { + syscallret_t ret = { + .errno = 0 + }; + + __assert(pid == 0); + ret.ret = jobctl_getsid(_cpu()->thread->proc); + return ret; +} diff --git a/kernel-src/sys/syscalls/setpid.c b/kernel-src/sys/syscalls/setpid.c new file mode 100644 index 00000000..a143a0a2 --- /dev/null +++ b/kernel-src/sys/syscalls/setpid.c @@ -0,0 +1,21 @@ +#include +#include +#include + +syscallret_t syscall_setsid(context_t *) { + syscallret_t ret; + + ret.errno = jobctl_newsession(_cpu()->thread->proc); + ret.ret = ret.errno ? -1 : _cpu()->thread->proc->pid; + return ret; +} + +syscallret_t syscall_setpgid(context_t *, pid_t pid, pid_t pgid) { + syscallret_t ret; + __assert(pid == 0 || pid == _cpu()->thread->proc->pid); + __assert(pgid == 0 || pgid == _cpu()->thread->proc->pid); + + ret.errno = jobctl_newgroup(_cpu()->thread->proc); + ret.ret = ret.errno ? -1 : _cpu()->thread->proc->pid; + return ret; +} diff --git a/patches/mlibc/jinx-working-patch.patch b/patches/mlibc/jinx-working-patch.patch index 94cf505c..e0f7ce59 100644 --- a/patches/mlibc/jinx-working-patch.patch +++ b/patches/mlibc/jinx-working-patch.patch @@ -188,10 +188,10 @@ index 0000000..e5b087a + diff --git mlibc-workdir/sysdeps/astral/generic/generic.cpp mlibc-workdir/sysdeps/astral/generic/generic.cpp new file mode 100644 -index 0000000..00537fa +index 0000000..d2ec1c5 --- /dev/null +++ mlibc-workdir/sysdeps/astral/generic/generic.cpp -@@ -0,0 +1,599 @@ +@@ -0,0 +1,618 @@ +#include +#include +#include @@ -276,13 +276,20 @@ index 0000000..00537fa + } + + pid_t sys_getppid() { -+ // TODO UNSTUB -+ return 1; ++ long ret; ++ syscall(SYSCALL_GETPPID, &ret); ++ return ret; ++ } ++ ++ int sys_getsid(pid_t pid, pid_t *pgid) { ++ long ret; ++ long error = syscall(SYSCALL_GETSID, &ret, pid); ++ return 0; + } + + int sys_getpgid(pid_t pid, pid_t *pgid) { -+ // TODO UNSTUB -+ *pgid = 1; ++ long ret; ++ long error = syscall(SYSCALL_GETPGID, &ret, pid); + return 0; + } + @@ -327,6 +334,18 @@ index 0000000..00537fa + return 0; + } + ++ int sys_setpgid(pid_t pid, pid_t pgid) { ++ long ret; ++ return syscall(SYSCALL_SETPGID, &ret, pid, pgid); ++ } ++ ++ int sys_setsid(pid_t *out) { ++ long ret; ++ long error = syscall(SYSCALL_SETSID, &ret); ++ *out = ret; ++ return error; ++ } ++ + int sys_futex_tid() { + long ret; + syscall(SYSCALL_GETTID, &ret); @@ -810,10 +829,10 @@ index 0000000..990eca0 +#endif diff --git mlibc-workdir/sysdeps/astral/include/astral/syscall.h mlibc-workdir/sysdeps/astral/include/astral/syscall.h new file mode 100644 -index 0000000..c57a0fa +index 0000000..859c459 --- /dev/null +++ mlibc-workdir/sysdeps/astral/include/astral/syscall.h -@@ -0,0 +1,76 @@ +@@ -0,0 +1,81 @@ +#ifndef _SYSCALL_H_INCLUDE +#define _SYSCALL_H_INCLUDE + @@ -870,6 +889,11 @@ index 0000000..c57a0fa +#define SYSCALL_THREADEXIT 50 +#define SYSCALL_FUTEX 51 +#define SYSCALL_GETTID 52 ++#define SYSCALL_GETPPID 53 ++#define SYSCALL_GETPGID 54 ++#define SYSCALL_GETSID 55 ++#define SYSCALL_SETSID 56 ++#define SYSCALL_SETPGID 57 + +#include +#include