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 /arch/frv/kernel/signal.c | |
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>
Diffstat (limited to 'arch/frv/kernel/signal.c')
-rw-r--r-- | arch/frv/kernel/signal.c | 120 |
1 files changed, 44 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() */ |