30acd0316bec2eaf1c471b5b87b2f11f4dc5c69b
[openwrt/svn-archive/archive.git] / target / linux / generic / patches-2.6.30 / 965-arm_restore_sigmask_v2.patch
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
6
7 ARM: 5677/1: ARM support for TIF_RESTORE_SIGMASK/pselect6/ppoll/epoll_pwait
8
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.
12
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.
17
18 The other arch's support for TIF_RESTORE_SIGMASK has evolved
19 over time:
20
21 In 2.6.16:
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 &current->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
34 is set
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()
39
40 In 2.6.19:
41 - hook up sys_epoll_pwait()
42
43 In 2.6.26:
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
50 TIF_RESTORE_SIGMASK
51
52 In 2.6.29-rc:
53 - kill sys_pselect7() which no arch wanted
54
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
72 is set
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.
77
78 Signed-off-by: Mikael Pettersson <mikpe@it.uu.se>
79 Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
80 ---
81
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
86 #define TIF_MEMDIE 18
87 #define TIF_FREEZE 19
88 +#define TIF_RESTORE_SIGMASK 20
89
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)
97
98 /*
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
102 @@ -360,8 +360,8 @@
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)
113 @@ -372,7 +372,7 @@
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)
122 @@ -430,6 +430,7 @@
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
127
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
132 @@ -81,7 +81,7 @@
133 CALL(sys_ni_syscall) /* was sys_ssetmask */
134 /* 70 */ CALL(sys_setreuid16)
135 CALL(sys_setregid16)
136 - CALL(sys_sigsuspend_wrapper)
137 + CALL(sys_sigsuspend)
138 CALL(sys_sigpending)
139 CALL(sys_sethostname)
140 /* 75 */ CALL(sys_setrlimit)
141 @@ -188,7 +188,7 @@
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))
149 CALL(sys_chown16)
150 @@ -344,8 +344,8 @@
151 CALL(sys_readlinkat)
152 CALL(sys_fchmodat)
153 CALL(sys_faccessat)
154 -/* 335 */ CALL(sys_ni_syscall) /* eventually pselect6 */
155 - CALL(sys_ni_syscall) /* eventually ppoll */
156 +/* 335 */ CALL(sys_pselect6)
157 + CALL(sys_ppoll)
158 CALL(sys_unshare)
159 CALL(sys_set_robust_list)
160 CALL(sys_get_robust_list)
161 @@ -355,7 +355,7 @@
162 CALL(sys_vmsplice)
163 CALL(sys_move_pages)
164 /* 345 */ CALL(sys_getcpu)
165 - CALL(sys_ni_syscall) /* eventually epoll_pwait */
166 + CALL(sys_epoll_pwait)
167 CALL(sys_kexec_load)
168 CALL(sys_utimensat)
169 CALL(sys_signalfd)
170 --- a/arch/arm/kernel/entry-common.S
171 +++ b/arch/arm/kernel/entry-common.S
172 @@ -370,16 +370,6 @@ sys_clone_wrapper:
173 b sys_clone
174 ENDPROC(sys_clone_wrapper)
175
176 -sys_sigsuspend_wrapper:
177 - add r3, sp, #S_OFF
178 - b sys_sigsuspend
179 -ENDPROC(sys_sigsuspend_wrapper)
180 -
181 -sys_rt_sigsuspend_wrapper:
182 - add r2, sp, #S_OFF
183 - b sys_rt_sigsuspend
184 -ENDPROC(sys_rt_sigsuspend_wrapper)
185 -
186 sys_sigreturn_wrapper:
187 add r0, sp, #S_OFF
188 b sys_sigreturn
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,
193 };
194
195 -static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
196 -
197 /*
198 * atomically swap in the new signal mask, and wait for a signal.
199 */
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)
202 {
203 - sigset_t saveset;
204 -
205 mask &= _BLOCKABLE;
206 spin_lock_irq(&current->sighand->siglock);
207 - saveset = current->blocked;
208 + current->saved_sigmask = current->blocked;
209 siginitset(&current->blocked, mask);
210 recalc_sigpending();
211 spin_unlock_irq(&current->sighand->siglock);
212 - regs->ARM_r0 = -EINTR;
213 -
214 - while (1) {
215 - current->state = TASK_INTERRUPTIBLE;
216 - schedule();
217 - if (do_signal(&saveset, regs, 0))
218 - return regs->ARM_r0;
219 - }
220 -}
221 -
222 -asmlinkage int
223 -sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs)
224 -{
225 - sigset_t saveset, newset;
226 -
227 - /* XXX: Don't preclude handling different sized sigset_t's. */
228 - if (sigsetsize != sizeof(sigset_t))
229 - return -EINVAL;
230 -
231 - if (copy_from_user(&newset, unewset, sizeof(newset)))
232 - return -EFAULT;
233 - sigdelsetmask(&newset, ~_BLOCKABLE);
234 -
235 - spin_lock_irq(&current->sighand->siglock);
236 - saveset = current->blocked;
237 - current->blocked = newset;
238 - recalc_sigpending();
239 - spin_unlock_irq(&current->sighand->siglock);
240 - regs->ARM_r0 = -EINTR;
241
242 - while (1) {
243 - current->state = TASK_INTERRUPTIBLE;
244 - schedule();
245 - if (do_signal(&saveset, regs, 0))
246 - return regs->ARM_r0;
247 - }
248 + current->state = TASK_INTERRUPTIBLE;
249 + schedule();
250 + set_restore_sigmask();
251 + return -ERESTARTNOHAND;
252 }
253
254 asmlinkage int
255 @@ -541,7 +506,7 @@ static inline void restart_syscall(struc
256 /*
257 * OK, we're invoking a handler
258 */
259 -static void
260 +static int
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
265
266 if (ret != 0) {
267 force_sigsegv(sig, tsk);
268 - return;
269 + return ret;
270 }
271
272 /*
273 @@ -606,6 +571,7 @@ handle_signal(unsigned long sig, struct
274 recalc_sigpending();
275 spin_unlock_irq(&tsk->sighand->siglock);
276
277 + return 0;
278 }
279
280 /*
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.
284 */
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)
287 {
288 struct k_sigaction ka;
289 siginfo_t info;
290 int signr;
291 + sigset_t *oldset;
292
293 /*
294 * We want the common case to go fast, which
295 @@ -630,18 +597,32 @@ static int do_signal(sigset_t *oldset, s
296 * if so.
297 */
298 if (!user_mode(regs))
299 - return 0;
300 + return;
301
302 if (try_to_freeze())
303 goto no_signal;
304
305 single_step_clear(current);
306
307 + if (test_thread_flag(TIF_RESTORE_SIGMASK))
308 + oldset = &current->saved_sigmask;
309 + else
310 + oldset = &current->blocked;
311 +
312 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
313 if (signr > 0) {
314 - handle_signal(signr, &ka, &info, oldset, regs, syscall);
315 + if (handle_signal(signr, &ka, &info, oldset, regs, syscall) == 0) {
316 + /*
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.
321 + */
322 + if (test_thread_flag(TIF_RESTORE_SIGMASK))
323 + clear_thread_flag(TIF_RESTORE_SIGMASK);
324 + }
325 single_step_set(current);
326 - return 1;
327 + return;
328 }
329
330 no_signal:
331 @@ -693,14 +674,21 @@ static int do_signal(sigset_t *oldset, s
332 regs->ARM_r0 == -ERESTARTNOINTR) {
333 restart_syscall(regs);
334 }
335 +
336 + /* If there's no signal to deliver, we just put the saved sigmask
337 + * back.
338 + */
339 + if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
340 + clear_thread_flag(TIF_RESTORE_SIGMASK);
341 + sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
342 + }
343 }
344 single_step_set(current);
345 - return 0;
346 }
347
348 asmlinkage void
349 do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
350 {
351 if (thread_flags & _TIF_SIGPENDING)
352 - do_signal(&current->blocked, regs, syscall);
353 + do_signal(regs, syscall);
354 }