summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2006-02-08 12:58:41 +0000
committerRalf Baechle <ralf@linux-mips.org>2006-02-08 17:52:24 +0000
commit7b3e2fc847c8325a7b35185fa1fc2f1729ed9c5b (patch)
treeb6e8728ad6cbf756f049b9dea106b679230710a7
parentac171c46667c1cb2ee9e22312291df6ed78e1b6e (diff)
downloadlwn-7b3e2fc847c8325a7b35185fa1fc2f1729ed9c5b.tar.gz
lwn-7b3e2fc847c8325a7b35185fa1fc2f1729ed9c5b.zip
[MIPS] Add support for TIF_RESTORE_SIGMASK.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org> ---
-rw-r--r--arch/mips/kernel/process.c4
-rw-r--r--arch/mips/kernel/signal.c86
-rw-r--r--arch/mips/kernel/signal32.c8
-rw-r--r--arch/mips/kernel/signal_n32.c4
-rw-r--r--include/asm-mips/abi.h4
-rw-r--r--include/asm-mips/thread_info.h2
6 files changed, 62 insertions, 46 deletions
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index fa98f10d0132..02adc7384153 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -58,8 +58,8 @@ ATTRIB_NORET void cpu_idle(void)
}
}
-extern int do_signal(sigset_t *oldset, struct pt_regs *regs);
-extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
+extern int do_signal(struct pt_regs *regs);
+extern int do_signal32(struct pt_regs *regs);
/*
* Native o32 and N64 ABI without DSP ASE
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index aaec4785e9a6..86a14d7b8534 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -39,8 +39,6 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-int do_signal(sigset_t *oldset, struct pt_regs *regs);
-
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
@@ -50,7 +48,7 @@ save_static_function(sys_sigsuspend);
__attribute_used__ noinline static int
_sys_sigsuspend(nabi_no_regargs struct pt_regs regs)
{
- sigset_t saveset, newset;
+ sigset_t newset;
sigset_t __user *uset;
uset = (sigset_t __user *) regs.regs[4];
@@ -59,19 +57,15 @@ _sys_sigsuspend(nabi_no_regargs struct pt_regs regs)
sigdelsetmask(&newset, ~_BLOCKABLE);
spin_lock_irq(&current->sighand->siglock);
- saveset = current->blocked;
+ current->saved_sigmask = current->blocked;
current->blocked = newset;
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
- regs.regs[2] = EINTR;
- regs.regs[7] = 1;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(&saveset, &regs))
- return -EINTR;
- }
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ set_thread_flag(TIF_RESTORE_SIGMASK);
+ return -ERESTARTNOHAND;
}
#endif
@@ -79,7 +73,7 @@ save_static_function(sys_rt_sigsuspend);
__attribute_used__ noinline static int
_sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
{
- sigset_t saveset, newset;
+ sigset_t newset;
sigset_t __user *unewset;
size_t sigsetsize;
@@ -94,19 +88,15 @@ _sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
sigdelsetmask(&newset, ~_BLOCKABLE);
spin_lock_irq(&current->sighand->siglock);
- saveset = current->blocked;
+ current->saved_sigmask = current->blocked;
current->blocked = newset;
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
- regs.regs[2] = EINTR;
- regs.regs[7] = 1;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(&saveset, &regs))
- return -EINTR;
- }
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ set_thread_flag(TIF_RESTORE_SIGMASK);
+ return -ERESTARTNOHAND;
}
#ifdef CONFIG_TRAD_SIGNALS
@@ -315,11 +305,11 @@ int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
current->comm, current->pid,
frame, regs->cp0_epc, frame->regs[31]);
#endif
- return 1;
+ return 0;
give_sigsegv:
force_sigsegv(signr, current);
- return 0;
+ return -EFAULT;
}
#endif
@@ -375,11 +365,11 @@ int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
current->comm, current->pid,
frame, regs->cp0_epc, regs->regs[31]);
#endif
- return 1;
+ return 0;
give_sigsegv:
force_sigsegv(signr, current);
- return 0;
+ return -EFAULT;
}
static inline int handle_signal(unsigned long sig, siginfo_t *info,
@@ -393,7 +383,7 @@ static inline int handle_signal(unsigned long sig, siginfo_t *info,
regs->regs[2] = EINTR;
break;
case ERESTARTSYS:
- if(!(ka->sa.sa_flags & SA_RESTART)) {
+ if (!(ka->sa.sa_flags & SA_RESTART)) {
regs->regs[2] = EINTR;
break;
}
@@ -420,9 +410,10 @@ static inline int handle_signal(unsigned long sig, siginfo_t *info,
return ret;
}
-int do_signal(sigset_t *oldset, struct pt_regs *regs)
+int do_signal(struct pt_regs *regs)
{
struct k_sigaction ka;
+ sigset_t *oldset;
siginfo_t info;
int signr;
@@ -437,12 +428,26 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
if (try_to_freeze())
goto no_signal;
- if (!oldset)
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = &current->saved_sigmask;
+ else
oldset = &current->blocked;
+
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
- if (signr > 0)
- return handle_signal(signr, &info, &ka, oldset, regs);
+ if (signr > 0) {
+ /* Whee! Actually deliver the signal. */
+ if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
+ /*
+ * A signal was successfully delivered; the saved
+ * sigmask will have been stored in the signal frame,
+ * and will be restored by sigreturn, so we can simply
+ * clear the TIF_RESTORE_SIGMASK flag.
+ */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ }
+ }
no_signal:
/*
@@ -463,18 +468,27 @@ no_signal:
regs->cp0_epc -= 4;
}
}
+
+ /*
+ * If there's no signal to deliver, we just put the saved sigmask
+ * back
+ */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+ }
+
return 0;
}
/*
* notification of userspace execution resumption
- * - triggered by current->work.notify_resume
+ * - triggered by the TIF_WORK_MASK flags
*/
-asmlinkage void do_notify_resume(struct pt_regs *regs, sigset_t *oldset,
+asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
__u32 thread_info_flags)
{
/* deal with pending signal delivery */
- if (thread_info_flags & _TIF_SIGPENDING) {
- current->thread.abi->do_signal(oldset, regs);
- }
+ if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+ current->thread.abi->do_signal(regs);
}
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 136260c8f756..da3271e1fdac 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -694,11 +694,11 @@ int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
current->comm, current->pid,
frame, regs->cp0_epc, frame->sf_code);
#endif
- return 1;
+ return 0;
give_sigsegv:
force_sigsegv(signr, current);
- return 0;
+ return -EFAULT;
}
int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
@@ -765,11 +765,11 @@ int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
current->comm, current->pid,
frame, regs->cp0_epc, frame->rs_code);
#endif
- return 1;
+ return 0;
give_sigsegv:
force_sigsegv(signr, current);
- return 0;
+ return -EFAULT;
}
static inline int handle_signal(unsigned long sig, siginfo_t *info,
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
index 9156863c1a5d..384fc4a639a4 100644
--- a/arch/mips/kernel/signal_n32.c
+++ b/arch/mips/kernel/signal_n32.c
@@ -186,9 +186,9 @@ int setup_rt_frame_n32(struct k_sigaction * ka,
current->comm, current->pid,
frame, regs->cp0_epc, regs->regs[31]);
#endif
- return 1;
+ return 0;
give_sigsegv:
force_sigsegv(signr, current);
- return 0;
+ return -EFAULT;
}
diff --git a/include/asm-mips/abi.h b/include/asm-mips/abi.h
index 2e7e651c3e3f..5edd69bf0f24 100644
--- a/include/asm-mips/abi.h
+++ b/include/asm-mips/abi.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2005 by Ralf Baechle
+ * Copyright (C) 2005, 06 by Ralf Baechle (ralf@linux-mips.org)
* Copyright (C) 2005 MIPS Technologies, Inc.
*/
#ifndef _ASM_ABI_H
@@ -13,7 +13,7 @@
#include <asm/siginfo.h>
struct mips_abi {
- int (* const do_signal)(sigset_t *oldset, struct pt_regs *regs);
+ int (* const do_signal)(struct pt_regs *regs);
int (* const setup_frame)(struct k_sigaction * ka,
struct pt_regs *regs, int signr,
sigset_t *set);
diff --git a/include/asm-mips/thread_info.h b/include/asm-mips/thread_info.h
index 1612b3fe1080..fa193f861e71 100644
--- a/include/asm-mips/thread_info.h
+++ b/include/asm-mips/thread_info.h
@@ -114,6 +114,7 @@ register struct thread_info *__current_thread_info __asm__("$28");
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_SYSCALL_AUDIT 4 /* syscall auditing active */
#define TIF_SECCOMP 5 /* secure computing */
+#define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */
#define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */
#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 18
@@ -125,6 +126,7 @@ register struct thread_info *__current_thread_info __asm__("$28");
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1<<TIF_SECCOMP)
+#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_USEDFPU (1<<TIF_USEDFPU)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)