aboutsummaryrefslogtreecommitdiff
path: root/arch/sparc/kernel/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel/signal.c')
-rw-r--r--arch/sparc/kernel/signal.c117
1 files changed, 31 insertions, 86 deletions
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index 5f34d7dc2b89..0748d8147bbf 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -35,9 +35,6 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
void *fpqueue, unsigned long *fpqdepth);
extern void fpload(unsigned long *fpregs, unsigned long *fsr);
-asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
- unsigned long orig_o0, int restart_syscall);
-
/* Signal frames: the original one (compatible with SunOS):
*
* Set up a signal frame... Make the stack look the way SunOS
@@ -95,98 +92,30 @@ struct rt_signal_frame {
#define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7)))
#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7)))
-/*
- * atomically swap in the new signal mask, and wait for a signal.
- * This is really tricky on the Sparc, watch out...
- */
-asmlinkage void _sigpause_common(old_sigset_t set, struct pt_regs *regs)
+static int _sigpause_common(old_sigset_t set)
{
- sigset_t saveset;
-
set &= _BLOCKABLE;
spin_lock_irq(&current->sighand->siglock);
- saveset = current->blocked;
+ current->saved_sigmask = current->blocked;
siginitset(&current->blocked, set);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
- regs->pc = regs->npc;
- regs->npc += 4;
-
- /* Condition codes and return value where set here for sigpause,
- * and so got used by setup_frame, which again causes sigreturn()
- * to return -EINTR.
- */
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- /*
- * Return -EINTR and set condition code here,
- * so the interrupted system call actually returns
- * these.
- */
- regs->psr |= PSR_C;
- regs->u_regs[UREG_I0] = EINTR;
- if (do_signal(&saveset, regs, 0, 0))
- return;
- }
-}
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ set_thread_flag(TIF_RESTORE_SIGMASK);
-asmlinkage void do_sigpause(unsigned int set, struct pt_regs *regs)
-{
- _sigpause_common(set, regs);
+ return -ERESTARTNOHAND;
}
-asmlinkage void do_sigsuspend (struct pt_regs *regs)
+asmlinkage int sys_sigpause(unsigned int set)
{
- _sigpause_common(regs->u_regs[UREG_I0], regs);
+ return _sigpause_common(set);
}
-asmlinkage void do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize,
- struct pt_regs *regs)
+asmlinkage int sys_sigsuspend(old_sigset_t set)
{
- sigset_t oldset, set;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t)) {
- regs->psr |= PSR_C;
- regs->u_regs[UREG_I0] = EINVAL;
- return;
- }
-
- if (copy_from_user(&set, uset, sizeof(set))) {
- regs->psr |= PSR_C;
- regs->u_regs[UREG_I0] = EFAULT;
- return;
- }
-
- sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- oldset = current->blocked;
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- regs->pc = regs->npc;
- regs->npc += 4;
-
- /* Condition codes and return value where set here for sigpause,
- * and so got used by setup_frame, which again causes sigreturn()
- * to return -EINTR.
- */
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- /*
- * Return -EINTR and set condition code here,
- * so the interrupted system call actually returns
- * these.
- */
- regs->psr |= PSR_C;
- regs->u_regs[UREG_I0] = EINTR;
- if (do_signal(&oldset, regs, 0, 0))
- return;
- }
+ return _sigpause_common(set);
}
static inline int
@@ -1067,13 +996,13 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*/
-asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
- unsigned long orig_i0, int restart_syscall)
+asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int restart_syscall)
{
siginfo_t info;
struct sparc_deliver_cookie cookie;
struct k_sigaction ka;
int signr;
+ sigset_t *oldset;
/*
* XXX Disable svr4 signal handling until solaris emulation works.
@@ -1089,7 +1018,9 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
cookie.restart_syscall = restart_syscall;
cookie.orig_i0 = orig_i0;
- 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, &cookie);
@@ -1098,7 +1029,14 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
syscall_restart(cookie.orig_i0, regs, &ka.sa);
handle_signal(signr, &ka, &info, oldset,
regs, svr4_signal);
- return 1;
+ /* 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);
+ return;
}
if (cookie.restart_syscall &&
(regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
@@ -1115,7 +1053,14 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
regs->pc -= 4;
regs->npc -= 4;
}
- return 0;
+
+ /* 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);
+ }
}
asmlinkage int