1 From: Mikael Pettersson <mikpe@it.uu.se>
2 Date: Sat, 15 Aug 2009 11:58:11 +0000 (+0100)
3 Subject: ARM: 5677/1: ARM support for TIF_RESTORE_SIGMASK/pselect6/ppoll/epoll_pwait
4 X-Git-Tag: next-20090817~86^2~1^6
5 X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fnext%2Flinux-next.git;a=commitdiff_plain;h=369842658a36bcea28ecb643ba4bdb53919330dd
7 ARM: 5677/1: ARM support for TIF_RESTORE_SIGMASK/pselect6/ppoll/epoll_pwait
9 This patch adds support for TIF_RESTORE_SIGMASK to ARM's
10 signal handling, which allows to hook up the pselect6, ppoll,
11 and epoll_pwait syscalls on ARM.
13 Tested here with eabi userspace and a test program with a
14 deliberate race between a child's exit and the parent's
15 sigprocmask/select sequence. Using sys_pselect6() instead
16 of sigprocmask/select reliably prevents the race.
18 The other arch's support for TIF_RESTORE_SIGMASK has evolved
22 - add TIF_RESTORE_SIGMASK which parallels TIF_SIGPENDING
23 - test both when checking for pending signal [changed later]
24 - reimplement sys_sigsuspend() to use current->saved_sigmask,
25 TIF_RESTORE_SIGMASK [changed later], and -ERESTARTNOHAND;
26 ditto for sys_rt_sigsuspend(), but drop private code and
27 use common code via __ARCH_WANT_SYS_RT_SIGSUSPEND;
28 - there are now no "extra" calls to do_signal() so its oldset
29 parameter is always ¤t->blocked so need not be passed,
30 also its return value is changed to void
31 - change handle_signal() to return 0/-errno
32 - change do_signal() to honor TIF_RESTORE_SIGMASK:
33 + get oldset from current->saved_sigmask if TIF_RESTORE_SIGMASK
35 + if handle_signal() was successful then clear TIF_RESTORE_SIGMASK
36 + if no signal was delivered and TIF_RESTORE_SIGMASK is set then
37 clear it and restore the sigmask
38 - hook up sys_pselect6() and sys_ppoll()
41 - hook up sys_epoll_pwait()
44 - allow archs to override how TIF_RESTORE_SIGMASK is implemented;
45 default set_restore_sigmask() sets both TIF_RESTORE_SIGMASK and
46 TIF_SIGPENDING; archs need now just test TIF_SIGPENDING again
47 when checking for pending signal work; some archs now implement
48 TIF_RESTORE_SIGMASK as a secondary/non-atomic thread flag bit
49 - call set_restore_sigmask() in sys_sigsuspend() instead of setting
53 - kill sys_pselect7() which no arch wanted
55 So for 2.6.31-rc6/ARM this patch does the following:
56 - Add TIF_RESTORE_SIGMASK. Use the generic set_restore_sigmask()
57 which sets both TIF_SIGPENDING and TIF_RESTORE_SIGMASK, so
58 TIF_RESTORE_SIGMASK need not claim one of the scarce low thread
59 flags, and existing TIF_SIGPENDING and _TIF_WORK_MASK tests need
60 not be extended for TIF_RESTORE_SIGMASK.
61 - sys_sigsuspend() is reimplemented to use current->saved_sigmask
62 and set_restore_sigmask(), making it identical to most other archs
63 - The private code for sys_rt_sigsuspend() is removed, instead
64 generic code supplies it via __ARCH_WANT_SYS_RT_SIGSUSPEND.
65 - sys_sigsuspend() and sys_rt_sigsuspend() no longer need a pt_regs
66 parameter, so their assembly code wrappers are removed.
67 - handle_signal() is changed to return 0 on success or -errno.
68 - The oldset parameter to do_signal() is now redundant and removed,
69 and the return value is now also redundant and changed to void.
70 - do_signal() is changed to honor TIF_RESTORE_SIGMASK:
71 + get oldset from current->saved_sigmask if TIF_RESTORE_SIGMASK
73 + if handle_signal() was successful then clear TIF_RESTORE_SIGMASK
74 + if no signal was delivered and TIF_RESTORE_SIGMASK is set then
75 clear it and restore the sigmask
76 - Hook up sys_pselect6, sys_ppoll, and sys_epoll_pwait.
78 Signed-off-by: Mikael Pettersson <mikpe@it.uu.se>
79 Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
82 --- a/arch/arm/include/asm/thread_info.h
83 +++ b/arch/arm/include/asm/thread_info.h
84 @@ -140,6 +140,7 @@ extern void vfp_sync_state(struct thread
85 #define TIF_USING_IWMMXT 17
88 +#define TIF_RESTORE_SIGMASK 20
90 #define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
91 #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
92 @@ -147,6 +148,7 @@ extern void vfp_sync_state(struct thread
93 #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
94 #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT)
95 #define _TIF_FREEZE (1 << TIF_FREEZE)
96 +#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
99 * Change these and you break ASM code in entry-common.S
100 --- a/arch/arm/include/asm/unistd.h
101 +++ b/arch/arm/include/asm/unistd.h
103 #define __NR_readlinkat (__NR_SYSCALL_BASE+332)
104 #define __NR_fchmodat (__NR_SYSCALL_BASE+333)
105 #define __NR_faccessat (__NR_SYSCALL_BASE+334)
106 - /* 335 for pselect6 */
107 - /* 336 for ppoll */
108 +#define __NR_pselect6 (__NR_SYSCALL_BASE+335)
109 +#define __NR_ppoll (__NR_SYSCALL_BASE+336)
110 #define __NR_unshare (__NR_SYSCALL_BASE+337)
111 #define __NR_set_robust_list (__NR_SYSCALL_BASE+338)
112 #define __NR_get_robust_list (__NR_SYSCALL_BASE+339)
114 #define __NR_vmsplice (__NR_SYSCALL_BASE+343)
115 #define __NR_move_pages (__NR_SYSCALL_BASE+344)
116 #define __NR_getcpu (__NR_SYSCALL_BASE+345)
117 - /* 346 for epoll_pwait */
118 +#define __NR_epoll_pwait (__NR_SYSCALL_BASE+346)
119 #define __NR_kexec_load (__NR_SYSCALL_BASE+347)
120 #define __NR_utimensat (__NR_SYSCALL_BASE+348)
121 #define __NR_signalfd (__NR_SYSCALL_BASE+349)
123 #define __ARCH_WANT_SYS_SIGPENDING
124 #define __ARCH_WANT_SYS_SIGPROCMASK
125 #define __ARCH_WANT_SYS_RT_SIGACTION
126 +#define __ARCH_WANT_SYS_RT_SIGSUSPEND
128 #if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT)
129 #define __ARCH_WANT_SYS_TIME
130 --- a/arch/arm/kernel/calls.S
131 +++ b/arch/arm/kernel/calls.S
133 CALL(sys_ni_syscall) /* was sys_ssetmask */
134 /* 70 */ CALL(sys_setreuid16)
136 - CALL(sys_sigsuspend_wrapper)
137 + CALL(sys_sigsuspend)
139 CALL(sys_sethostname)
140 /* 75 */ CALL(sys_setrlimit)
142 CALL(sys_rt_sigpending)
143 CALL(sys_rt_sigtimedwait)
144 CALL(sys_rt_sigqueueinfo)
145 - CALL(sys_rt_sigsuspend_wrapper)
146 + CALL(sys_rt_sigsuspend)
147 /* 180 */ CALL(ABI(sys_pread64, sys_oabi_pread64))
148 CALL(ABI(sys_pwrite64, sys_oabi_pwrite64))
154 -/* 335 */ CALL(sys_ni_syscall) /* eventually pselect6 */
155 - CALL(sys_ni_syscall) /* eventually ppoll */
156 +/* 335 */ CALL(sys_pselect6)
159 CALL(sys_set_robust_list)
160 CALL(sys_get_robust_list)
164 /* 345 */ CALL(sys_getcpu)
165 - CALL(sys_ni_syscall) /* eventually epoll_pwait */
166 + CALL(sys_epoll_pwait)
170 --- a/arch/arm/kernel/entry-common.S
171 +++ b/arch/arm/kernel/entry-common.S
172 @@ -370,16 +370,6 @@ sys_clone_wrapper:
174 ENDPROC(sys_clone_wrapper)
176 -sys_sigsuspend_wrapper:
179 -ENDPROC(sys_sigsuspend_wrapper)
181 -sys_rt_sigsuspend_wrapper:
183 - b sys_rt_sigsuspend
184 -ENDPROC(sys_rt_sigsuspend_wrapper)
186 sys_sigreturn_wrapper:
189 --- a/arch/arm/kernel/signal.c
190 +++ b/arch/arm/kernel/signal.c
191 @@ -47,57 +47,22 @@ const unsigned long sigreturn_codes[7] =
192 MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
195 -static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
198 * atomically swap in the new signal mask, and wait for a signal.
200 -asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask, struct pt_regs *regs)
201 +asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)
206 spin_lock_irq(¤t->sighand->siglock);
207 - saveset = current->blocked;
208 + current->saved_sigmask = current->blocked;
209 siginitset(¤t->blocked, mask);
211 spin_unlock_irq(¤t->sighand->siglock);
212 - regs->ARM_r0 = -EINTR;
215 - current->state = TASK_INTERRUPTIBLE;
217 - if (do_signal(&saveset, regs, 0))
218 - return regs->ARM_r0;
223 -sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs)
225 - sigset_t saveset, newset;
227 - /* XXX: Don't preclude handling different sized sigset_t's. */
228 - if (sigsetsize != sizeof(sigset_t))
231 - if (copy_from_user(&newset, unewset, sizeof(newset)))
233 - sigdelsetmask(&newset, ~_BLOCKABLE);
235 - spin_lock_irq(¤t->sighand->siglock);
236 - saveset = current->blocked;
237 - current->blocked = newset;
238 - recalc_sigpending();
239 - spin_unlock_irq(¤t->sighand->siglock);
240 - regs->ARM_r0 = -EINTR;
243 - current->state = TASK_INTERRUPTIBLE;
245 - if (do_signal(&saveset, regs, 0))
246 - return regs->ARM_r0;
248 + current->state = TASK_INTERRUPTIBLE;
250 + set_restore_sigmask();
251 + return -ERESTARTNOHAND;
255 @@ -541,7 +506,7 @@ static inline void restart_syscall(struc
257 * OK, we're invoking a handler
261 handle_signal(unsigned long sig, struct k_sigaction *ka,
262 siginfo_t *info, sigset_t *oldset,
263 struct pt_regs * regs, int syscall)
264 @@ -592,7 +557,7 @@ handle_signal(unsigned long sig, struct
267 force_sigsegv(sig, tsk);
273 @@ -606,6 +571,7 @@ handle_signal(unsigned long sig, struct
275 spin_unlock_irq(&tsk->sighand->siglock);
281 @@ -617,11 +583,12 @@ handle_signal(unsigned long sig, struct
282 * the kernel can handle, and then we build all the user-level signal handling
283 * stack-frames in one go after that.
285 -static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
286 +static void do_signal(struct pt_regs *regs, int syscall)
288 struct k_sigaction ka;
294 * We want the common case to go fast, which
295 @@ -630,18 +597,32 @@ static int do_signal(sigset_t *oldset, s
298 if (!user_mode(regs))
305 single_step_clear(current);
307 + if (test_thread_flag(TIF_RESTORE_SIGMASK))
308 + oldset = ¤t->saved_sigmask;
310 + oldset = ¤t->blocked;
312 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
314 - handle_signal(signr, &ka, &info, oldset, regs, syscall);
315 + if (handle_signal(signr, &ka, &info, oldset, regs, syscall) == 0) {
317 + * A signal was successfully delivered; the saved
318 + * sigmask will have been stored in the signal frame,
319 + * and will be restored by sigreturn, so we can simply
320 + * clear the TIF_RESTORE_SIGMASK flag.
322 + if (test_thread_flag(TIF_RESTORE_SIGMASK))
323 + clear_thread_flag(TIF_RESTORE_SIGMASK);
325 single_step_set(current);
331 @@ -693,14 +674,21 @@ static int do_signal(sigset_t *oldset, s
332 regs->ARM_r0 == -ERESTARTNOINTR) {
333 restart_syscall(regs);
336 + /* If there's no signal to deliver, we just put the saved sigmask
339 + if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
340 + clear_thread_flag(TIF_RESTORE_SIGMASK);
341 + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
344 single_step_set(current);
349 do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
351 if (thread_flags & _TIF_SIGPENDING)
352 - do_signal(¤t->blocked, regs, syscall);
353 + do_signal(regs, syscall);