From: David Woodhouse 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 Signed-off-by: Andrew Morton --- arch/powerpc/kernel/signal_32.c | 56 ++---------------------------- arch/powerpc/kernel/signal_64.c | 36 ------------------- include/asm-powerpc/unistd.h | 2 + include/linux/sched.h | 1 kernel/compat.c | 28 +++++++++++++++ kernel/signal.c | 26 +++++++++++++ 6 files changed, 62 insertions(+), 87 deletions(-) diff -puN arch/powerpc/kernel/signal_32.c~generic-sys_rt_sigsuspend arch/powerpc/kernel/signal_32.c --- 25/arch/powerpc/kernel/signal_32.c~generic-sys_rt_sigsuspend Fri Jan 13 17:54:39 2006 +++ 25-akpm/arch/powerpc/kernel/signal_32.c Fri Jan 13 17:54:39 2006 @@ -252,8 +252,7 @@ int do_signal(sigset_t *oldset, struct p /* * Atomically swap in the new signal mask, and wait for a signal. */ -long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7, - struct pt_regs *regs) +long sys_sigsuspend(old_sigset_t mask) { sigset_t saveset; @@ -264,55 +263,10 @@ long sys_sigsuspend(old_sigset_t mask, i recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - regs->result = -EINTR; - regs->gpr[3] = EINTR; - regs->ccr |= 0x10000000; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(&saveset, regs)) { - set_thread_flag(TIF_RESTOREALL); - return 0; - } - } -} - -long sys_rt_sigsuspend( -#ifdef CONFIG_PPC64 - compat_sigset_t __user *unewset, -#else - sigset_t __user *unewset, -#endif - size_t sigsetsize, int p3, int p4, - int p6, int p7, struct pt_regs *regs) -{ - sigset_t saveset, newset; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - if (get_sigset_t(&newset, unewset)) - return -EFAULT; - sigdelsetmask(&newset, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - current->blocked = newset; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - regs->result = -EINTR; - regs->gpr[3] = EINTR; - regs->ccr |= 0x10000000; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(&saveset, regs)) { - set_thread_flag(TIF_RESTOREALL); - return 0; - } - } + current->state = TASK_INTERRUPTIBLE; + schedule(); + set_thread_flag(TIF_RESTORE_SIGMASK); + return -ERESTARTNOHAND; } #ifdef CONFIG_PPC32 diff -puN arch/powerpc/kernel/signal_64.c~generic-sys_rt_sigsuspend arch/powerpc/kernel/signal_64.c --- 25/arch/powerpc/kernel/signal_64.c~generic-sys_rt_sigsuspend Fri Jan 13 17:54:39 2006 +++ 25-akpm/arch/powerpc/kernel/signal_64.c Fri Jan 13 17:54:39 2006 @@ -67,42 +67,6 @@ struct rt_sigframe { char abigap[288]; } __attribute__ ((aligned (16))); - -/* - * Atomically swap in the new signal mask, and wait for a signal. - */ -long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, int p3, int p4, - int p6, int p7, struct pt_regs *regs) -{ - sigset_t saveset, newset; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&newset, unewset, sizeof(newset))) - return -EFAULT; - sigdelsetmask(&newset, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - current->blocked = newset; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - regs->result = -EINTR; - regs->gpr[3] = EINTR; - regs->ccr |= 0x10000000; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(&saveset, regs)) { - set_thread_flag(TIF_RESTOREALL); - return 0; - } - } -} - long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, unsigned long r5, unsigned long r6, unsigned long r7, unsigned long r8, struct pt_regs *regs) diff -puN include/asm-powerpc/unistd.h~generic-sys_rt_sigsuspend include/asm-powerpc/unistd.h --- 25/include/asm-powerpc/unistd.h~generic-sys_rt_sigsuspend Fri Jan 13 17:54:39 2006 +++ 25-akpm/include/asm-powerpc/unistd.h Fri Jan 13 17:54:39 2006 @@ -444,11 +444,13 @@ type name(type1 arg1, type2 arg2, type3 #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION +#define __ARCH_WANT_SYS_RT_SIGSUSPEND #ifdef CONFIG_PPC32 #define __ARCH_WANT_OLD_STAT #endif #ifdef CONFIG_PPC64 #define __ARCH_WANT_COMPAT_SYS_TIME +#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND #endif /* diff -puN include/linux/sched.h~generic-sys_rt_sigsuspend include/linux/sched.h --- 25/include/linux/sched.h~generic-sys_rt_sigsuspend Fri Jan 13 17:54:39 2006 +++ 25-akpm/include/linux/sched.h Fri Jan 13 17:54:39 2006 @@ -822,6 +822,7 @@ struct task_struct { struct sighand_struct *sighand; sigset_t blocked, real_blocked; + sigset_t saved_sigmask; /* To be restored with TIF_RESTORE_SIGMASK */ struct sigpending pending; unsigned long sas_ss_sp; diff -puN kernel/compat.c~generic-sys_rt_sigsuspend kernel/compat.c --- 25/kernel/compat.c~generic-sys_rt_sigsuspend Fri Jan 13 17:54:39 2006 +++ 25-akpm/kernel/compat.c Fri Jan 13 17:54:39 2006 @@ -871,3 +871,31 @@ asmlinkage long compat_sys_stime(compat_ } #endif /* __ARCH_WANT_COMPAT_SYS_TIME */ + +#ifdef __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND +long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat_size_t sigsetsize) +{ + sigset_t newset; + compat_sigset_t newset32; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t))) + return -EFAULT; + sigset_from_compat(&newset, &newset32); + sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP)); + + spin_lock_irq(¤t->sighand->siglock); + current->saved_sigmask = current->blocked; + current->blocked = newset; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + current->state = TASK_INTERRUPTIBLE; + schedule(); + set_thread_flag(TIF_RESTORE_SIGMASK); + return -ERESTARTNOHAND; +} +#endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */ diff -puN kernel/signal.c~generic-sys_rt_sigsuspend kernel/signal.c --- 25/kernel/signal.c~generic-sys_rt_sigsuspend Fri Jan 13 17:54:39 2006 +++ 25-akpm/kernel/signal.c Fri Jan 13 17:54:39 2006 @@ -2721,6 +2721,32 @@ sys_pause(void) #endif +#ifdef __ARCH_WANT_SYS_RT_SIGSUSPEND +long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) +{ + sigset_t newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP)); + + spin_lock_irq(¤t->sighand->siglock); + current->saved_sigmask = current->blocked; + current->blocked = newset; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + current->state = TASK_INTERRUPTIBLE; + schedule(); + set_thread_flag(TIF_RESTORE_SIGMASK); + return -ERESTARTNOHAND; +} +#endif /* __ARCH_WANT_SYS_RT_SIGSUSPEND */ + void __init signals_init(void) { sigqueue_cachep = _