summaryrefslogtreecommitdiff
path: root/arch/sh/kernel/signal_64.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/signal_64.c')
-rw-r--r--arch/sh/kernel/signal_64.c154
1 files changed, 80 insertions, 74 deletions
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c
index ce3e851dffcb..b22fdfaaa191 100644
--- a/arch/sh/kernel/signal_64.c
+++ b/arch/sh/kernel/signal_64.c
@@ -2,7 +2,7 @@
* arch/sh/kernel/signal_64.c
*
* Copyright (C) 2000, 2001 Paolo Alberelli
- * Copyright (C) 2003 Paul Mundt
+ * Copyright (C) 2003 - 2008 Paul Mundt
* Copyright (C) 2004 Richard Curnow
*
* This file is subject to the terms and conditions of the GNU General Public
@@ -43,10 +43,38 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-static void
+static int
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
sigset_t *oldset, struct pt_regs * regs);
+static inline void
+handle_syscall_restart(struct pt_regs *regs, struct sigaction *sa)
+{
+ /* If we're not from a syscall, bail out */
+ if (regs->syscall_nr < 0)
+ return;
+
+ /* check for system call restart.. */
+ switch (regs->regs[REG_RET]) {
+ case -ERESTART_RESTARTBLOCK:
+ case -ERESTARTNOHAND:
+ no_system_call_restart:
+ regs->regs[REG_RET] = -EINTR;
+ regs->sr |= 1;
+ break;
+
+ case -ERESTARTSYS:
+ if (!(sa->sa_flags & SA_RESTART))
+ goto no_system_call_restart;
+ /* fallthrough */
+ case -ERESTARTNOINTR:
+ /* Decode syscall # */
+ regs->regs[REG_RET] = regs->syscall_nr;
+ regs->pc -= 4;
+ break;
+ }
+}
+
/*
* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -80,21 +108,23 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset)
oldset = &current->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, 0);
-
if (signr > 0) {
- /* Whee! Actually deliver the signal. */
- handle_signal(signr, &info, &ka, oldset, regs);
+ if (regs->sr & 1)
+ handle_syscall_restart(regs, &ka.sa);
- /*
- * If a signal was successfully delivered, the saved sigmask
- * is in its frame, and we can clear the TIF_RESTORE_SIGMASK
- * flag.
- */
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- clear_thread_flag(TIF_RESTORE_SIGMASK);
-
- tracehook_signal_handler(signr, &info, &ka, regs, 0);
- return 1;
+ /* Whee! Actually deliver the signal. */
+ if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
+ /*
+ * If a signal was successfully delivered, the
+ * saved sigmask is in its frame, and we can
+ * clear the TIF_RESTORE_SIGMASK flag.
+ */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+ tracehook_signal_handler(signr, &info, &ka, regs, 0);
+ return 1;
+ }
}
no_signal:
@@ -129,7 +159,6 @@ no_signal:
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
-
asmlinkage int
sys_sigsuspend(old_sigset_t mask,
unsigned long r3, unsigned long r4, unsigned long r5,
@@ -235,20 +264,16 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
return do_sigaltstack(uss, uoss, REF_REG_SP);
}
-
/*
* Do a signal return; undo the signal stack.
*/
-
-struct sigframe
-{
+struct sigframe {
struct sigcontext sc;
unsigned long extramask[_NSIG_WORDS-1];
long long retcode[2];
};
-struct rt_sigframe
-{
+struct rt_sigframe {
struct siginfo __user *pinfo;
void *puc;
struct siginfo info;
@@ -450,7 +475,6 @@ badframe:
/*
* Set up a signal frame.
*/
-
static int
setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
unsigned long mask)
@@ -504,8 +528,8 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
void sa_default_restorer(void); /* See comments below */
void sa_default_rt_restorer(void); /* See comments below */
-static void setup_frame(int sig, struct k_sigaction *ka,
- sigset_t *set, struct pt_regs *regs)
+static int setup_frame(int sig, struct k_sigaction *ka,
+ sigset_t *set, struct pt_regs *regs)
{
struct sigframe __user *frame;
int err = 0;
@@ -596,23 +620,21 @@ static void setup_frame(int sig, struct k_sigaction *ka,
set_fs(USER_DS);
-#if DEBUG_SIG
/* Broken %016Lx */
- printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
- signal,
- current->comm, current->pid, frame,
- regs->pc >> 32, regs->pc & 0xffffffff,
- DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
-#endif
+ pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
+ signal, current->comm, current->pid, frame,
+ regs->pc >> 32, regs->pc & 0xffffffff,
+ DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
- return;
+ return 0;
give_sigsegv:
force_sigsegv(sig, current);
+ return -EFAULT;
}
-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
- sigset_t *set, struct pt_regs *regs)
+static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
int err = 0;
@@ -702,62 +724,46 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
set_fs(USER_DS);
-#if DEBUG_SIG
- /* Broken %016Lx */
- printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
- signal,
- current->comm, current->pid, frame,
- regs->pc >> 32, regs->pc & 0xffffffff,
- DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
-#endif
+ pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
+ signal, current->comm, current->pid, frame,
+ regs->pc >> 32, regs->pc & 0xffffffff,
+ DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
- return;
+ return 0;
give_sigsegv:
force_sigsegv(sig, current);
+ return -EFAULT;
}
/*
* OK, we're invoking a handler
*/
-
-static void
+static int
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
sigset_t *oldset, struct pt_regs * regs)
{
- /* Are we from a system call? */
- if (regs->syscall_nr >= 0) {
- /* If so, check system call restarting.. */
- switch (regs->regs[REG_RET]) {
- case -ERESTART_RESTARTBLOCK:
- case -ERESTARTNOHAND:
- no_system_call_restart:
- regs->regs[REG_RET] = -EINTR;
- break;
-
- case -ERESTARTSYS:
- if (!(ka->sa.sa_flags & SA_RESTART))
- goto no_system_call_restart;
- /* fallthrough */
- case -ERESTARTNOINTR:
- /* Decode syscall # */
- regs->regs[REG_RET] = regs->syscall_nr;
- regs->pc -= 4;
- }
- }
+ int ret;
/* Set up the stack frame */
if (ka->sa.sa_flags & SA_SIGINFO)
- setup_rt_frame(sig, ka, info, oldset, regs);
+ ret = setup_rt_frame(sig, ka, info, oldset, regs);
else
- setup_frame(sig, ka, oldset, regs);
+ ret = setup_frame(sig, ka, oldset, regs);
+
+ if (ka->sa.sa_flags & SA_ONESHOT)
+ ka->sa.sa_handler = SIG_DFL;
+
+ if (ret == 0) {
+ spin_lock_irq(&current->sighand->siglock);
+ sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ if (!(ka->sa.sa_flags & SA_NODEFER))
+ sigaddset(&current->blocked,sig);
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+ }
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked,sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ return ret;
}
asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)