aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/signal.c
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2006-09-26 04:52:26 -0400
committerAndi Kleen <andi@basil.nowhere.org>2006-09-26 04:52:26 -0400
commit1d001df19d5323e642ba8ac821c713675ebccd82 (patch)
tree6eec46bca129524fc6e9ee55772a3943ff091a2f /arch/x86_64/kernel/signal.c
parent3adbbcce9a49b900d4cc118cdccfdefa78bf1afb (diff)
[PATCH] Add TIF_RESTORE_SIGMASK
We need TIF_RESTORE_SIGMASK in order to support ppoll() and pselect() system calls. This patch originally came from Andi, and was based heavily on David Howells' implementation of same on i386. I fixed a typo which was causing do_signal() to use the wrong signal mask. Signed-off-by: David Woodhouse <dwmw2@infradead.org> Signed-off-by: Andi Kleen <ak@suse.de>
Diffstat (limited to 'arch/x86_64/kernel/signal.c')
-rw-r--r--arch/x86_64/kernel/signal.c82
1 files changed, 35 insertions, 47 deletions
diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c
index 28161170fb0a..7f58bc9a056d 100644
--- a/arch/x86_64/kernel/signal.c
+++ b/arch/x86_64/kernel/signal.c
@@ -38,37 +38,6 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
38 sigset_t *set, struct pt_regs * regs); 38 sigset_t *set, struct pt_regs * regs);
39 39
40asmlinkage long 40asmlinkage long
41sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs)
42{
43 sigset_t saveset, newset;
44
45 /* XXX: Don't preclude handling different sized sigset_t's. */
46 if (sigsetsize != sizeof(sigset_t))
47 return -EINVAL;
48
49 if (copy_from_user(&newset, unewset, sizeof(newset)))
50 return -EFAULT;
51 sigdelsetmask(&newset, ~_BLOCKABLE);
52
53 spin_lock_irq(&current->sighand->siglock);
54 saveset = current->blocked;
55 current->blocked = newset;
56 recalc_sigpending();
57 spin_unlock_irq(&current->sighand->siglock);
58#ifdef DEBUG_SIG
59 printk("rt_sigsuspend savset(%lx) newset(%lx) regs(%p) rip(%lx)\n",
60 saveset, newset, regs, regs->rip);
61#endif
62 regs->rax = -EINTR;
63 while (1) {
64 current->state = TASK_INTERRUPTIBLE;
65 schedule();
66 if (do_signal(regs, &saveset))
67 return -EINTR;
68 }
69}
70
71asmlinkage long
72sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, 41sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
73 struct pt_regs *regs) 42 struct pt_regs *regs)
74{ 43{
@@ -341,11 +310,11 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
341 current->comm, current->pid, frame, regs->rip, frame->pretcode); 310 current->comm, current->pid, frame, regs->rip, frame->pretcode);
342#endif 311#endif
343 312
344 return 1; 313 return 0;
345 314
346give_sigsegv: 315give_sigsegv:
347 force_sigsegv(sig, current); 316 force_sigsegv(sig, current);
348 return 0; 317 return -EFAULT;
349} 318}
350 319
351/* 320/*
@@ -408,7 +377,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
408#endif 377#endif
409 ret = setup_rt_frame(sig, ka, info, oldset, regs); 378 ret = setup_rt_frame(sig, ka, info, oldset, regs);
410 379
411 if (ret) { 380 if (ret == 0) {
412 spin_lock_irq(&current->sighand->siglock); 381 spin_lock_irq(&current->sighand->siglock);
413 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask); 382 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
414 if (!(ka->sa.sa_flags & SA_NODEFER)) 383 if (!(ka->sa.sa_flags & SA_NODEFER))
@@ -425,11 +394,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
425 * want to handle. Thus you cannot kill init even with a SIGKILL even by 394 * want to handle. Thus you cannot kill init even with a SIGKILL even by
426 * mistake. 395 * mistake.
427 */ 396 */
428int do_signal(struct pt_regs *regs, sigset_t *oldset) 397static void do_signal(struct pt_regs *regs)
429{ 398{
430 struct k_sigaction ka; 399 struct k_sigaction ka;
431 siginfo_t info; 400 siginfo_t info;
432 int signr; 401 int signr;
402 sigset_t *oldset;
433 403
434 /* 404 /*
435 * We want the common case to go fast, which 405 * We want the common case to go fast, which
@@ -438,9 +408,11 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
438 * if so. 408 * if so.
439 */ 409 */
440 if (!user_mode(regs)) 410 if (!user_mode(regs))
441 return 1; 411 return;
442 412
443 if (!oldset) 413 if (test_thread_flag(TIF_RESTORE_SIGMASK))
414 oldset = &current->saved_sigmask;
415 else
444 oldset = &current->blocked; 416 oldset = &current->blocked;
445 417
446 signr = get_signal_to_deliver(&info, &ka, regs, NULL); 418 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
@@ -454,30 +426,46 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
454 set_debugreg(current->thread.debugreg7, 7); 426 set_debugreg(current->thread.debugreg7, 7);
455 427
456 /* Whee! Actually deliver the signal. */ 428 /* Whee! Actually deliver the signal. */
457 return handle_signal(signr, &info, &ka, oldset, regs); 429 if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
430 /* a signal was successfully delivered; the saved
431 * sigmask will have been stored in the signal frame,
432 * and will be restored by sigreturn, so we can simply
433 * clear the TIF_RESTORE_SIGMASK flag */
434 clear_thread_flag(TIF_RESTORE_SIGMASK);
435 }
436 return;
458 } 437 }
459 438
460 /* Did we come from a system call? */ 439 /* Did we come from a system call? */
461 if ((long)regs->orig_rax >= 0) { 440 if ((long)regs->orig_rax >= 0) {
462 /* Restart the system call - no handlers present */ 441 /* Restart the system call - no handlers present */
463 long res = regs->rax; 442 long res = regs->rax;
464 if (res == -ERESTARTNOHAND || 443 switch (res) {
465 res == -ERESTARTSYS || 444 case -ERESTARTNOHAND:
466 res == -ERESTARTNOINTR) { 445 case -ERESTARTSYS:
446 case -ERESTARTNOINTR:
467 regs->rax = regs->orig_rax; 447 regs->rax = regs->orig_rax;
468 regs->rip -= 2; 448 regs->rip -= 2;
469 } 449 break;
470 if (regs->rax == (unsigned long)-ERESTART_RESTARTBLOCK) { 450 case -ERESTART_RESTARTBLOCK:
471 regs->rax = test_thread_flag(TIF_IA32) ? 451 regs->rax = test_thread_flag(TIF_IA32) ?
472 __NR_ia32_restart_syscall : 452 __NR_ia32_restart_syscall :
473 __NR_restart_syscall; 453 __NR_restart_syscall;
474 regs->rip -= 2; 454 regs->rip -= 2;
455 break;
475 } 456 }
476 } 457 }
477 return 0; 458
459 /* if there's no signal to deliver, we just put the saved sigmask
460 back. */
461 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
462 clear_thread_flag(TIF_RESTORE_SIGMASK);
463 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
464 }
478} 465}
479 466
480void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, __u32 thread_info_flags) 467void
468do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
481{ 469{
482#ifdef DEBUG_SIG 470#ifdef DEBUG_SIG
483 printk("do_notify_resume flags:%x rip:%lx rsp:%lx caller:%lx pending:%lx\n", 471 printk("do_notify_resume flags:%x rip:%lx rsp:%lx caller:%lx pending:%lx\n",
@@ -491,8 +479,8 @@ void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, __u32 thread_info_
491 } 479 }
492 480
493 /* deal with pending signal delivery */ 481 /* deal with pending signal delivery */
494 if (thread_info_flags & _TIF_SIGPENDING) 482 if (thread_info_flags & (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK))
495 do_signal(regs,oldset); 483 do_signal(regs);
496} 484}
497 485
498void signal_fault(struct pt_regs *regs, void __user *frame, char *where) 486void signal_fault(struct pt_regs *regs, void __user *frame, char *where)