Message ID | f17812d71002240249y7b851387mdc06d1d94010f895@mail.gmail.com |
---|---|
State | Not Applicable |
Delegated to: | Andy Whitcroft |
Headers | show |
On 10 Feb 24, Eric Miao wrote: > Bryan, could you please check if this is applicable to dove as well, or its > just backport for imx51? > Dove is already 2.6.32-based. The patch was integrated in 2.6.32. /Amit > > On Feb 24, 2010 6:05 PM, "Bryan Wu" <bryan.wu@canonical.com> wrote: > > From: Mikael Pettersson <mikpe@it.uu.se> > > This patch adds support for TIF_RESTORE_SIGMASK to ARM's > signal handling, which allows to hook up the pselect6, ppoll, > and epoll_pwait syscalls on ARM. > > Tested here with eabi userspace and a test program with a > deliberate race between a child's exit and the parent's > sigprocmask/select sequence. Using sys_pselect6() instead > of sigprocmask/select reliably prevents the race. > > The other arch's support for TIF_RESTORE_SIGMASK has evolved > over time: > > In 2.6.16: > - add TIF_RESTORE_SIGMASK which parallels TIF_SIGPENDING > - test both when checking for pending signal [changed later] > - reimplement sys_sigsuspend() to use current->saved_sigmask, > TIF_RESTORE_SIGMASK [changed later], and -ERESTARTNOHAND; > ditto for sys_rt_sigsuspend(), but drop private code and > use common code via __ARCH_WANT_SYS_RT_SIGSUSPEND; > - there are now no "extra" calls to do_signal() so its oldset > parameter is always ¤t->blocked so need not be passed, > also its return value is changed to void > - change handle_signal() to return 0/-errno > - change do_signal() to honor TIF_RESTORE_SIGMASK: > + get oldset from current->saved_sigmask if TIF_RESTORE_SIGMASK > is set > + if handle_signal() was successful then clear TIF_RESTORE_SIGMASK > + if no signal was delivered and TIF_RESTORE_SIGMASK is set then > clear it and restore the sigmask > - hook up sys_pselect6() and sys_ppoll() > > In 2.6.19: > - hook up sys_epoll_pwait() > > In 2.6.26: > - allow archs to override how TIF_RESTORE_SIGMASK is implemented; > default set_restore_sigmask() sets both TIF_RESTORE_SIGMASK and > TIF_SIGPENDING; archs need now just test TIF_SIGPENDING again > when checking for pending signal work; some archs now implement > TIF_RESTORE_SIGMASK as a secondary/non-atomic thread flag bit > - call set_restore_sigmask() in sys_sigsuspend() instead of setting > TIF_RESTORE_SIGMASK > > In 2.6.29-rc: > - kill sys_pselect7() which no arch wanted > > So for 2.6.31-rc6/ARM this patch does the following: > - Add TIF_RESTORE_SIGMASK. Use the generic set_restore_sigmask() > which sets both TIF_SIGPENDING and TIF_RESTORE_SIGMASK, so > TIF_RESTORE_SIGMASK need not claim one of the scarce low thread > flags, and existing TIF_SIGPENDING and _TIF_WORK_MASK tests need > not be extended for TIF_RESTORE_SIGMASK. > - sys_sigsuspend() is reimplemented to use current->saved_sigmask > and set_restore_sigmask(), making it identical to most other archs > - The private code for sys_rt_sigsuspend() is removed, instead > generic code supplies it via __ARCH_WANT_SYS_RT_SIGSUSPEND. > - sys_sigsuspend() and sys_rt_sigsuspend() no longer need a pt_regs > parameter, so their assembly code wrappers are removed. > - handle_signal() is changed to return 0 on success or -errno. > - The oldset parameter to do_signal() is now redundant and removed, > and the return value is now also redundant and changed to void. > - do_signal() is changed to honor TIF_RESTORE_SIGMASK: > + get oldset from current->saved_sigmask if TIF_RESTORE_SIGMASK > is set > + if handle_signal() was successful then clear TIF_RESTORE_SIGMASK > + if no signal was delivered and TIF_RESTORE_SIGMASK is set then > clear it and restore the sigmask > - Hook up sys_pselect6, sys_ppoll, and sys_epoll_pwait. > > BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/319729 > (cherry-picked from commit 369842658a36bcea28ecb643ba4bdb53919330dd) > > Signed-off-by: Mikael Pettersson <mikpe@it.uu.se> > Signed-off-by: Russell King > <rmk+kernel@arm.linux.org.uk<rmk%2Bkernel@arm.linux.org.uk> > > > Signed-off-by: Bryan Wu <bryan.wu@canonical.com> > --- > arch/arm/include/asm/thread_info.h | 2 + > arch/arm/include/asm/unistd.h | 7 ++- > arch/arm/kernel/calls.S | 10 ++-- > arch/arm/kernel/entry-common.S | 10 ---- > arch/arm/kernel/signal.c | 86 > +++++++++++++++-------------------- > 5 files changed, 48 insertions(+), 67 deletions(-) > > diff --git a/arch/arm/include/asm/thread_info.h > b/arch/arm/include/asm/thread_info.h > index 73394e5..e20d805 100644 > --- a/arch/arm/include/asm/thread_info.h > +++ b/arch/arm/include/asm/thread_info.h > @@ -140,6 +140,7 @@ extern void vfp_sync_state(struct thread_info *thread); > #define TIF_USING_IWMMXT 17 > #define TIF_MEMDIE 18 > #define TIF_FREEZE 19 > +#define TIF_RESTORE_SIGMASK 20 > > #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) > #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) > @@ -147,6 +148,7 @@ extern void vfp_sync_state(struct thread_info *thread); > #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) > #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) > #define _TIF_FREEZE (1 << TIF_FREEZE) > +#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) > > /* > * Change these and you break ASM code in entry-common.S > diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h > index 0e97b8c..9122c9e 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) > @@ -432,6 +432,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 6e1b8bf..9296c59 100644 > --- a/arch/arm/kernel/calls.S > +++ b/arch/arm/kernel/calls.S > @@ -81,7 +81,7 @@ > CALL(sys_ni_syscall) /* was sys_ssetmask */ > /* 70 */ CALL(sys_setreuid16) > CALL(sys_setregid16) > - CALL(sys_sigsuspend_wrapper) > + CALL(sys_sigsuspend) > CALL(sys_sigpending) > CALL(sys_sethostname) > /* 75 */ CALL(sys_setrlimit) > @@ -188,7 +188,7 @@ > CALL(sys_rt_sigpending) > CALL(sys_rt_sigtimedwait) > CALL(sys_rt_sigqueueinfo) > - CALL(sys_rt_sigsuspend_wrapper) > + CALL(sys_rt_sigsuspend) > /* 180 */ CALL(ABI(sys_pread64, sys_oabi_pread64)) > CALL(ABI(sys_pwrite64, sys_oabi_pwrite64)) > CALL(sys_chown16) > @@ -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/entry-common.S b/arch/arm/kernel/entry-common.S > index a762152..9565752 100644 > --- a/arch/arm/kernel/entry-common.S > +++ b/arch/arm/kernel/entry-common.S > @@ -373,16 +373,6 @@ sys_clone_wrapper: > b sys_clone > ENDPROC(sys_clone_wrapper) > > -sys_sigsuspend_wrapper: > - add r3, sp, #S_OFF > - b sys_sigsuspend > -ENDPROC(sys_sigsuspend_wrapper) > - > -sys_rt_sigsuspend_wrapper: > - add r2, sp, #S_OFF > - b sys_rt_sigsuspend > -ENDPROC(sys_rt_sigsuspend_wrapper) > - > sys_sigreturn_wrapper: > add r0, sp, #S_OFF > b sys_sigreturn > diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c > index 6dd5008..7dfd3b8 100644 > --- a/arch/arm/kernel/signal.c > +++ b/arch/arm/kernel/signal.c > @@ -48,57 +48,22 @@ 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); > - > /* > * 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_restore_sigmask(); > + return -ERESTARTNOHAND; > } > > asmlinkage int > @@ -628,7 +593,7 @@ static inline void setup_syscall_restart(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) > @@ -679,7 +644,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, > > if (ret != 0) { > force_sigsegv(sig, tsk); > - return; > + return ret; > } > > /* > @@ -693,6 +658,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, > recalc_sigpending(); > spin_unlock_irq(&tsk->sighand->siglock); > > + return 0; > } > > /* > @@ -704,7 +670,7 @@ 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; > @@ -717,7 +683,7 @@ 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; > @@ -726,9 +692,24 @@ static int do_signal(sigset_t *oldset, struct pt_regs > *regs, int syscall) > > signr = get_signal_to_deliver(&info, &ka, regs, NULL); > if (signr > 0) { > - handle_signal(signr, &ka, &info, oldset, regs, syscall); > + sigset_t *oldset; > + > + if (test_thread_flag(TIF_RESTORE_SIGMASK)) > + oldset = ¤t->saved_sigmask; > + else > + oldset = ¤t->blocked; > + 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. > + */ > + if (test_thread_flag(TIF_RESTORE_SIGMASK)) > + clear_thread_flag(TIF_RESTORE_SIGMASK); > + } > single_step_set(current); > - return 1; > + return; > } > > no_signal: > @@ -780,14 +761,21 @@ static int do_signal(sigset_t *oldset, struct pt_regs > *regs, int syscall) > regs->ARM_r0 == -ERESTARTNOINTR) { > setup_syscall_restart(regs); > } > + > + /* 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); > + } > } > single_step_set(current); > - return 0; > } > > 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); > + do_signal(regs, syscall); > } > -- > 1.6.3.3 > > > -- > kernel-team mailing list > kernel-team@lists.ubuntu.com > https://lists.ubuntu.com/mailman/listinfo/kernel-team > -- > kernel-team mailing list > kernel-team@lists.ubuntu.com > https://lists.ubuntu.com/mailman/listinfo/kernel-team
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 73394e5..e20d805 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -140,6 +140,7 @@ extern void vfp_sync_state(struct thread_info *thread); #define TIF_USING_IWMMXT 17 #define TIF_MEMDIE 18 #define TIF_FREEZE 19 +#define TIF_RESTORE_SIGMASK 20 #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) @@ -147,6 +148,7 @@ extern void vfp_sync_state(struct thread_info *thread); #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) #define _TIF_FREEZE (1 << TIF_FREEZE) +#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) /* * Change these and you break ASM code in entry-common.S diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index 0e97b8c..9122c9e 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) @@ -432,6 +432,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 6e1b8bf..9296c59 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -81,7 +81,7 @@ CALL(sys_ni_syscall) /* was sys_ssetmask */ /* 70 */ CALL(sys_setreuid16) CALL(sys_setregid16) - CALL(sys_sigsuspend_wrapper) + CALL(sys_sigsuspend) CALL(sys_sigpending) CALL(sys_sethostname) /* 75 */ CALL(sys_setrlimit) @@ -188,7 +188,7 @@ CALL(sys_rt_sigpending) CALL(sys_rt_sigtimedwait) CALL(sys_rt_sigqueueinfo) - CALL(sys_rt_sigsuspend_wrapper) + CALL(sys_rt_sigsuspend) /* 180 */ CALL(ABI(sys_pread64, sys_oabi_pread64)) CALL(ABI(sys_pwrite64, sys_oabi_pwrite64)) CALL(sys_chown16) @@ -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/entry-common.S b/arch/arm/kernel/entry-common.S index a762152..9565752 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -373,16 +373,6 @@ sys_clone_wrapper: b sys_clone ENDPROC(sys_clone_wrapper) -sys_sigsuspend_wrapper: - add r3, sp, #S_OFF - b sys_sigsuspend -ENDPROC(sys_sigsuspend_wrapper) - -sys_rt_sigsuspend_wrapper: - add r2, sp, #S_OFF - b sys_rt_sigsuspend -ENDPROC(sys_rt_sigsuspend_wrapper) - sys_sigreturn_wrapper: add r0, sp, #S_OFF b sys_sigreturn diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 6dd5008..7dfd3b8 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -48,57 +48,22 @@ 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); - /* * 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_restore_sigmask(); + return -ERESTARTNOHAND;