<p>Bryan, could you please check if this is applicable to dove as well, or its just backport for imx51?</p>
<p>--sent from my G1</p>
<p><blockquote type="cite">On Feb 24, 2010 6:05 PM, "Bryan Wu" <<a href="mailto:bryan.wu@canonical.com">bryan.wu@canonical.com</a>> wrote:<br><br>From: Mikael Pettersson <<a href="mailto:mikpe@it.uu.se">mikpe@it.uu.se</a>><br>

<br>
This patch adds support for TIF_RESTORE_SIGMASK to ARM's<br>
signal handling, which allows to hook up the pselect6, ppoll,<br>
and epoll_pwait syscalls on ARM.<br>
<br>
Tested here with eabi userspace and a test program with a<br>
deliberate race between a child's exit and the parent's<br>
sigprocmask/select sequence. Using sys_pselect6() instead<br>
of sigprocmask/select reliably prevents the race.<br>
<br>
The other arch's support for TIF_RESTORE_SIGMASK has evolved<br>
over time:<br>
<br>
In 2.6.16:<br>
- add TIF_RESTORE_SIGMASK which parallels TIF_SIGPENDING<br>
- test both when checking for pending signal [changed later]<br>
- reimplement sys_sigsuspend() to use current->saved_sigmask,<br>
  TIF_RESTORE_SIGMASK [changed later], and -ERESTARTNOHAND;<br>
  ditto for sys_rt_sigsuspend(), but drop private code and<br>
  use common code via __ARCH_WANT_SYS_RT_SIGSUSPEND;<br>
- there are now no "extra" calls to do_signal() so its oldset<br>
  parameter is always &current->blocked so need not be passed,<br>
  also its return value is changed to void<br>
- change handle_signal() to return 0/-errno<br>
- change do_signal() to honor TIF_RESTORE_SIGMASK:<br>
  + get oldset from current->saved_sigmask if TIF_RESTORE_SIGMASK<br>
    is set<br>
  + if handle_signal() was successful then clear TIF_RESTORE_SIGMASK<br>
  + if no signal was delivered and TIF_RESTORE_SIGMASK is set then<br>
    clear it and restore the sigmask<br>
- hook up sys_pselect6() and sys_ppoll()<br>
<br>
In 2.6.19:<br>
- hook up sys_epoll_pwait()<br>
<br>
In 2.6.26:<br>
- allow archs to override how TIF_RESTORE_SIGMASK is implemented;<br>
  default set_restore_sigmask() sets both TIF_RESTORE_SIGMASK and<br>
  TIF_SIGPENDING; archs need now just test TIF_SIGPENDING again<br>
  when checking for pending signal work; some archs now implement<br>
  TIF_RESTORE_SIGMASK as a secondary/non-atomic thread flag bit<br>
- call set_restore_sigmask() in sys_sigsuspend() instead of setting<br>
  TIF_RESTORE_SIGMASK<br>
<br>
In 2.6.29-rc:<br>
- kill sys_pselect7() which no arch wanted<br>
<br>
So for 2.6.31-rc6/ARM this patch does the following:<br>
- Add TIF_RESTORE_SIGMASK. Use the generic set_restore_sigmask()<br>
  which sets both TIF_SIGPENDING and TIF_RESTORE_SIGMASK, so<br>
  TIF_RESTORE_SIGMASK need not claim one of the scarce low thread<br>
  flags, and existing TIF_SIGPENDING and _TIF_WORK_MASK tests need<br>
  not be extended for TIF_RESTORE_SIGMASK.<br>
- sys_sigsuspend() is reimplemented to use current->saved_sigmask<br>
  and set_restore_sigmask(), making it identical to most other archs<br>
- The private code for sys_rt_sigsuspend() is removed, instead<br>
  generic code supplies it via __ARCH_WANT_SYS_RT_SIGSUSPEND.<br>
- sys_sigsuspend() and sys_rt_sigsuspend() no longer need a pt_regs<br>
  parameter, so their assembly code wrappers are removed.<br>
- handle_signal() is changed to return 0 on success or -errno.<br>
- The oldset parameter to do_signal() is now redundant and removed,<br>
  and the return value is now also redundant and changed to void.<br>
- do_signal() is changed to honor TIF_RESTORE_SIGMASK:<br>
  + get oldset from current->saved_sigmask if TIF_RESTORE_SIGMASK<br>
    is set<br>
  + if handle_signal() was successful then clear TIF_RESTORE_SIGMASK<br>
  + if no signal was delivered and TIF_RESTORE_SIGMASK is set then<br>
    clear it and restore the sigmask<br>
- Hook up sys_pselect6, sys_ppoll, and sys_epoll_pwait.<br>
<br>
BugLink: <a href="https://bugs.launchpad.net/ubuntu/+source/linux/+bug/319729
(cherry-picked" target="_blank">https://bugs.launchpad.net/ubuntu/+source/linux/+bug/319729<br>
(cherry-picked</a> from commit 369842658a36bcea28ecb643ba4bdb53919330dd)<br>
<br>
Signed-off-by: Mikael Pettersson <<a href="mailto:mikpe@it.uu.se">mikpe@it.uu.se</a>><br>
Signed-off-by: Russell King <<a href="mailto:rmk%2Bkernel@arm.linux.org.uk">rmk+kernel@arm.linux.org.uk</a>><br>
Signed-off-by: Bryan Wu <<a href="mailto:bryan.wu@canonical.com">bryan.wu@canonical.com</a>><br>
---<br>
 arch/arm/include/asm/thread_info.h |    2 +<br>
 arch/arm/include/asm/unistd.h      |    7 ++-<br>
 arch/arm/kernel/calls.S            |   10 ++--<br>
 arch/arm/kernel/entry-common.S     |   10 ----<br>
 arch/arm/kernel/signal.c           |   86 +++++++++++++++--------------------<br>
 5 files changed, 48 insertions(+), 67 deletions(-)<br>
<br>
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h<br>
index 73394e5..e20d805 100644<br>
--- a/arch/arm/include/asm/thread_info.h<br>
+++ b/arch/arm/include/asm/thread_info.h<br>
@@ -140,6 +140,7 @@ extern void vfp_sync_state(struct thread_info *thread);<br>
 #define TIF_USING_IWMMXT       17<br>
 #define TIF_MEMDIE             18<br>
 #define TIF_FREEZE             19<br>
+#define TIF_RESTORE_SIGMASK    20<br>
<br>
 #define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)<br>
 #define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)<br>
@@ -147,6 +148,7 @@ extern void vfp_sync_state(struct thread_info *thread);<br>
 #define _TIF_POLLING_NRFLAG    (1 << TIF_POLLING_NRFLAG)<br>
 #define _TIF_USING_IWMMXT      (1 << TIF_USING_IWMMXT)<br>
 #define _TIF_FREEZE            (1 << TIF_FREEZE)<br>
+#define _TIF_RESTORE_SIGMASK   (1 << TIF_RESTORE_SIGMASK)<br>
<br>
 /*<br>
  * Change these and you break ASM code in entry-common.S<br>
diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h<br>
index 0e97b8c..9122c9e 100644<br>
--- a/arch/arm/include/asm/unistd.h<br>
+++ b/arch/arm/include/asm/unistd.h<br>
@@ -360,8 +360,8 @@<br>
 #define __NR_readlinkat                        (__NR_SYSCALL_BASE+332)<br>
 #define __NR_fchmodat                  (__NR_SYSCALL_BASE+333)<br>
 #define __NR_faccessat                 (__NR_SYSCALL_BASE+334)<br>
-                                       /* 335 for pselect6 */<br>
-                                       /* 336 for ppoll */<br>
+#define __NR_pselect6                  (__NR_SYSCALL_BASE+335)<br>
+#define __NR_ppoll                     (__NR_SYSCALL_BASE+336)<br>
 #define __NR_unshare                   (__NR_SYSCALL_BASE+337)<br>
 #define __NR_set_robust_list           (__NR_SYSCALL_BASE+338)<br>
 #define __NR_get_robust_list           (__NR_SYSCALL_BASE+339)<br>
@@ -372,7 +372,7 @@<br>
 #define __NR_vmsplice                  (__NR_SYSCALL_BASE+343)<br>
 #define __NR_move_pages                        (__NR_SYSCALL_BASE+344)<br>
 #define __NR_getcpu                    (__NR_SYSCALL_BASE+345)<br>
-                                       /* 346 for epoll_pwait */<br>
+#define __NR_epoll_pwait               (__NR_SYSCALL_BASE+346)<br>
 #define __NR_kexec_load                        (__NR_SYSCALL_BASE+347)<br>
 #define __NR_utimensat                 (__NR_SYSCALL_BASE+348)<br>
 #define __NR_signalfd                  (__NR_SYSCALL_BASE+349)<br>
@@ -432,6 +432,7 @@<br>
 #define __ARCH_WANT_SYS_SIGPENDING<br>
 #define __ARCH_WANT_SYS_SIGPROCMASK<br>
 #define __ARCH_WANT_SYS_RT_SIGACTION<br>
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND<br>
<br>
 #if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT)<br>
 #define __ARCH_WANT_SYS_TIME<br>
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S<br>
index 6e1b8bf..9296c59 100644<br>
--- a/arch/arm/kernel/calls.S<br>
+++ b/arch/arm/kernel/calls.S<br>
@@ -81,7 +81,7 @@<br>
                CALL(sys_ni_syscall)            /* was sys_ssetmask */<br>
 /* 70 */       CALL(sys_setreuid16)<br>
                CALL(sys_setregid16)<br>
-               CALL(sys_sigsuspend_wrapper)<br>
+               CALL(sys_sigsuspend)<br>
                CALL(sys_sigpending)<br>
                CALL(sys_sethostname)<br>
 /* 75 */       CALL(sys_setrlimit)<br>
@@ -188,7 +188,7 @@<br>
                CALL(sys_rt_sigpending)<br>
                CALL(sys_rt_sigtimedwait)<br>
                CALL(sys_rt_sigqueueinfo)<br>
-               CALL(sys_rt_sigsuspend_wrapper)<br>
+               CALL(sys_rt_sigsuspend)<br>
 /* 180 */      CALL(ABI(sys_pread64, sys_oabi_pread64))<br>
                CALL(ABI(sys_pwrite64, sys_oabi_pwrite64))<br>
                CALL(sys_chown16)<br>
@@ -344,8 +344,8 @@<br>
                CALL(sys_readlinkat)<br>
                CALL(sys_fchmodat)<br>
                CALL(sys_faccessat)<br>
-/* 335 */      CALL(sys_ni_syscall)            /* eventually pselect6 */<br>
-               CALL(sys_ni_syscall)            /* eventually ppoll */<br>
+/* 335 */      CALL(sys_pselect6)<br>
+               CALL(sys_ppoll)<br>
                CALL(sys_unshare)<br>
                CALL(sys_set_robust_list)<br>
                CALL(sys_get_robust_list)<br>
@@ -355,7 +355,7 @@<br>
                CALL(sys_vmsplice)<br>
                CALL(sys_move_pages)<br>
 /* 345 */      CALL(sys_getcpu)<br>
-               CALL(sys_ni_syscall)            /* eventually epoll_pwait */<br>
+               CALL(sys_epoll_pwait)<br>
                CALL(sys_kexec_load)<br>
                CALL(sys_utimensat)<br>
                CALL(sys_signalfd)<br>
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S<br>
index a762152..9565752 100644<br>
--- a/arch/arm/kernel/entry-common.S<br>
+++ b/arch/arm/kernel/entry-common.S<br>
@@ -373,16 +373,6 @@ sys_clone_wrapper:<br>
                b       sys_clone<br>
 ENDPROC(sys_clone_wrapper)<br>
<br>
-sys_sigsuspend_wrapper:<br>
-               add     r3, sp, #S_OFF<br>
-               b       sys_sigsuspend<br>
-ENDPROC(sys_sigsuspend_wrapper)<br>
-<br>
-sys_rt_sigsuspend_wrapper:<br>
-               add     r2, sp, #S_OFF<br>
-               b       sys_rt_sigsuspend<br>
-ENDPROC(sys_rt_sigsuspend_wrapper)<br>
-<br>
 sys_sigreturn_wrapper:<br>
                add     r0, sp, #S_OFF<br>
                b       sys_sigreturn<br>
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c<br>
index 6dd5008..7dfd3b8 100644<br>
--- a/arch/arm/kernel/signal.c<br>
+++ b/arch/arm/kernel/signal.c<br>
@@ -48,57 +48,22 @@ const unsigned long sigreturn_codes[7] = {<br>
        MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,<br>
 };<br>
<br>
-static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);<br>
-<br>
 /*<br>
  * atomically swap in the new signal mask, and wait for a signal.<br>
  */<br>
-asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask, struct pt_regs *regs)<br>
+asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)<br>
 {<br>
-       sigset_t saveset;<br>
-<br>
        mask &= _BLOCKABLE;<br>
        spin_lock_irq(&current->sighand->siglock);<br>
-       saveset = current->blocked;<br>
+       current->saved_sigmask = current->blocked;<br>
        siginitset(&current->blocked, mask);<br>
        recalc_sigpending();<br>
        spin_unlock_irq(&current->sighand->siglock);<br>
-       regs->ARM_r0 = -EINTR;<br>
-<br>
-       while (1) {<br>
-               current->state = TASK_INTERRUPTIBLE;<br>
-               schedule();<br>
-               if (do_signal(&saveset, regs, 0))<br>
-                       return regs->ARM_r0;<br>
-       }<br>
-}<br>
-<br>
-asmlinkage int<br>
-sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs)<br>
-{<br>
-       sigset_t saveset, newset;<br>
-<br>
-       /* XXX: Don't preclude handling different sized sigset_t's. */<br>
-       if (sigsetsize != sizeof(sigset_t))<br>
-               return -EINVAL;<br>
-<br>
-       if (copy_from_user(&newset, unewset, sizeof(newset)))<br>
-               return -EFAULT;<br>
-       sigdelsetmask(&newset, ~_BLOCKABLE);<br>
-<br>
-       spin_lock_irq(&current->sighand->siglock);<br>
-       saveset = current->blocked;<br>
-       current->blocked = newset;<br>
-       recalc_sigpending();<br>
-       spin_unlock_irq(&current->sighand->siglock);<br>
-       regs->ARM_r0 = -EINTR;<br>
<br>
-       while (1) {<br>
-               current->state = TASK_INTERRUPTIBLE;<br>
-               schedule();<br>
-               if (do_signal(&saveset, regs, 0))<br>
-                       return regs->ARM_r0;<br>
-       }<br>
+       current->state = TASK_INTERRUPTIBLE;<br>
+       schedule();<br>
+       set_restore_sigmask();<br>
+       return -ERESTARTNOHAND;<br>
 }<br>
<br>
 asmlinkage int<br>
@@ -628,7 +593,7 @@ static inline void setup_syscall_restart(struct pt_regs *regs)<br>
 /*<br>
  * OK, we're invoking a handler<br>
  */<br>
-static void<br>
+static int<br>
 handle_signal(unsigned long sig, struct k_sigaction *ka,<br>
              siginfo_t *info, sigset_t *oldset,<br>
              struct pt_regs * regs, int syscall)<br>
@@ -679,7 +644,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,<br>
<br>
        if (ret != 0) {<br>
                force_sigsegv(sig, tsk);<br>
-               return;<br>
+               return ret;<br>
        }<br>
<br>
        /*<br>
@@ -693,6 +658,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,<br>
        recalc_sigpending();<br>
        spin_unlock_irq(&tsk->sighand->siglock);<br>
<br>
+       return 0;<br>
 }<br>
<br>
 /*<br>
@@ -704,7 +670,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,<br>
  * the kernel can handle, and then we build all the user-level signal handling<br>
  * stack-frames in one go after that.<br>
  */<br>
-static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)<br>
+static void do_signal(struct pt_regs *regs, int syscall)<br>
 {<br>
        struct k_sigaction ka;<br>
        siginfo_t info;<br>
@@ -717,7 +683,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)<br>
         * if so.<br>
         */<br>
        if (!user_mode(regs))<br>
-               return 0;<br>
+               return;<br>
<br>
        if (try_to_freeze())<br>
                goto no_signal;<br>
@@ -726,9 +692,24 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)<br>
<br>
        signr = get_signal_to_deliver(&info, &ka, regs, NULL);<br>
        if (signr > 0) {<br>
-               handle_signal(signr, &ka, &info, oldset, regs, syscall);<br>
+               sigset_t *oldset;<br>
+<br>
+               if (test_thread_flag(TIF_RESTORE_SIGMASK))<br>
+                       oldset = &current->saved_sigmask;<br>
+               else<br>
+                       oldset = &current->blocked;<br>
+               if (handle_signal(signr, &ka, &info, oldset, regs, syscall) == 0) {<br>
+                       /*<br>
+                        * A signal was successfully delivered; the saved<br>
+                        * sigmask will have been stored in the signal frame,<br>
+                        * and will be restored by sigreturn, so we can simply<br>
+                        * clear the TIF_RESTORE_SIGMASK flag.<br>
+                        */<br>
+                       if (test_thread_flag(TIF_RESTORE_SIGMASK))<br>
+                               clear_thread_flag(TIF_RESTORE_SIGMASK);<br>
+               }<br>
                single_step_set(current);<br>
-               return 1;<br>
+               return;<br>
        }<br>
<br>
  no_signal:<br>
@@ -780,14 +761,21 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)<br>
                    regs->ARM_r0 == -ERESTARTNOINTR) {<br>
                        setup_syscall_restart(regs);<br>
                }<br>
+<br>
+               /* If there's no signal to deliver, we just put the saved sigmask<br>
+                * back.<br>
+                */<br>
+               if (test_thread_flag(TIF_RESTORE_SIGMASK)) {<br>
+                       clear_thread_flag(TIF_RESTORE_SIGMASK);<br>
+                       sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);<br>
+               }<br>
        }<br>
        single_step_set(current);<br>
-       return 0;<br>
 }<br>
<br>
 asmlinkage void<br>
 do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)<br>
 {<br>
        if (thread_flags & _TIF_SIGPENDING)<br>
-               do_signal(&current->blocked, regs, syscall);<br>
+               do_signal(regs, syscall);<br>
 }<br>
--<br>
1.6.3.3<br>
<font color="#888888"><br>
<br>
--<br>
kernel-team mailing list<br>
<a href="mailto:kernel-team@lists.ubuntu.com">kernel-team@lists.ubuntu.com</a><br>
<a href="https://lists.ubuntu.com/mailman/listinfo/kernel-team" target="_blank">https://lists.ubuntu.com/mailman/listinfo/kernel-team</a><br>
</font></blockquote></p>