Backport arm ppoll()/pselect6() etc. implementation from linux-next@36984265a3
[10.03/openwrt.git] / target / linux / generic-2.6 / 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        2009-04-18 18:55:23.000000000 +0200
83 +++ b/arch/arm/include/asm/thread_info.h        2009-04-18 19:10:22.000000000 +0200
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     2008-10-11 10:43:49.000000000 +0200
101 +++ b/arch/arm/include/asm/unistd.h     2009-04-18 19:10:22.000000000 +0200
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 @@ -428,6 +428,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   2009-03-24 18:00:31.000000000 +0100
131 +++ b/arch/arm/kernel/calls.S   2009-04-18 19:10:22.000000000 +0200
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    2009-04-18 18:55:23.000000000 +0200
171 +++ b/arch/arm/kernel/entry-common.S    2009-04-18 19:10:22.000000000 +0200
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  2008-12-25 15:54:13.000000000 +0100
190 +++ b/arch/arm/kernel/signal.c  2009-04-18 19:10:22.000000000 +0200
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  }