aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/signal.c')
-rw-r--r--arch/arm/kernel/signal.c94
1 files changed, 45 insertions, 49 deletions
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index f6bc5d44278..1423a341978 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -12,6 +12,7 @@
12#include <linux/personality.h> 12#include <linux/personality.h>
13#include <linux/freezer.h> 13#include <linux/freezer.h>
14#include <linux/uaccess.h> 14#include <linux/uaccess.h>
15#include <linux/tracehook.h>
15 16
16#include <asm/elf.h> 17#include <asm/elf.h>
17#include <asm/cacheflush.h> 18#include <asm/cacheflush.h>
@@ -47,57 +48,22 @@ const unsigned long sigreturn_codes[7] = {
47 MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN, 48 MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
48}; 49};
49 50
50static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
51
52/* 51/*
53 * atomically swap in the new signal mask, and wait for a signal. 52 * atomically swap in the new signal mask, and wait for a signal.
54 */ 53 */
55asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask, struct pt_regs *regs) 54asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)
56{ 55{
57 sigset_t saveset;
58
59 mask &= _BLOCKABLE; 56 mask &= _BLOCKABLE;
60 spin_lock_irq(&current->sighand->siglock); 57 spin_lock_irq(&current->sighand->siglock);
61 saveset = current->blocked; 58 current->saved_sigmask = current->blocked;
62 siginitset(&current->blocked, mask); 59 siginitset(&current->blocked, mask);
63 recalc_sigpending(); 60 recalc_sigpending();
64 spin_unlock_irq(&current->sighand->siglock); 61 spin_unlock_irq(&current->sighand->siglock);
65 regs->ARM_r0 = -EINTR;
66 62
67 while (1) { 63 current->state = TASK_INTERRUPTIBLE;
68 current->state = TASK_INTERRUPTIBLE; 64 schedule();
69 schedule(); 65 set_restore_sigmask();
70 if (do_signal(&saveset, regs, 0)) 66 return -ERESTARTNOHAND;
71 return regs->ARM_r0;
72 }
73}
74
75asmlinkage int
76sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs)
77{
78 sigset_t saveset, newset;
79
80 /* XXX: Don't preclude handling different sized sigset_t's. */
81 if (sigsetsize != sizeof(sigset_t))
82 return -EINVAL;
83
84 if (copy_from_user(&newset, unewset, sizeof(newset)))
85 return -EFAULT;
86 sigdelsetmask(&newset, ~_BLOCKABLE);
87
88 spin_lock_irq(&current->sighand->siglock);
89 saveset = current->blocked;
90 current->blocked = newset;
91 recalc_sigpending();
92 spin_unlock_irq(&current->sighand->siglock);
93 regs->ARM_r0 = -EINTR;
94
95 while (1) {
96 current->state = TASK_INTERRUPTIBLE;
97 schedule();
98 if (do_signal(&saveset, regs, 0))
99 return regs->ARM_r0;
100 }
101} 67}
102 68
103asmlinkage int 69asmlinkage int
@@ -545,7 +511,7 @@ static inline void setup_syscall_restart(struct pt_regs *regs)
545/* 511/*
546 * OK, we're invoking a handler 512 * OK, we're invoking a handler
547 */ 513 */
548static void 514static int
549handle_signal(unsigned long sig, struct k_sigaction *ka, 515handle_signal(unsigned long sig, struct k_sigaction *ka,
550 siginfo_t *info, sigset_t *oldset, 516 siginfo_t *info, sigset_t *oldset,
551 struct pt_regs * regs, int syscall) 517 struct pt_regs * regs, int syscall)
@@ -596,7 +562,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
596 562
597 if (ret != 0) { 563 if (ret != 0) {
598 force_sigsegv(sig, tsk); 564 force_sigsegv(sig, tsk);
599 return; 565 return ret;
600 } 566 }
601 567
602 /* 568 /*
@@ -610,6 +576,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
610 recalc_sigpending(); 576 recalc_sigpending();
611 spin_unlock_irq(&tsk->sighand->siglock); 577 spin_unlock_irq(&tsk->sighand->siglock);
612 578
579 return 0;
613} 580}
614 581
615/* 582/*
@@ -621,7 +588,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
621 * the kernel can handle, and then we build all the user-level signal handling 588 * the kernel can handle, and then we build all the user-level signal handling
622 * stack-frames in one go after that. 589 * stack-frames in one go after that.
623 */ 590 */
624static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) 591static void do_signal(struct pt_regs *regs, int syscall)
625{ 592{
626 struct k_sigaction ka; 593 struct k_sigaction ka;
627 siginfo_t info; 594 siginfo_t info;
@@ -634,7 +601,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
634 * if so. 601 * if so.
635 */ 602 */
636 if (!user_mode(regs)) 603 if (!user_mode(regs))
637 return 0; 604 return;
638 605
639 if (try_to_freeze()) 606 if (try_to_freeze())
640 goto no_signal; 607 goto no_signal;
@@ -643,9 +610,24 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
643 610
644 signr = get_signal_to_deliver(&info, &ka, regs, NULL); 611 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
645 if (signr > 0) { 612 if (signr > 0) {
646 handle_signal(signr, &ka, &info, oldset, regs, syscall); 613 sigset_t *oldset;
614
615 if (test_thread_flag(TIF_RESTORE_SIGMASK))
616 oldset = &current->saved_sigmask;
617 else
618 oldset = &current->blocked;
619 if (handle_signal(signr, &ka, &info, oldset, regs, syscall) == 0) {
620 /*
621 * A signal was successfully delivered; the saved
622 * sigmask will have been stored in the signal frame,
623 * and will be restored by sigreturn, so we can simply
624 * clear the TIF_RESTORE_SIGMASK flag.
625 */
626 if (test_thread_flag(TIF_RESTORE_SIGMASK))
627 clear_thread_flag(TIF_RESTORE_SIGMASK);
628 }
647 single_step_set(current); 629 single_step_set(current);
648 return 1; 630 return;
649 } 631 }
650 632
651 no_signal: 633 no_signal:
@@ -697,14 +679,28 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
697 regs->ARM_r0 == -ERESTARTNOINTR) { 679 regs->ARM_r0 == -ERESTARTNOINTR) {
698 setup_syscall_restart(regs); 680 setup_syscall_restart(regs);
699 } 681 }
682
683 /* If there's no signal to deliver, we just put the saved sigmask
684 * back.
685 */
686 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
687 clear_thread_flag(TIF_RESTORE_SIGMASK);
688 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
689 }
700 } 690 }
701 single_step_set(current); 691 single_step_set(current);
702 return 0;
703} 692}
704 693
705asmlinkage void 694asmlinkage void
706do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) 695do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
707{ 696{
708 if (thread_flags & _TIF_SIGPENDING) 697 if (thread_flags & _TIF_SIGPENDING)
709 do_signal(&current->blocked, regs, syscall); 698 do_signal(regs, syscall);
699
700 if (thread_flags & _TIF_NOTIFY_RESUME) {
701 clear_thread_flag(TIF_NOTIFY_RESUME);
702 tracehook_notify_resume(regs);
703 if (current->replacement_session_keyring)
704 key_replace_session_keyring();
705 }
710} 706}