mov r0, sp @ 'regs'
mov r2, why @ 'syscall'
bl do_work_pending
- tst r0, #1
- beq no_work_pending
- mov r0, sp @ pointer to regs
- ldmia r0, {r0 - r5} @ have to reload r0 - r5
- b local_restart @ ... and off we go
-
+ b no_work_pending
/*
* "slow" syscall return path. "why" tells us if this was a real syscall.
*/
eor scno, scno, #__NR_SYSCALL_BASE @ check OS number
#endif
-local_restart:
ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing
stmdb sp!, {r4, r5} @ push fifth and sixth args
* 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(struct pt_regs *regs, int syscall)
+static void do_signal(struct pt_regs *regs, int syscall)
{
unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
struct k_sigaction ka;
siginfo_t info;
int signr;
- int restart = 0;
/*
* If we were from a system call, check for system call restarting...
* debugger will see the already changed PSW.
*/
switch (retval) {
- case -ERESTART_RESTARTBLOCK:
- restart++;
case -ERESTARTNOHAND:
case -ERESTARTSYS:
case -ERESTARTNOINTR:
- restart++;
+ case -ERESTART_RESTARTBLOCK:
regs->ARM_r0 = regs->ARM_ORIG_r0;
regs->ARM_pc = restart_addr;
break;
* point the debugger may change all our registers ...
*/
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
- /*
- * Depending on the signal settings we may need to revert the
- * decision to restart the system call. But skip this if a
- * debugger has chosen to restart at a different PC.
- */
- if (regs->ARM_pc != restart_addr)
- restart = 0;
if (signr > 0) {
- if (unlikely(restart)) {
+ /*
+ * Depending on the signal settings we may need to revert the
+ * decision to restart the system call. But skip this if a
+ * debugger has chosen to restart at a different PC.
+ */
+ if (regs->ARM_pc == restart_addr) {
if (retval == -ERESTARTNOHAND ||
retval == -ERESTART_RESTARTBLOCK
|| (retval == -ERESTARTSYS
regs->ARM_r0 = -EINTR;
regs->ARM_pc = continue_addr;
}
+ clear_thread_flag(TIF_SYSCALL_RESTARTSYS);
}
handle_signal(signr, &ka, &info, regs);
- return 0;
+ return;
}
- if (unlikely(restart)) {
- if (restart > 1)
+ if (syscall) {
+ /*
+ * Handle restarting a different system call. As above,
+ * if a debugger has chosen to restart at a different PC,
+ * ignore the restart.
+ */
+ if (retval == -ERESTART_RESTARTBLOCK
+ && regs->ARM_pc == restart_addr)
set_thread_flag(TIF_SYSCALL_RESTARTSYS);
- regs->ARM_pc = continue_addr;
}
restore_saved_sigmask();
- return restart;
}
-asmlinkage int
+asmlinkage void
do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
{
do {
schedule();
} else {
if (unlikely(!user_mode(regs)))
- return 0;
+ return;
local_irq_enable();
if (thread_flags & _TIF_SIGPENDING) {
- if (unlikely(do_signal(regs, syscall))) {
- /*
- * Restart without handlers.
- * Deal with it without leaving
- * the kernel space.
- */
- return 1;
- }
+ do_signal(regs, syscall);
syscall = 0;
} else {
clear_thread_flag(TIF_NOTIFY_RESUME);
local_irq_disable();
thread_flags = current_thread_info()->flags;
} while (thread_flags & _TIF_WORK_MASK);
- return 0;
}