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 | /* |