aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/signal.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-01-18 20:44:00 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-18 22:20:29 -0500
commit283828f3c19ceb3a64a8544d42cc189003e8b0fe (patch)
treea3ba8f54e809bc1036bce6a404d88c93d578b0c2 /arch/i386/kernel/signal.c
parenta411aee96ea7fe6fe065df65bf29ea755bcdb554 (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/kernel/signal.c')
-rw-r--r--arch/i386/kernel/signal.c109
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 @@
37asmlinkage int 37asmlinkage int
38sys_sigsuspend(int history0, int history1, old_sigset_t mask) 38sys_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(&current->sighand->siglock); 41 spin_lock_irq(&current->sighand->siglock);
45 saveset = current->blocked; 42 current->saved_sigmask = current->blocked;
46 siginitset(&current->blocked, mask); 43 siginitset(&current->blocked, mask);
47 recalc_sigpending(); 44 recalc_sigpending();
48 spin_unlock_irq(&current->sighand->siglock); 45 spin_unlock_irq(&current->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
59asmlinkage int
60sys_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(&current->sighand->siglock);
73 saveset = current->blocked;
74 current->blocked = newset;
75 recalc_sigpending();
76 spin_unlock_irq(&current->sighand->siglock);
77
78 regs.eax = -EINTR;
79 while (1) {
80 current->state = TASK_INTERRUPTIBLE;
81 schedule();
82 if (do_signal(&regs, &saveset))
83 return -EINTR;
84 }
85} 51}
86 52
87asmlinkage int 53asmlinkage 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
438give_sigsegv: 404give_sigsegv:
439 force_sigsegv(sig, current); 405 force_sigsegv(sig, current);
440 return 0; 406 return -EFAULT;
441} 407}
442 408
443static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, 409static 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
532give_sigsegv: 498give_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(&current->sighand->siglock); 551 spin_lock_irq(&current->sighand->siglock);
586 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask); 552 sigorsets(&current->blocked,&current->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 */
601int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset) 567static 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 = &current->saved_sigmask;
590 else
622 oldset = &current->blocked; 591 oldset = &current->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: 616no_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, &current->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)))
662void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, 648void 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}