aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMikael Pettersson <mikpe@it.uu.se>2009-08-15 07:58:11 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-08-15 10:10:31 -0400
commit369842658a36bcea28ecb643ba4bdb53919330dd (patch)
tree1a590eabceea85b974360eca2cfba54d86ae4933
parent4bf1fa5a34aa2dd0d2cc58f0fc213a2e22d007a4 (diff)
ARM: 5677/1: ARM support for TIF_RESTORE_SIGMASK/pselect6/ppoll/epoll_pwait
This patch adds support for TIF_RESTORE_SIGMASK to ARM's signal handling, which allows to hook up the pselect6, ppoll, and epoll_pwait syscalls on ARM. Tested here with eabi userspace and a test program with a deliberate race between a child's exit and the parent's sigprocmask/select sequence. Using sys_pselect6() instead of sigprocmask/select reliably prevents the race. The other arch's support for TIF_RESTORE_SIGMASK has evolved over time: In 2.6.16: - add TIF_RESTORE_SIGMASK which parallels TIF_SIGPENDING - test both when checking for pending signal [changed later] - reimplement sys_sigsuspend() to use current->saved_sigmask, TIF_RESTORE_SIGMASK [changed later], and -ERESTARTNOHAND; ditto for sys_rt_sigsuspend(), but drop private code and use common code via __ARCH_WANT_SYS_RT_SIGSUSPEND; - there are now no "extra" calls to do_signal() so its oldset parameter is always &current->blocked so need not be passed, also its return value is changed to void - change handle_signal() to return 0/-errno - change do_signal() to honor TIF_RESTORE_SIGMASK: + get oldset from current->saved_sigmask if TIF_RESTORE_SIGMASK is set + if handle_signal() was successful then clear TIF_RESTORE_SIGMASK + if no signal was delivered and TIF_RESTORE_SIGMASK is set then clear it and restore the sigmask - hook up sys_pselect6() and sys_ppoll() In 2.6.19: - hook up sys_epoll_pwait() In 2.6.26: - allow archs to override how TIF_RESTORE_SIGMASK is implemented; default set_restore_sigmask() sets both TIF_RESTORE_SIGMASK and TIF_SIGPENDING; archs need now just test TIF_SIGPENDING again when checking for pending signal work; some archs now implement TIF_RESTORE_SIGMASK as a secondary/non-atomic thread flag bit - call set_restore_sigmask() in sys_sigsuspend() instead of setting TIF_RESTORE_SIGMASK In 2.6.29-rc: - kill sys_pselect7() which no arch wanted So for 2.6.31-rc6/ARM this patch does the following: - Add TIF_RESTORE_SIGMASK. Use the generic set_restore_sigmask() which sets both TIF_SIGPENDING and TIF_RESTORE_SIGMASK, so TIF_RESTORE_SIGMASK need not claim one of the scarce low thread flags, and existing TIF_SIGPENDING and _TIF_WORK_MASK tests need not be extended for TIF_RESTORE_SIGMASK. - sys_sigsuspend() is reimplemented to use current->saved_sigmask and set_restore_sigmask(), making it identical to most other archs - The private code for sys_rt_sigsuspend() is removed, instead generic code supplies it via __ARCH_WANT_SYS_RT_SIGSUSPEND. - sys_sigsuspend() and sys_rt_sigsuspend() no longer need a pt_regs parameter, so their assembly code wrappers are removed. - handle_signal() is changed to return 0 on success or -errno. - The oldset parameter to do_signal() is now redundant and removed, and the return value is now also redundant and changed to void. - do_signal() is changed to honor TIF_RESTORE_SIGMASK: + get oldset from current->saved_sigmask if TIF_RESTORE_SIGMASK is set + if handle_signal() was successful then clear TIF_RESTORE_SIGMASK + if no signal was delivered and TIF_RESTORE_SIGMASK is set then clear it and restore the sigmask - Hook up sys_pselect6, sys_ppoll, and sys_epoll_pwait. Signed-off-by: Mikael Pettersson <mikpe@it.uu.se> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/include/asm/thread_info.h2
-rw-r--r--arch/arm/include/asm/unistd.h7
-rw-r--r--arch/arm/kernel/calls.S10
-rw-r--r--arch/arm/kernel/entry-common.S10
-rw-r--r--arch/arm/kernel/signal.c86
5 files changed, 48 insertions, 67 deletions
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index 73394e50cbca..e20d80539b42 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -140,6 +140,7 @@ extern void vfp_sync_state(struct thread_info *thread);
140#define TIF_USING_IWMMXT 17 140#define TIF_USING_IWMMXT 17
141#define TIF_MEMDIE 18 141#define TIF_MEMDIE 18
142#define TIF_FREEZE 19 142#define TIF_FREEZE 19
143#define TIF_RESTORE_SIGMASK 20
143 144
144#define _TIF_SIGPENDING (1 << TIF_SIGPENDING) 145#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
145#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) 146#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
@@ -147,6 +148,7 @@ extern void vfp_sync_state(struct thread_info *thread);
147#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) 148#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
148#define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) 149#define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT)
149#define _TIF_FREEZE (1 << TIF_FREEZE) 150#define _TIF_FREEZE (1 << TIF_FREEZE)
151#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
150 152
151/* 153/*
152 * Change these and you break ASM code in entry-common.S 154 * Change these and you break ASM code in entry-common.S
diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h
index 0e97b8cb77d5..9122c9ee18fb 100644
--- a/arch/arm/include/asm/unistd.h
+++ b/arch/arm/include/asm/unistd.h
@@ -360,8 +360,8 @@
360#define __NR_readlinkat (__NR_SYSCALL_BASE+332) 360#define __NR_readlinkat (__NR_SYSCALL_BASE+332)
361#define __NR_fchmodat (__NR_SYSCALL_BASE+333) 361#define __NR_fchmodat (__NR_SYSCALL_BASE+333)
362#define __NR_faccessat (__NR_SYSCALL_BASE+334) 362#define __NR_faccessat (__NR_SYSCALL_BASE+334)
363 /* 335 for pselect6 */ 363#define __NR_pselect6 (__NR_SYSCALL_BASE+335)
364 /* 336 for ppoll */ 364#define __NR_ppoll (__NR_SYSCALL_BASE+336)
365#define __NR_unshare (__NR_SYSCALL_BASE+337) 365#define __NR_unshare (__NR_SYSCALL_BASE+337)
366#define __NR_set_robust_list (__NR_SYSCALL_BASE+338) 366#define __NR_set_robust_list (__NR_SYSCALL_BASE+338)
367#define __NR_get_robust_list (__NR_SYSCALL_BASE+339) 367#define __NR_get_robust_list (__NR_SYSCALL_BASE+339)
@@ -372,7 +372,7 @@
372#define __NR_vmsplice (__NR_SYSCALL_BASE+343) 372#define __NR_vmsplice (__NR_SYSCALL_BASE+343)
373#define __NR_move_pages (__NR_SYSCALL_BASE+344) 373#define __NR_move_pages (__NR_SYSCALL_BASE+344)
374#define __NR_getcpu (__NR_SYSCALL_BASE+345) 374#define __NR_getcpu (__NR_SYSCALL_BASE+345)
375 /* 346 for epoll_pwait */ 375#define __NR_epoll_pwait (__NR_SYSCALL_BASE+346)
376#define __NR_kexec_load (__NR_SYSCALL_BASE+347) 376#define __NR_kexec_load (__NR_SYSCALL_BASE+347)
377#define __NR_utimensat (__NR_SYSCALL_BASE+348) 377#define __NR_utimensat (__NR_SYSCALL_BASE+348)
378#define __NR_signalfd (__NR_SYSCALL_BASE+349) 378#define __NR_signalfd (__NR_SYSCALL_BASE+349)
@@ -432,6 +432,7 @@
432#define __ARCH_WANT_SYS_SIGPENDING 432#define __ARCH_WANT_SYS_SIGPENDING
433#define __ARCH_WANT_SYS_SIGPROCMASK 433#define __ARCH_WANT_SYS_SIGPROCMASK
434#define __ARCH_WANT_SYS_RT_SIGACTION 434#define __ARCH_WANT_SYS_RT_SIGACTION
435#define __ARCH_WANT_SYS_RT_SIGSUSPEND
435 436
436#if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT) 437#if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT)
437#define __ARCH_WANT_SYS_TIME 438#define __ARCH_WANT_SYS_TIME
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index f776e72a4cb8..ecfa98954d1d 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -81,7 +81,7 @@
81 CALL(sys_ni_syscall) /* was sys_ssetmask */ 81 CALL(sys_ni_syscall) /* was sys_ssetmask */
82/* 70 */ CALL(sys_setreuid16) 82/* 70 */ CALL(sys_setreuid16)
83 CALL(sys_setregid16) 83 CALL(sys_setregid16)
84 CALL(sys_sigsuspend_wrapper) 84 CALL(sys_sigsuspend)
85 CALL(sys_sigpending) 85 CALL(sys_sigpending)
86 CALL(sys_sethostname) 86 CALL(sys_sethostname)
87/* 75 */ CALL(sys_setrlimit) 87/* 75 */ CALL(sys_setrlimit)
@@ -188,7 +188,7 @@
188 CALL(sys_rt_sigpending) 188 CALL(sys_rt_sigpending)
189 CALL(sys_rt_sigtimedwait) 189 CALL(sys_rt_sigtimedwait)
190 CALL(sys_rt_sigqueueinfo) 190 CALL(sys_rt_sigqueueinfo)
191 CALL(sys_rt_sigsuspend_wrapper) 191 CALL(sys_rt_sigsuspend)
192/* 180 */ CALL(ABI(sys_pread64, sys_oabi_pread64)) 192/* 180 */ CALL(ABI(sys_pread64, sys_oabi_pread64))
193 CALL(ABI(sys_pwrite64, sys_oabi_pwrite64)) 193 CALL(ABI(sys_pwrite64, sys_oabi_pwrite64))
194 CALL(sys_chown16) 194 CALL(sys_chown16)
@@ -344,8 +344,8 @@
344 CALL(sys_readlinkat) 344 CALL(sys_readlinkat)
345 CALL(sys_fchmodat) 345 CALL(sys_fchmodat)
346 CALL(sys_faccessat) 346 CALL(sys_faccessat)
347/* 335 */ CALL(sys_ni_syscall) /* eventually pselect6 */ 347/* 335 */ CALL(sys_pselect6)
348 CALL(sys_ni_syscall) /* eventually ppoll */ 348 CALL(sys_ppoll)
349 CALL(sys_unshare) 349 CALL(sys_unshare)
350 CALL(sys_set_robust_list) 350 CALL(sys_set_robust_list)
351 CALL(sys_get_robust_list) 351 CALL(sys_get_robust_list)
@@ -355,7 +355,7 @@
355 CALL(sys_vmsplice) 355 CALL(sys_vmsplice)
356 CALL(sys_move_pages) 356 CALL(sys_move_pages)
357/* 345 */ CALL(sys_getcpu) 357/* 345 */ CALL(sys_getcpu)
358 CALL(sys_ni_syscall) /* eventually epoll_pwait */ 358 CALL(sys_epoll_pwait)
359 CALL(sys_kexec_load) 359 CALL(sys_kexec_load)
360 CALL(sys_utimensat) 360 CALL(sys_utimensat)
361 CALL(sys_signalfd) 361 CALL(sys_signalfd)
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 366e5097a41a..bfa7f0af7ede 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -373,16 +373,6 @@ sys_clone_wrapper:
373 b sys_clone 373 b sys_clone
374ENDPROC(sys_clone_wrapper) 374ENDPROC(sys_clone_wrapper)
375 375
376sys_sigsuspend_wrapper:
377 add r3, sp, #S_OFF
378 b sys_sigsuspend
379ENDPROC(sys_sigsuspend_wrapper)
380
381sys_rt_sigsuspend_wrapper:
382 add r2, sp, #S_OFF
383 b sys_rt_sigsuspend
384ENDPROC(sys_rt_sigsuspend_wrapper)
385
386sys_sigreturn_wrapper: 376sys_sigreturn_wrapper:
387 add r0, sp, #S_OFF 377 add r0, sp, #S_OFF
388 b sys_sigreturn 378 b sys_sigreturn
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 93bb4247b7ed..e27ee1f701d5 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -47,57 +47,22 @@ const unsigned long sigreturn_codes[7] = {
47 MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN, 47 MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
48}; 48};
49 49
50static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
51
52/* 50/*
53 * atomically swap in the new signal mask, and wait for a signal. 51 * atomically swap in the new signal mask, and wait for a signal.
54 */ 52 */
55asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask, struct pt_regs *regs) 53asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)
56{ 54{
57 sigset_t saveset;
58
59 mask &= _BLOCKABLE; 55 mask &= _BLOCKABLE;
60 spin_lock_irq(&current->sighand->siglock); 56 spin_lock_irq(&current->sighand->siglock);
61 saveset = current->blocked; 57 current->saved_sigmask = current->blocked;
62 siginitset(&current->blocked, mask); 58 siginitset(&current->blocked, mask);
63 recalc_sigpending(); 59 recalc_sigpending();
64 spin_unlock_irq(&current->sighand->siglock); 60 spin_unlock_irq(&current->sighand->siglock);
65 regs->ARM_r0 = -EINTR;
66
67 while (1) {
68 current->state = TASK_INTERRUPTIBLE;
69 schedule();
70 if (do_signal(&saveset, regs, 0))
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 61
95 while (1) { 62 current->state = TASK_INTERRUPTIBLE;
96 current->state = TASK_INTERRUPTIBLE; 63 schedule();
97 schedule(); 64 set_restore_sigmask();
98 if (do_signal(&saveset, regs, 0)) 65 return -ERESTARTNOHAND;
99 return regs->ARM_r0;
100 }
101} 66}
102 67
103asmlinkage int 68asmlinkage int
@@ -545,7 +510,7 @@ static inline void setup_syscall_restart(struct pt_regs *regs)
545/* 510/*
546 * OK, we're invoking a handler 511 * OK, we're invoking a handler
547 */ 512 */
548static void 513static int
549handle_signal(unsigned long sig, struct k_sigaction *ka, 514handle_signal(unsigned long sig, struct k_sigaction *ka,
550 siginfo_t *info, sigset_t *oldset, 515 siginfo_t *info, sigset_t *oldset,
551 struct pt_regs * regs, int syscall) 516 struct pt_regs * regs, int syscall)
@@ -596,7 +561,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
596 561
597 if (ret != 0) { 562 if (ret != 0) {
598 force_sigsegv(sig, tsk); 563 force_sigsegv(sig, tsk);
599 return; 564 return ret;
600 } 565 }
601 566
602 /* 567 /*
@@ -610,6 +575,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
610 recalc_sigpending(); 575 recalc_sigpending();
611 spin_unlock_irq(&tsk->sighand->siglock); 576 spin_unlock_irq(&tsk->sighand->siglock);
612 577
578 return 0;
613} 579}
614 580
615/* 581/*
@@ -621,7 +587,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 587 * the kernel can handle, and then we build all the user-level signal handling
622 * stack-frames in one go after that. 588 * stack-frames in one go after that.
623 */ 589 */
624static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) 590static void do_signal(struct pt_regs *regs, int syscall)
625{ 591{
626 struct k_sigaction ka; 592 struct k_sigaction ka;
627 siginfo_t info; 593 siginfo_t info;
@@ -634,7 +600,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
634 * if so. 600 * if so.
635 */ 601 */
636 if (!user_mode(regs)) 602 if (!user_mode(regs))
637 return 0; 603 return;
638 604
639 if (try_to_freeze()) 605 if (try_to_freeze())
640 goto no_signal; 606 goto no_signal;
@@ -643,9 +609,24 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
643 609
644 signr = get_signal_to_deliver(&info, &ka, regs, NULL); 610 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
645 if (signr > 0) { 611 if (signr > 0) {
646 handle_signal(signr, &ka, &info, oldset, regs, syscall); 612 sigset_t *oldset;
613
614 if (test_thread_flag(TIF_RESTORE_SIGMASK))
615 oldset = &current->saved_sigmask;
616 else
617 oldset = &current->blocked;
618 if (handle_signal(signr, &ka, &info, oldset, regs, syscall) == 0) {
619 /*
620 * A signal was successfully delivered; the saved
621 * sigmask will have been stored in the signal frame,
622 * and will be restored by sigreturn, so we can simply
623 * clear the TIF_RESTORE_SIGMASK flag.
624 */
625 if (test_thread_flag(TIF_RESTORE_SIGMASK))
626 clear_thread_flag(TIF_RESTORE_SIGMASK);
627 }
647 single_step_set(current); 628 single_step_set(current);
648 return 1; 629 return;
649 } 630 }
650 631
651 no_signal: 632 no_signal:
@@ -697,14 +678,21 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
697 regs->ARM_r0 == -ERESTARTNOINTR) { 678 regs->ARM_r0 == -ERESTARTNOINTR) {
698 setup_syscall_restart(regs); 679 setup_syscall_restart(regs);
699 } 680 }
681
682 /* If there's no signal to deliver, we just put the saved sigmask
683 * back.
684 */
685 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
686 clear_thread_flag(TIF_RESTORE_SIGMASK);
687 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
688 }
700 } 689 }
701 single_step_set(current); 690 single_step_set(current);
702 return 0;
703} 691}
704 692
705asmlinkage void 693asmlinkage void
706do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) 694do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
707{ 695{
708 if (thread_flags & _TIF_SIGPENDING) 696 if (thread_flags & _TIF_SIGPENDING)
709 do_signal(&current->blocked, regs, syscall); 697 do_signal(regs, syscall);
710} 698}