signal part 4 (sigsuspend etc)

This commit is contained in:
Tomoki Shirasawa
2014-01-24 10:14:49 +09:00
parent c421965542
commit 26d68d391d
6 changed files with 202 additions and 83 deletions

View File

@@ -368,7 +368,7 @@ void setup_x86_ap(void (*next_func)(void))
} }
void arch_show_interrupt_context(const void *reg); void arch_show_interrupt_context(const void *reg);
void set_signal(int, void *, int); void set_signal(int, void *);
void check_signal(long, void *); void check_signal(long, void *);
void handle_interrupt(int vector, struct x86_regs *regs) void handle_interrupt(int vector, struct x86_regs *regs)
@@ -409,7 +409,7 @@ void gpe_handler(struct x86_regs *regs)
kprintf("General protection fault (err: %lx, %lx:%lx)\n", kprintf("General protection fault (err: %lx, %lx:%lx)\n",
regs->error, regs->cs, regs->rip); regs->error, regs->cs, regs->rip);
arch_show_interrupt_context(regs); arch_show_interrupt_context(regs);
set_signal(SIGILL, regs, 1); set_signal(SIGILL, regs);
check_signal(0, regs); check_signal(0, regs);
// panic("GPF"); // panic("GPF");
} }

View File

@@ -33,6 +33,16 @@ struct sigaction {
sigset_t sa_mask; sigset_t sa_mask;
}; };
//// work in progress
struct sigbackup {
unsigned long rc; // return code of rt_sigreturn (rax)
void *uctx;
sigset_t mask;
double fpregs[16];
};
////
struct k_sigaction { struct k_sigaction {
struct sigaction sa; struct sigaction sa;
}; };

View File

@@ -41,6 +41,7 @@ SYSCALL_DELEGATED(20, writev)
SYSCALL_DELEGATED(21, access) SYSCALL_DELEGATED(21, access)
SYSCALL_HANDLED(24, sched_yield) SYSCALL_HANDLED(24, sched_yield)
SYSCALL_HANDLED(28, madvise) SYSCALL_HANDLED(28, madvise)
SYSCALL_HANDLED(34, pause)
SYSCALL_HANDLED(39, getpid) SYSCALL_HANDLED(39, getpid)
SYSCALL_HANDLED(56, clone) SYSCALL_HANDLED(56, clone)
SYSCALL_HANDLED(59, execve) SYSCALL_HANDLED(59, execve)

View File

@@ -95,6 +95,8 @@ SYSCALL_DECLARE(rt_sigreturn)
regs -= 16; regs -= 16;
memcpy(regs, proc->sigstack, 128); memcpy(regs, proc->sigstack, 128);
proc->sigmask.__val[0] = proc->supmask.__val[0];
return proc->sigrc; return proc->sigrc;
} }
@@ -104,58 +106,18 @@ extern void interrupt_syscall(int all);
extern int num_processors; extern int num_processors;
void void
check_signal(unsigned long rc, unsigned long *regs) do_signal(unsigned long rc, unsigned long *regs, struct process *proc, struct sig_pending *pending)
{ {
struct process *proc;
struct k_sigaction *k; struct k_sigaction *k;
int sig; int sig;
struct sig_pending *pending;
struct sig_pending *next;
struct list_head *head;
ihk_spinlock_t *lock;
__sigset_t w; __sigset_t w;
int irqstate; int irqstate;
if(clv == NULL)
return;
proc = cpu_local_var(current);
if(proc == NULL || proc->pid == 0)
return;
w = proc->sigmask.__val[0];
lock = &proc->sigshared->lock;
head = &proc->sigshared->sigpending;
pending = NULL;
irqstate = ihk_mc_spinlock_lock(lock);
list_for_each_entry_safe(pending, next, head, list){
if(!(pending->sigmask.__val[0] & w)){
list_del(&pending->list);
break;
}
}
if(&pending->list == head)
pending = NULL;
ihk_mc_spinlock_unlock(lock, irqstate);
if(!pending){
lock = &proc->sigpendinglock;
head = &proc->sigpending;
irqstate = ihk_mc_spinlock_lock(lock);
list_for_each_entry_safe(pending, next, head, list){
if(!(pending->sigmask.__val[0] & w)){
list_del(&pending->list);
break;
}
}
if(&pending->list == head)
pending = NULL;
ihk_mc_spinlock_unlock(lock, irqstate);
}
if(!pending)
return;
for(w = pending->sigmask.__val[0], sig = 0; w; sig++, w >>= 1); for(w = pending->sigmask.__val[0], sig = 0; w; sig++, w >>= 1);
if(sig == SIGKILL || sig == SIGTERM)
terminate(0, sig, (ihk_mc_user_context_t *)regs[14]);
irqstate = ihk_mc_spinlock_lock(&proc->sighandler->lock); irqstate = ihk_mc_spinlock_lock(&proc->sighandler->lock);
if(regs == NULL){ /* call from syscall */ if(regs == NULL){ /* call from syscall */
asm volatile ("movq %%gs:132,%0" : "=r" (regs)); asm volatile ("movq %%gs:132,%0" : "=r" (regs));
@@ -174,14 +136,6 @@ check_signal(unsigned long rc, unsigned long *regs)
else if(k->sa.sa_handler){ else if(k->sa.sa_handler){
unsigned long *usp; /* user stack */ unsigned long *usp; /* user stack */
if(regs[14] & 0x8000000000000000){ // kernel addr
int flag = ihk_mc_spinlock_lock(lock);
list_add(&pending->list, head);
ihk_mc_spinlock_unlock(lock, flag);
ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate);
return;
}
usp = (void *)regs[14]; usp = (void *)regs[14];
memcpy(proc->sigstack, regs, 128); memcpy(proc->sigstack, regs, 128);
proc->sigrc = rc; proc->sigrc = rc;
@@ -192,6 +146,7 @@ check_signal(unsigned long rc, unsigned long *regs)
regs[11] = (unsigned long)k->sa.sa_handler; regs[11] = (unsigned long)k->sa.sa_handler;
regs[14] = (unsigned long)usp; regs[14] = (unsigned long)usp;
kfree(pending); kfree(pending);
proc->sigmask.__val[0] |= pending->sigmask.__val[0];
ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate); ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate);
} }
else{ else{
@@ -203,6 +158,63 @@ check_signal(unsigned long rc, unsigned long *regs)
} }
} }
void
check_signal(unsigned long rc, unsigned long *regs)
{
struct process *proc;
struct sig_pending *pending;
struct sig_pending *next;
struct list_head *head;
ihk_spinlock_t *lock;
__sigset_t w;
int irqstate;
if(clv == NULL)
return;
proc = cpu_local_var(current);
if(proc == NULL || proc->pid == 0)
return;
if(regs != NULL && (regs[14] & 0x8000000000000000))
return;
for(;;){
w = proc->sigmask.__val[0];
lock = &proc->sigshared->lock;
head = &proc->sigshared->sigpending;
pending = NULL;
irqstate = ihk_mc_spinlock_lock(lock);
list_for_each_entry_safe(pending, next, head, list){
if(!(pending->sigmask.__val[0] & w)){
list_del(&pending->list);
break;
}
}
if(&pending->list == head)
pending = NULL;
ihk_mc_spinlock_unlock(lock, irqstate);
if(!pending){
lock = &proc->sigpendinglock;
head = &proc->sigpending;
irqstate = ihk_mc_spinlock_lock(lock);
list_for_each_entry_safe(pending, next, head, list){
if(!(pending->sigmask.__val[0] & w)){
list_del(&pending->list);
break;
}
}
if(&pending->list == head)
pending = NULL;
ihk_mc_spinlock_unlock(lock, irqstate);
}
if(!pending)
return;
do_signal(rc, regs, proc, pending);
}
}
unsigned long unsigned long
do_kill(int pid, int tid, int sig) do_kill(int pid, int tid, int sig)
{ {
@@ -284,6 +296,7 @@ do_kill(int pid, int tid, int sig)
} }
else{ else{
list_add_tail(&pending->list, head); list_add_tail(&pending->list, head);
proc->sigevent = 1;
} }
} }
if(tid == -1){ if(tid == -1){
@@ -297,17 +310,16 @@ do_kill(int pid, int tid, int sig)
} }
void void
set_signal(int sig, unsigned long *regs, int nonmaskable) set_signal(int sig, unsigned long *regs)
{ {
struct process *proc = cpu_local_var(current); struct process *proc = cpu_local_var(current);
if(proc == NULL || proc->pid == 0) if(proc == NULL || proc->pid == 0)
return; return;
if(__sigmask(sig) & proc->sigmask.__val[0]){ if((__sigmask(sig) & proc->sigmask.__val[0]) ||
if(nonmaskable){ (regs[14] & 0x8000000000000000))
terminate(0, sig, (ihk_mc_user_context_t *)regs[14]); terminate(0, sig, (ihk_mc_user_context_t *)regs[14]);
} else
} do_kill(proc->pid, proc->tid, sig);
do_kill(proc->pid, proc->tid, sig);
} }

View File

@@ -164,7 +164,7 @@ static struct ihk_mc_interrupt_handler query_free_mem_handler = {
.priv = NULL, .priv = NULL,
}; };
void set_signal(int, unsigned long *, int); void set_signal(int, unsigned long *);
void check_signal(long, unsigned long *); void check_signal(long, unsigned long *);
static void unhandled_page_fault(struct process *proc, void *fault_addr, void *regs) static void unhandled_page_fault(struct process *proc, void *fault_addr, void *regs)
@@ -234,10 +234,10 @@ static void page_fault_handler(void *fault_addr, uint64_t reason, void *regs)
reason, regs, error); reason, regs, error);
unhandled_page_fault(proc, fault_addr, regs); unhandled_page_fault(proc, fault_addr, regs);
if (error == -ERANGE) { if (error == -ERANGE) {
set_signal(SIGBUS, regs, 1); set_signal(SIGBUS, regs);
} }
else { else {
set_signal(SIGSEGV, regs, 1); set_signal(SIGSEGV, regs);
} }
check_signal(0, regs); check_signal(0, regs);
goto out; goto out;

View File

@@ -93,6 +93,7 @@ static char *syscall_name[] MCKERNEL_UNUSED = {
}; };
void check_signal(long rc, unsigned long *regs); void check_signal(long rc, unsigned long *regs);
void do_signal(long rc, unsigned long *regs, struct process *proc, struct sig_pending *pending);
int copy_from_user(struct process *, void *, const void *, size_t); int copy_from_user(struct process *, void *, const void *, size_t);
int copy_to_user(struct process *, void *, const void *, size_t); int copy_to_user(struct process *, void *, const void *, size_t);
@@ -1154,37 +1155,132 @@ SYSCALL_DECLARE(rt_sigpending)
SYSCALL_DECLARE(rt_sigtimedwait) SYSCALL_DECLARE(rt_sigtimedwait)
{ {
/* struct process *proc = cpu_local_var(current);
sigset_t * const sigset_t *set = (const sigset_t *)ihk_mc_syscall_arg0(ctx);
siginfo_t * siginfo_t *info = (siginfo_t *)ihk_mc_syscall_arg1(ctx);
struct timespec * void *timeout = (void *)ihk_mc_syscall_arg2(ctx);
size_t size_t sigsetsize = (size_t)ihk_mc_syscall_arg3(ctx);
*/ siginfo_t winfo;
return 0; __sigset_t wset;
long wtimeout[2];
if (sigsetsize > sizeof(sigset_t))
return -EINVAL;
memset(&winfo, '\0', sizeof winfo);
if(copy_from_user(proc, &wset, set, sizeof wset))
return -EFAULT;
if(copy_from_user(proc, wtimeout, timeout, sizeof wtimeout))
return -EFAULT;
if(copy_to_user(proc, info, &winfo, sizeof winfo))
return -EFAULT;
return -EOPNOTSUPP;
} }
SYSCALL_DECLARE(rt_sigqueueinfo) SYSCALL_DECLARE(rt_sigqueueinfo)
{ {
/* struct process *proc = cpu_local_var(current);
pid_t int pid = (int)ihk_mc_syscall_arg0(ctx);
int int sig = (int)ihk_mc_syscall_arg1(ctx);
siginfo_t * siginfo_t *info = (siginfo_t *)ihk_mc_syscall_arg2(ctx);
*/ siginfo_t winfo;
return 0;
if(copy_from_user(proc, &winfo, info, sizeof winfo))
return -EFAULT;
return -EOPNOTSUPP;
}
static int
do_sigsuspend(struct process *proc, const sigset_t *set)
{
__sigset_t wset;
int flag;
struct sig_pending *pending;
struct list_head *head;
ihk_spinlock_t *lock;
wset = set->__val[0];
wset &= ~__sigmask(SIGKILL);
wset &= ~__sigmask(SIGTERM);
proc->sigmask.__val[0] = wset;
for(;;){
while(proc->sigevent == 0);
proc->sigevent = 0;
lock = &proc->sigshared->lock;
head = &proc->sigshared->sigpending;
flag = ihk_mc_spinlock_lock(lock);
list_for_each_entry(pending, head, list){
if(!(pending->sigmask.__val[0] & wset))
break;
}
if(&pending->list == head){
ihk_mc_spinlock_unlock(lock, flag);
lock = &proc->sigpendinglock;
head = &proc->sigpending;
flag = ihk_mc_spinlock_lock(lock);
list_for_each_entry(pending, head, list){
if(!(pending->sigmask.__val[0] & wset))
break;
}
}
if(&pending->list == head){
ihk_mc_spinlock_unlock(lock, flag);
continue;
}
list_del(&pending->list);
ihk_mc_spinlock_unlock(lock, flag);
do_signal(-EINTR, NULL, proc, pending);
break;
}
return -EINTR;
}
SYSCALL_DECLARE(pause)
{
struct process *proc = cpu_local_var(current);
return do_sigsuspend(proc, &proc->sigmask);
} }
SYSCALL_DECLARE(rt_sigsuspend) SYSCALL_DECLARE(rt_sigsuspend)
{ {
/* struct process *proc = cpu_local_var(current);
sigset_t * const sigset_t *set = (const sigset_t *)ihk_mc_syscall_arg0(ctx);
size_t size_t sigsetsize = (size_t)ihk_mc_syscall_arg1(ctx);
*/ sigset_t wset;
return 0;
if (sigsetsize > sizeof(sigset_t))
return -EINVAL;
if(copy_from_user(proc, &wset, set, sizeof wset))
return -EFAULT;
return do_sigsuspend(proc, &wset);
} }
SYSCALL_DECLARE(sigaltstack) SYSCALL_DECLARE(sigaltstack)
{ {
return 0; struct process *proc = cpu_local_var(current);
const stack_t *ss = (const stack_t *)ihk_mc_syscall_arg0(ctx);
stack_t *oss = (stack_t *)ihk_mc_syscall_arg1(ctx);
stack_t wss;
memset(&wss, '\0', sizeof wss);
if(oss)
if(copy_to_user(proc, oss, &wss, sizeof wss))
return -EFAULT;
if(ss)
if(copy_from_user(proc, &wss, ss, sizeof wss))
return -EFAULT;
return -EOPNOTSUPP;
} }
SYSCALL_DECLARE(madvise) SYSCALL_DECLARE(madvise)