Commit 150256d8aadb3a337c31efa9e175cbd25bf06b06

Authored by David Woodhouse
Committed by Linus Torvalds
1 parent a60fc5190a

[PATCH] Generic sys_rt_sigsuspend()

The TIF_RESTORE_SIGMASK flag allows us to have a generic implementation of
sys_rt_sigsuspend() instead of duplicating it for each architecture.  This
provides such an implementation and makes arch/powerpc use it.

It also tidies up the ppc32 sys_sigsuspend() to use TIF_RESTORE_SIGMASK.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 6 changed files with 62 additions and 87 deletions Side-by-side Diff

arch/powerpc/kernel/signal_32.c
... ... @@ -252,8 +252,7 @@
252 252 /*
253 253 * Atomically swap in the new signal mask, and wait for a signal.
254 254 */
255   -long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
256   - struct pt_regs *regs)
  255 +long sys_sigsuspend(old_sigset_t mask)
257 256 {
258 257 sigset_t saveset;
259 258  
... ... @@ -264,55 +263,10 @@
264 263 recalc_sigpending();
265 264 spin_unlock_irq(&current->sighand->siglock);
266 265  
267   - regs->result = -EINTR;
268   - regs->gpr[3] = EINTR;
269   - regs->ccr |= 0x10000000;
270   - while (1) {
271   - current->state = TASK_INTERRUPTIBLE;
272   - schedule();
273   - if (do_signal(&saveset, regs)) {
274   - set_thread_flag(TIF_RESTOREALL);
275   - return 0;
276   - }
277   - }
278   -}
279   -
280   -long sys_rt_sigsuspend(
281   -#ifdef CONFIG_PPC64
282   - compat_sigset_t __user *unewset,
283   -#else
284   - sigset_t __user *unewset,
285   -#endif
286   - size_t sigsetsize, int p3, int p4,
287   - int p6, int p7, struct pt_regs *regs)
288   -{
289   - sigset_t saveset, newset;
290   -
291   - /* XXX: Don't preclude handling different sized sigset_t's. */
292   - if (sigsetsize != sizeof(sigset_t))
293   - return -EINVAL;
294   -
295   - if (get_sigset_t(&newset, unewset))
296   - return -EFAULT;
297   - sigdelsetmask(&newset, ~_BLOCKABLE);
298   -
299   - spin_lock_irq(&current->sighand->siglock);
300   - saveset = current->blocked;
301   - current->blocked = newset;
302   - recalc_sigpending();
303   - spin_unlock_irq(&current->sighand->siglock);
304   -
305   - regs->result = -EINTR;
306   - regs->gpr[3] = EINTR;
307   - regs->ccr |= 0x10000000;
308   - while (1) {
309   - current->state = TASK_INTERRUPTIBLE;
310   - schedule();
311   - if (do_signal(&saveset, regs)) {
312   - set_thread_flag(TIF_RESTOREALL);
313   - return 0;
314   - }
315   - }
  266 + current->state = TASK_INTERRUPTIBLE;
  267 + schedule();
  268 + set_thread_flag(TIF_RESTORE_SIGMASK);
  269 + return -ERESTARTNOHAND;
316 270 }
317 271  
318 272 #ifdef CONFIG_PPC32
arch/powerpc/kernel/signal_64.c
... ... @@ -67,42 +67,6 @@
67 67 char abigap[288];
68 68 } __attribute__ ((aligned (16)));
69 69  
70   -
71   -/*
72   - * Atomically swap in the new signal mask, and wait for a signal.
73   - */
74   -long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, int p3, int p4,
75   - int p6, int p7, struct pt_regs *regs)
76   -{
77   - sigset_t saveset, newset;
78   -
79   - /* XXX: Don't preclude handling different sized sigset_t's. */
80   - if (sigsetsize != sizeof(sigset_t))
81   - return -EINVAL;
82   -
83   - if (copy_from_user(&newset, unewset, sizeof(newset)))
84   - return -EFAULT;
85   - sigdelsetmask(&newset, ~_BLOCKABLE);
86   -
87   - spin_lock_irq(&current->sighand->siglock);
88   - saveset = current->blocked;
89   - current->blocked = newset;
90   - recalc_sigpending();
91   - spin_unlock_irq(&current->sighand->siglock);
92   -
93   - regs->result = -EINTR;
94   - regs->gpr[3] = EINTR;
95   - regs->ccr |= 0x10000000;
96   - while (1) {
97   - current->state = TASK_INTERRUPTIBLE;
98   - schedule();
99   - if (do_signal(&saveset, regs)) {
100   - set_thread_flag(TIF_RESTOREALL);
101   - return 0;
102   - }
103   - }
104   -}
105   -
106 70 long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, unsigned long r5,
107 71 unsigned long r6, unsigned long r7, unsigned long r8,
108 72 struct pt_regs *regs)
include/asm-powerpc/unistd.h
... ... @@ -444,11 +444,13 @@
444 444 #define __ARCH_WANT_SYS_SIGPENDING
445 445 #define __ARCH_WANT_SYS_SIGPROCMASK
446 446 #define __ARCH_WANT_SYS_RT_SIGACTION
  447 +#define __ARCH_WANT_SYS_RT_SIGSUSPEND
447 448 #ifdef CONFIG_PPC32
448 449 #define __ARCH_WANT_OLD_STAT
449 450 #endif
450 451 #ifdef CONFIG_PPC64
451 452 #define __ARCH_WANT_COMPAT_SYS_TIME
  453 +#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
452 454 #endif
453 455  
454 456 /*
include/linux/sched.h
... ... @@ -809,6 +809,7 @@
809 809 struct sighand_struct *sighand;
810 810  
811 811 sigset_t blocked, real_blocked;
  812 + sigset_t saved_sigmask; /* To be restored with TIF_RESTORE_SIGMASK */
812 813 struct sigpending pending;
813 814  
814 815 unsigned long sas_ss_sp;
... ... @@ -871,4 +871,32 @@
871 871 }
872 872  
873 873 #endif /* __ARCH_WANT_COMPAT_SYS_TIME */
  874 +
  875 +#ifdef __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
  876 +asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat_size_t sigsetsize)
  877 +{
  878 + sigset_t newset;
  879 + compat_sigset_t newset32;
  880 +
  881 + /* XXX: Don't preclude handling different sized sigset_t's. */
  882 + if (sigsetsize != sizeof(sigset_t))
  883 + return -EINVAL;
  884 +
  885 + if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t)))
  886 + return -EFAULT;
  887 + sigset_from_compat(&newset, &newset32);
  888 + sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
  889 +
  890 + spin_lock_irq(&current->sighand->siglock);
  891 + current->saved_sigmask = current->blocked;
  892 + current->blocked = newset;
  893 + recalc_sigpending();
  894 + spin_unlock_irq(&current->sighand->siglock);
  895 +
  896 + current->state = TASK_INTERRUPTIBLE;
  897 + schedule();
  898 + set_thread_flag(TIF_RESTORE_SIGMASK);
  899 + return -ERESTARTNOHAND;
  900 +}
  901 +#endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */
... ... @@ -2721,6 +2721,32 @@
2721 2721  
2722 2722 #endif
2723 2723  
  2724 +#ifdef __ARCH_WANT_SYS_RT_SIGSUSPEND
  2725 +asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
  2726 +{
  2727 + sigset_t newset;
  2728 +
  2729 + /* XXX: Don't preclude handling different sized sigset_t's. */
  2730 + if (sigsetsize != sizeof(sigset_t))
  2731 + return -EINVAL;
  2732 +
  2733 + if (copy_from_user(&newset, unewset, sizeof(newset)))
  2734 + return -EFAULT;
  2735 + sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
  2736 +
  2737 + spin_lock_irq(&current->sighand->siglock);
  2738 + current->saved_sigmask = current->blocked;
  2739 + current->blocked = newset;
  2740 + recalc_sigpending();
  2741 + spin_unlock_irq(&current->sighand->siglock);
  2742 +
  2743 + current->state = TASK_INTERRUPTIBLE;
  2744 + schedule();
  2745 + set_thread_flag(TIF_RESTORE_SIGMASK);
  2746 + return -ERESTARTNOHAND;
  2747 +}
  2748 +#endif /* __ARCH_WANT_SYS_RT_SIGSUSPEND */
  2749 +
2724 2750 void __init signals_init(void)
2725 2751 {
2726 2752 sigqueue_cachep =