diff options
| -rw-r--r-- | arch/i386/kernel/signal.c | 109 | ||||
| -rw-r--r-- | include/asm-i386/signal.h | 1 | ||||
| -rw-r--r-- | include/asm-i386/thread_info.h | 2 | ||||
| -rw-r--r-- | include/asm-i386/unistd.h | 1 | 
4 files changed, 51 insertions, 62 deletions
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index adcd069db91e..963616d364ec 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c  | |||
| @@ -37,51 +37,17 @@ | |||
| 37 | asmlinkage int | 37 | asmlinkage int | 
| 38 | sys_sigsuspend(int history0, int history1, old_sigset_t mask) | 38 | sys_sigsuspend(int history0, int history1, old_sigset_t mask) | 
| 39 | { | 39 | { | 
| 40 | struct pt_regs * regs = (struct pt_regs *) &history0; | ||
| 41 | sigset_t saveset; | ||
| 42 | |||
| 43 | mask &= _BLOCKABLE; | 40 | mask &= _BLOCKABLE; | 
| 44 | spin_lock_irq(¤t->sighand->siglock); | 41 | spin_lock_irq(¤t->sighand->siglock); | 
| 45 | saveset = current->blocked; | 42 | current->saved_sigmask = current->blocked; | 
| 46 | siginitset(¤t->blocked, mask); | 43 | siginitset(¤t->blocked, mask); | 
| 47 | recalc_sigpending(); | 44 | recalc_sigpending(); | 
| 48 | spin_unlock_irq(¤t->sighand->siglock); | 45 | spin_unlock_irq(¤t->sighand->siglock); | 
| 49 | 46 | ||
| 50 | regs->eax = -EINTR; | 47 | current->state = TASK_INTERRUPTIBLE; | 
| 51 | while (1) { | 48 | schedule(); | 
| 52 | current->state = TASK_INTERRUPTIBLE; | 49 | set_thread_flag(TIF_RESTORE_SIGMASK); | 
| 53 | schedule(); | 50 | return -ERESTARTNOHAND; | 
| 54 | if (do_signal(regs, &saveset)) | ||
| 55 | return -EINTR; | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | asmlinkage int | ||
| 60 | sys_rt_sigsuspend(struct pt_regs regs) | ||
| 61 | { | ||
| 62 | sigset_t saveset, newset; | ||
| 63 | |||
| 64 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
| 65 | if (regs.ecx != sizeof(sigset_t)) | ||
| 66 | return -EINVAL; | ||
| 67 | |||
| 68 | if (copy_from_user(&newset, (sigset_t __user *)regs.ebx, sizeof(newset))) | ||
| 69 | return -EFAULT; | ||
| 70 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
| 71 | |||
| 72 | spin_lock_irq(¤t->sighand->siglock); | ||
| 73 | saveset = current->blocked; | ||
| 74 | current->blocked = newset; | ||
| 75 | recalc_sigpending(); | ||
| 76 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 77 | |||
| 78 | regs.eax = -EINTR; | ||
| 79 | while (1) { | ||
| 80 | current->state = TASK_INTERRUPTIBLE; | ||
| 81 | schedule(); | ||
| 82 | if (do_signal(®s, &saveset)) | ||
| 83 | return -EINTR; | ||
| 84 | } | ||
| 85 | } | 51 | } | 
| 86 | 52 | ||
| 87 | asmlinkage int | 53 | asmlinkage int | 
| @@ -433,11 +399,11 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
| 433 | current->comm, current->pid, frame, regs->eip, frame->pretcode); | 399 | current->comm, current->pid, frame, regs->eip, frame->pretcode); | 
| 434 | #endif | 400 | #endif | 
| 435 | 401 | ||
| 436 | return 1; | 402 | return 0; | 
| 437 | 403 | ||
| 438 | give_sigsegv: | 404 | give_sigsegv: | 
| 439 | force_sigsegv(sig, current); | 405 | force_sigsegv(sig, current); | 
| 440 | return 0; | 406 | return -EFAULT; | 
| 441 | } | 407 | } | 
| 442 | 408 | ||
| 443 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 409 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 
| @@ -527,11 +493,11 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 527 | current->comm, current->pid, frame, regs->eip, frame->pretcode); | 493 | current->comm, current->pid, frame, regs->eip, frame->pretcode); | 
| 528 | #endif | 494 | #endif | 
| 529 | 495 | ||
| 530 | return 1; | 496 | return 0; | 
| 531 | 497 | ||
| 532 | give_sigsegv: | 498 | give_sigsegv: | 
| 533 | force_sigsegv(sig, current); | 499 | force_sigsegv(sig, current); | 
| 534 | return 0; | 500 | return -EFAULT; | 
| 535 | } | 501 | } | 
| 536 | 502 | ||
| 537 | /* | 503 | /* | 
| @@ -581,7 +547,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
| 581 | else | 547 | else | 
| 582 | ret = setup_frame(sig, ka, oldset, regs); | 548 | ret = setup_frame(sig, ka, oldset, regs); | 
| 583 | 549 | ||
| 584 | if (ret) { | 550 | if (ret == 0) { | 
| 585 | spin_lock_irq(¤t->sighand->siglock); | 551 | spin_lock_irq(¤t->sighand->siglock); | 
| 586 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 552 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 
| 587 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 553 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 
| @@ -598,11 +564,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
| 598 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 564 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 
| 599 | * mistake. | 565 | * mistake. | 
| 600 | */ | 566 | */ | 
| 601 | int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset) | 567 | static void fastcall do_signal(struct pt_regs *regs) | 
| 602 | { | 568 | { | 
| 603 | siginfo_t info; | 569 | siginfo_t info; | 
| 604 | int signr; | 570 | int signr; | 
| 605 | struct k_sigaction ka; | 571 | struct k_sigaction ka; | 
| 572 | sigset_t *oldset; | ||
| 606 | 573 | ||
| 607 | /* | 574 | /* | 
| 608 | * We want the common case to go fast, which | 575 | * We want the common case to go fast, which | 
| @@ -613,12 +580,14 @@ int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
| 613 | * CS suffices. | 580 | * CS suffices. | 
| 614 | */ | 581 | */ | 
| 615 | if (!user_mode(regs)) | 582 | if (!user_mode(regs)) | 
| 616 | return 1; | 583 | return; | 
| 617 | 584 | ||
| 618 | if (try_to_freeze()) | 585 | if (try_to_freeze()) | 
| 619 | goto no_signal; | 586 | goto no_signal; | 
| 620 | 587 | ||
| 621 | if (!oldset) | 588 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 
| 589 | oldset = ¤t->saved_sigmask; | ||
| 590 | else | ||
| 622 | oldset = ¤t->blocked; | 591 | oldset = ¤t->blocked; | 
| 623 | 592 | ||
| 624 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 593 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 
| @@ -628,38 +597,55 @@ int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
| 628 | * have been cleared if the watchpoint triggered | 597 | * have been cleared if the watchpoint triggered | 
| 629 | * inside the kernel. | 598 | * inside the kernel. | 
| 630 | */ | 599 | */ | 
| 631 | if (unlikely(current->thread.debugreg[7])) { | 600 | if (unlikely(current->thread.debugreg[7])) | 
| 632 | set_debugreg(current->thread.debugreg[7], 7); | 601 | set_debugreg(current->thread.debugreg[7], 7); | 
| 633 | } | ||
| 634 | 602 | ||
| 635 | /* Whee! Actually deliver the signal. */ | 603 | /* Whee! Actually deliver the signal. */ | 
| 636 | return handle_signal(signr, &info, &ka, oldset, regs); | 604 | if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { | 
| 605 | /* a signal was successfully delivered; the saved | ||
| 606 | * sigmask will have been stored in the signal frame, | ||
| 607 | * and will be restored by sigreturn, so we can simply | ||
| 608 | * clear the TIF_RESTORE_SIGMASK flag */ | ||
| 609 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
| 610 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 611 | } | ||
| 612 | |||
| 613 | return; | ||
| 637 | } | 614 | } | 
| 638 | 615 | ||
| 639 | no_signal: | 616 | no_signal: | 
| 640 | /* Did we come from a system call? */ | 617 | /* Did we come from a system call? */ | 
| 641 | if (regs->orig_eax >= 0) { | 618 | if (regs->orig_eax >= 0) { | 
| 642 | /* Restart the system call - no handlers present */ | 619 | /* Restart the system call - no handlers present */ | 
| 643 | if (regs->eax == -ERESTARTNOHAND || | 620 | switch (regs->eax) { | 
| 644 | regs->eax == -ERESTARTSYS || | 621 | case -ERESTARTNOHAND: | 
| 645 | regs->eax == -ERESTARTNOINTR) { | 622 | case -ERESTARTSYS: | 
| 623 | case -ERESTARTNOINTR: | ||
| 646 | regs->eax = regs->orig_eax; | 624 | regs->eax = regs->orig_eax; | 
| 647 | regs->eip -= 2; | 625 | regs->eip -= 2; | 
| 648 | } | 626 | break; | 
| 649 | if (regs->eax == -ERESTART_RESTARTBLOCK){ | 627 | |
| 628 | case -ERESTART_RESTARTBLOCK: | ||
| 650 | regs->eax = __NR_restart_syscall; | 629 | regs->eax = __NR_restart_syscall; | 
| 651 | regs->eip -= 2; | 630 | regs->eip -= 2; | 
| 631 | break; | ||
| 652 | } | 632 | } | 
| 653 | } | 633 | } | 
| 654 | return 0; | 634 | |
| 635 | /* if there's no signal to deliver, we just put the saved sigmask | ||
| 636 | * back */ | ||
| 637 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
| 638 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 639 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
| 640 | } | ||
| 655 | } | 641 | } | 
| 656 | 642 | ||
| 657 | /* | 643 | /* | 
| 658 | * notification of userspace execution resumption | 644 | * notification of userspace execution resumption | 
| 659 | * - triggered by current->work.notify_resume | 645 | * - triggered by the TIF_WORK_MASK flags | 
| 660 | */ | 646 | */ | 
| 661 | __attribute__((regparm(3))) | 647 | __attribute__((regparm(3))) | 
| 662 | void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, | 648 | void do_notify_resume(struct pt_regs *regs, void *_unused, | 
| 663 | __u32 thread_info_flags) | 649 | __u32 thread_info_flags) | 
| 664 | { | 650 | { | 
| 665 | /* Pending single-step? */ | 651 | /* Pending single-step? */ | 
| @@ -667,9 +653,10 @@ void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, | |||
| 667 | regs->eflags |= TF_MASK; | 653 | regs->eflags |= TF_MASK; | 
| 668 | clear_thread_flag(TIF_SINGLESTEP); | 654 | clear_thread_flag(TIF_SINGLESTEP); | 
| 669 | } | 655 | } | 
| 656 | |||
| 670 | /* deal with pending signal delivery */ | 657 | /* deal with pending signal delivery */ | 
| 671 | if (thread_info_flags & _TIF_SIGPENDING) | 658 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) | 
| 672 | do_signal(regs,oldset); | 659 | do_signal(regs); | 
| 673 | 660 | ||
| 674 | clear_thread_flag(TIF_IRET); | 661 | clear_thread_flag(TIF_IRET); | 
| 675 | } | 662 | } | 
diff --git a/include/asm-i386/signal.h b/include/asm-i386/signal.h index 76524b4052ac..026fd231488d 100644 --- a/include/asm-i386/signal.h +++ b/include/asm-i386/signal.h  | |||
| @@ -218,7 +218,6 @@ static __inline__ int sigfindinword(unsigned long word) | |||
| 218 | } | 218 | } | 
| 219 | 219 | ||
| 220 | struct pt_regs; | 220 | struct pt_regs; | 
| 221 | extern int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset)); | ||
| 222 | 221 | ||
| 223 | #define ptrace_signal_deliver(regs, cookie) \ | 222 | #define ptrace_signal_deliver(regs, cookie) \ | 
| 224 | do { \ | 223 | do { \ | 
diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h index 2493e77e8c30..e20e99551d71 100644 --- a/include/asm-i386/thread_info.h +++ b/include/asm-i386/thread_info.h  | |||
| @@ -140,6 +140,7 @@ register unsigned long current_stack_pointer asm("esp") __attribute_used__; | |||
| 140 | #define TIF_SYSCALL_EMU 6 /* syscall emulation active */ | 140 | #define TIF_SYSCALL_EMU 6 /* syscall emulation active */ | 
| 141 | #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ | 141 | #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ | 
| 142 | #define TIF_SECCOMP 8 /* secure computing */ | 142 | #define TIF_SECCOMP 8 /* secure computing */ | 
| 143 | #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ | ||
| 143 | #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ | 144 | #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ | 
| 144 | #define TIF_MEMDIE 17 | 145 | #define TIF_MEMDIE 17 | 
| 145 | 146 | ||
| @@ -152,6 +153,7 @@ register unsigned long current_stack_pointer asm("esp") __attribute_used__; | |||
| 152 | #define _TIF_SYSCALL_EMU (1<<TIF_SYSCALL_EMU) | 153 | #define _TIF_SYSCALL_EMU (1<<TIF_SYSCALL_EMU) | 
| 153 | #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) | 154 | #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) | 
| 154 | #define _TIF_SECCOMP (1<<TIF_SECCOMP) | 155 | #define _TIF_SECCOMP (1<<TIF_SECCOMP) | 
| 156 | #define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) | ||
| 155 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) | 157 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) | 
| 156 | 158 | ||
| 157 | /* work to do on interrupt/exception return */ | 159 | /* work to do on interrupt/exception return */ | 
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index e3028aaf6d83..3400441b3f91 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h  | |||
| @@ -430,6 +430,7 @@ __syscall_return(type,__res); \ | |||
| 430 | #define __ARCH_WANT_SYS_SIGPENDING | 430 | #define __ARCH_WANT_SYS_SIGPENDING | 
| 431 | #define __ARCH_WANT_SYS_SIGPROCMASK | 431 | #define __ARCH_WANT_SYS_SIGPROCMASK | 
| 432 | #define __ARCH_WANT_SYS_RT_SIGACTION | 432 | #define __ARCH_WANT_SYS_RT_SIGACTION | 
| 433 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | ||
| 433 | #endif | 434 | #endif | 
| 434 | 435 | ||
| 435 | #ifdef __KERNEL_SYSCALLS__ | 436 | #ifdef __KERNEL_SYSCALLS__ | 
