mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 20:58:22 +00:00
initial signal implementation
This commit is contained in:
@@ -267,8 +267,12 @@ static void pfisr(isr_t *self, context_t *ctx) {
|
||||
if (ctx->error & ERROR_FETCH)
|
||||
vmmerror |= VMM_ACTION_EXEC;
|
||||
|
||||
if (vmm_pagefault((void *)ctx->cr2, ctx->cs != 8, vmmerror) == false)
|
||||
_panic("Page fault", ctx);
|
||||
if (vmm_pagefault((void *)ctx->cr2, ctx->cs != 8, vmmerror) == false) {
|
||||
if (ARCH_CONTEXT_ISUSER(ctx))
|
||||
signal_signalthread(_cpu()->thread, SIGSEGV, true);
|
||||
else
|
||||
_panic("Page fault", ctx);
|
||||
}
|
||||
}
|
||||
|
||||
void arch_mmu_init() {
|
||||
|
||||
@@ -57,6 +57,11 @@ extern syscall_getpgid
|
||||
extern syscall_getsid
|
||||
extern syscall_setsid
|
||||
extern syscall_setpgid
|
||||
extern syscall_sigaction
|
||||
extern syscall_sigaltstack
|
||||
extern syscall_sigprocmask
|
||||
extern syscall_kill
|
||||
extern syscall_sigreturn
|
||||
syscalltab:
|
||||
dq syscall_print
|
||||
dq syscall_mmap
|
||||
@@ -116,7 +121,12 @@ dq syscall_getpgid
|
||||
dq syscall_getsid
|
||||
dq syscall_setsid
|
||||
dq syscall_setpgid
|
||||
syscallcount equ 58
|
||||
dq syscall_sigaction
|
||||
dq syscall_sigaltstack
|
||||
dq syscall_sigprocmask
|
||||
dq syscall_kill
|
||||
dq syscall_sigreturn
|
||||
syscallcount equ 63
|
||||
section .text
|
||||
global arch_syscall_entry
|
||||
; on entry:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#ifdef SYSCALL_LOGGING
|
||||
|
||||
#define SYSCALL_COUNT 58
|
||||
#define SYSCALL_COUNT 63
|
||||
#define LOGSTR(x) arch_e9_puts(x)
|
||||
|
||||
static char *name[] = {
|
||||
@@ -65,7 +65,12 @@ static char *name[] = {
|
||||
"getpgid",
|
||||
"getsid",
|
||||
"setsid",
|
||||
"setpgid"
|
||||
"setpgid",
|
||||
"sigaction",
|
||||
"sigaltstack",
|
||||
"sigprocmask",
|
||||
"kill",
|
||||
"sigreturn"
|
||||
};
|
||||
|
||||
static char *args[] = {
|
||||
@@ -127,6 +132,11 @@ static char *args[] = {
|
||||
"pid %d", // getsid
|
||||
"N/A", // setsid
|
||||
"pid %d pgid %d", // setpgid
|
||||
"signal %d new %p old %p", // sigaction
|
||||
"new %p old %p", // sigaltstack
|
||||
"how %d set %p oldset %p", // sigprocmask
|
||||
"pid %d signal %d", // kill
|
||||
"N/A" // sigreturn
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+2
-2
@@ -346,10 +346,10 @@ int vfs_lookup(vnode_t **result, vnode_t *start, char *path, char *lastcomp, int
|
||||
vnode_t *derefstart = current;
|
||||
|
||||
if (*linkderef == '/' && _cpu()->thread && _cpu()->thread->proc) {
|
||||
spinlock_acquire(&_cpu()->thread->proc->lock);
|
||||
MUTEX_ACQUIRE(&_cpu()->thread->proc->mutex, false);
|
||||
derefstart = _cpu()->thread->proc->root;
|
||||
VOP_HOLD(derefstart);
|
||||
spinlock_release(&_cpu()->thread->proc->lock);
|
||||
MUTEX_RELEASE(&_cpu()->thread->proc->mutex);
|
||||
} else if (*linkderef == '/') {
|
||||
derefstart = vfsroot;
|
||||
VOP_HOLD(derefstart);
|
||||
|
||||
@@ -13,5 +13,6 @@ 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);
|
||||
int jobctl_signal(proc_t *proc, int signal);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <kernel/vfs.h>
|
||||
#include <semaphore.h>
|
||||
#include <mutex.h>
|
||||
#include <kernel/signal.h>
|
||||
|
||||
#define SCHED_THREAD_FLAGS_QUEUED 1
|
||||
#define SCHED_THREAD_FLAGS_RUNNING 2
|
||||
@@ -48,10 +49,17 @@ typedef struct thread_t {
|
||||
int wakeupreason;
|
||||
bool shouldexit;
|
||||
void *kernelarg;
|
||||
struct {
|
||||
spinlock_t lock;
|
||||
stack_t stack;
|
||||
sigset_t mask;
|
||||
sigset_t pending;
|
||||
sigset_t urgent;
|
||||
} signals;
|
||||
} thread_t;
|
||||
|
||||
typedef struct proc_t {
|
||||
spinlock_t lock;
|
||||
mutex_t mutex;
|
||||
int refcount;
|
||||
int status;
|
||||
int state;
|
||||
@@ -84,7 +92,6 @@ typedef struct proc_t {
|
||||
// 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 {
|
||||
@@ -96,23 +103,33 @@ typedef struct proc_t {
|
||||
|
||||
// these are only applicable if the process is leader
|
||||
spinlock_t lock; // protects the linked list
|
||||
int processcount; // refcount
|
||||
} pgrp;
|
||||
struct {
|
||||
spinlock_t lock;
|
||||
sigaction_t actions[NSIG];
|
||||
sigset_t pending;
|
||||
} signals;
|
||||
} proc_t;
|
||||
|
||||
#include <arch/cpu.h>
|
||||
|
||||
#define UMASK(mode) ((mode) & ~_cpu()->thread->proc->umask)
|
||||
#define PROC_HOLD(v) __atomic_add_fetch(&(v)->refcount, 1, __ATOMIC_SEQ_CST)
|
||||
// the acquire of the pid table mutex is done here to prevent a nasty race condition where sched_inactiveproc could be called multiple times
|
||||
// due to the pid table itself not holding any references to the process
|
||||
#define PROC_RELEASE(v) {\
|
||||
MUTEX_ACQUIRE(&sched_pidtablemutex, false); \
|
||||
if (__atomic_sub_fetch(&(v)->refcount, 1, __ATOMIC_SEQ_CST) == 0) {\
|
||||
sched_inactiveproc(v); \
|
||||
(v) = NULL; \
|
||||
} \
|
||||
MUTEX_RELEASE(&sched_pidtablemutex); \
|
||||
}
|
||||
|
||||
extern proc_t *sched_initproc;
|
||||
extern mutex_t sched_pidtablemutex;
|
||||
|
||||
proc_t *sched_getprocfrompid(int pid);
|
||||
void sched_init();
|
||||
void sched_stopotherthreads();
|
||||
void sched_runinit();
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
#ifndef _SIGNAL_H
|
||||
#define _SIGNAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct {
|
||||
void *base;
|
||||
int flags;
|
||||
size_t size;
|
||||
} stack_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t sig[1024 / 64];
|
||||
} sigset_t;
|
||||
|
||||
#define SIGNAL_GET(sigset, signal) ((sigset)->sig[(signal) / 64] & (1lu << ((signal) % 64)))
|
||||
#define SIGNAL_SETON(sigset, signal) (sigset)->sig[(signal) / 64] |= (1lu << ((signal) % 64))
|
||||
#define SIGNAL_SETOFF(sigset, signal) (sigset)->sig[(signal) / 64] &= ~(1lu << ((signal) % 64))
|
||||
|
||||
#define SIG_DFL ((void *)(0))
|
||||
#define SIG_IGN ((void *)(1))
|
||||
|
||||
#define SA_NOCLDSTOP 1
|
||||
#define SA_NOCLDWAIT 2
|
||||
#define SA_SIGINFO 4
|
||||
#define SA_ONSTACK 0x08000000
|
||||
#define SA_RESTART 0x10000000
|
||||
#define SA_NODEFER 0x40000000
|
||||
#define SA_RESETHAND 0x80000000
|
||||
#define SA_RESTORER 0x04000000
|
||||
|
||||
#define NSIG 65
|
||||
|
||||
typedef struct {
|
||||
void *address;
|
||||
unsigned long flags;
|
||||
void (*restorer)(void);
|
||||
sigset_t mask;
|
||||
} sigaction_t;
|
||||
|
||||
#define POLL_IN 1
|
||||
#define POLL_OUT 2
|
||||
#define POLL_MSG 3
|
||||
#define POLL_ERR 4
|
||||
#define POLL_PRI 5
|
||||
#define POLL_HUP 6
|
||||
|
||||
union sigval {
|
||||
int sival_int;
|
||||
void *sival_ptr;
|
||||
};
|
||||
|
||||
typedef long clock_t;
|
||||
|
||||
// struct taken from musl.
|
||||
|
||||
typedef struct {
|
||||
int si_signo, si_errno, si_code;
|
||||
union {
|
||||
char __pad[128 - 2*sizeof(int) - sizeof(long)];
|
||||
struct {
|
||||
union {
|
||||
struct {
|
||||
pid_t si_pid;
|
||||
uid_t si_uid;
|
||||
} __piduid;
|
||||
struct {
|
||||
int si_timerid;
|
||||
int si_overrun;
|
||||
} __timer;
|
||||
} __first;
|
||||
union {
|
||||
union sigval si_value;
|
||||
struct {
|
||||
int si_status;
|
||||
clock_t si_utime, si_stime;
|
||||
} __sigchld;
|
||||
} __second;
|
||||
} __si_common;
|
||||
struct {
|
||||
void *si_addr;
|
||||
short si_addr_lsb;
|
||||
union {
|
||||
struct {
|
||||
void *si_lower;
|
||||
void *si_upper;
|
||||
} __addr_bnd;
|
||||
unsigned si_pkey;
|
||||
} __first;
|
||||
} __sigfault;
|
||||
struct {
|
||||
long si_band;
|
||||
int si_fd;
|
||||
} __sigpoll;
|
||||
struct {
|
||||
void *si_call_addr;
|
||||
int si_syscall;
|
||||
unsigned si_arch;
|
||||
} __sigsys;
|
||||
} __si_fields;
|
||||
} siginfo_t;
|
||||
|
||||
#define SIGHUP 1
|
||||
#define SIGQUIT 3
|
||||
#define SIGTRAP 5
|
||||
#define SIGABRT 6
|
||||
#define SIGIOT SIGABRT
|
||||
#define SIGBUS 7
|
||||
#define SIGKILL 9
|
||||
#define SIGUSR1 10
|
||||
#define SIGUSR2 12
|
||||
#define SIGPIPE 13
|
||||
#define SIGALRM 14
|
||||
#define SIGSTKFLT 16
|
||||
#define SIGCHLD 17
|
||||
#define SIGCONT 18
|
||||
#define SIGSTOP 19
|
||||
#define SIGTSTP 20
|
||||
#define SIGTTIN 21
|
||||
#define SIGTTOU 22
|
||||
#define SIGURG 23
|
||||
#define SIGXCPU 24
|
||||
#define SIGXFSZ 25
|
||||
#define SIGVTALRM 26
|
||||
#define SIGWINCH 28
|
||||
#define SIGPOLL 29
|
||||
#define SIGSYS 31
|
||||
#define SIGUNUSED SIGSYS
|
||||
#define SIGCANCEL 32
|
||||
#define SIGABRT 6
|
||||
#define SIGFPE 8
|
||||
#define SIGILL 4
|
||||
#define SIGINT 2
|
||||
#define SIGSEGV 11
|
||||
#define SIGTERM 15
|
||||
#define SIGPROF 27
|
||||
#define SIGIO 29
|
||||
#define SIGPWR 30
|
||||
#define SIGRTMIN 35
|
||||
#define SIGRTMAX 64
|
||||
|
||||
#define SIG_BLOCK 0
|
||||
#define SIG_UNBLOCK 1
|
||||
#define SIG_SETMASK 2
|
||||
|
||||
struct proc_t;
|
||||
struct thread_t;
|
||||
void signal_action(struct proc_t *proc, int signal, sigaction_t *new, sigaction_t *old);
|
||||
void signal_altstack(struct thread_t *thread, stack_t *new, stack_t *old);
|
||||
void signal_changemask(struct thread_t *thread, int how, sigset_t *new, sigset_t *old);
|
||||
void signal_signalproc(struct proc_t *proc, int signal);
|
||||
void signal_signalthread(struct thread_t *thread, int signal, bool urgent);
|
||||
void signal_pending(struct thread_t *, sigset_t *sigset);
|
||||
void signal_check(struct thread_t *thread, context_t *context);
|
||||
|
||||
#endif
|
||||
@@ -40,9 +40,9 @@ typedef struct {
|
||||
typedef struct {
|
||||
uint64_t gsbase;
|
||||
uint64_t fsbase;
|
||||
uint8_t fx[512];
|
||||
__attribute__((aligned(16))) uint8_t fx[512];
|
||||
uint32_t mxcsr;
|
||||
} extracontext_t __attribute__((aligned(16)));
|
||||
} extracontext_t;
|
||||
|
||||
#define CTX_INIT(x,u,interrupts) \
|
||||
if (u) { \
|
||||
@@ -67,6 +67,9 @@ typedef struct {
|
||||
#define CTX_IP(x) (x)->rip
|
||||
#define CTX_RET(x) (x)->rax
|
||||
#define CTX_ERRNO(x) (x)->rdx
|
||||
#define CTX_ARG0(x) (x)->rdi
|
||||
#define CTX_ARG1(x) (x)->rsi
|
||||
#define CTX_ARG2(x) (x)->rdx
|
||||
|
||||
#define PRINT_CTX(x) { \
|
||||
printf("cr2: %016lx gs: %04x\nrax: %016lx fs: %04x\nrbx: %016lx es: %04x\nrcx: %016lx ds: %04x\nrdx: %016lx cs: %04x\n r8: %016lx ss: %04x\n r9: %016lx r10: %016lx\nr11: %016lx r12: %016lx\nr13: %016lx r14: %016lx\nr15: %016lx rdi: %016lx\nrsi: %016lx rbp: %016lx\nrip: %016lx rsp: %016lx\nerr: %016lx rfl: %016lx\n", \
|
||||
@@ -103,6 +106,18 @@ void arch_context_saveandcall(void (*fn)(context_t *context), void *stack);
|
||||
asm("fxrstor (%%rax)" : : "a"(&(t)->extracontext.fx[0])); \
|
||||
asm("ldmxcsr (%%rax)" : : "a"(&(t)->extracontext.mxcsr));
|
||||
|
||||
#define ARCH_EXTRACONTEXT_LOAD(c) \
|
||||
wrmsr(MSR_KERNELGSBASE, (c)->gsbase); \
|
||||
wrmsr(MSR_FSBASE, (c)->fsbase); \
|
||||
asm("fxrstor (%%rax)" : : "a"(&(c)->fx[0])); \
|
||||
asm("ldmxcsr (%%rax)" : : "a"(&(c)->mxcsr));
|
||||
|
||||
#define ARCH_EXTRACONTEXT_SAVE(c) \
|
||||
(c)->gsbase = rdmsr(MSR_KERNELGSBASE); \
|
||||
(c)->fsbase = rdmsr(MSR_FSBASE); \
|
||||
asm("fxsave (%%rax)" : : "a"(&(c)->fx[0])); \
|
||||
asm("stmxcsr (%%rax)" : : "a"(&(c)->mxcsr));
|
||||
|
||||
#define ARCH_CONTEXT_INTSTATUS(x) ((x)->rflags & 0x200 ? true : false)
|
||||
#define ARCH_CONTEXT_ISUSER(x) ((x)->cs == 0x23)
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef _ARCH_SIGNAL_H
|
||||
#define _ARCH_SIGNAL_H
|
||||
|
||||
#include <kernel/signal.h>
|
||||
|
||||
#define ARCH_SIGNAL_STACK_GROWS_DOWNWARDS 1
|
||||
#define ARCH_SIGNAL_REDZONE_SIZE 128
|
||||
|
||||
#define ARCH_SIGNAL_GETFROMRETURN(x)
|
||||
|
||||
typedef struct {
|
||||
void *restorer;
|
||||
stack_t oldstack;
|
||||
sigset_t oldmask;
|
||||
context_t context;
|
||||
extracontext_t extracontext;
|
||||
siginfo_t siginfo;
|
||||
} sigframe_t;
|
||||
|
||||
#endif
|
||||
@@ -284,3 +284,9 @@ void jobctl_procremove(proc_t *proc) {
|
||||
tty_t *tty = proc->session.controllingtty;
|
||||
VOP_RELEASE(tty->mastervnode);
|
||||
}
|
||||
|
||||
// proc can be null if the signal is being sent to the calling processes own process group
|
||||
// since that is only passed from a userland thread, we can assume _cpu()->thread->proc is not null
|
||||
int jobctl_signal(proc_t *proc, int signal) {
|
||||
|
||||
}
|
||||
|
||||
@@ -29,10 +29,21 @@ typedef struct {
|
||||
static rqueue_t runqueue[RUNQUEUE_COUNT];
|
||||
static uint64_t runqueuebitmap;
|
||||
static spinlock_t runqueuelock;
|
||||
static hashtable_t pidtable;
|
||||
// not defined as static because its acquired/released from a macro in kernel/scheduler.h
|
||||
mutex_t sched_pidtablemutex;
|
||||
|
||||
proc_t *sched_initproc;
|
||||
static pid_t currpid = 1;
|
||||
|
||||
proc_t *sched_getprocfrompid(int pid) {
|
||||
MUTEX_ACQUIRE(&sched_pidtablemutex, false);
|
||||
void *proc = NULL;
|
||||
hashtable_get(&pidtable, &proc, &pid, sizeof(pid));
|
||||
MUTEX_RELEASE(&sched_pidtablemutex);
|
||||
return proc;
|
||||
}
|
||||
|
||||
proc_t *sched_newproc() {
|
||||
proc_t *proc = slab_allocate(processcache);
|
||||
if (proc == NULL)
|
||||
@@ -50,7 +61,7 @@ proc_t *sched_newproc() {
|
||||
proc->state = SCHED_PROC_STATE_NORMAL;
|
||||
proc->threadtablesize = 1;
|
||||
proc->runningthreadcount = 1;
|
||||
SPINLOCK_INIT(proc->lock);
|
||||
MUTEX_INIT(&proc->mutex);
|
||||
SPINLOCK_INIT(proc->nodeslock);
|
||||
proc->fdcount = 3;
|
||||
proc->refcount = 1;
|
||||
@@ -59,6 +70,7 @@ proc_t *sched_newproc() {
|
||||
SEMAPHORE_INIT(&proc->waitsem, 0);
|
||||
SPINLOCK_INIT(proc->jobctllock);
|
||||
SPINLOCK_INIT(proc->pgrp.lock);
|
||||
SPINLOCK_INIT(proc->signals.lock);
|
||||
|
||||
proc->fd = alloc(sizeof(fd_t) * 3);
|
||||
if (proc->fd == NULL) {
|
||||
@@ -70,6 +82,17 @@ proc_t *sched_newproc() {
|
||||
proc->pid = __atomic_fetch_add(&currpid, 1, __ATOMIC_SEQ_CST);
|
||||
proc->umask = 022; // default umask
|
||||
|
||||
// add to pid table
|
||||
MUTEX_ACQUIRE(&sched_pidtablemutex, false);
|
||||
if (hashtable_set(&pidtable, proc, &proc->pid, sizeof(proc->pid), true)) {
|
||||
MUTEX_RELEASE(&sched_pidtablemutex);
|
||||
free(proc->fd);
|
||||
free(proc->threads);
|
||||
slab_free(processcache, proc);
|
||||
return NULL;
|
||||
}
|
||||
MUTEX_RELEASE(&sched_pidtablemutex);
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
@@ -105,6 +128,7 @@ thread_t *sched_newthread(void *ip, size_t kstacksize, int priority, proc_t *pro
|
||||
CTX_SP(&thread->context) = proc ? (ctxreg_t)ustack : (ctxreg_t)thread->kernelstacktop;
|
||||
CTX_IP(&thread->context) = (ctxreg_t)ip;
|
||||
SPINLOCK_INIT(thread->sleeplock);
|
||||
SPINLOCK_INIT(thread->signals.lock);
|
||||
|
||||
return thread;
|
||||
}
|
||||
@@ -241,6 +265,7 @@ __attribute__((noreturn)) void sched_stopcurrentthread() {
|
||||
// called when all threads in a process have exited
|
||||
void sched_procexit() {
|
||||
proc_t *proc = _cpu()->thread->proc;
|
||||
__assert(proc != sched_initproc);
|
||||
|
||||
// the process is going to be referenced by the child list, hold it
|
||||
// it only holds it now because it has to have running threads to be in the list
|
||||
@@ -254,7 +279,7 @@ void sched_procexit() {
|
||||
fd_close(fd);
|
||||
|
||||
// zombify the proc
|
||||
spinlock_acquire(&proc->lock);
|
||||
MUTEX_ACQUIRE(&proc->mutex, false);
|
||||
|
||||
VOP_RELEASE(proc->root);
|
||||
VOP_RELEASE(proc->cwd);
|
||||
@@ -263,7 +288,7 @@ void sched_procexit() {
|
||||
proc_t *lastchild = proc->child;
|
||||
|
||||
|
||||
spinlock_acquire(&sched_initproc->lock);
|
||||
MUTEX_ACQUIRE(&sched_initproc->mutex, false);
|
||||
|
||||
bool haszombie = false;
|
||||
|
||||
@@ -280,8 +305,8 @@ void sched_procexit() {
|
||||
sched_initproc->child = proc->child;
|
||||
}
|
||||
|
||||
spinlock_release(&sched_initproc->lock);
|
||||
spinlock_release(&proc->lock);
|
||||
MUTEX_RELEASE(&sched_initproc->mutex);
|
||||
MUTEX_RELEASE(&proc->mutex);
|
||||
|
||||
semaphore_signal(&proc->parent->waitsem);
|
||||
if (haszombie)
|
||||
@@ -290,9 +315,10 @@ void sched_procexit() {
|
||||
|
||||
void sched_inactiveproc(proc_t *proc) {
|
||||
// proc refcount 0, we can free the structure
|
||||
// TODO remove from the pid list
|
||||
// the pid table lock is already acquired.
|
||||
|
||||
hashtable_remove(&pidtable, &proc->pid, sizeof(proc->pid));
|
||||
|
||||
//printf("destroying proc!\n");
|
||||
sched_destroyproc(proc);
|
||||
}
|
||||
|
||||
@@ -346,12 +372,14 @@ __attribute__((no_caller_saved_registers)) void sched_userspacecheck(context_t *
|
||||
interrupt_set(true);
|
||||
sched_threadexit();
|
||||
}
|
||||
|
||||
signal_check(thread, context);
|
||||
}
|
||||
|
||||
void sched_stopotherthreads() {
|
||||
thread_t *thread = _cpu()->thread;
|
||||
proc_t *proc = thread->proc;
|
||||
spinlock_acquire(&proc->lock);
|
||||
MUTEX_ACQUIRE(&proc->mutex, false);
|
||||
proc->nomorethreads = true;
|
||||
|
||||
for (int i = 0; i < proc->threadtablesize; ++i) {
|
||||
@@ -363,7 +391,7 @@ void sched_stopotherthreads() {
|
||||
proc->threads[i] = NULL;
|
||||
}
|
||||
|
||||
spinlock_release(&proc->lock);
|
||||
MUTEX_RELEASE(&proc->mutex);
|
||||
|
||||
while (__atomic_load_n(&proc->runningthreadcount, __ATOMIC_SEQ_CST) > 1) sched_yield();
|
||||
|
||||
@@ -563,6 +591,9 @@ void sched_init() {
|
||||
processcache = slab_newcache(sizeof(proc_t), 0, NULL, NULL);
|
||||
__assert(processcache);
|
||||
|
||||
__assert(hashtable_init(&pidtable, 100) == 0);
|
||||
MUTEX_INIT(&sched_pidtablemutex);
|
||||
|
||||
_cpu()->schedulerstack = vmm_map(NULL, SCHEDULER_STACK_SIZE, VMM_FLAGS_ALLOCATE, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, NULL);
|
||||
__assert(_cpu()->schedulerstack);
|
||||
_cpu()->schedulerstack = (void *)((uintptr_t)_cpu()->schedulerstack + SCHEDULER_STACK_SIZE);
|
||||
@@ -658,6 +689,8 @@ void sched_runinit() {
|
||||
thread_t *uthread = sched_newthread(entry, PAGE_SIZE * 16, 1, proc, stack);
|
||||
__assert(uthread);
|
||||
|
||||
proc->threads[0] = uthread;
|
||||
|
||||
uthread->vmmctx = vmmctx;
|
||||
sched_queue(uthread);
|
||||
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
#include <kernel/scheduler.h>
|
||||
#include <arch/signal.h>
|
||||
#include <logging.h>
|
||||
|
||||
#define PROCESS_ENTER(proc) \
|
||||
bool procintstatus = interrupt_set(false); \
|
||||
spinlock_acquire(&proc->signals.lock);
|
||||
|
||||
#define PROCESS_LEAVE(proc) \
|
||||
spinlock_release(&proc->signals.lock); \
|
||||
interrupt_set(procintstatus);
|
||||
|
||||
#define THREAD_ENTER(thread) \
|
||||
bool threadintstatus = interrupt_set(false); \
|
||||
spinlock_acquire(&thread->signals.lock);
|
||||
|
||||
#define THREAD_LEAVE(thread) \
|
||||
spinlock_release(&thread->signals.lock); \
|
||||
interrupt_set(threadintstatus);
|
||||
|
||||
#define SIGNAL_ASSERT(s) __assert((s) < NSIG && (s) >= 0)
|
||||
|
||||
void signal_action(struct proc_t *proc, int signal, sigaction_t *new, sigaction_t *old) {
|
||||
SIGNAL_ASSERT(signal);
|
||||
PROCESS_ENTER(proc);
|
||||
|
||||
if (old)
|
||||
*old = proc->signals.actions[signal];
|
||||
|
||||
if (new)
|
||||
proc->signals.actions[signal] = *new;
|
||||
|
||||
PROCESS_LEAVE(proc);
|
||||
}
|
||||
|
||||
void signal_altstack(struct thread_t *thread, stack_t *new, stack_t *old) {
|
||||
THREAD_ENTER(thread);
|
||||
|
||||
if (old)
|
||||
*old = thread->signals.stack;
|
||||
|
||||
if (new)
|
||||
thread->signals.stack = *new;
|
||||
|
||||
THREAD_LEAVE(thread);
|
||||
}
|
||||
|
||||
void signal_changemask(struct thread_t *thread, int how, sigset_t *new, sigset_t *old) {
|
||||
THREAD_ENTER(thread);
|
||||
|
||||
if (old)
|
||||
*old = thread->signals.mask;
|
||||
|
||||
if (new) {
|
||||
switch (how) {
|
||||
case SIG_BLOCK:
|
||||
case SIG_UNBLOCK: {
|
||||
for (int i = 0; i < NSIG; ++i) {
|
||||
if (SIGNAL_GET(new, i) == 0)
|
||||
continue;
|
||||
|
||||
if (how == SIG_BLOCK && SIGNAL_GET(&thread->signals.mask, i) == 0)
|
||||
SIGNAL_SETON(&thread->signals.mask, i);
|
||||
else if (how == SIG_UNBLOCK && SIGNAL_GET(&thread->signals.mask, i))
|
||||
SIGNAL_SETOFF(&thread->signals.mask, i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SIG_SETMASK: {
|
||||
thread->signals.mask = *new;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
__assert(!"bad how");
|
||||
}
|
||||
}
|
||||
|
||||
THREAD_LEAVE(thread);
|
||||
}
|
||||
|
||||
void signal_pending(struct thread_t *thread, sigset_t *sigset) {
|
||||
proc_t *proc = thread->proc;
|
||||
PROCESS_ENTER(proc);
|
||||
THREAD_ENTER(thread);
|
||||
|
||||
// urgent set doesn't get returned here as it will always be handled
|
||||
// before a return to userspace
|
||||
memset(sigset, 0, sizeof(sigset_t));
|
||||
for (int i = 0; i < NSIG; ++i) {
|
||||
if (SIGNAL_GET(&proc->signals.pending, i))
|
||||
SIGNAL_SETON(sigset, i);
|
||||
|
||||
if (SIGNAL_GET(&thread->signals.pending, i))
|
||||
SIGNAL_SETON(sigset, i);
|
||||
}
|
||||
|
||||
THREAD_LEAVE(thread);
|
||||
PROCESS_LEAVE(proc);
|
||||
}
|
||||
|
||||
void signal_signalthread(struct thread_t *thread, int signal, bool urgent) {
|
||||
THREAD_ENTER(thread);
|
||||
|
||||
sigset_t *sigset = urgent ? &thread->signals.urgent : &thread->signals.pending;
|
||||
SIGNAL_SETON(sigset, signal);
|
||||
if (signal == SIGKILL || signal == SIGSTOP || urgent || SIGNAL_GET(&thread->signals.mask, signal) == 0)
|
||||
sched_wakeup(thread, SCHED_WAKEUP_REASON_INTERRUPTED);
|
||||
|
||||
THREAD_LEAVE(thread);
|
||||
}
|
||||
|
||||
void signal_signalproc(struct proc_t *proc, int signal) {
|
||||
// first, check if any threads have the signal unmasked, and set as pending for the first one
|
||||
MUTEX_ACQUIRE(&proc->mutex, false);
|
||||
PROCESS_ENTER(proc);
|
||||
for (int i = 0; i < proc->threadtablesize; ++i) {
|
||||
if (proc->threads[i] == NULL || (proc->threads[i]->flags & SCHED_THREAD_FLAGS_DEAD))
|
||||
continue;
|
||||
|
||||
THREAD_ENTER(proc->threads[i]);
|
||||
|
||||
// sigcont will wake up all the threads or unset sigstop as pending
|
||||
if (signal == SIGCONT) {
|
||||
// TODO this
|
||||
} else if (SIGNAL_GET(&proc->threads[i]->signals.mask, signal) == 0 || signal == SIGKILL || signal == SIGSTOP) {
|
||||
SIGNAL_SETON(&proc->threads[i]->signals.pending, signal);
|
||||
// TODO ipi if running isn't self
|
||||
sched_wakeup(proc->threads[i], SCHED_WAKEUP_REASON_INTERRUPTED);
|
||||
THREAD_LEAVE(proc->threads[i]);
|
||||
PROCESS_LEAVE(proc);
|
||||
MUTEX_RELEASE(&proc->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
THREAD_LEAVE(proc->threads[i]);
|
||||
}
|
||||
MUTEX_RELEASE(&proc->mutex);
|
||||
|
||||
// there wasn't any thread with it unmasked, so set it as pending for the whole process
|
||||
|
||||
SIGNAL_SETON(&proc->signals.pending, signal);
|
||||
|
||||
PROCESS_LEAVE(proc);
|
||||
}
|
||||
|
||||
#define ACTION_TERM 0
|
||||
#define ACTION_IGN 1
|
||||
#define ACTION_CORE 2
|
||||
#define ACTION_STOP 3
|
||||
#define ACTION_CONT 4
|
||||
|
||||
static int defaultactions[NSIG] = {
|
||||
[SIGABRT] = ACTION_CORE,
|
||||
[SIGALRM] = ACTION_TERM,
|
||||
[SIGBUS] = ACTION_CORE,
|
||||
[SIGCHLD] = ACTION_IGN,
|
||||
[SIGCONT] = ACTION_CONT,
|
||||
[SIGFPE] = ACTION_CORE,
|
||||
[SIGHUP] = ACTION_TERM,
|
||||
[SIGILL] = ACTION_CORE,
|
||||
[SIGINT] = ACTION_TERM,
|
||||
[SIGIO] = ACTION_TERM,
|
||||
[SIGKILL] = ACTION_TERM,
|
||||
[SIGPIPE] = ACTION_TERM,
|
||||
[SIGPOLL] = ACTION_TERM,
|
||||
[SIGPROF] = ACTION_TERM,
|
||||
[SIGPWR] = ACTION_TERM,
|
||||
[SIGQUIT] = ACTION_CORE,
|
||||
[SIGSEGV] = ACTION_CORE,
|
||||
[SIGSTOP] = ACTION_STOP,
|
||||
[SIGTSTP] = ACTION_STOP,
|
||||
[SIGSYS] = ACTION_CORE,
|
||||
[SIGTERM] = ACTION_TERM,
|
||||
[SIGTRAP] = ACTION_CORE,
|
||||
[SIGTTIN] = ACTION_STOP,
|
||||
[SIGTTOU] = ACTION_STOP,
|
||||
[SIGURG] = ACTION_IGN,
|
||||
[SIGUSR1] = ACTION_TERM,
|
||||
[SIGUSR2] = ACTION_TERM,
|
||||
[SIGVTALRM] = ACTION_TERM,
|
||||
[SIGXCPU] = ACTION_CORE,
|
||||
[SIGXFSZ] = ACTION_CORE,
|
||||
[SIGWINCH] = ACTION_IGN
|
||||
};
|
||||
|
||||
void signal_check(struct thread_t *thread, context_t *context) {
|
||||
proc_t *proc = thread->proc;
|
||||
|
||||
PROCESS_ENTER(proc);
|
||||
THREAD_ENTER(thread);
|
||||
|
||||
if (SIGNAL_GET(&proc->signals.pending, SIGKILL) || SIGNAL_GET(&thread->signals.pending, SIGKILL)) {
|
||||
THREAD_LEAVE(thread);
|
||||
PROCESS_LEAVE(proc);
|
||||
proc->status = SIGKILL;
|
||||
interrupt_set(true);
|
||||
sched_threadexit();
|
||||
}
|
||||
|
||||
// find the first pending signal which is unmasked
|
||||
|
||||
int signal;
|
||||
sigset_t *sigset = NULL;
|
||||
|
||||
// check the urgent sigset first
|
||||
for (int i = 0; i < NSIG; ++i) {
|
||||
if (SIGNAL_GET(&thread->signals.urgent, i) == 0)
|
||||
continue;
|
||||
|
||||
signal = i;
|
||||
sigset = &thread->signals.urgent;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NSIG && sigset == NULL; ++i) {
|
||||
if (SIGNAL_GET(&thread->signals.mask, i))
|
||||
continue;
|
||||
|
||||
if (SIGNAL_GET(&thread->signals.pending, i)) {
|
||||
signal = i;
|
||||
sigset = &thread->signals.pending;
|
||||
break;
|
||||
}
|
||||
|
||||
if (SIGNAL_GET(&proc->signals.pending, i)) {
|
||||
signal = i;
|
||||
sigset = &proc->signals.pending;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sigset == NULL)
|
||||
goto leave;
|
||||
|
||||
sigaction_t *action = &proc->signals.actions[signal];
|
||||
SIGNAL_SETOFF(sigset, signal);
|
||||
|
||||
// urgent signals cannot be ignored, if they are the default action will be run
|
||||
if (action->address == SIG_IGN && sigset != &thread->signals.urgent) {
|
||||
goto leave;
|
||||
} else if ((action->address == SIG_DFL && (action->flags & SA_SIGINFO) == 0) || (action->address == SIG_IGN && sigset == &thread->signals.urgent)) {
|
||||
// default action
|
||||
int defaction = defaultactions[signal];
|
||||
switch (defaction) {
|
||||
case ACTION_IGN:
|
||||
goto leave;
|
||||
case ACTION_CORE:
|
||||
case ACTION_TERM:
|
||||
proc->status = signal;
|
||||
interrupt_set(true);
|
||||
sched_threadexit();
|
||||
default:
|
||||
__assert(!"unsupported signal action");
|
||||
}
|
||||
} else {
|
||||
// execute handler
|
||||
ARCH_CONTEXT_THREADSAVE(thread, context);
|
||||
|
||||
void *altstack = NULL;
|
||||
// figure out the stack we will be running the signal handler in
|
||||
if (action->flags & SA_ONSTACK && thread->signals.stack.size > 0)
|
||||
altstack = thread->signals.stack.base;
|
||||
|
||||
// get where in memory to put the frame
|
||||
void *stack = altstack ? altstack : (void *)CTX_SP(context);
|
||||
#if ARCH_SIGNAL_STACK_GROWS_DOWNWARDS == 1
|
||||
stack = (void *)(((uintptr_t)stack - ARCH_SIGNAL_REDZONE_SIZE - sizeof(sigframe_t)) & ~0xf);
|
||||
#else
|
||||
#error unsupported
|
||||
#endif
|
||||
|
||||
// configure stack frame
|
||||
sigframe_t *sigframe = stack;
|
||||
sigframe->restorer = action->restorer;
|
||||
if (altstack) {
|
||||
memcpy(&sigframe->oldstack, &thread->signals.stack, sizeof(stack_t));
|
||||
memset(&thread->signals.stack, 0, sizeof(stack_t));
|
||||
}
|
||||
memcpy(&sigframe->oldmask, &thread->signals.mask, sizeof(sigset_t));
|
||||
memcpy(&sigframe->context, context, sizeof(context_t));
|
||||
memcpy(&sigframe->extracontext, &thread->extracontext, sizeof(extracontext_t));
|
||||
// TODO siginfo
|
||||
|
||||
// configure new thread signal mask
|
||||
if ((action->flags & SA_NODEFER) == 0)
|
||||
SIGNAL_SETON(&thread->signals.mask, signal);
|
||||
|
||||
for (int i = 0; i < signal; ++i) {
|
||||
if (SIGNAL_GET(&action->mask, i) == 0)
|
||||
continue;
|
||||
|
||||
SIGNAL_SETON(&thread->signals.mask, i);
|
||||
}
|
||||
|
||||
// configure return context
|
||||
memset(context, 0, sizeof(context_t));
|
||||
CTX_INIT(context, true, true);
|
||||
CTX_IP(context) = (uint64_t)action->address;
|
||||
CTX_SP(context) = (uint64_t)stack;
|
||||
CTX_ARG0(context) = signal;
|
||||
CTX_ARG1(context) = 0; // TODO pass siginfo
|
||||
CTX_ARG2(context) = 0; // TODO ucontext
|
||||
|
||||
// reset handler if asked for
|
||||
if (action->flags & SA_RESETHAND)
|
||||
memset(&action, 0, sizeof(sigaction_t));
|
||||
}
|
||||
|
||||
leave:
|
||||
THREAD_LEAVE(thread);
|
||||
PROCESS_LEAVE(proc);
|
||||
}
|
||||
@@ -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