use MCS locks in signal handling code

This commit is contained in:
Balazs Gerofi
2016-12-05 18:07:08 +09:00
parent 87d36a7752
commit a8c4ab221b
4 changed files with 81 additions and 57 deletions

View File

@ -695,7 +695,7 @@ do_signal(unsigned long rc, void *regs0, struct thread *thread, struct sig_pendi
int orgsig;
int ptraceflag = 0;
struct mcs_rwlock_node_irqsave lock;
unsigned long irqstate;
struct mcs_rwlock_node_irqsave mcs_rw_node;
for(w = pending->sigmask.__val[0], sig = 0; w; sig++, w >>= 1);
dkprintf("do_signal(): tid=%d, pid=%d, sig=%d\n", thread->tid, proc->pid, sig);
@ -718,12 +718,12 @@ do_signal(unsigned long rc, void *regs0, struct thread *thread, struct sig_pendi
rc = regs->gpr.rax;
}
irqstate = ihk_mc_spinlock_lock(&thread->sigcommon->lock);
mcs_rwlock_writer_lock(&thread->sigcommon->lock, &mcs_rw_node);
k = thread->sigcommon->action + sig - 1;
if(k->sa.sa_handler == SIG_IGN){
kfree(pending);
ihk_mc_spinlock_unlock(&thread->sigcommon->lock, irqstate);
mcs_rwlock_writer_unlock(&thread->sigcommon->lock, &mcs_rw_node);
return;
}
else if(k->sa.sa_handler){
@ -808,7 +808,7 @@ do_signal(unsigned long rc, void *regs0, struct thread *thread, struct sig_pendi
if(copy_to_user(sigsp, &ksigsp, sizeof ksigsp)){
kfree(pending);
ihk_mc_spinlock_unlock(&thread->sigcommon->lock, irqstate);
mcs_rwlock_writer_unlock(&thread->sigcommon->lock, &mcs_rw_node);
kprintf("do_signal,write_process_vm failed\n");
terminate(0, sig);
return;
@ -827,7 +827,7 @@ do_signal(unsigned long rc, void *regs0, struct thread *thread, struct sig_pendi
if(!(k->sa.sa_flags & SA_NODEFER))
thread->sigmask.__val[0] |= pending->sigmask.__val[0];
kfree(pending);
ihk_mc_spinlock_unlock(&thread->sigcommon->lock, irqstate);
mcs_rwlock_writer_unlock(&thread->sigcommon->lock, &mcs_rw_node);
if(regs->gpr.rflags & RFLAGS_TF){
struct siginfo info;
@ -853,7 +853,7 @@ do_signal(unsigned long rc, void *regs0, struct thread *thread, struct sig_pendi
}
else
kfree(pending);
ihk_mc_spinlock_unlock(&thread->sigcommon->lock, irqstate);
mcs_rwlock_writer_unlock(&thread->sigcommon->lock, &mcs_rw_node);
switch (sig) {
case SIGSTOP:
case SIGTSTP:
@ -954,11 +954,11 @@ do_signal(unsigned long rc, void *regs0, struct thread *thread, struct sig_pendi
static struct sig_pending *
getsigpending(struct thread *thread, int delflag){
struct list_head *head;
ihk_spinlock_t *lock;
mcs_rwlock_lock_t *lock;
struct mcs_rwlock_node_irqsave mcs_rw_node;
struct sig_pending *next;
struct sig_pending *pending;
__sigset_t w;
int irqstate;
__sigset_t x;
int sig;
struct k_sigaction *k;
@ -967,8 +967,12 @@ getsigpending(struct thread *thread, int delflag){
lock = &thread->sigcommon->lock;
head = &thread->sigcommon->sigpending;
for(;;){
irqstate = ihk_mc_spinlock_lock(lock);
for(;;) {
if (delflag)
mcs_rwlock_writer_lock(lock, &mcs_rw_node);
else
mcs_rwlock_reader_lock(lock, &mcs_rw_node);
list_for_each_entry_safe(pending, next, head, list){
for(x = pending->sigmask.__val[0], sig = 0; x; sig++, x >>= 1);
k = thread->sigcommon->action + sig - 1;
@ -977,17 +981,26 @@ getsigpending(struct thread *thread, int delflag){
(k->sa.sa_handler != (void *)1 &&
k->sa.sa_handler != NULL)){
if(!(pending->sigmask.__val[0] & w)){
if(delflag)
if(delflag)
list_del(&pending->list);
ihk_mc_spinlock_unlock(lock, irqstate);
if (delflag)
mcs_rwlock_writer_unlock(lock, &mcs_rw_node);
else
mcs_rwlock_reader_unlock(lock, &mcs_rw_node);
return pending;
}
}
}
ihk_mc_spinlock_unlock(lock, irqstate);
if (delflag)
mcs_rwlock_writer_unlock(lock, &mcs_rw_node);
else
mcs_rwlock_reader_unlock(lock, &mcs_rw_node);
if(lock == &thread->sigpendinglock)
return NULL;
lock = &thread->sigpendinglock;
head = &thread->sigpending;
}
@ -1035,22 +1048,25 @@ check_signal(unsigned long rc, void *regs0, int num)
}
}
ihk_mc_spinlock_unlock(&(cpu_local_var(runq_lock)), irqstate);
return;
goto out;
}
if(regs != NULL && !interrupt_from_user(regs)) {
return;
goto out;
}
for(;;){
pending = getsigpending(thread, 1);
if(!pending) {
dkprintf("check_signal,queue is empty\n");
return;
goto out;
}
do_signal(rc, regs, thread, pending, num);
}
out:
return;
}
unsigned long
@ -1064,7 +1080,8 @@ do_kill(struct thread *thread, int pid, int tid, int sig, siginfo_t *info,
struct thread *tthread = NULL;
int i;
__sigset_t mask;
ihk_spinlock_t *savelock = NULL;
mcs_rwlock_lock_t *savelock = NULL;
struct mcs_rwlock_node mcs_rw_node;
struct list_head *head = NULL;
int rc;
unsigned long irqstate = 0;
@ -1248,7 +1265,7 @@ done:
doint = 0;
ihk_mc_spinlock_lock_noirq(savelock);
mcs_rwlock_writer_lock_noirq(savelock, &mcs_rw_node);
/* Put signal event even when handler is SIG_IGN or SIG_DFL
because target ptraced thread must call ptrace_report_signal
@ -1287,7 +1304,7 @@ done:
}
}
}
ihk_mc_spinlock_unlock_noirq(savelock);
mcs_rwlock_writer_unlock_noirq(savelock, &mcs_rw_node);
cpu_restore_interrupt(irqstate);
if (doint && !(mask & tthread->sigmask.__val[0])) {

View File

@ -407,7 +407,7 @@ struct mckfd {
#define SFD_NONBLOCK 04000
struct sig_common {
ihk_spinlock_t lock;
mcs_rwlock_lock_t lock;
ihk_atomic_t use;
struct k_sigaction action[_NSIG];
struct list_head sigpending;
@ -624,7 +624,7 @@ struct thread {
sigset_t sigmask;
stack_t sigstack;
struct list_head sigpending;
ihk_spinlock_t sigpendinglock;
mcs_rwlock_lock_t sigpendinglock;
volatile int sigevent;
// gpio

View File

@ -277,10 +277,10 @@ create_thread(unsigned long user_pc)
dkprintf("fork(): sigshared\n");
ihk_atomic_set(&thread->sigcommon->use, 1);
ihk_mc_spinlock_init(&thread->sigcommon->lock);
mcs_rwlock_init(&thread->sigcommon->lock);
INIT_LIST_HEAD(&thread->sigcommon->sigpending);
ihk_mc_spinlock_init(&thread->sigpendinglock);
mcs_rwlock_init(&thread->sigpendinglock);
INIT_LIST_HEAD(&thread->sigpending);
thread->sigstack.ss_sp = NULL;
@ -441,11 +441,11 @@ clone_thread(struct thread *org, unsigned long pc, unsigned long sp,
memcpy(thread->sigcommon->action, org->sigcommon->action,
sizeof(struct k_sigaction) * _NSIG);
ihk_atomic_set(&thread->sigcommon->use, 1);
ihk_mc_spinlock_init(&thread->sigcommon->lock);
mcs_rwlock_init(&thread->sigcommon->lock);
INIT_LIST_HEAD(&thread->sigcommon->sigpending);
// TODO: copy signalfd
}
ihk_mc_spinlock_init(&thread->sigpendinglock);
mcs_rwlock_init(&thread->sigpendinglock);
INIT_LIST_HEAD(&thread->sigpending);
thread->sigmask = org->sigmask;

View File

@ -2627,16 +2627,16 @@ do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
{
struct thread *thread = cpu_local_var(current);
struct k_sigaction *k;
long irqstate;
struct mcs_rwlock_node_irqsave mcs_rw_node;
ihk_mc_user_context_t ctx0;
irqstate = ihk_mc_spinlock_lock(&thread->sigcommon->lock);
mcs_rwlock_writer_lock(&thread->sigcommon->lock, &mcs_rw_node);
k = thread->sigcommon->action + sig - 1;
if(oact)
memcpy(oact, k, sizeof(struct k_sigaction));
if(act)
memcpy(k, act, sizeof(struct k_sigaction));
ihk_mc_spinlock_unlock(&thread->sigcommon->lock, irqstate);
mcs_rwlock_writer_unlock(&thread->sigcommon->lock, &mcs_rw_node);
if(act){
ihk_mc_syscall_arg0(&ctx0) = sig;
@ -2808,10 +2808,10 @@ fault:
SYSCALL_DECLARE(rt_sigpending)
{
int flag;
struct sig_pending *pending;
struct list_head *head;
ihk_spinlock_t *lock;
mcs_rwlock_lock_t *lock;
struct mcs_rwlock_node_irqsave mcs_rw_node;
__sigset_t w = 0;
struct thread *thread = cpu_local_var(current);
sigset_t *set = (sigset_t *)ihk_mc_syscall_arg0(ctx);
@ -2822,19 +2822,19 @@ SYSCALL_DECLARE(rt_sigpending)
lock = &thread->sigcommon->lock;
head = &thread->sigcommon->sigpending;
flag = ihk_mc_spinlock_lock(lock);
mcs_rwlock_writer_lock(lock, &mcs_rw_node);
list_for_each_entry(pending, head, list){
w |= pending->sigmask.__val[0];
}
ihk_mc_spinlock_unlock(lock, flag);
mcs_rwlock_writer_unlock(lock, &mcs_rw_node);
lock = &thread->sigpendinglock;
head = &thread->sigpending;
flag = ihk_mc_spinlock_lock(lock);
mcs_rwlock_writer_lock(lock, &mcs_rw_node);
list_for_each_entry(pending, head, list){
w |= pending->sigmask.__val[0];
}
ihk_mc_spinlock_unlock(lock, flag);
mcs_rwlock_writer_unlock(lock, &mcs_rw_node);
if(copy_to_user(set->__val, &w, sizeof w))
return -EFAULT;
@ -3369,10 +3369,10 @@ SYSCALL_DECLARE(rt_sigtimedwait)
__sigset_t wset;
__sigset_t nset;
struct timespec wtimeout;
unsigned long flag;
struct sig_pending *pending;
struct list_head *head;
ihk_spinlock_t *lock;
mcs_rwlock_lock_t *lock;
struct mcs_rwlock_node_irqsave mcs_rw_node;
int w;
int sig;
struct timespec ats;
@ -3438,18 +3438,18 @@ SYSCALL_DECLARE(rt_sigtimedwait)
lock = &thread->sigcommon->lock;
head = &thread->sigcommon->sigpending;
flag = ihk_mc_spinlock_lock(lock);
mcs_rwlock_writer_lock(lock, &mcs_rw_node);
list_for_each_entry(pending, head, list){
if(pending->sigmask.__val[0] & wset)
break;
}
if(&pending->list == head){
ihk_mc_spinlock_unlock(lock, flag);
mcs_rwlock_writer_unlock(lock, &mcs_rw_node);
lock = &thread->sigpendinglock;
head = &thread->sigpending;
flag = ihk_mc_spinlock_lock(lock);
mcs_rwlock_writer_lock(lock, &mcs_rw_node);
list_for_each_entry(pending, head, list){
if(pending->sigmask.__val[0] & wset)
break;
@ -3459,25 +3459,25 @@ SYSCALL_DECLARE(rt_sigtimedwait)
if(&pending->list != head){
list_del(&pending->list);
thread->sigmask.__val[0] = bset;
ihk_mc_spinlock_unlock(lock, flag);
mcs_rwlock_writer_unlock(lock, &mcs_rw_node);
break;
}
ihk_mc_spinlock_unlock(lock, flag);
mcs_rwlock_writer_unlock(lock, &mcs_rw_node);
lock = &thread->sigcommon->lock;
head = &thread->sigcommon->sigpending;
flag = ihk_mc_spinlock_lock(lock);
mcs_rwlock_writer_lock(lock, &mcs_rw_node);
list_for_each_entry(pending, head, list){
if(pending->sigmask.__val[0] & nset)
break;
}
if(&pending->list == head){
ihk_mc_spinlock_unlock(lock, flag);
mcs_rwlock_writer_unlock(lock, &mcs_rw_node);
lock = &thread->sigpendinglock;
head = &thread->sigpending;
flag = ihk_mc_spinlock_lock(lock);
mcs_rwlock_writer_lock(lock, &mcs_rw_node);
list_for_each_entry(pending, head, list){
if(pending->sigmask.__val[0] & nset)
break;
@ -3487,11 +3487,11 @@ SYSCALL_DECLARE(rt_sigtimedwait)
if(&pending->list != head){
list_del(&pending->list);
thread->sigmask.__val[0] = bset;
ihk_mc_spinlock_unlock(lock, flag);
mcs_rwlock_writer_unlock(lock, &mcs_rw_node);
do_signal(-EINTR, NULL, thread, pending, 0);
return -EINTR;
}
ihk_mc_spinlock_unlock(lock, flag);
mcs_rwlock_writer_unlock(lock, &mcs_rw_node);
thread->sigevent = 0;
}
@ -3528,10 +3528,10 @@ do_sigsuspend(struct thread *thread, const sigset_t *set)
{
__sigset_t wset;
__sigset_t bset;
unsigned long flag;
struct sig_pending *pending;
struct list_head *head;
ihk_spinlock_t *lock;
mcs_rwlock_lock_t *lock;
struct mcs_rwlock_node_irqsave mcs_rw_node;
wset = set->__val[0];
wset &= ~__sigmask(SIGKILL);
@ -3546,31 +3546,31 @@ do_sigsuspend(struct thread *thread, const sigset_t *set)
lock = &thread->sigcommon->lock;
head = &thread->sigcommon->sigpending;
flag = ihk_mc_spinlock_lock(lock);
mcs_rwlock_writer_lock(lock, &mcs_rw_node);
list_for_each_entry(pending, head, list){
if(!(pending->sigmask.__val[0] & wset))
break;
}
if(&pending->list == head){
ihk_mc_spinlock_unlock(lock, flag);
mcs_rwlock_writer_unlock(lock, &mcs_rw_node);
lock = &thread->sigpendinglock;
head = &thread->sigpending;
flag = ihk_mc_spinlock_lock(lock);
mcs_rwlock_writer_lock(lock, &mcs_rw_node);
list_for_each_entry(pending, head, list){
if(!(pending->sigmask.__val[0] & wset))
break;
}
}
if(&pending->list == head){
ihk_mc_spinlock_unlock(lock, flag);
mcs_rwlock_writer_unlock(lock, &mcs_rw_node);
thread->sigevent = 0;
continue;
}
list_del(&pending->list);
ihk_mc_spinlock_unlock(lock, flag);
mcs_rwlock_writer_unlock(lock, &mcs_rw_node);
thread->sigmask.__val[0] = bset;
do_signal(-EINTR, NULL, thread, pending, 0);
break;
@ -8458,8 +8458,11 @@ long syscall(int num, ihk_mc_user_context_t *ctx)
l = syscall_generic_forwarding(num, ctx);
}
check_signal(l, NULL, num);
if (num != __NR_sched_yield &&
num != __NR_futex) {
check_signal(l, NULL, num);
}
#ifdef TRACK_SYSCALLS
if (num < 300) {
if (!cpu_local_var(current)->syscall_cnts) {
@ -8471,11 +8474,15 @@ long syscall(int num, ihk_mc_user_context_t *ctx)
}
}
else {
dkprintf("syscall > 300?? : %d\n", num);
if (num != 701)
kprintf("syscall > 300?? : %d\n", num);
}
#endif // TRACK_SYSCALLS
check_need_resched();
if (num != __NR_sched_yield &&
num != __NR_futex) {
check_need_resched();
}
if (cpu_local_var(current)->proc->ptrace) {
ptrace_syscall_exit(cpu_local_var(current));