signal (part 2) sigpending

This commit is contained in:
Tomoki Shirasawa
2014-01-07 19:52:06 +09:00
parent a8c249ddaf
commit 0465cc16b9
4 changed files with 200 additions and 55 deletions

View File

@@ -21,6 +21,7 @@
#include <process.h> #include <process.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <kmalloc.h>
void terminate(int, int, ihk_mc_user_context_t *); void terminate(int, int, ihk_mc_user_context_t *);
@@ -108,56 +109,97 @@ check_signal(unsigned long rc, unsigned long *regs)
struct process *proc; 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;
int irqstate;
if(clv == NULL) if(clv == NULL)
return; return;
proc = cpu_local_var(current); proc = cpu_local_var(current);
if(proc == NULL || proc->pid == 0) if(proc == NULL || proc->pid == 0)
return; return;
sig = proc->signal;
proc->signal = 0; w = proc->sigmask.__val[0];
if(sig){ lock = &proc->sigshared->lock;
int irqstate = ihk_mc_spinlock_lock(&proc->sighandler->lock); head = &proc->sigshared->sigpending;
if(regs == NULL){ /* call from syscall */ pending = NULL;
asm volatile ("movq %%gs:132,%0" : "=r" (regs)); irqstate = ihk_mc_spinlock_lock(lock);
regs -= 16; list_for_each_entry_safe(pending, next, head, list){
if(!(pending->sigmask.__val[0] & w)){
list_del(&pending->list);
break;
} }
else{ }
rc = regs[9]; /* rax */ if(&pending->list == head)
} pending = NULL;
k = proc->sighandler->action + sig - 1; ihk_mc_spinlock_unlock(lock, irqstate);
if(k->sa.sa_handler == (void *)1){ 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);
irqstate = ihk_mc_spinlock_lock(&proc->sighandler->lock);
if(regs == NULL){ /* call from syscall */
asm volatile ("movq %%gs:132,%0" : "=r" (regs));
regs -= 16;
}
else{
rc = regs[9]; /* rax */
}
k = proc->sighandler->action + sig - 1;
if(k->sa.sa_handler == (void *)1){
kfree(pending);
ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate);
return;
}
else if(k->sa.sa_handler){
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); ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate);
return; return;
} }
else if(k->sa.sa_handler){
unsigned long *usp; /* user stack */
if(regs[14] & 0x8000000000000000){ // kernel addr usp = (void *)regs[14];
proc->signal = sig; memcpy(proc->sigstack, regs, 128);
ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate); proc->sigrc = rc;
return; usp--;
} *usp = (unsigned long)k->sa.sa_restorer;
usp = (void *)regs[14]; regs[4] = (unsigned long)sig;
memcpy(proc->sigstack, regs, 128); regs[11] = (unsigned long)k->sa.sa_handler;
proc->sigrc = rc; regs[14] = (unsigned long)usp;
usp--; kfree(pending);
*usp = (unsigned long)k->sa.sa_restorer; ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate);
}
regs[4] = (unsigned long)sig; else{
regs[11] = (unsigned long)k->sa.sa_handler; kfree(pending);
regs[14] = (unsigned long)usp; ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate);
ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate); if(sig == SIGCHLD || sig == SIGURG)
} return;
else{ terminate(0, sig, (ihk_mc_user_context_t *)regs[14]);
ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate);
if(sig == SIGCHLD || sig == SIGURG)
return;
terminate(0, sig, (ihk_mc_user_context_t *)regs[14]);
}
} }
} }
@@ -166,7 +208,12 @@ do_kill(int pid, int tid, int sig)
{ {
struct process *proc = cpu_local_var(current); struct process *proc = cpu_local_var(current);
struct process *tproc = NULL; struct process *tproc = NULL;
int i; int i;
__sigset_t mask;
struct sig_pending *pending;
struct list_head *head;
int irqstate;
int rc;
if(proc == NULL || proc->pid == 0){ if(proc == NULL || proc->pid == 0){
return -ESRCH; return -ESRCH;
@@ -176,7 +223,11 @@ do_kill(int pid, int tid, int sig)
return -EINVAL; return -EINVAL;
if(tid == -1){ if(tid == -1){
if(pid == proc->pid || pid <= 0){ if(pid == -1)
return -EPERM;
if(proc->pid == -pid)
pid = -pid;
if(pid == proc->pid || pid == 0){
tproc = proc; tproc = proc;
} }
} }
@@ -206,13 +257,43 @@ do_kill(int pid, int tid, int sig)
if(sig == 0) if(sig == 0)
return 0; return 0;
if(__sigmask(sig) & proc->sigmask.__val[0]){ if(tid == -1){
// TODO: masked signal: ignore -> pending irqstate = ihk_mc_spinlock_lock(&tproc->sigshared->lock);
return 0; head = &tproc->sigshared->sigpending;
}
else{
irqstate = ihk_mc_spinlock_lock(&tproc->sigpendinglock);
head = &tproc->sigpending;
}
mask = __sigmask(sig);
pending = NULL;
rc = 0;
if(sig < 34){
list_for_each_entry(pending, head, list){
if(pending->sigmask.__val[0] == mask)
break;
}
if(&pending->list == head)
pending = NULL;
}
if(pending == NULL){
pending = kmalloc(sizeof(struct sig_pending), IHK_MC_AP_NOWAIT);
pending->sigmask.__val[0] = mask;
if(!pending){
rc = -ENOMEM;
}
else{
list_add_tail(&pending->list, head);
}
}
if(tid == -1){
ihk_mc_spinlock_unlock(&tproc->sigshared->lock, irqstate);
}
else{
ihk_mc_spinlock_unlock(&tproc->sigpendinglock, irqstate);
} }
proc->signal = sig;
interrupt_syscall(1); interrupt_syscall(1);
return 0; return rc;
} }
void void
@@ -227,11 +308,6 @@ set_signal(int sig, unsigned long *regs, int nonmaskable)
if(nonmaskable){ if(nonmaskable){
terminate(0, sig, (ihk_mc_user_context_t *)regs[14]); terminate(0, sig, (ihk_mc_user_context_t *)regs[14]);
} }
else{
// TODO: masked signal: ignore -> pending
return;
}
} }
proc->signal = sig; do_kill(proc->pid, proc->tid, sig);
interrupt_syscall(1);
} }

View File

@@ -84,6 +84,18 @@ struct sig_handler {
struct k_sigaction action[_NSIG]; struct k_sigaction action[_NSIG];
}; };
struct sig_pending {
struct list_head list;
sigset_t sigmask;
// TODO: siginfo
};
struct sig_shared {
ihk_spinlock_t lock;
ihk_atomic_t use;
struct list_head sigpending;
};
typedef void pgio_func_t(void *arg); typedef void pgio_func_t(void *arg);
struct process { struct process {
@@ -110,10 +122,10 @@ struct process {
int tid; int tid;
sigset_t sigmask; sigset_t sigmask;
int signal; ihk_spinlock_t sigpendinglock;
// sigset_t sigpend; struct list_head sigpending;
struct sig_shared *sigshared;
struct sig_handler *sighandler; struct sig_handler *sighandler;
// ihk_mc_kernel_context_t sigctx;
char sigstack[512]; // TODO: 1. move to user stack char sigstack[512]; // TODO: 1. move to user stack
// TODO: 2. backup FR and MMX regs // TODO: 2. backup FR and MMX regs
unsigned long sigrc; // return code of rt_sigreturn (x86_64: rax reg.) unsigned long sigrc; // return code of rt_sigreturn (x86_64: rax reg.)

View File

@@ -83,9 +83,20 @@ struct process *create_process(unsigned long user_pc)
ihk_mc_free_pages(proc, KERNEL_STACK_NR_PAGES); ihk_mc_free_pages(proc, KERNEL_STACK_NR_PAGES);
return NULL; return NULL;
} }
proc->sigshared = kmalloc(sizeof(struct sig_shared), IHK_MC_AP_NOWAIT);
if(!proc->sigshared){
ihk_mc_free_pages(proc->sighandler, KERNEL_STACK_NR_PAGES);
ihk_mc_free_pages(proc, KERNEL_STACK_NR_PAGES);
return NULL;
}
memset(proc->sighandler, '\0', sizeof(struct sig_handler)); memset(proc->sighandler, '\0', sizeof(struct sig_handler));
ihk_atomic_set(&proc->sighandler->use, 1); ihk_atomic_set(&proc->sighandler->use, 1);
ihk_mc_spinlock_init(&proc->sighandler->lock); ihk_mc_spinlock_init(&proc->sighandler->lock);
ihk_atomic_set(&proc->sigshared->use, 1);
ihk_mc_spinlock_init(&proc->sigshared->lock);
INIT_LIST_HEAD(&proc->sigshared->sigpending);
ihk_mc_spinlock_init(&proc->sigpendinglock);
INIT_LIST_HEAD(&proc->sigpending);
ihk_mc_init_user_process(&proc->ctx, &proc->uctx, ihk_mc_init_user_process(&proc->ctx, &proc->uctx,
((char *)proc) + ((char *)proc) +
@@ -133,6 +144,12 @@ struct process *clone_process(struct process *org, unsigned long pc,
proc->sighandler = org->sighandler; proc->sighandler = org->sighandler;
ihk_atomic_inc(&org->sighandler->use); ihk_atomic_inc(&org->sighandler->use);
proc->sigshared = org->sigshared;
ihk_atomic_inc(&org->sigshared->use);
ihk_mc_spinlock_init(&proc->sigpendinglock);
INIT_LIST_HEAD(&proc->sigpending);
ihk_mc_spinlock_init(&proc->spin_sleep_lock); ihk_mc_spinlock_init(&proc->spin_sleep_lock);
proc->spin_sleep = 0; proc->spin_sleep = 0;
@@ -1339,9 +1356,23 @@ void hold_process(struct process *proc)
void destroy_process(struct process *proc) void destroy_process(struct process *proc)
{ {
struct sig_pending *pending;
struct sig_pending *next;
if(ihk_atomic_dec_and_test(&proc->sighandler->use)){ if(ihk_atomic_dec_and_test(&proc->sighandler->use)){
kfree(proc->sighandler); kfree(proc->sighandler);
} }
if(ihk_atomic_dec_and_test(&proc->sigshared->use)){
list_for_each_entry_safe(pending, next, &proc->sigshared->sigpending, list){
list_del(&pending->list);
kfree(pending);
}
list_del(&proc->sigshared->sigpending);
kfree(proc->sigshared);
}
list_for_each_entry_safe(pending, next, &proc->sigpending, list){
list_del(&pending->list);
kfree(pending);
}
ihk_mc_free_pages(proc, KERNEL_STACK_NR_PAGES); ihk_mc_free_pages(proc, KERNEL_STACK_NR_PAGES);
} }

View File

@@ -1075,7 +1075,7 @@ SYSCALL_DECLARE(rt_sigprocmask)
const sigset_t *set = (const sigset_t *)ihk_mc_syscall_arg1(ctx); const sigset_t *set = (const sigset_t *)ihk_mc_syscall_arg1(ctx);
sigset_t *oldset = (sigset_t *)ihk_mc_syscall_arg2(ctx); sigset_t *oldset = (sigset_t *)ihk_mc_syscall_arg2(ctx);
struct process *proc = cpu_local_var(current); struct process *proc = cpu_local_var(current);
int irqstate; int flag;
if(set && if(set &&
how != SIG_BLOCK && how != SIG_BLOCK &&
@@ -1083,7 +1083,7 @@ SYSCALL_DECLARE(rt_sigprocmask)
how != SIG_SETMASK) how != SIG_SETMASK)
return -EINVAL; return -EINVAL;
irqstate = ihk_mc_spinlock_lock(&proc->sighandler->lock); flag = ihk_mc_spinlock_lock(&proc->sighandler->lock);
if(oldset) if(oldset)
oldset->__val[0] = proc->sigmask.__val[0]; oldset->__val[0] = proc->sigmask.__val[0];
if(set){ if(set){
@@ -1099,12 +1099,38 @@ SYSCALL_DECLARE(rt_sigprocmask)
break; break;
} }
} }
ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate); ihk_mc_spinlock_unlock(&proc->sighandler->lock, flag);
return 0; return 0;
} }
SYSCALL_DECLARE(rt_sigpending) SYSCALL_DECLARE(rt_sigpending)
{ {
int flag;
struct sig_pending *pending;
struct list_head *head;
ihk_spinlock_t *lock;
__sigset_t w = 0;
struct process *proc = cpu_local_var(current);
sigset_t *set = (sigset_t *)ihk_mc_syscall_arg0(ctx);
lock = &proc->sigshared->lock;
head = &proc->sigshared->sigpending;
flag = ihk_mc_spinlock_lock(lock);
list_for_each_entry(pending, head, list){
w |= pending->sigmask.__val[0];
}
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){
w |= pending->sigmask.__val[0];
}
ihk_mc_spinlock_unlock(lock, flag);
set->__val[0] = w;
return 0; return 0;
} }