From 8a7643b09856f4f661403dcedbe0455b3cbeeea9 Mon Sep 17 00:00:00 2001 From: Steven Newbury Date: Fri, 22 May 2009 14:25:40 +0200 Subject: [PATCH] implement TIF_RESTORE_SIGMASK support and enable the related syscalls: pselect6 ppoll epoll_pwait Based on http://www.spinics.net/lists/arm-kernel/msg38114.html --- arch/arm/include/asm/thread_info.h | 2 + arch/arm/include/asm/unistd.h | 7 ++- arch/arm/kernel/calls.S | 6 +- arch/arm/kernel/signal.c | 90 +++++++++++++++--------------------- 4 files changed, 46 insertions(+), 59 deletions(-) diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 4f88482..2cf0917 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -136,6 +136,7 @@ extern void vfp_sync_state(struct thread_info *thread); #define TIF_SIGPENDING 0 #define TIF_NEED_RESCHED 1 #define TIF_SYSCALL_TRACE 8 +#define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal */ #define TIF_POLLING_NRFLAG 16 #define TIF_USING_IWMMXT 17 #define TIF_MEMDIE 18 @@ -144,6 +145,7 @@ extern void vfp_sync_state(struct thread_info *thread); #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) +#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) #define _TIF_FREEZE (1 << TIF_FREEZE) diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index 94cc58e..cd1eaa0 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h @@ -360,8 +360,8 @@ #define __NR_readlinkat (__NR_SYSCALL_BASE+332) #define __NR_fchmodat (__NR_SYSCALL_BASE+333) #define __NR_faccessat (__NR_SYSCALL_BASE+334) - /* 335 for pselect6 */ - /* 336 for ppoll */ +#define __NR_pselect6 (__NR_SYSCALL_BASE+335) +#define __NR_ppoll (__NR_SYSCALL_BASE+336) #define __NR_unshare (__NR_SYSCALL_BASE+337) #define __NR_set_robust_list (__NR_SYSCALL_BASE+338) #define __NR_get_robust_list (__NR_SYSCALL_BASE+339) @@ -372,7 +372,7 @@ #define __NR_vmsplice (__NR_SYSCALL_BASE+343) #define __NR_move_pages (__NR_SYSCALL_BASE+344) #define __NR_getcpu (__NR_SYSCALL_BASE+345) - /* 346 for epoll_pwait */ +#define __NR_epoll_pwait (__NR_SYSCALL_BASE+346) #define __NR_kexec_load (__NR_SYSCALL_BASE+347) #define __NR_utimensat (__NR_SYSCALL_BASE+348) #define __NR_signalfd (__NR_SYSCALL_BASE+349) @@ -430,6 +430,7 @@ #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION +#define __ARCH_WANT_SYS_RT_SIGSUSPEND #if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT) #define __ARCH_WANT_SYS_TIME diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index 1680e9e..534000d 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -344,8 +344,8 @@ CALL(sys_readlinkat) CALL(sys_fchmodat) CALL(sys_faccessat) -/* 335 */ CALL(sys_ni_syscall) /* eventually pselect6 */ - CALL(sys_ni_syscall) /* eventually ppoll */ +/* 335 */ CALL(sys_pselect6) + CALL(sys_ppoll) CALL(sys_unshare) CALL(sys_set_robust_list) CALL(sys_get_robust_list) @@ -355,7 +355,7 @@ CALL(sys_vmsplice) CALL(sys_move_pages) /* 345 */ CALL(sys_getcpu) - CALL(sys_ni_syscall) /* eventually epoll_pwait */ + CALL(sys_epoll_pwait) CALL(sys_kexec_load) CALL(sys_utimensat) CALL(sys_signalfd) diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 80b8b5c..7645048 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -47,57 +47,23 @@ const unsigned long sigreturn_codes[7] = { MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN, }; -static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall); +static void do_signal(struct pt_regs * regs, int syscall); /* * atomically swap in the new signal mask, and wait for a signal. */ -asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask, struct pt_regs *regs) +asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask) { - sigset_t saveset; - mask &= _BLOCKABLE; spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; + current->saved_sigmask = current->blocked; siginitset(¤t->blocked, mask); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - regs->ARM_r0 = -EINTR; - - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(&saveset, regs, 0)) - return regs->ARM_r0; - } -} - -asmlinkage int -sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, 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->ARM_r0 = -EINTR; - - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(&saveset, regs, 0)) - return regs->ARM_r0; - } + current->state = TASK_INTERRUPTIBLE; + schedule(); + set_thread_flag(TIF_RESTORE_SIGMASK); + return -ERESTARTNOHAND; } asmlinkage int @@ -290,7 +256,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) badframe: force_sig(SIGSEGV, current); - return 0; + return -EFAULT; } asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) @@ -325,7 +291,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) badframe: force_sig(SIGSEGV, current); - return 0; + return -EFAULT; } static int @@ -541,7 +507,7 @@ static inline void restart_syscall(struct pt_regs *regs) /* * OK, we're invoking a handler */ -static void +static int handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs * regs, int syscall) @@ -592,7 +558,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, if (ret != 0) { force_sigsegv(sig, tsk); - return; + return ret; } /* @@ -606,6 +572,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, recalc_sigpending(); spin_unlock_irq(&tsk->sighand->siglock); + return ret; } /* @@ -617,11 +584,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ -static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) +static void do_signal(struct pt_regs *regs, int syscall) { struct k_sigaction ka; siginfo_t info; int signr; + sigset_t *oldset; /* * We want the common case to go fast, which @@ -630,18 +598,29 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) * if so. */ if (!user_mode(regs)) - return 0; + return; if (try_to_freeze()) goto no_signal; single_step_clear(current); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { - handle_signal(signr, &ka, &info, oldset, regs, syscall); + if (handle_signal(signr, &ka, &info, oldset, regs, syscall) == 0) { + /* a signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag */ + clear_thread_flag(TIF_RESTORE_SIGMASK); + } single_step_set(current); - return 1; + return; } no_signal: @@ -665,7 +644,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) usp = (u32 __user *)regs->ARM_sp; /* - * Either we supports OABI only, or we have + * Either we support OABI only, or we have * EABI with the OABI compat layer enabled. * In the later case we don't know if user * space is EABI or not, and if not we must @@ -695,12 +674,17 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) } } single_step_set(current); - return 0; + /* if there's no signal to deliver, we just put the saved sigmask + back. */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } } asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) { - if (thread_flags & _TIF_SIGPENDING) - do_signal(¤t->blocked, regs, syscall); + if (thread_flags & (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK)) + do_signal(regs, syscall); } -- 1.6.2.4