aboutsummaryrefslogtreecommitdiffstats
path: root/arch/frv
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-01-18 20:43:59 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-18 22:20:29 -0500
commita411aee96ea7fe6fe065df65bf29ea755bcdb554 (patch)
tree3a6cfece835c6d896a035e05fbcfe34a4c691bfc /arch/frv
parent150256d8aadb3a337c31efa9e175cbd25bf06b06 (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')
-rw-r--r--arch/frv/kernel/signal.c120
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
38static 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 */
43asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask) 41asmlinkage 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(&current->sighand->siglock); 44 spin_lock_irq(&current->sighand->siglock);
49 saveset = current->blocked; 45 current->saved_sigmask = current->blocked;
50 siginitset(&current->blocked, mask); 46 siginitset(&current->blocked, mask);
51 recalc_sigpending(); 47 recalc_sigpending();
52 spin_unlock_irq(&current->sighand->siglock); 48 spin_unlock_irq(&current->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
72asmlinkage 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(&current->sighand->siglock);
85 saveset = current->blocked;
86 current->blocked = newset;
87 recalc_sigpending();
88 spin_unlock_irq(&current->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
108asmlinkage int sys_sigaction(int sig, 56asmlinkage 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
377give_sigsegv: 325give_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
476give_sigsegv: 424give_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(&current->sighand->siglock); 468 spin_lock_irq(&current->sighand->siglock);
521 sigorsets(&current->blocked, &current->blocked, 469 sigorsets(&current->blocked, &current->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 */
539static int do_signal(sigset_t *oldset) 487static 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 = &current->saved_sigmask;
508 else
558 oldset = &current->blocked; 509 oldset = &current->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
564no_signal: 525no_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, &current->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 */
590asmlinkage void do_notify_resume(__u32 thread_info_flags) 558asmlinkage 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() */