Skip to content

Commit

Permalink
[PATCH] Generic sys_rt_sigsuspend()
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
dwmw2 authored and Linus Torvalds committed Jan 19, 2006
1 parent a60fc51 commit 150256d
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 87 deletions.
56 changes: 5 additions & 51 deletions arch/powerpc/kernel/signal_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
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;

Expand All @@ -264,55 +263,10 @@ long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
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_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;
}
}
current->state = TASK_INTERRUPTIBLE;
schedule();
set_thread_flag(TIF_RESTORE_SIGMASK);
return -ERESTARTNOHAND;
}

#ifdef CONFIG_PPC32
Expand Down
36 changes: 0 additions & 36 deletions arch/powerpc/kernel/signal_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -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(&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,
unsigned long r6, unsigned long r7, unsigned long r8,
struct pt_regs *regs)
Expand Down
2 changes: 2 additions & 0 deletions include/asm-powerpc/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_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

/*
Expand Down
1 change: 1 addition & 0 deletions include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,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;
Expand Down
28 changes: 28 additions & 0 deletions kernel/compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -871,3 +871,31 @@ asmlinkage long compat_sys_stime(compat_time_t __user *tptr)
}

#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 */
26 changes: 26 additions & 0 deletions kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -2721,6 +2721,32 @@ sys_pause(void)

#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)
{
sigqueue_cachep =
Expand Down

0 comments on commit 150256d

Please sign in to comment.