diff options
| author | David Howells <dhowells@redhat.com> | 2006-01-18 20:43:59 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-18 22:20:29 -0500 |
| commit | a411aee96ea7fe6fe065df65bf29ea755bcdb554 (patch) | |
| tree | 3a6cfece835c6d896a035e05fbcfe34a4c691bfc | |
| parent | 150256d8aadb3a337c31efa9e175cbd25bf06b06 (diff) | |
[PATCH] Handle TIF_RESTORE_SIGMASK for FRV
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 FRV.
(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) Make 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.
This patch depends on the FRV signalling patches as well as the
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>
| -rw-r--r-- | arch/frv/kernel/signal.c | 120 | ||||
| -rw-r--r-- | include/asm-frv/thread_info.h | 2 | ||||
| -rw-r--r-- | include/asm-frv/unistd.h | 1 |
3 files changed, 47 insertions, 76 deletions
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index 5b7146f54fd5..679c1d5cc958 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c | |||
| @@ -35,74 +35,22 @@ struct fdpic_func_descriptor { | |||
| 35 | unsigned long GOT; | 35 | unsigned long GOT; |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | static int do_signal(sigset_t *oldset); | ||
| 39 | |||
| 40 | /* | 38 | /* |
| 41 | * Atomically swap in the new signal mask, and wait for a signal. | 39 | * Atomically swap in the new signal mask, and wait for a signal. |
| 42 | */ | 40 | */ |
| 43 | asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask) | 41 | asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask) |
| 44 | { | 42 | { |
| 45 | sigset_t saveset; | ||
| 46 | |||
| 47 | mask &= _BLOCKABLE; | 43 | mask &= _BLOCKABLE; |
| 48 | spin_lock_irq(¤t->sighand->siglock); | 44 | spin_lock_irq(¤t->sighand->siglock); |
| 49 | saveset = current->blocked; | 45 | current->saved_sigmask = current->blocked; |
| 50 | siginitset(¤t->blocked, mask); | 46 | siginitset(¤t->blocked, mask); |
| 51 | recalc_sigpending(); | 47 | recalc_sigpending(); |
| 52 | spin_unlock_irq(¤t->sighand->siglock); | 48 | spin_unlock_irq(¤t->sighand->siglock); |
| 53 | 49 | ||
| 54 | __frame->gr8 = -EINTR; | 50 | current->state = TASK_INTERRUPTIBLE; |
| 55 | while (1) { | 51 | schedule(); |
| 56 | current->state = TASK_INTERRUPTIBLE; | 52 | set_thread_flag(TIF_RESTORE_SIGMASK); |
| 57 | schedule(); | 53 | return -ERESTARTNOHAND; |
| 58 | if (do_signal(&saveset)) | ||
| 59 | /* return the signal number as the return value of this function | ||
| 60 | * - this is an utterly evil hack. syscalls should not invoke do_signal() | ||
| 61 | * as entry.S sets regs->gr8 to the return value of the system call | ||
| 62 | * - we can't just use sigpending() as we'd have to discard SIG_IGN signals | ||
| 63 | * and call waitpid() if SIGCHLD needed discarding | ||
| 64 | * - this only works on the i386 because it passes arguments to the signal | ||
| 65 | * handler on the stack, and the return value in EAX is effectively | ||
| 66 | * discarded | ||
| 67 | */ | ||
| 68 | return __frame->gr8; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | asmlinkage int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) | ||
| 73 | { | ||
| 74 | sigset_t saveset, newset; | ||
| 75 | |||
| 76 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
| 77 | if (sigsetsize != sizeof(sigset_t)) | ||
| 78 | return -EINVAL; | ||
| 79 | |||
| 80 | if (copy_from_user(&newset, unewset, sizeof(newset))) | ||
| 81 | return -EFAULT; | ||
| 82 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
| 83 | |||
| 84 | spin_lock_irq(¤t->sighand->siglock); | ||
| 85 | saveset = current->blocked; | ||
| 86 | current->blocked = newset; | ||
| 87 | recalc_sigpending(); | ||
| 88 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 89 | |||
| 90 | __frame->gr8 = -EINTR; | ||
| 91 | while (1) { | ||
| 92 | current->state = TASK_INTERRUPTIBLE; | ||
| 93 | schedule(); | ||
| 94 | if (do_signal(&saveset)) | ||
| 95 | /* return the signal number as the return value of this function | ||
| 96 | * - this is an utterly evil hack. syscalls should not invoke do_signal() | ||
| 97 | * as entry.S sets regs->gr8 to the return value of the system call | ||
| 98 | * - we can't just use sigpending() as we'd have to discard SIG_IGN signals | ||
| 99 | * and call waitpid() if SIGCHLD needed discarding | ||
| 100 | * - this only works on the i386 because it passes arguments to the signal | ||
| 101 | * handler on the stack, and the return value in EAX is effectively | ||
| 102 | * discarded | ||
| 103 | */ | ||
| 104 | return __frame->gr8; | ||
| 105 | } | ||
| 106 | } | 54 | } |
| 107 | 55 | ||
| 108 | asmlinkage int sys_sigaction(int sig, | 56 | asmlinkage int sys_sigaction(int sig, |
| @@ -372,11 +320,11 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set) | |||
| 372 | frame->pretcode); | 320 | frame->pretcode); |
| 373 | #endif | 321 | #endif |
| 374 | 322 | ||
| 375 | return 1; | 323 | return 0; |
| 376 | 324 | ||
| 377 | give_sigsegv: | 325 | give_sigsegv: |
| 378 | force_sig(SIGSEGV, current); | 326 | force_sig(SIGSEGV, current); |
| 379 | return 0; | 327 | return -EFAULT; |
| 380 | 328 | ||
| 381 | } /* end setup_frame() */ | 329 | } /* end setup_frame() */ |
| 382 | 330 | ||
| @@ -471,11 +419,11 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 471 | frame->pretcode); | 419 | frame->pretcode); |
| 472 | #endif | 420 | #endif |
| 473 | 421 | ||
| 474 | return 1; | 422 | return 0; |
| 475 | 423 | ||
| 476 | give_sigsegv: | 424 | give_sigsegv: |
| 477 | force_sig(SIGSEGV, current); | 425 | force_sig(SIGSEGV, current); |
| 478 | return 0; | 426 | return -EFAULT; |
| 479 | 427 | ||
| 480 | } /* end setup_rt_frame() */ | 428 | } /* end setup_rt_frame() */ |
| 481 | 429 | ||
| @@ -516,7 +464,7 @@ static int handle_signal(unsigned long sig, siginfo_t *info, | |||
| 516 | else | 464 | else |
| 517 | ret = setup_frame(sig, ka, oldset); | 465 | ret = setup_frame(sig, ka, oldset); |
| 518 | 466 | ||
| 519 | if (ret) { | 467 | if (ret == 0) { |
| 520 | spin_lock_irq(¤t->sighand->siglock); | 468 | spin_lock_irq(¤t->sighand->siglock); |
| 521 | sigorsets(¤t->blocked, ¤t->blocked, | 469 | sigorsets(¤t->blocked, ¤t->blocked, |
| 522 | &ka->sa.sa_mask); | 470 | &ka->sa.sa_mask); |
| @@ -536,10 +484,11 @@ static int handle_signal(unsigned long sig, siginfo_t *info, | |||
| 536 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 484 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
| 537 | * mistake. | 485 | * mistake. |
| 538 | */ | 486 | */ |
| 539 | static int do_signal(sigset_t *oldset) | 487 | static void do_signal(void) |
| 540 | { | 488 | { |
| 541 | struct k_sigaction ka; | 489 | struct k_sigaction ka; |
| 542 | siginfo_t info; | 490 | siginfo_t info; |
| 491 | sigset_t *oldset; | ||
| 543 | int signr; | 492 | int signr; |
| 544 | 493 | ||
| 545 | /* | 494 | /* |
| @@ -549,43 +498,62 @@ static int do_signal(sigset_t *oldset) | |||
| 549 | * if so. | 498 | * if so. |
| 550 | */ | 499 | */ |
| 551 | if (!user_mode(__frame)) | 500 | if (!user_mode(__frame)) |
| 552 | return 1; | 501 | return; |
| 553 | 502 | ||
| 554 | if (try_to_freeze()) | 503 | if (try_to_freeze()) |
| 555 | goto no_signal; | 504 | goto no_signal; |
| 556 | 505 | ||
| 557 | if (!oldset) | 506 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
| 507 | oldset = ¤t->saved_sigmask; | ||
| 508 | else | ||
| 558 | oldset = ¤t->blocked; | 509 | oldset = ¤t->blocked; |
| 559 | 510 | ||
| 560 | signr = get_signal_to_deliver(&info, &ka, __frame, NULL); | 511 | signr = get_signal_to_deliver(&info, &ka, __frame, NULL); |
| 561 | if (signr > 0) | 512 | if (signr > 0) { |
| 562 | return handle_signal(signr, &info, &ka, oldset); | 513 | if (handle_signal(signr, &info, &ka, oldset) == 0) { |
| 514 | /* a signal was successfully delivered; the saved | ||
| 515 | * sigmask will have been stored in the signal frame, | ||
| 516 | * and will be restored by sigreturn, so we can simply | ||
| 517 | * clear the TIF_RESTORE_SIGMASK flag */ | ||
| 518 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
| 519 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 520 | } | ||
| 521 | |||
| 522 | return; | ||
| 523 | } | ||
| 563 | 524 | ||
| 564 | no_signal: | 525 | no_signal: |
| 565 | /* Did we come from a system call? */ | 526 | /* Did we come from a system call? */ |
| 566 | if (__frame->syscallno >= 0) { | 527 | if (__frame->syscallno >= 0) { |
| 567 | /* Restart the system call - no handlers present */ | 528 | /* Restart the system call - no handlers present */ |
| 568 | if (__frame->gr8 == -ERESTARTNOHAND || | 529 | switch (__frame->gr8) { |
| 569 | __frame->gr8 == -ERESTARTSYS || | 530 | case -ERESTARTNOHAND: |
| 570 | __frame->gr8 == -ERESTARTNOINTR) { | 531 | case -ERESTARTSYS: |
| 532 | case -ERESTARTNOINTR: | ||
| 571 | __frame->gr8 = __frame->orig_gr8; | 533 | __frame->gr8 = __frame->orig_gr8; |
| 572 | __frame->pc -= 4; | 534 | __frame->pc -= 4; |
| 573 | } | 535 | break; |
| 574 | 536 | ||
| 575 | if (__frame->gr8 == -ERESTART_RESTARTBLOCK){ | 537 | case -ERESTART_RESTARTBLOCK: |
| 576 | __frame->gr8 = __NR_restart_syscall; | 538 | __frame->gr8 = __NR_restart_syscall; |
| 577 | __frame->pc -= 4; | 539 | __frame->pc -= 4; |
| 540 | break; | ||
| 578 | } | 541 | } |
| 579 | } | 542 | } |
| 580 | 543 | ||
| 581 | return 0; | 544 | /* if there's no signal to deliver, we just put the saved sigmask |
| 545 | * back */ | ||
| 546 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
| 547 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 548 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
| 549 | } | ||
| 582 | 550 | ||
| 583 | } /* end do_signal() */ | 551 | } /* end do_signal() */ |
| 584 | 552 | ||
| 585 | /*****************************************************************************/ | 553 | /*****************************************************************************/ |
| 586 | /* | 554 | /* |
| 587 | * notification of userspace execution resumption | 555 | * notification of userspace execution resumption |
| 588 | * - triggered by current->work.notify_resume | 556 | * - triggered by the TIF_WORK_MASK flags |
| 589 | */ | 557 | */ |
| 590 | asmlinkage void do_notify_resume(__u32 thread_info_flags) | 558 | asmlinkage void do_notify_resume(__u32 thread_info_flags) |
| 591 | { | 559 | { |
| @@ -594,7 +562,7 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags) | |||
| 594 | clear_thread_flag(TIF_SINGLESTEP); | 562 | clear_thread_flag(TIF_SINGLESTEP); |
| 595 | 563 | ||
| 596 | /* deal with pending signal delivery */ | 564 | /* deal with pending signal delivery */ |
| 597 | if (thread_info_flags & _TIF_SIGPENDING) | 565 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) |
| 598 | do_signal(NULL); | 566 | do_signal(); |
| 599 | 567 | ||
| 600 | } /* end do_notify_resume() */ | 568 | } /* end do_notify_resume() */ |
diff --git a/include/asm-frv/thread_info.h b/include/asm-frv/thread_info.h index a5576e02dd1d..ea426abf01d3 100644 --- a/include/asm-frv/thread_info.h +++ b/include/asm-frv/thread_info.h | |||
| @@ -129,6 +129,7 @@ register struct thread_info *__current_thread_info asm("gr15"); | |||
| 129 | #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ | 129 | #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ |
| 130 | #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */ | 130 | #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */ |
| 131 | #define TIF_IRET 5 /* return with iret */ | 131 | #define TIF_IRET 5 /* return with iret */ |
| 132 | #define TIF_RESTORE_SIGMASK 6 /* restore signal mask in do_signal() */ | ||
| 132 | #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ | 133 | #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ |
| 133 | #define TIF_MEMDIE 17 /* OOM killer killed process */ | 134 | #define TIF_MEMDIE 17 /* OOM killer killed process */ |
| 134 | 135 | ||
| @@ -138,6 +139,7 @@ register struct thread_info *__current_thread_info asm("gr15"); | |||
| 138 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) | 139 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) |
| 139 | #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) | 140 | #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) |
| 140 | #define _TIF_IRET (1 << TIF_IRET) | 141 | #define _TIF_IRET (1 << TIF_IRET) |
| 142 | #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) | ||
| 141 | #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) | 143 | #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) |
| 142 | 144 | ||
| 143 | #define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */ | 145 | #define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */ |
diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h index cde376a7a857..4d994d2e99e3 100644 --- a/include/asm-frv/unistd.h +++ b/include/asm-frv/unistd.h | |||
| @@ -486,6 +486,7 @@ static inline pid_t wait(int * wait_stat) | |||
| 486 | /* #define __ARCH_WANT_SYS_SIGPENDING */ | 486 | /* #define __ARCH_WANT_SYS_SIGPENDING */ |
| 487 | #define __ARCH_WANT_SYS_SIGPROCMASK | 487 | #define __ARCH_WANT_SYS_SIGPROCMASK |
| 488 | #define __ARCH_WANT_SYS_RT_SIGACTION | 488 | #define __ARCH_WANT_SYS_RT_SIGACTION |
| 489 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | ||
| 489 | #endif | 490 | #endif |
| 490 | 491 | ||
| 491 | /* | 492 | /* |
