alpha: take SIGPENDING/NOTIFY_RESUME loop into signal.c
Al Viro [Wed, 5 Sep 2012 22:30:34 +0000 (18:30 -0400)]
Turn the slow side of work_pending into C function, including all
the looping.  What we get out of that:
* we do _not_ call get_signal_to_deliver() with IRQs disabled
anymore
* no need to save/restore volatiles on each pass if there
turns to be more than one (unlikely, but still)
* all double-restart prevention is in C now.
* glue gets simpler.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

arch/alpha/kernel/entry.S
arch/alpha/kernel/signal.c

index 802108b..0c30cce 100644 (file)
@@ -390,15 +390,9 @@ $work_notifysig:
        bsr     $1, do_switch_stack
        mov     $sp, $17
        mov     $5, $18
-       mov     $19, $9         /* save old syscall number */
-       mov     $20, $10        /* save old a3 */
-       and     $5, _TIF_SIGPENDING, $2
-       cmovne  $2, 0, $9       /* we don't want double syscall restarts */
-       jsr     $26, do_notify_resume
-       mov     $9, $19
-       mov     $10, $20
+       jsr     $26, do_work_pending
        bsr     $1, undo_switch_stack
-       br      ret_to_user
+       br      restore_all
 .end work_pending
 
 /*
index a8c97d4..235a867 100644 (file)
@@ -568,15 +568,24 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw,
 }
 
 void
-do_notify_resume(struct pt_regs *regs, struct switch_stack *sw,
-                unsigned long thread_info_flags,
+do_work_pending(struct pt_regs *regs, struct switch_stack *sw,
+                unsigned long thread_flags,
                 unsigned long r0, unsigned long r19)
 {
-       if (thread_info_flags & _TIF_SIGPENDING)
-               do_signal(regs, sw, r0, r19);
-
-       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
-               clear_thread_flag(TIF_NOTIFY_RESUME);
-               tracehook_notify_resume(regs);
-       }
+       do {
+               if (thread_flags & _TIF_NEED_RESCHED) {
+                       schedule();
+               } else {
+                       local_irq_enable();
+                       if (thread_flags & _TIF_SIGPENDING) {
+                               do_signal(regs, sw, r0, r19);
+                               r0 = 0;
+                       } else {
+                               clear_thread_flag(TIF_NOTIFY_RESUME);
+                               tracehook_notify_resume(regs);
+                       }
+               }
+               local_irq_disable();
+               thread_flags = current_thread_info()->flags;
+       } while (thread_flags & _TIF_WORK_MASK);
 }