syscalls: fchdir, setitimer, getitimer

This commit is contained in:
Matheus
2024-05-29 11:10:24 -03:00
parent 5b5d300fc1
commit 5f7791cd08
11 changed files with 313 additions and 13 deletions
+88
View File
@@ -0,0 +1,88 @@
#include <kernel/itimer.h>
#include <logging.h>
static void itimer_dpc(context_t *context, dpcarg_t arg) {
itimer_t *itimer = arg;
spinlock_acquire(&itimer->lock);
if (itimer->paused)
goto leave;
itimer->remainingus = itimer->repeatus ? itimer->repeatus : 0;
itimer->paused = itimer->repeatus == 0;
itimer->fn(context, itimer->arg);
if (itimer->repeatus) {
timer_insert(_cpu()->timer, &itimer->entry, itimer_dpc, itimer, itimer->remainingus, false);
}
leave:
spinlock_release(&itimer->lock);
}
void itimer_init(itimer_t *itimer, dpcfn_t fn, dpcarg_t arg) {
memset(itimer, 0, sizeof(itimer_t));
itimer->fn = fn;
itimer->arg = arg;
itimer->paused = true;
SPINLOCK_INIT(itimer->lock);
}
void itimer_pause(itimer_t *itimer, uintmax_t *remainingus, uintmax_t *repeatus) {
bool intstatus = interrupt_set(false);
spinlock_acquire(&itimer->lock);
while (itimer->cpu && itimer->cpu != _cpu()) {
// schedule on the itimer cpu
sched_targetcpu(itimer->cpu);
spinlock_release(&itimer->lock);
sched_yield();
sched_targetcpu(NULL);
spinlock_acquire(&itimer->lock);
}
if (itimer->paused)
goto cleanup;
itimer->cpu = NULL;
itimer->remainingus = timer_remove(_cpu()->timer, &itimer->entry);
if (itimer->remainingus == 0) {
// while we were running in the cpu, the timer fired.
// the dpc won't be handled because the timer entry
// has already been removed from the queue.
// this will be handled as a ''timer was one microsecond away from firing''
// situation as its the cleanest way of doing this.
itimer->remainingus = 1;
}
itimer->paused = true;
cleanup:
spinlock_release(&itimer->lock);
interrupt_set(intstatus);
if (remainingus)
*remainingus = itimer->remainingus;
if (repeatus)
*repeatus = itimer->repeatus;
}
void itimer_set(itimer_t *itimer, uintmax_t timerus, uintmax_t repeatus) {
bool intstatus = interrupt_set(false);
spinlock_acquire(&itimer->lock);
itimer->remainingus = timerus;
itimer->repeatus = repeatus;
spinlock_release(&itimer->lock);
interrupt_set(intstatus);
}
void itimer_resume(itimer_t *itimer) {
bool intstatus = interrupt_set(false);
spinlock_acquire(&itimer->lock);
__assert(itimer->paused && itimer->remainingus);
itimer->cpu = _cpu();
itimer->paused = false;
timer_insert(_cpu()->timer, &itimer->entry, itimer_dpc, itimer, itimer->remainingus, false);
spinlock_release(&itimer->lock);
interrupt_set(intstatus);
}
+30 -2
View File
@@ -49,6 +49,27 @@ proc_t *sched_getprocfrompid(int pid) {
return proc;
}
static void rtdpc(context_t *, dpcarg_t arg) {
proc_t *proc = arg;
// XXX this can sleep and if it does the entire system burns down sooooooo yeah fix this for the love of god
__assert(proc->threadtablesize == 1);
signal_signalproc(arg, SIGALRM);
}
static void vtdpc(context_t *, dpcarg_t arg) {
proc_t *proc = arg;
// XXX this can sleep and if it does the entire system burns down sooooooo yeah fix this for the love of god
__assert(proc->threadtablesize == 1);
signal_signalproc(arg, SIGVTALRM);
}
static void profdpc(context_t *, dpcarg_t arg) {
proc_t *proc = arg;
// XXX this can sleep and if it does the entire system burns down sooooooo yeah fix this for the love of god
__assert(proc->threadtablesize == 1);
signal_signalproc(arg, SIGPROF);
}
proc_t *sched_newproc() {
proc_t *proc = slab_allocate(processcache);
if (proc == NULL)
@@ -76,6 +97,10 @@ proc_t *sched_newproc() {
SPINLOCK_INIT(proc->jobctllock);
SPINLOCK_INIT(proc->pgrp.lock);
SPINLOCK_INIT(proc->signals.lock);
MUTEX_INIT(&proc->timer.mutex);
itimer_init(&proc->timer.realtime, rtdpc, proc);
itimer_init(&proc->timer.virtualtime, vtdpc, proc);
itimer_init(&proc->timer.profiling, profdpc, proc);
proc->fd = alloc(sizeof(fd_t) * 3);
if (proc->fd == NULL) {
@@ -127,7 +152,6 @@ thread_t *sched_newthread(void *ip, size_t kstacksize, int priority, proc_t *pro
thread->tid = __atomic_fetch_add(&currpid, 1, __ATOMIC_SEQ_CST);
}
CTX_INIT(&thread->context, proc != NULL, true);
CTX_XINIT(&thread->extracontext, proc != NULL);
CTX_SP(&thread->context) = proc ? (ctxreg_t)ustack : (ctxreg_t)thread->kernelstacktop;
@@ -291,6 +315,11 @@ void sched_procexit() {
for (int fd = 0; fd < proc->fdcount; ++fd)
fd_close(fd);
// turn off interval timers
itimer_pause(&proc->timer.realtime, NULL, NULL);
itimer_pause(&proc->timer.virtualtime, NULL, NULL);
itimer_pause(&proc->timer.profiling, NULL, NULL);
// zombify the proc
MUTEX_ACQUIRE(&proc->mutex, false);
@@ -392,7 +421,6 @@ typedef struct {
// SHOULD NOT BE CALLED WITH THE SCHEDULER STACK
static void userspacecheck(void *_args) {
checkargs_t *args = _args;
__assert(_cpu() >= (cpu_t *)0xffffffff80000000);
thread_t *thread = _cpu()->thread;
if (thread->shouldexit) {
+24
View File
@@ -42,3 +42,27 @@ syscallret_t syscall_chdir(context_t *, const char *upath) {
return ret;
}
syscallret_t syscall_fchdir(context_t *, int fd) {
syscallret_t ret = {
.ret = -1
};
file_t *file = fd_get(fd);
if (file == NULL) {
ret.errno = EBADF;
return ret;
}
if (file->vnode->type != V_TYPE_DIR) {
ret.errno = ENOTDIR;
goto cleanup;
}
sched_setcwd(file->vnode);
ret.errno = 0;
cleanup:
fd_release(file);
return ret;
}
+3 -1
View File
@@ -124,7 +124,9 @@ syscallret_t syscall_futex(context_t *, uint32_t *futexp, int op, uint32_t value
MUTEX_RELEASE(&futexmutex);
ret.errno = poll_dowait(&desc, us);
int revents = desc.event->revents;
int revents = 0;
if (desc.event)
revents = desc.event->revents;
MUTEX_ACQUIRE(&futexmutex, false);
+96
View File
@@ -0,0 +1,96 @@
#include <kernel/syscalls.h>
#include <time.h>
#include <kernel/scheduler.h>
#include <logging.h>
#define ITIMER_REAL 0
#define ITIMER_VIRTUAL 1
#define ITIMER_PROF 2
typedef struct {
timeval_t interval;
timeval_t value;
} itimerval_t;
static itimer_t *selectitimer(int which) {
itimer_t *itimer = NULL;
if (which == ITIMER_REAL)
itimer = &_cpu()->thread->proc->timer.realtime;
else if (which == ITIMER_VIRTUAL)
itimer = &_cpu()->thread->proc->timer.virtualtime;
else if (which == ITIMER_PROF)
itimer = &_cpu()->thread->proc->timer.profiling;
return itimer;
}
syscallret_t syscall_getitimer(context_t *context, int which, itimerval_t *value) {
syscallret_t ret = {
.ret = -1
};
__assert(which == ITIMER_REAL);
itimer_t *itimer = selectitimer(which);
if (itimer == NULL) {
ret.errno = EINVAL;
return ret;
}
MUTEX_ACQUIRE(&_cpu()->thread->proc->timer.mutex, false);
uintmax_t oldremaining, oldrepeat;
itimer_pause(itimer, &oldremaining, &oldrepeat);
if (oldremaining)
itimer_resume(itimer);
MUTEX_RELEASE(&_cpu()->thread->proc->timer.mutex);
value->interval.s = oldrepeat / 1000000;
value->interval.us = oldrepeat % 1000000;
value->value.s = oldremaining / 1000000;
value->value.us = oldremaining % 1000000;
ret.errno = 0;
return ret;
}
syscallret_t syscall_setitimer(context_t *context, int which, itimerval_t *unew, itimerval_t *uold) {
syscallret_t ret = {
.ret = -1
};
__assert(which == ITIMER_REAL);
itimer_t *itimer = selectitimer(which);
if (itimer == NULL) {
ret.errno = EINVAL;
return ret;
}
itimerval_t val = {0};
if (unew)
val = *unew;
MUTEX_ACQUIRE(&_cpu()->thread->proc->timer.mutex, false);
uintmax_t oldremaining, oldrepeat;
itimer_pause(itimer, &oldremaining, &oldrepeat);
// TODO overflow check
uintmax_t repeatus = val.interval.s * 1000000 + val.interval.us;
uintmax_t newus = val.value.s * 1000000 + val.value.us;
itimer_set(itimer, newus, repeatus);
if (newus)
itimer_resume(itimer);
MUTEX_RELEASE(&_cpu()->thread->proc->timer.mutex);
if (uold) {
uold->interval.s = oldrepeat / 1000000;
uold->interval.us = oldrepeat % 1000000;
uold->value.s = oldremaining / 1000000;
uold->value.us = oldremaining % 1000000;
}
ret.errno = 0;
return ret;
}