diff options
author | David Howells <dhowells@redhat.com> | 2006-01-18 20:44:00 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-18 22:20:29 -0500 |
commit | 283828f3c19ceb3a64a8544d42cc189003e8b0fe (patch) | |
tree | a3ba8f54e809bc1036bce6a404d88c93d578b0c2 /arch/i386 | |
parent | a411aee96ea7fe6fe065df65bf29ea755bcdb554 (diff) |
[PATCH] Handle TIF_RESTORE_SIGMASK for i386
Handle TIF_RESTORE_SIGMASK as added by David Woodhouse's patch entitled:
[PATCH] 2/3 Add TIF_RESTORE_SIGMASK support for arch/powerpc
[PATCH] 3/3 Generic sys_rt_sigsuspend
It does the following:
(1) Declares TIF_RESTORE_SIGMASK for i386.
(2) Invokes it over to do_signal() when TIF_RESTORE_SIGMASK is set.
(3) Makes do_signal() support TIF_RESTORE_SIGMASK, using the signal mask saved
in current->saved_sigmask.
(4) Discards sys_rt_sigsuspend() from the arch, using the generic one instead.
(5) Makes sys_sigsuspend() save the signal mask and set TIF_RESTORE_SIGMASK
rather than attempting to fudge the return registers.
(6) Makes sys_sigsuspend() return -ERESTARTNOHAND rather than looping
intrinsically.
(7) Makes setup_frame(), setup_rt_frame() and handle_signal() return 0 or
-EFAULT rather than true/false to be consistent with the rest of the
kernel.
Due to the fact do_signal() is then only called from one place:
(8) Makes do_signal() no longer have a return value is it was just being
ignored; force_sig() takes care of this.
(9) Discards the old sigmask argument to do_signal() as it's no longer
necessary.
(10) Makes do_signal() static.
(11) Marks the second argument to do_notify_resume() as unused. The unused
argument should remain in the middle as the arguments are passed in as
registers, and the ordering is specific in entry.S
Given the way do_signal() is now no longer called from sys_{,rt_}sigsuspend(),
they no longer need access to the exception frame, and so can just take
arguments normally.
This patch depends on sys_rt_sigsuspend patch.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386')
-rw-r--r-- | arch/i386/kernel/signal.c | 109 |
1 files changed, 48 insertions, 61 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 | } |