Commit 150256d8 authored by David Woodhouse's avatar David Woodhouse Committed by Linus Torvalds

[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: default avatarDavid Woodhouse <dwmw2@infradead.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent a60fc519
...@@ -252,8 +252,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs); ...@@ -252,8 +252,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs);
/* /*
* Atomically swap in the new signal mask, and wait for a signal. * 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, long sys_sigsuspend(old_sigset_t mask)
struct pt_regs *regs)
{ {
sigset_t saveset; sigset_t saveset;
...@@ -264,55 +263,10 @@ long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7, ...@@ -264,55 +263,10 @@ long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
regs->result = -EINTR; current->state = TASK_INTERRUPTIBLE;
regs->gpr[3] = EINTR; schedule();
regs->ccr |= 0x10000000; set_thread_flag(TIF_RESTORE_SIGMASK);
while (1) { return -ERESTARTNOHAND;
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(&current->sighand->siglock);
saveset = current->blocked;
current->blocked = newset;
recalc_sigpending();
spin_unlock_irq(&current->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;
}
}
} }
#ifdef CONFIG_PPC32 #ifdef CONFIG_PPC32
......
...@@ -67,42 +67,6 @@ struct rt_sigframe { ...@@ -67,42 +67,6 @@ struct rt_sigframe {
char abigap[288]; char abigap[288];
} __attribute__ ((aligned (16))); } __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(&current->sighand->siglock);
saveset = current->blocked;
current->blocked = newset;
recalc_sigpending();
spin_unlock_irq(&current->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, long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, unsigned long r5,
unsigned long r6, unsigned long r7, unsigned long r8, unsigned long r6, unsigned long r7, unsigned long r8,
struct pt_regs *regs) struct pt_regs *regs)
......
...@@ -444,11 +444,13 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6 ...@@ -444,11 +444,13 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6
#define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION #define __ARCH_WANT_SYS_RT_SIGACTION
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#ifdef CONFIG_PPC32 #ifdef CONFIG_PPC32
#define __ARCH_WANT_OLD_STAT #define __ARCH_WANT_OLD_STAT
#endif #endif
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
#define __ARCH_WANT_COMPAT_SYS_TIME #define __ARCH_WANT_COMPAT_SYS_TIME
#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
#endif #endif
/* /*
......
...@@ -809,6 +809,7 @@ struct task_struct { ...@@ -809,6 +809,7 @@ struct task_struct {
struct sighand_struct *sighand; struct sighand_struct *sighand;
sigset_t blocked, real_blocked; sigset_t blocked, real_blocked;
sigset_t saved_sigmask; /* To be restored with TIF_RESTORE_SIGMASK */
struct sigpending pending; struct sigpending pending;
unsigned long sas_ss_sp; unsigned long sas_ss_sp;
......
...@@ -871,3 +871,31 @@ asmlinkage long compat_sys_stime(compat_time_t __user *tptr) ...@@ -871,3 +871,31 @@ asmlinkage long compat_sys_stime(compat_time_t __user *tptr)
} }
#endif /* __ARCH_WANT_COMPAT_SYS_TIME */ #endif /* __ARCH_WANT_COMPAT_SYS_TIME */
#ifdef __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
asmlinkage 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(&current->sighand->siglock);
current->saved_sigmask = current->blocked;
current->blocked = newset;
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
current->state = TASK_INTERRUPTIBLE;
schedule();
set_thread_flag(TIF_RESTORE_SIGMASK);
return -ERESTARTNOHAND;
}
#endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */
...@@ -2721,6 +2721,32 @@ sys_pause(void) ...@@ -2721,6 +2721,32 @@ sys_pause(void)
#endif #endif
#ifdef __ARCH_WANT_SYS_RT_SIGSUSPEND
asmlinkage 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(&current->sighand->siglock);
current->saved_sigmask = current->blocked;
current->blocked = newset;
recalc_sigpending();
spin_unlock_irq(&current->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) void __init signals_init(void)
{ {
sigqueue_cachep = sigqueue_cachep =
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment