mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-28 13:18:22 +00:00
job control: sessions and process groups
This commit is contained in:
@@ -0,0 +1,286 @@
|
||||
#include <kernel/jobctl.h>
|
||||
#include <kernel/interrupt.h>
|
||||
#include <kernel/tty.h>
|
||||
#include <errno.h>
|
||||
#include <logging.h>
|
||||
|
||||
// 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);
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <kernel/file.h>
|
||||
#include <semaphore.h>
|
||||
#include <kernel/devfs.h>
|
||||
#include <kernel/jobctl.h>
|
||||
|
||||
#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();
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#include <errno.h>
|
||||
#include <kernel/file.h>
|
||||
#include <kernel/interrupt.h>
|
||||
#include <kernel/jobctl.h>
|
||||
|
||||
#include <logging.h>
|
||||
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;
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <kernel/syscalls.h>
|
||||
#include <arch/cpu.h>
|
||||
#include <kernel/jobctl.h>
|
||||
#include <logging.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#include <kernel/syscalls.h>
|
||||
#include <kernel/jobctl.h>
|
||||
#include <logging.h>
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user