#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
asmlinkage void ret_from_sys_call(void);
-static void do_signal(struct pt_regs *, struct switch_stack *,
- unsigned long, unsigned long);
-
/*
* The OSF/1 sigprocmask calling sequence is different from the
SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
-
- mask &= _BLOCKABLE;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
asmlinkage int
oldsp = rdusp();
frame = get_sigframe(ka, oldsp, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
+ return -EFAULT;
err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp);
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
/* Check that everything was written properly. */
if (err)
- goto give_sigsegv;
+ return err;
/* "Return" to the handler */
regs->r26 = r26;
printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
current->comm, current->pid, frame, regs->pc, regs->r26);
#endif
-
return 0;
-
-give_sigsegv:
- force_sigsegv(sig, current);
- return -EFAULT;
}
static int
oldsp = rdusp();
frame = get_sigframe(ka, oldsp, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
+ return -EFAULT;
err |= copy_siginfo_to_user(&frame->info, info);
set->sig[0], oldsp);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
}
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* "Return" to the handler */
regs->r26 = r26;
#endif
return 0;
-
-give_sigsegv:
- force_sigsegv(sig, current);
- return -EFAULT;
}
/*
* OK, we're invoking a handler.
*/
-static inline int
+static inline void
handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
- sigset_t *oldset, struct pt_regs * regs, struct switch_stack *sw)
+ struct pt_regs * regs, struct switch_stack *sw)
{
+ sigset_t *oldset = ¤t->blocked;
int ret;
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = ¤t->saved_sigmask;
+
if (ka->sa.sa_flags & SA_SIGINFO)
ret = setup_rt_frame(sig, ka, info, oldset, regs, sw);
else
ret = setup_frame(sig, ka, oldset, regs, sw);
- if (ret == 0)
- block_sigmask(ka, sig);
-
- return ret;
+ if (ret) {
+ force_sigsegv(sig, current);
+ return;
+ }
+ block_sigmask(ka, sig);
+ /* A signal was successfully delivered, and the
+ saved sigmask was stored on the signal frame,
+ and will be restored by sigreturn. So we can
+ simply clear the restore sigmask flag. */
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
}
static inline void
int signr;
unsigned long single_stepping = ptrace_cancel_bpt(current);
struct k_sigaction ka;
- sigset_t *oldset;
-
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- oldset = ¤t->saved_sigmask;
- else
- oldset = ¤t->blocked;
/* This lets the debugger run, ... */
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
/* Whee! Actually deliver the signal. */
if (r0)
syscall_restart(r0, r19, regs, &ka);
- if (handle_signal(signr, &ka, &info, oldset, regs, sw) == 0) {
- /* A signal was successfully delivered, and the
- saved sigmask was stored on the signal frame,
- and will be restored by sigreturn. So we can
- simply clear the restore sigmask flag. */
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- clear_thread_flag(TIF_RESTORE_SIGMASK);
- }
+ handle_signal(signr, &ka, &info, regs, sw);
if (single_stepping)
ptrace_set_bpt(current); /* re-set bpt */
return;
}
/* If there's no signal to deliver, we just restore the saved mask. */
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
- sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
- }
+ if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
+ set_current_blocked(¤t->saved_sigmask);
if (single_stepping)
ptrace_set_bpt(current); /* re-set breakpoint */
unsigned long thread_info_flags,
unsigned long r0, unsigned long r19)
{
- if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+ if (thread_info_flags & _TIF_SIGPENDING)
do_signal(regs, sw, r0, r19);
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
-
- mask &= _BLOCKABLE;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_restore_sigmask();
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
asmlinkage int
#include <asm-generic/signal-defs.h>
#ifdef __KERNEL__
-struct old_sigaction {
- __sighandler_t sa_handler;
- old_sigset_t sa_mask;
- unsigned long sa_flags;
- __sigrestore_t sa_restorer;
-};
-
struct sigaction {
__sighandler_t sa_handler;
unsigned long sa_flags;
struct rt_sigframe __user *frame;
sigset_t set;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
frame = (struct rt_sigframe __user *)regs->sp;
pr_debug("SIG return: frame = %p\n", frame);
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
*/
ret |= !valid_user_regs(regs);
- /*
- * Block the signal if we were unsuccessful.
- */
- if (ret != 0 || !(ka->sa.sa_flags & SA_NODEFER)) {
- spin_lock_irq(¤t->sighand->siglock);
- sigorsets(¤t->blocked, ¤t->blocked,
- &ka->sa.sa_mask);
- sigaddset(¤t->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
- }
-
- if (ret == 0)
+ if (ret != 0) {
+ force_sigsegv(sig, current);
return;
+ }
- force_sigsegv(sig, current);
+ /*
+ * Block the signal if we were successful.
+ */
+ block_sigmask(ka, sig);
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
}
/*
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ set_current_blocked(&set);
if (rt_restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
goto badframe;
return 0;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
return -EFAULT;
}
/* set up the stack frame */
ret = setup_rt_frame(sig, ka, info, oldset, regs);
- if (ret == 0) {
- spin_lock_irq(¤t->sighand->siglock);
- sigorsets(¤t->blocked, ¤t->blocked,
- &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(¤t->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
- }
+ if (ret == 0)
+ block_sigmask(ka, sig);
+
return ret;
}
struct rt_sigframe __user *frame;
sigset_t set;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
/*
* Since we stacked the signal on a dword boundary,
* 'sp' should be dword aligned here. If it's
* dummy arguments to be able to reach the regs argument. (Note that this
* arrangement relies on old_sigset_t occupying one register.)
*/
-int sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof,
- long srp, struct pt_regs *regs)
+int sys_sigsuspend(old_sigset_t mask)
{
- mask &= _BLOCKABLE;
- spin_lock_irq(¤t->sighand->siglock);
- current->saved_sigmask = current->blocked;
- siginitset(¤t->blocked, mask);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ sigset_t blocked;
+ siginitset(&blocked, mask);
+ return sigsuspend(&blocked);
}
int sys_sigaction(int sig, const struct old_sigaction __user *act,
old_sigset_t mask;
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
}
if (!ret && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
return ret;
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->sc))
goto badframe;
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
else
ret = setup_frame(sig, ka, oldset, regs);
- if (ret == 0) {
- spin_lock_irq(¤t->sighand->siglock);
- sigorsets(¤t->blocked, ¤t->blocked,
- &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(¤t->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
- }
+ if (ret == 0)
+ block_sigmask(ka, sig);
+
return ret;
}
* dummy arguments to be able to reach the regs argument.
*/
int
-sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof,
- long srp, struct pt_regs *regs)
+sys_sigsuspend(old_sigset_t mask)
{
- mask &= _BLOCKABLE;
- spin_lock_irq(¤t->sighand->siglock);
- current->saved_sigmask = current->blocked;
- siginitset(¤t->blocked, mask);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ sigset_t blocked;
+ siginitset(&blocked, mask);
+ return sigsuspend(&blocked);
}
int
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(newk.sa.sa_handler, &act->sa_handler) ||
- __get_user(newk.sa.sa_restorer, &act->sa_restorer))
+ __get_user(newk.sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(newk.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(newk.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&newk.sa.sa_mask, mask);
}
if (!retval && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(oldk.sa.sa_handler, &oact->sa_handler) ||
- __put_user(oldk.sa.sa_restorer, &oact->sa_restorer))
+ __put_user(oldk.sa.sa_restorer, &oact->sa_restorer) ||
+ __put_user(oldk.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(oldk.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
- __put_user(oldk.sa.sa_flags, &oact->sa_flags);
- __put_user(oldk.sa.sa_mask.sig[0], &oact->sa_mask);
}
return retval;
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
-
- current->blocked = set;
-
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->sc))
goto badframe;
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
-
- current->blocked = set;
-
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
return 0;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
-
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
return -EFAULT;
}
return 0;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
-
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
return -EFAULT;
}
else
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(¤t->sighand->siglock);
- sigorsets(¤t->blocked, ¤t->blocked,
- &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(¤t->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
- }
+ if (ret == 0)
+ block_sigmask(ka, sig);
return ret;
}
*/
asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask)
{
- mask &= _BLOCKABLE;
- spin_lock_irq(¤t->sighand->siglock);
- current->saved_sigmask = current->blocked;
- siginitset(¤t->blocked, mask);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ sigset_t blocked;
+ siginitset(&blocked, mask);
+ return sigsuspend(&blocked);
}
asmlinkage int sys_sigaction(int sig,
old_sigset_t mask;
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
}
if (!ret && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
return ret;
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(&frame->sc, &gr8))
goto badframe;
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(&frame->uc.uc_mcontext, &gr8))
goto badframe;
else
ret = setup_frame(sig, ka, oldset);
- if (ret == 0) {
- spin_lock_irq(¤t->sighand->siglock);
- sigorsets(¤t->blocked, ¤t->blocked,
- &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(¤t->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
- }
+ if (ret == 0)
+ block_sigmask(ka, sig);
return ret;
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
/*
* "Conditional" syscalls
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
-
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
-asmlinkage int do_sigsuspend(struct pt_regs *regs)
-{
- old_sigset_t mask = regs->er3;
- sigset_t saveset;
-
- mask &= _BLOCKABLE;
- spin_lock_irq(¤t->sighand->siglock);
- saveset = current->blocked;
- siginitset(¤t->blocked, mask);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
-
- regs->er0 = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(regs, &saveset))
- return -EINTR;
- }
-}
-
asmlinkage int
-do_rt_sigsuspend(struct pt_regs *regs)
+sys_sigsuspend(int unused1, int unused2, old_sigset_t mask)
{
- sigset_t *unewset = (sigset_t *)regs->er1;
- size_t sigsetsize = (size_t)regs->er2;
- sigset_t saveset, newset;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- if (copy_from_user(&newset, unewset, sizeof(newset)))
- return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
-
- spin_lock_irq(¤t->sighand->siglock);
- saveset = current->blocked;
- current->blocked = newset;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
-
- regs->er0 = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(regs, &saveset))
- return -EINTR;
- }
+ sigset_t blocked;
+ siginitset(&blocked, mask);
+ return sigsuspend(&blocked);
}
asmlinkage int
old_sigset_t mask;
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
}
if (!ret && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
return ret;
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->sc, &er0))
goto badframe;
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_unlock_irq(¤t->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_lock_irq(¤t->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &er0))
goto badframe;
return (void *)((usp - frame_size) & -8UL);
}
-static void setup_frame (int sig, struct k_sigaction *ka,
+static int setup_frame (int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs *regs)
{
struct sigframe *frame;
regs->er1 = (unsigned long)&(frame->sc);
regs->er5 = current->mm->start_data; /* GOT base */
- 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,
+static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe *frame;
regs->er2 = (unsigned long)&frame->uc;
regs->er5 = current->mm->start_data; /* GOT base */
- return;
+ return 0;
give_sigsegv:
force_sigsegv(sig, current);
+ return -EFAULT;
}
/*
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
sigset_t *oldset, struct pt_regs * regs)
{
+ int ret;
/* are we from a system call? */
if (regs->orig_er0 >= 0) {
switch (regs->er0) {
/* 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);
-
- spin_lock_irq(¤t->sighand->siglock);
- sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(¤t->blocked,sig);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ ret = setup_frame(sig, ka, oldset, regs);
+
+ if (!ret) {
+ block_sigmask(ka, sig);
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ }
}
/*
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*/
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset)
+statis void do_signal(struct pt_regs *regs)
{
siginfo_t info;
int signr;
struct k_sigaction ka;
+ sigset_t *oldset;
/*
* We want the common case to go fast, which
* if so.
*/
if ((regs->ccr & 0x10))
- return 1;
+ return;
if (try_to_freeze())
goto no_signal;
current->thread.esp0 = (unsigned long) regs;
- if (!oldset)
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = ¤t->saved_sigmask;
+ else
oldset = ¤t->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
/* Whee! Actually deliver the signal. */
handle_signal(signr, &info, &ka, oldset, regs);
- return 1;
+ return;
}
no_signal:
/* Did we come from a system call? */
regs->pc -= 2;
}
}
- return 0;
+
+ /* If there's no signal to deliver, we just restore the saved mask. */
+ if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
+ set_current_blocked(¤t->saved_sigmask);
}
asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
{
- if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
- do_signal(regs, NULL);
+ if (thread_info_flags & _TIF_SIGPENDING)
+ do_signal(regs);
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
SYMBOL_NAME_LABEL(sys_clone)
call_sp h8300_clone
-SYMBOL_NAME_LABEL(sys_sigsuspend)
- call_sp do_sigsuspend
-
-SYMBOL_NAME_LABEL(sys_rt_sigsuspend)
- call_sp do_rt_sigsuspend
-
SYMBOL_NAME_LABEL(sys_sigreturn)
call_sp do_sigreturn
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
+ tracehook_notify_resume(regs);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
struct rt_sigframe __user *frame;
sigset_t blocked;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
frame = (struct rt_sigframe __user *)pt_psp(regs);
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
goto give_sigsegv;
sigdelsetmask(&set, ~_BLOCKABLE);
-
- spin_lock_irq(¤t->sighand->siglock);
- {
- current->blocked = set;
- recalc_sigpending();
- }
- spin_unlock_irq(¤t->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(sc, scr))
goto give_sigsegv;
if (!setup_frame(sig, ka, info, oldset, scr))
return 0;
- spin_lock_irq(¤t->sighand->siglock);
- sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(¤t->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ block_sigmask(ka, sig);
/*
* Let tracing know that we've done the handler setup.
#include <asm-generic/signal-defs.h>
#ifdef __KERNEL__
-struct old_sigaction {
- __sighandler_t sa_handler;
- old_sigset_t sa_mask;
- unsigned long sa_flags;
- __sigrestore_t sa_restorer;
-};
-
struct sigaction {
__sighandler_t sa_handler;
unsigned long sa_flags;
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &result))
goto badframe;
if (setup_rt_frame(sig, ka, info, oldset, regs))
return -EFAULT;
- spin_lock_irq(¤t->sighand->siglock);
- sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(¤t->blocked,sig);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ block_sigmask(ka, sig);
return 0;
}
* bits 0-7 are tested at every exception exit
* bits 8-15 are also tested at syscall exit
*/
+#define TIF_NOTIFY_RESUME 5 /* callback before returning to user */
#define TIF_SIGPENDING 6 /* signal pending */
#define TIF_NEED_RESCHED 7 /* rescheduling necessary */
#define TIF_DELAYED_TRACE 14 /* single step a syscall */
jcs do_trace_exit
jmi do_delayed_trace
lslw #8,%d0
- jmi do_signal_return
+ jne do_signal_return
pea resume_userspace
jra schedule
| save top of frame
movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
lslb #1,%d0
- jmi do_signal_return
+ jne do_signal_return
pea resume_userspace
jra schedule
subql #4,%sp | dummy return address
SAVE_SWITCH_STACK
pea %sp@(SWITCH_STACK_SIZE)
- bsrl do_signal
+ bsrl do_notify_resume
addql #4,%sp
RESTORE_SWITCH_STACK
addql #4,%sp
#include <linux/tty.h>
#include <linux/binfmts.h>
#include <linux/module.h>
+#include <linux/tracehook.h>
#include <asm/setup.h>
#include <asm/uaccess.h>
asmlinkage int
sys_sigsuspend(int unused0, int unused1, old_sigset_t mask)
{
- mask &= _BLOCKABLE;
- spin_lock_irq(¤t->sighand->siglock);
- current->saved_sigmask = current->blocked;
- siginitset(¤t->blocked, mask);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_restore_sigmask();
-
- return -ERESTARTNOHAND;
+ sigset_t blocked;
+ siginitset(&blocked, mask);
+ return sigsuspend(&blocked);
}
asmlinkage int
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- current->blocked = set;
- recalc_sigpending();
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->sc, frame + 1))
goto badframe;
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- current->blocked = set;
- recalc_sigpending();
+ set_current_blocked(&set);
if (rt_restore_ucontext(regs, sw, &frame->uc))
goto badframe;
if (err)
return;
- sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(¤t->blocked,sig);
- recalc_sigpending();
+ block_sigmask(ka, sig);
if (test_thread_flag(TIF_DELAYED_TRACE)) {
regs->sr &= ~0x8000;
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*/
-asmlinkage void do_signal(struct pt_regs *regs)
+static void do_signal(struct pt_regs *regs)
{
siginfo_t info;
struct k_sigaction ka;
sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
}
}
+
+void do_notify_resume(struct pt_regs *regs)
+{
+ if (test_thread_flag(TIF_SIGPENDING))
+ do_signal(regs);
+
+ if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
+ tracehook_notify_resume(regs);
+ if (current->replacement_session_keyring)
+ key_replace_session_keyring();
+ }
+}
subql #4,%sp /* dummy return address*/
SAVE_SWITCH_STACK
pea %sp@(SWITCH_STACK_SIZE)
- bsrw do_signal
+ bsrw do_notify_resume
addql #4,%sp
RESTORE_SWITCH_STACK
addql #4,%sp
subql #4,%sp /* dummy return address*/
SAVE_SWITCH_STACK
pea %sp@(SWITCH_STACK_SIZE)
- bsrw do_signal
+ bsrw do_notify_resume
addql #4,%sp
RESTORE_SWITCH_STACK
addql #4,%sp
subql #4,%sp /* dummy return address */
SAVE_SWITCH_STACK
pea %sp@(SWITCH_STACK_SIZE)
- jsr do_signal
+ jsr do_notify_resume
addql #4,%sp
RESTORE_SWITCH_STACK
addql #4,%sp
beqi r11, 1f
bralid r15, schedule
nop
-1: andi r11, r19, _TIF_SIGPENDING
+1: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
beqid r11, no_intr_resched
addk r5, r1, r0
- addk r7, r0, r0
- bralid r15, do_signal
+ bralid r15, do_notify_resume
addk r6, r0, r0
no_intr_resched:
/*
* Debug traps are like a system call, but entered via brki r14, 0x60
- * All we need to do is send the SIGTRAP signal to current, ptrace and do_signal
- * will handle the rest
+ * All we need to do is send the SIGTRAP signal to current, ptrace and
+ * do_notify_resume will handle the rest
*/
ENTRY(_debug_exception)
swi r1, r0, PER_CPU(ENTRY_SP) /* save the current sp */
beqi r11, 1f
bralid r15, schedule
nop
-1: andi r11, r19, _TIF_SIGPENDING
+1: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
beqi r11, no_work_pending
addk r5, r1, r0
- addik r7, r0, 1
- bralid r15, do_signal
- addk r6, r0, r0
+ bralid r15, do_notify_resume
+ addik r6, r0, 1
bri no_work_pending
ENTRY(ret_to_user)
brid sys_rt_sigreturn
addk r5, r1, r0
-sys_rt_sigsuspend_wrapper:
- brid sys_rt_sigsuspend
- addk r7, r1, r0
-
/* Interrupt vector table */
.section .init.ivt, "ax"
.org 0x0
5: /* get thread info from current task*/
lwi r11, CURRENT_TASK, TS_THREAD_INFO;
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
- andi r11, r11, _TIF_SIGPENDING;
+ andi r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
beqi r11, 1f; /* Signals to handle, handle them */
addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */
- addi r7, r0, 1; /* Arg 3: int in_syscall */
- bralid r15, do_signal; /* Handle any signals */
- add r6, r0, r0; /* Arg 2: sigset_t *oldset */
+ bralid r15, do_notify_resume; /* Handle any signals */
+ addi r6, r0, 1; /* Arg 2: int in_syscall */
/* Finally, return to user state. */
1: set_bip; /* Ints masked for state restore */
/* Maybe handle a signal */
5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
- andi r11, r11, _TIF_SIGPENDING;
+ andi r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
beqi r11, 1f; /* Signals to handle, handle them */
/*
* traps), but signal handlers may want to examine or change the
* complete register state. Here we save anything not saved by
* the normal entry sequence, so that it may be safely restored
- * (in a possibly modified form) after do_signal returns. */
+ * (in a possibly modified form) after do_notify_resume returns. */
addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */
- addi r7, r0, 0; /* Arg 3: int in_syscall */
- bralid r15, do_signal; /* Handle any signals */
- add r6, r0, r0; /* Arg 2: sigset_t *oldset */
+ bralid r15, do_notify_resume; /* Handle any signals */
+ addi r6, r0, 0; /* Arg 2: int in_syscall */
/* Finally, return to user state. */
1: set_bip; /* Ints masked for state restore */
/* Maybe handle a signal */
5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* MS: get thread info */
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
- andi r11, r11, _TIF_SIGPENDING;
+ andi r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
beqid r11, no_intr_resched
/* Handle a signal return; Pending signals should be in r18. */
- addi r7, r0, 0; /* Arg 3: int in_syscall */
addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */
- bralid r15, do_signal; /* Handle any signals */
- add r6, r0, r0; /* Arg 2: sigset_t *oldset */
+ bralid r15, do_notify_resume; /* Handle any signals */
+ addi r6, r0, 0; /* Arg 2: int in_syscall */
/* Finally, return to user state. */
no_intr_resched:
/* Maybe handle a signal */
5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
- andi r11, r11, _TIF_SIGPENDING;
+ andi r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
beqi r11, 1f; /* Signals to handle, handle them */
addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */
- addi r7, r0, 0; /* Arg 3: int in_syscall */
- bralid r15, do_signal; /* Handle any signals */
- add r6, r0, r0; /* Arg 2: sigset_t *oldset */
+ bralid r15, do_notify_resume; /* Handle any signals */
+ addi r6, r0, 0; /* Arg 2: int in_syscall */
/* Finally, return to user state. */
1: swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
#include <linux/personality.h>
#include <linux/percpu.h>
#include <linux/linkage.h>
+#include <linux/tracehook.h>
#include <asm/entry.h>
#include <asm/ucontext.h>
#include <linux/uaccess.h>
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall);
-
asmlinkage long
sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
struct pt_regs *regs)
sigset_t set;
int rval;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval))
goto badframe;
return (void __user *)((sp - frame_size) & -8UL);
}
-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+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;
current->comm, current->pid, frame, regs->pc);
#endif
- return;
+ return 0;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
+ return -EFAULT;
}
/* Handle restarting system calls */
handle_signal(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
{
+ 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_rt_frame(sig, ka, NULL, oldset, regs);
-
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
-
- if (!(ka->sa.sa_flags & SA_NODEFER)) {
- spin_lock_irq(¤t->sighand->siglock);
- sigorsets(¤t->blocked,
- ¤t->blocked, &ka->sa.sa_mask);
- sigaddset(¤t->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
- }
- return 1;
+ ret = setup_rt_frame(sig, ka, NULL, oldset, regs);
+
+ if (ret)
+ return ret;
+
+ block_sigmask(ka, sig);
+
+ return 0;
}
/*
* the kernel can handle, and then we build all the user-level signal handling
* stack-frames in one go after that.
*/
-int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall)
+static void do_signal(struct pt_regs *regs, int in_syscall)
{
siginfo_t info;
int signr;
struct k_sigaction ka;
+ sigset_t *oldset;
#ifdef DEBUG_SIG
- printk(KERN_INFO "do signal: %p %p %d\n", regs, oldset, in_syscall);
+ printk(KERN_INFO "do signal: %p %d\n", regs, in_syscall);
printk(KERN_INFO "do signal2: %lx %lx %ld [%lx]\n", regs->pc, regs->r1,
regs->r12, current_thread_info()->flags);
#endif
- /*
- * We want the common case to go fast, which
- * is why we may in certain cases get here from
- * kernel mode. Just return without doing anything
- * if so.
- */
- if (kernel_mode(regs))
- return 1;
if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = ¤t->saved_sigmask;
/* Whee! Actually deliver the signal. */
if (in_syscall)
handle_restart(regs, &ka, 1);
- if (handle_signal(signr, &ka, &info, oldset, regs)) {
+ if (!handle_signal(signr, &ka, &info, oldset, regs)) {
/*
* A signal was successfully delivered; the saved
* sigmask will have been stored in the signal frame,
current_thread_info()->status &=
~TS_RESTORE_SIGMASK;
}
- return 1;
+ return;
}
if (in_syscall)
current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
}
+}
- /* Did we come from a system call? */
- return 0;
+void do_notify_resume(struct pt_regs *regs, int in_syscall)
+{
+ /*
+ * We want the common case to go fast, which
+ * is why we may in certain cases get here from
+ * kernel mode. Just return without doing anything
+ * if so.
+ */
+ if (kernel_mode(regs))
+ return;
+
+ if (test_thread_flag(TIF_SIGPENDING))
+ do_signal(regs, in_syscall);
+
+ if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
+ tracehook_notify_resume(regs);
+ if (current->replacement_session_keyring)
+ key_replace_session_keyring();
+ }
}
uset = (sigset_t __user *) regs.regs[4];
if (copy_from_user(&newset, uset, sizeof(sigset_t)))
return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
-
- current->saved_sigmask = current->blocked;
- set_current_blocked(&newset);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ return sigsuspend(&newset);
}
#endif
unewset = (sigset_t __user *) regs.regs[4];
if (copy_from_user(&newset, unewset, sizeof(newset)))
return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
-
- current->saved_sigmask = current->blocked;
- set_current_blocked(&newset);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ return sigsuspend(&newset);
}
#ifdef CONFIG_TRAD_SIGNALS
uset = (compat_sigset_t __user *) regs.regs[4];
if (get_sigset(&newset, uset))
return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
-
- current->saved_sigmask = current->blocked;
- set_current_blocked(&newset);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ return sigsuspend(&newset);
}
asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
uset = (compat_sigset_t __user *) regs.regs[4];
if (get_sigset(&newset, uset))
return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
-
- current->saved_sigmask = current->blocked;
- set_current_blocked(&newset);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ return sigsuspend(&newset);
}
SYSCALL_DEFINE3(32_sigaction, long, sig, const struct sigaction32 __user *, act,
if (copy_from_user(&uset, unewset, sizeof(uset)))
return -EFAULT;
sigset_from_compat(&newset, &uset);
- sigdelsetmask(&newset, ~_BLOCKABLE);
-
- current->saved_sigmask = current->blocked;
- set_current_blocked(&newset);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ return sigsuspend(&newset);
}
asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
*/
asmlinkage long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
{
- mask &= _BLOCKABLE;
- spin_lock_irq(¤t->sighand->siglock);
- current->saved_sigmask = current->blocked;
- siginitset(¤t->blocked, mask);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ sigset_t blocked;
+ siginitset(&blocked, mask);
+ return sigsuspend(&blocked);
}
/*
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(current_frame(), &frame->sc, &d0))
goto badframe;
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(current_frame(), &frame->uc.uc_mcontext, &d0))
goto badframe;
else
ret = setup_frame(sig, ka, oldset, regs);
- if (ret == 0) {
- spin_lock_irq(¤t->sighand->siglock);
- sigorsets(¤t->blocked, ¤t->blocked,
- &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(¤t->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
- }
+ if (ret == 0)
+ block_sigmask(ka, sig);
return ret;
}
sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
#endif
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
/* Unwind the user stack to get the rt_sigframe structure. */
frame = (struct rt_sigframe __user *)
}
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ set_current_blocked(&set);
/* Good thing we saved the old gr[30], eh? */
#ifdef CONFIG_64BIT
if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall))
return 0;
- spin_lock_irq(¤t->sighand->siglock);
- sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(¤t->blocked,sig);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ block_sigmask(ka, sig);
tracehook_signal_handler(sig, info, ka, regs,
test_thread_flag(TIF_SINGLESTEP) ||
/* Check the return code */
switch (regs->gr[28]) {
case -ERESTART_RESTARTBLOCK:
- current_thread_info()->restart_block.fn =
- do_no_restart_syscall;
case -ERESTARTNOHAND:
DBG(1,"ERESTARTNOHAND: returning -EINTR\n");
regs->gr[28] = -EINTR;
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka->sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka->sa.sa_restorer, &act->sa_restorer))
+ __get_user(new_ka->sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(new_ka->sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(new_ka->sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka->sa.sa_mask, mask);
return 0;
}
long sys_sigsuspend(old_sigset_t mask)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
-
- mask &= _BLOCKABLE;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_restore_sigmask();
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
long sys_sigaction(int sig, struct old_sigaction __user *act,
SYSCALL_DEFINE3(sigsuspend, int, history0, int, history1, old_sigset_t, mask)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
- mask &= _BLOCKABLE;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- set_restore_sigmask();
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
SYSCALL_DEFINE3(sigaction, int, sig, const struct old_sigaction __user *, act,
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/uaccess.h>
+#include <linux/tracehook.h>
#include <asm/cacheflush.h>
#include <asm/syscalls.h>
stack_t st;
int sig;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
frame = (struct rt_sigframe __user *) regs->regs[0];
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ set_current_blocked(&set);
sig = restore_sigcontext(regs, &frame->rs_uc.uc_mcontext);
if (sig < 0)
return 0;
give_sigsegv:
- if (signr == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(signr, current);
return -EFAULT;
}
*/
ret = setup_rt_frame(ka, regs, sig, oldset, info);
- spin_lock_irq(¤t->sighand->siglock);
- sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(¤t->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ if (ret == 0)
+ block_sigmask(ka, sig);
return ret;
}
__u32 thread_info_flags)
{
/* deal with pending signal delivery */
- if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+ if (thread_info_flags & _TIF_SIGPENDING)
do_signal(regs);
+ if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+ clear_thread_flag(TIF_NOTIFY_RESUME);
+ tracehook_notify_resume(regs);
+ if (current->replacement_session_keyring)
+ key_replace_session_keyring();
+ }
}
const char __user *const __user *uargv,
const char __user *const __user *uenvp,
unsigned long r7, struct pt_regs __regs);
-asmlinkage int sys_sigsuspend(old_sigset_t mask, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs);
+asmlinkage int sys_sigsuspend(old_sigset_t mask);
asmlinkage int sys_sigaction(int sig, const struct old_sigaction __user *act,
struct old_sigaction __user *oact);
asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
#ifdef __KERNEL__
# ifdef CONFIG_SUPERH32
-
# include "unistd_32.h"
-# define __ARCH_WANT_SYS_RT_SIGSUSPEND
-
# else
# include "unistd_64.h"
# endif
+# define __ARCH_WANT_SYS_RT_SIGSUSPEND
# define __ARCH_WANT_IPC_PARSE_VERSION
# define __ARCH_WANT_OLD_READDIR
# define __ARCH_WANT_OLD_STAT
* Atomically swap in the new signal mask, and wait for a signal.
*/
asmlinkage int
-sys_sigsuspend(old_sigset_t mask,
- unsigned long r5, unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
+sys_sigsuspend(old_sigset_t mask)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
-
- mask &= _BLOCKABLE;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_restore_sigmask();
-
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
asmlinkage int
old_sigset_t mask;
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
}
if (!ret && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
return ret;
if (!(boot_cpu_data.flags & CPU_HAS_FPU))
return 0;
- if (!used_math()) {
- __put_user(0, &sc->sc_ownedfp);
- return 0;
- }
+ if (!used_math())
+ return __put_user(0, &sc->sc_ownedfp);
- __put_user(1, &sc->sc_ownedfp);
+ if (__put_user(1, &sc->sc_ownedfp))
+ return -EFAULT;
/* This will cause a "finit" to be triggered by the next
attempted FPU operation by the 'current' process.
regs->sr |= SR_FD; /* Release FPU */
clear_fpu(tsk, regs);
clear_used_math();
- __get_user (owned_fp, &sc->sc_ownedfp);
+ err |= __get_user (owned_fp, &sc->sc_ownedfp);
if (owned_fp)
err |= restore_sigcontext_fpu(sc);
}
struct fdpic_func_descriptor __user *funcptr =
(struct fdpic_func_descriptor __user *)ka->sa.sa_handler;
- __get_user(regs->pc, &funcptr->text);
- __get_user(regs->regs[12], &funcptr->GOT);
+ err |= __get_user(regs->pc, &funcptr->text);
+ err |= __get_user(regs->regs[12], &funcptr->GOT);
} else
regs->pc = (unsigned long)ka->sa.sa_handler;
+ if (err)
+ goto give_sigsegv;
+
set_fs(USER_DS);
pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
struct fdpic_func_descriptor __user *funcptr =
(struct fdpic_func_descriptor __user *)ka->sa.sa_handler;
- __get_user(regs->pc, &funcptr->text);
- __get_user(regs->regs[12], &funcptr->GOT);
+ err |= __get_user(regs->pc, &funcptr->text);
+ err |= __get_user(regs->regs[12], &funcptr->GOT);
} else
regs->pc = (unsigned long)ka->sa.sa_handler;
+ if (err)
+ goto give_sigsegv;
+
set_fs(USER_DS);
pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
* the kernel can handle, and then we build all the user-level signal handling
* stack-frames in one go after that.
*/
-static int do_signal(struct pt_regs *regs, sigset_t *oldset)
+static void do_signal(struct pt_regs *regs)
{
siginfo_t info;
int signr;
struct k_sigaction ka;
+ sigset_t *oldset;
/*
* We want the common case to go fast, which
* if so.
*/
if (!user_mode(regs))
- return 1;
+ return;
if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = ¤t->saved_sigmask;
- else if (!oldset)
+ else
oldset = ¤t->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, 0);
tracehook_signal_handler(signr, &info, &ka, regs,
test_thread_flag(TIF_SINGLESTEP));
- return 1;
+ return;
}
}
sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
}
- return 0;
+ return;
}
/*
* 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,
- unsigned long r6, unsigned long r7,
- struct pt_regs * regs)
+sys_sigsuspend(old_sigset_t mask)
{
- sigset_t saveset, blocked;
-
- saveset = current->blocked;
-
- mask &= _BLOCKABLE;
+ sigset_t blocked;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
-
- REF_REG_RET = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_restore_sigmask();
- regs->pc += 4; /* because sys_sigreturn decrements the pc */
- if (do_signal(regs, &saveset)) {
- /* pc now points at signal handler. Need to decrement
- it because entry.S will increment it. */
- regs->pc -= 4;
- return -EINTR;
- }
- }
-}
-
-asmlinkage int
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
- unsigned long r4, unsigned long r5, unsigned long r6,
- unsigned long r7,
- struct pt_regs * regs)
-{
- sigset_t saveset, newset;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- if (copy_from_user(&newset, unewset, sizeof(newset)))
- return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
- saveset = current->blocked;
- set_current_blocked(&newset);
-
- REF_REG_RET = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- regs->pc += 4; /* because sys_sigreturn decrements the pc */
- if (do_signal(regs, &saveset)) {
- /* pc now points at signal handler. Need to decrement
- it because entry.S will increment it. */
- regs->pc -= 4;
- return -EINTR;
- }
- }
+ return sigsuspend(&blocked);
}
asmlinkage int
old_sigset_t mask;
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
}
if (!ret && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
return ret;
asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
{
if (thread_info_flags & _TIF_SIGPENDING)
- do_signal(regs, 0);
+ do_signal(regs);
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
(((unsigned long) sf) & 3))
goto segv;
- get_user(pc, &sf->info.si_regs.pc);
- __get_user(npc, &sf->info.si_regs.npc);
+ if (get_user(pc, &sf->info.si_regs.pc) ||
+ __get_user(npc, &sf->info.si_regs.npc))
+ goto segv;
if ((pc | npc) & 3)
goto segv;
(((unsigned long) sf) & 3))
goto segv;
- get_user(pc, &sf->regs.pc);
- __get_user(npc, &sf->regs.npc);
+ if (get_user(pc, &sf->regs.pc) ||
+ __get_user(npc, &sf->regs.npc))
+ goto segv;
if ((pc | npc) & 3)
goto segv;
static int _sigpause_common(old_sigset_t set)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
-
- set &= _BLOCKABLE;
siginitset(&blocked, set);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
-
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
asmlinkage int sys_sigsuspend(old_sigset_t set)
static long _sigpause_common(old_sigset_t set)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
-
- set &= _BLOCKABLE;
siginitset(&blocked, set);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
-
- set_restore_sigmask();
-
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
asmlinkage long sys_sigpause(unsigned int set)
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
new_ka.ka_restorer = NULL;
}
ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
if (!ret && oact) {
- /* In the clone() case we could copy half consistent
- * state to the user, however this could sleep and
- * deadlock us if we held the signal lock on SMP. So for
- * now I take the easy way out and do no locking.
- */
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
return ret;
long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
{
sigset_t blocked;
-
- mask &= _BLOCKABLE;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
/*
* Block the signal if we were successful.
*/
- sigorsets(&blocked, &tsk->blocked, &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&blocked, sig);
- set_current_blocked(&blocked);
+ block_sigmask(ka, sig);
return 0;
}
regs->UCreg_00 == -ERESTARTNOINTR) {
setup_syscall_restart(regs);
}
-
- /* 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, ¤t->saved_sigmask, NULL);
- }
}
+ /* If there's no signal to deliver, we just put the saved
+ * sigmask back.
+ */
+ if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
+ set_current_blocked(¤t->saved_sigmask);
}
asmlinkage void do_notify_resume(struct pt_regs *regs,
asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
-
- mask &= _BLOCKABLE;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
-
- set_restore_sigmask();
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
sys_sigsuspend(int history0, int history1, old_sigset_t mask)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
-
- mask &= _BLOCKABLE;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
-
- set_restore_sigmask();
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
asmlinkage int
#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */
#ifdef __KERNEL__
-struct old_sigaction {
- __sighandler_t sa_handler;
- old_sigset_t sa_mask;
- unsigned long sa_flags;
- void (*sa_restorer)(void);
-};
-
struct sigaction {
__sighandler_t sa_handler;
unsigned long sa_flags;
asmlinkage long xtensa_ptrace(long, long, long, long);
asmlinkage long xtensa_sigreturn(struct pt_regs*);
asmlinkage long xtensa_rt_sigreturn(struct pt_regs*);
-asmlinkage long xtensa_sigsuspend(struct pt_regs*);
-asmlinkage long xtensa_rt_sigsuspend(struct pt_regs*);
-asmlinkage long xtensa_sigaction(int, const struct old_sigaction*,
- struct old_sigaction*);
asmlinkage long xtensa_sigaltstack(struct pt_regs *regs);
asmlinkage long sys_rt_sigaction(int,
const struct sigaction __user *,
#define TIF_IRET 4 /* return with iret */
#define TIF_MEMDIE 5 /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK 6 /* restore signal mask in do_signal() */
+#define TIF_NOTIFY_RESUME 7 /* callback before returning to user */
#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define __NR_rt_sigqueueinfo 230
__SYSCALL(230, sys_rt_sigqueueinfo, 3)
#define __NR_rt_sigsuspend 231
-__SYSCALL(231, xtensa_rt_sigsuspend, 2)
+__SYSCALL(231, sys_rt_sigsuspend, 2)
/* Message */
l32i a4, a2, TI_FLAGS
_bbsi.l a4, TIF_NEED_RESCHED, 3f
+ _bbsi.l a4, TIF_NOTIFY_RESUME, 2f
_bbci.l a4, TIF_SIGPENDING, 4f
- l32i a4, a1, PT_DEPC
+2: l32i a4, a1, PT_DEPC
bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f
/* Call do_signal() */
- movi a4, do_signal # int do_signal(struct pt_regs*, sigset_t*)
+ movi a4, do_notify_resume # int do_notify_resume(struct pt_regs*)
mov a6, a1
- movi a7, 0
callx4 a4
j 1b
#include <linux/ptrace.h>
#include <linux/personality.h>
#include <linux/freezer.h>
+#include <linux/tracehook.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
-
extern struct task_struct *coproc_owners[];
struct rt_sigframe
sigset_t set;
int ret;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
if (regs->depc > 64)
panic("rt_sigreturn in double exception!\n");
return -EFAULT;
}
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-
-asmlinkage long xtensa_rt_sigsuspend(sigset_t __user *unewset,
- size_t sigsetsize,
- long a2, long a3, long a4, long a5,
- struct pt_regs *regs)
-{
- sigset_t saveset, newset;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- if (copy_from_user(&newset, unewset, sizeof(newset)))
- return -EFAULT;
-
- sigdelsetmask(&newset, ~_BLOCKABLE);
- saveset = current->blocked;
- set_current_blocked(&newset);
-
- regs->areg[2] = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(regs, &saveset))
- return -EINTR;
- }
-}
-
asmlinkage long xtensa_sigaltstack(const stack_t __user *uss,
stack_t __user *uoss,
long a2, long a3, long a4, long a5,
* the kernel can handle, and then we build all the user-level signal handling
* stack-frames in one go after that.
*/
-int do_signal(struct pt_regs *regs, sigset_t *oldset)
+static void do_signal(struct pt_regs *regs)
{
siginfo_t info;
int signr;
struct k_sigaction ka;
-
- if (!user_mode(regs))
- return 0;
+ sigset_t oldset;
if (try_to_freeze())
goto no_signal;
- if (!oldset)
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = ¤t->saved_sigmask;
+ else
oldset = ¤t->blocked;
task_pt_regs(current)->icountlevel = 0;
/* Set up the stack frame */
ret = setup_frame(signr, &ka, &info, oldset, regs);
if (ret)
- return ret;
+ return;
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
block_sigmask(&ka, signr);
if (current->ptrace & PT_SINGLESTEP)
task_pt_regs(current)->icountlevel = 1;
- return 1;
+ return;
}
no_signal:
break;
}
}
+
+ /* If there's no signal to deliver, we just restore the saved mask. */
+ if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
+ set_current_blocked(¤t->saved_sigmask);
+
if (current->ptrace & PT_SINGLESTEP)
task_pt_regs(current)->icountlevel = 1;
- return 0;
+ return;
}
+void do_notify_resume(struct pt_regs *regs)
+{
+ if (!user_mode(regs))
+ return;
+
+ if (test_thread_flag(TIF_SIGPENDING))
+ do_signal(regs);
+
+ if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
+ tracehook_notify_resume(regs);
+ if (current->replacement_session_keyring)
+ key_replace_session_keyring();
+ }
+}
extern int sigprocmask(int, sigset_t *, sigset_t *);
extern void set_current_blocked(const sigset_t *);
extern int show_unhandled_signals;
+extern int sigsuspend(sigset_t *);
extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie);
extern void block_sigmask(struct k_sigaction *ka, int signr);
if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t)))
return -EFAULT;
sigset_from_compat(&newset, &newset32);
- sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
-
- current->saved_sigmask = current->blocked;
- set_current_blocked(&newset);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_restore_sigmask();
- return -ERESTARTNOHAND;
+ return sigsuspend(&newset);
}
#endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */
#endif
+#ifdef HAVE_SET_RESTORE_SIGMASK
+int sigsuspend(sigset_t *set)
+{
+ sigdelsetmask(set, sigmask(SIGKILL)|sigmask(SIGSTOP));
+
+ current->saved_sigmask = current->blocked;
+ set_current_blocked(set);
+
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ set_restore_sigmask();
+ return -ERESTARTNOHAND;
+}
+#endif
+
#ifdef __ARCH_WANT_SYS_RT_SIGSUSPEND
/**
* sys_rt_sigsuspend - replace the signal mask for a value with the
if (copy_from_user(&newset, unewset, sizeof(newset)))
return -EFAULT;
- sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
-
- current->saved_sigmask = current->blocked;
- set_current_blocked(&newset);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_restore_sigmask();
- return -ERESTARTNOHAND;
+ return sigsuspend(&newset);
}
#endif /* __ARCH_WANT_SYS_RT_SIGSUSPEND */