mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-28 21:28:21 +00:00
initial signal implementation
This commit is contained in:
@@ -8,12 +8,12 @@
|
||||
__attribute__((noreturn)) void syscall_exit(context_t *context, int status) {
|
||||
thread_t *thread = _cpu()->thread;
|
||||
proc_t *proc = thread->proc;
|
||||
__assert(proc != sched_initproc);
|
||||
__assert(spinlock_try(&proc->exiting)); // only one thread can exit at the same time
|
||||
if (spinlock_try(&proc->exiting) == false)
|
||||
sched_threadexit();
|
||||
|
||||
sched_stopotherthreads();
|
||||
|
||||
proc->status = status;
|
||||
proc->status = status << 8;
|
||||
|
||||
sched_threadexit();
|
||||
}
|
||||
|
||||
@@ -35,15 +35,13 @@ syscallret_t syscall_fork(context_t *ctx) {
|
||||
if (ret.errno)
|
||||
goto cleanup;
|
||||
|
||||
bool intstate = interrupt_set(false);
|
||||
spinlock_acquire(&proc->lock);
|
||||
MUTEX_ACQUIRE(&proc->mutex, false);
|
||||
|
||||
nproc->parent = proc;
|
||||
nproc->sibling = proc->child;
|
||||
proc->child = nproc;
|
||||
|
||||
spinlock_release(&proc->lock);
|
||||
interrupt_set(intstate);
|
||||
MUTEX_RELEASE(&proc->mutex);
|
||||
|
||||
nproc->umask = _cpu()->thread->proc->umask;
|
||||
nproc->root = sched_getroot();
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
#include <kernel/syscalls.h>
|
||||
#include <arch/cpu.h>
|
||||
#include <logging.h>
|
||||
|
||||
syscallret_t syscall_kill(context_t *context, int pid, int signal) {
|
||||
syscallret_t ret = {
|
||||
.ret = -1
|
||||
};
|
||||
|
||||
int effectivepid = -1;
|
||||
|
||||
if (pid > 0) // specific process
|
||||
effectivepid = pid;
|
||||
else if (pid == 0) // own process group
|
||||
effectivepid = 0;
|
||||
else if (pid == -1) // every process, unsupported atm
|
||||
effectivepid = -1;
|
||||
else if (pid < -1)
|
||||
effectivepid = -pid; // target specific process group
|
||||
|
||||
if (effectivepid == -1) {
|
||||
ret.errno = ESRCH;
|
||||
return ret;
|
||||
}
|
||||
|
||||
proc_t *target = sched_getprocfrompid(pid);
|
||||
if (target == NULL && pid != 0) {
|
||||
ret.errno = ESRCH;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pid >= 1)
|
||||
signal_signalproc(target, signal);
|
||||
else
|
||||
ret.errno = jobctl_signal(target, signal);
|
||||
|
||||
ret.errno = 0;
|
||||
ret.ret = 0;
|
||||
return ret;
|
||||
}
|
||||
@@ -16,11 +16,11 @@ syscallret_t syscall_newthread(context_t *, void *entry, void *stack) {
|
||||
|
||||
proc_t *proc = _cpu()->thread->proc;
|
||||
|
||||
spinlock_acquire(&proc->lock);
|
||||
MUTEX_ACQUIRE(&proc->mutex, false);
|
||||
|
||||
// if we currently don't want any more threads to start
|
||||
if (proc->nomorethreads == true) {
|
||||
spinlock_release(&proc->lock);
|
||||
MUTEX_RELEASE(&proc->mutex);
|
||||
ret.errno = EAGAIN;
|
||||
return ret;
|
||||
}
|
||||
@@ -63,6 +63,6 @@ syscallret_t syscall_newthread(context_t *, void *entry, void *stack) {
|
||||
sched_queue(proc->threads[i]);
|
||||
|
||||
cleanup:
|
||||
spinlock_release(&proc->lock);
|
||||
MUTEX_RELEASE(&proc->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#include <kernel/syscalls.h>
|
||||
#include <arch/cpu.h>
|
||||
#include <logging.h>
|
||||
|
||||
syscallret_t syscall_sigaction(context_t *, int sig, sigaction_t *new, sigaction_t *old) {
|
||||
syscallret_t ret = {
|
||||
.ret = -1
|
||||
};
|
||||
|
||||
if (sig > NSIG || sig == SIGKILL || sig == SIGSTOP) {
|
||||
ret.errno = EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
sigaction_t newtmp, oldtmp;
|
||||
if (new) {
|
||||
newtmp = *new;
|
||||
__assert(newtmp.flags & SA_RESTORER);
|
||||
}
|
||||
|
||||
signal_action(_cpu()->thread->proc, sig, new ? &newtmp : NULL, old ? &oldtmp : NULL);
|
||||
|
||||
if (old)
|
||||
*old = oldtmp;
|
||||
|
||||
ret.errno = 0;
|
||||
ret.ret = 0;
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#include <kernel/syscalls.h>
|
||||
#include <arch/cpu.h>
|
||||
|
||||
syscallret_t syscall_sigaltstack(context_t *, stack_t *new, stack_t *old) {
|
||||
syscallret_t ret = {
|
||||
.ret = -1
|
||||
};
|
||||
|
||||
stack_t newtmp, oldtmp;
|
||||
if (new)
|
||||
newtmp = *new;
|
||||
|
||||
signal_altstack(_cpu()->thread, new ? &newtmp : NULL, old ? &oldtmp : NULL);
|
||||
|
||||
if (old)
|
||||
*old = oldtmp;
|
||||
|
||||
ret.errno = 0;
|
||||
ret.ret = 0;
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#include <kernel/syscalls.h>
|
||||
#include <arch/cpu.h>
|
||||
|
||||
#define SIG_BLOCK 0
|
||||
#define SIG_UNBLOCK 1
|
||||
#define SIG_SETMASK 2
|
||||
|
||||
syscallret_t syscall_sigprocmask(context_t *, int how, sigset_t *set, sigset_t *oldset) {
|
||||
syscallret_t ret = {
|
||||
.ret = -1
|
||||
};
|
||||
|
||||
sigset_t new, old;
|
||||
|
||||
if (set) {
|
||||
if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK) {
|
||||
ret.errno = EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
new = *set;
|
||||
}
|
||||
|
||||
signal_changemask(_cpu()->thread, how, set ? &new : NULL, oldset ? &old : NULL);
|
||||
|
||||
if (oldset)
|
||||
*oldset = old;
|
||||
|
||||
ret.ret = 0;
|
||||
ret.errno = 0;
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#include <kernel/syscalls.h>
|
||||
#include <arch/signal.h>
|
||||
#include <arch/cpu.h>
|
||||
#include <logging.h>
|
||||
|
||||
// this expects CTX_SP to be pointing to the signal frame
|
||||
__attribute__((noreturn)) void syscall_sigreturn(context_t *context) {
|
||||
// TODO check if the information is valid
|
||||
sigframe_t sigframe;
|
||||
memcpy(&sigframe, (void *)CTX_SP(context), sizeof(sigframe_t));
|
||||
|
||||
interrupt_set(false);
|
||||
signal_altstack(_cpu()->thread, &sigframe.oldstack, NULL);
|
||||
signal_changemask(_cpu()->thread, SIG_SETMASK, &sigframe.oldmask, NULL);
|
||||
|
||||
__assert(ARCH_CONTEXT_ISUSER(&sigframe.context));
|
||||
memcpy(&_cpu()->thread->extracontext, &sigframe.extracontext, sizeof(extracontext_t));
|
||||
ARCH_CONTEXT_THREADLOAD(_cpu()->thread, context);
|
||||
|
||||
arch_context_switch(&sigframe.context);
|
||||
|
||||
// if we were to return normally, CTX_RET and CTX_ERRNO would be corrupted,
|
||||
// so we will manually call arch_context_switch, which will jump to the right userland code
|
||||
// (and also check for pending signals again)
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -19,7 +19,7 @@ syscallret_t syscall_waitpid(context_t *context, pid_t pid, int *status, int opt
|
||||
|
||||
thread_t *thread = _cpu()->thread;
|
||||
proc_t *proc = thread->proc;
|
||||
spinlock_acquire(&proc->lock);
|
||||
MUTEX_ACQUIRE(&proc->mutex, false);
|
||||
|
||||
proc_t *prev = NULL;
|
||||
proc_t *iterator = proc->child;
|
||||
@@ -29,10 +29,10 @@ syscallret_t syscall_waitpid(context_t *context, pid_t pid, int *status, int opt
|
||||
if (iterator == NULL) {
|
||||
if (pid > 0 && desired == NULL) {
|
||||
ret.errno = ECHILD;
|
||||
spinlock_release(&proc->lock);
|
||||
MUTEX_RELEASE(&proc->mutex);
|
||||
return ret;
|
||||
}
|
||||
spinlock_release(&proc->lock);
|
||||
MUTEX_RELEASE(&proc->mutex);
|
||||
if ((options & WNOHANG) && semaphore_test(&proc->waitsem) == false) {
|
||||
ret.errno = 0;
|
||||
ret.ret = 0;
|
||||
@@ -41,7 +41,7 @@ syscallret_t syscall_waitpid(context_t *context, pid_t pid, int *status, int opt
|
||||
ret.errno = EINTR;
|
||||
return ret;
|
||||
}
|
||||
spinlock_acquire(&proc->lock);
|
||||
MUTEX_ACQUIRE(&proc->mutex, false);
|
||||
prev = NULL;
|
||||
iterator = proc->child;
|
||||
desired = NULL; // set as null to be certain another thread didn't get it
|
||||
@@ -65,12 +65,12 @@ syscallret_t syscall_waitpid(context_t *context, pid_t pid, int *status, int opt
|
||||
else
|
||||
proc->child = iterator->sibling;
|
||||
|
||||
spinlock_release(&proc->lock);
|
||||
MUTEX_RELEASE(&proc->mutex);
|
||||
|
||||
// TODO memory safe operation
|
||||
// TODO the signal number goes in the low byte of status
|
||||
if (status)
|
||||
*status = iterator->status << 8;
|
||||
if (status) {
|
||||
*status = iterator->status;
|
||||
}
|
||||
|
||||
for (int i = 0; i < iterator->threadtablesize; ++i) {
|
||||
if (iterator->threads[i] == NULL)
|
||||
|
||||
Reference in New Issue
Block a user