diff options
Diffstat (limited to 'arch/arm/kernel/signal.c')
| -rw-r--r-- | arch/arm/kernel/signal.c | 86 | 
1 files changed, 37 insertions, 49 deletions
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 93bb4247b7ed..e27ee1f701d5 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c  | |||
| @@ -47,57 +47,22 @@ const unsigned long sigreturn_codes[7] = { | |||
| 47 | MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN, | 47 | MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN, | 
| 48 | }; | 48 | }; | 
| 49 | 49 | ||
| 50 | static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall); | ||
| 51 | |||
| 52 | /* | 50 | /* | 
| 53 | * atomically swap in the new signal mask, and wait for a signal. | 51 | * atomically swap in the new signal mask, and wait for a signal. | 
| 54 | */ | 52 | */ | 
| 55 | asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask, struct pt_regs *regs) | 53 | asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask) | 
| 56 | { | 54 | { | 
| 57 | sigset_t saveset; | ||
| 58 | |||
| 59 | mask &= _BLOCKABLE; | 55 | mask &= _BLOCKABLE; | 
| 60 | spin_lock_irq(¤t->sighand->siglock); | 56 | spin_lock_irq(¤t->sighand->siglock); | 
| 61 | saveset = current->blocked; | 57 | current->saved_sigmask = current->blocked; | 
| 62 | siginitset(¤t->blocked, mask); | 58 | siginitset(¤t->blocked, mask); | 
| 63 | recalc_sigpending(); | 59 | recalc_sigpending(); | 
| 64 | spin_unlock_irq(¤t->sighand->siglock); | 60 | spin_unlock_irq(¤t->sighand->siglock); | 
| 65 | regs->ARM_r0 = -EINTR; | ||
| 66 | |||
| 67 | while (1) { | ||
| 68 | current->state = TASK_INTERRUPTIBLE; | ||
| 69 | schedule(); | ||
| 70 | if (do_signal(&saveset, regs, 0)) | ||
| 71 | return regs->ARM_r0; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | asmlinkage int | ||
| 76 | sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs) | ||
| 77 | { | ||
| 78 | sigset_t saveset, newset; | ||
| 79 | |||
| 80 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
| 81 | if (sigsetsize != sizeof(sigset_t)) | ||
| 82 | return -EINVAL; | ||
| 83 | |||
| 84 | if (copy_from_user(&newset, unewset, sizeof(newset))) | ||
| 85 | return -EFAULT; | ||
| 86 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
| 87 | |||
| 88 | spin_lock_irq(¤t->sighand->siglock); | ||
| 89 | saveset = current->blocked; | ||
| 90 | current->blocked = newset; | ||
| 91 | recalc_sigpending(); | ||
| 92 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 93 | regs->ARM_r0 = -EINTR; | ||
| 94 | 61 | ||
| 95 | while (1) { | 62 | current->state = TASK_INTERRUPTIBLE; | 
| 96 | current->state = TASK_INTERRUPTIBLE; | 63 | schedule(); | 
| 97 | schedule(); | 64 | set_restore_sigmask(); | 
| 98 | if (do_signal(&saveset, regs, 0)) | 65 | return -ERESTARTNOHAND; | 
| 99 | return regs->ARM_r0; | ||
| 100 | } | ||
| 101 | } | 66 | } | 
| 102 | 67 | ||
| 103 | asmlinkage int | 68 | asmlinkage int | 
| @@ -545,7 +510,7 @@ static inline void setup_syscall_restart(struct pt_regs *regs) | |||
| 545 | /* | 510 | /* | 
| 546 | * OK, we're invoking a handler | 511 | * OK, we're invoking a handler | 
| 547 | */ | 512 | */ | 
| 548 | static void | 513 | static int | 
| 549 | handle_signal(unsigned long sig, struct k_sigaction *ka, | 514 | handle_signal(unsigned long sig, struct k_sigaction *ka, | 
| 550 | siginfo_t *info, sigset_t *oldset, | 515 | siginfo_t *info, sigset_t *oldset, | 
| 551 | struct pt_regs * regs, int syscall) | 516 | struct pt_regs * regs, int syscall) | 
| @@ -596,7 +561,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, | |||
| 596 | 561 | ||
| 597 | if (ret != 0) { | 562 | if (ret != 0) { | 
| 598 | force_sigsegv(sig, tsk); | 563 | force_sigsegv(sig, tsk); | 
| 599 | return; | 564 | return ret; | 
| 600 | } | 565 | } | 
| 601 | 566 | ||
| 602 | /* | 567 | /* | 
| @@ -610,6 +575,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, | |||
| 610 | recalc_sigpending(); | 575 | recalc_sigpending(); | 
| 611 | spin_unlock_irq(&tsk->sighand->siglock); | 576 | spin_unlock_irq(&tsk->sighand->siglock); | 
| 612 | 577 | ||
| 578 | return 0; | ||
| 613 | } | 579 | } | 
| 614 | 580 | ||
| 615 | /* | 581 | /* | 
| @@ -621,7 +587,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, | |||
| 621 | * the kernel can handle, and then we build all the user-level signal handling | 587 | * the kernel can handle, and then we build all the user-level signal handling | 
| 622 | * stack-frames in one go after that. | 588 | * stack-frames in one go after that. | 
| 623 | */ | 589 | */ | 
| 624 | static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) | 590 | static void do_signal(struct pt_regs *regs, int syscall) | 
| 625 | { | 591 | { | 
| 626 | struct k_sigaction ka; | 592 | struct k_sigaction ka; | 
| 627 | siginfo_t info; | 593 | siginfo_t info; | 
| @@ -634,7 +600,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) | |||
| 634 | * if so. | 600 | * if so. | 
| 635 | */ | 601 | */ | 
| 636 | if (!user_mode(regs)) | 602 | if (!user_mode(regs)) | 
| 637 | return 0; | 603 | return; | 
| 638 | 604 | ||
| 639 | if (try_to_freeze()) | 605 | if (try_to_freeze()) | 
| 640 | goto no_signal; | 606 | goto no_signal; | 
| @@ -643,9 +609,24 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) | |||
| 643 | 609 | ||
| 644 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 610 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 
| 645 | if (signr > 0) { | 611 | if (signr > 0) { | 
| 646 | handle_signal(signr, &ka, &info, oldset, regs, syscall); | 612 | sigset_t *oldset; | 
| 613 | |||
| 614 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
| 615 | oldset = ¤t->saved_sigmask; | ||
| 616 | else | ||
| 617 | oldset = ¤t->blocked; | ||
| 618 | if (handle_signal(signr, &ka, &info, oldset, regs, syscall) == 0) { | ||
| 619 | /* | ||
| 620 | * A signal was successfully delivered; the saved | ||
| 621 | * sigmask will have been stored in the signal frame, | ||
| 622 | * and will be restored by sigreturn, so we can simply | ||
| 623 | * clear the TIF_RESTORE_SIGMASK flag. | ||
| 624 | */ | ||
| 625 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
| 626 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 627 | } | ||
| 647 | single_step_set(current); | 628 | single_step_set(current); | 
| 648 | return 1; | 629 | return; | 
| 649 | } | 630 | } | 
| 650 | 631 | ||
| 651 | no_signal: | 632 | no_signal: | 
| @@ -697,14 +678,21 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) | |||
| 697 | regs->ARM_r0 == -ERESTARTNOINTR) { | 678 | regs->ARM_r0 == -ERESTARTNOINTR) { | 
| 698 | setup_syscall_restart(regs); | 679 | setup_syscall_restart(regs); | 
| 699 | } | 680 | } | 
| 681 | |||
| 682 | /* If there's no signal to deliver, we just put the saved sigmask | ||
| 683 | * back. | ||
| 684 | */ | ||
| 685 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
| 686 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 687 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
| 688 | } | ||
| 700 | } | 689 | } | 
| 701 | single_step_set(current); | 690 | single_step_set(current); | 
| 702 | return 0; | ||
| 703 | } | 691 | } | 
| 704 | 692 | ||
| 705 | asmlinkage void | 693 | asmlinkage void | 
| 706 | do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) | 694 | do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) | 
| 707 | { | 695 | { | 
| 708 | if (thread_flags & _TIF_SIGPENDING) | 696 | if (thread_flags & _TIF_SIGPENDING) | 
| 709 | do_signal(¤t->blocked, regs, syscall); | 697 | do_signal(regs, syscall); | 
| 710 | } | 698 | } | 
