Root/target/linux/generic/patches-2.6.31/965-arm_restore_sigmask_v2.patch

1From: Mikael Pettersson <mikpe@it.uu.se>
2Date: Sat, 15 Aug 2009 11:58:11 +0000 (+0100)
3Subject: ARM: 5677/1: ARM support for TIF_RESTORE_SIGMASK/pselect6/ppoll/epoll_pwait
4X-Git-Tag: next-20090817~86^2~1^6
5X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fnext%2Flinux-next.git;a=commitdiff_plain;h=369842658a36bcea28ecb643ba4bdb53919330dd
6
7ARM: 5677/1: ARM support for TIF_RESTORE_SIGMASK/pselect6/ppoll/epoll_pwait
8
9This patch adds support for TIF_RESTORE_SIGMASK to ARM's
10signal handling, which allows to hook up the pselect6, ppoll,
11and epoll_pwait syscalls on ARM.
12
13Tested here with eabi userspace and a test program with a
14deliberate race between a child's exit and the parent's
15sigprocmask/select sequence. Using sys_pselect6() instead
16of sigprocmask/select reliably prevents the race.
17
18The other arch's support for TIF_RESTORE_SIGMASK has evolved
19over time:
20
21In 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
40In 2.6.19:
41- hook up sys_epoll_pwait()
42
43In 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
52In 2.6.29-rc:
53- kill sys_pselect7() which no arch wanted
54
55So 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
78Signed-off-by: Mikael Pettersson <mikpe@it.uu.se>
79Signed-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@@ -141,6 +141,7 @@
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@@ -148,6 +149,7 @@
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@@ -432,6 +432,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@@ -373,16 +373,6 @@
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 @@
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@@ -545,7 +510,7 @@
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@@ -596,7 +561,7 @@
265 
266     if (ret != 0) {
267         force_sigsegv(sig, tsk);
268- return;
269+ return ret;
270     }
271 
272     /*
273@@ -610,6 +575,7 @@
274     recalc_sigpending();
275     spin_unlock_irq(&tsk->sighand->siglock);
276 
277+ return 0;
278 }
279 
280 /*
281@@ -621,11 +587,12 @@
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@@ -634,18 +601,32 @@
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@@ -697,14 +678,21 @@
332             regs->ARM_r0 == -ERESTARTNOINTR) {
333             setup_syscall_restart(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 }
355

Archive Download this file



interactive