aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64
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
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')
-rw-r--r--arch/x86_64/ia32/ia32_signal.c28
-rw-r--r--arch/x86_64/kernel/signal.c82
2 files changed, 46 insertions, 64 deletions
diff --git a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c
index 25e5ca22204c..549de439fb2d 100644
--- a/arch/x86_64/ia32/ia32_signal.c
+++ b/arch/x86_64/ia32/ia32_signal.c
@@ -113,25 +113,19 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
113} 113}
114 114
115asmlinkage long 115asmlinkage long
116sys32_sigsuspend(int history0, int history1, old_sigset_t mask, 116sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
117 struct pt_regs *regs)
118{ 117{
119 sigset_t saveset;
120
121 mask &= _BLOCKABLE; 118 mask &= _BLOCKABLE;
122 spin_lock_irq(&current->sighand->siglock); 119 spin_lock_irq(&current->sighand->siglock);
123 saveset = current->blocked; 120 current->saved_sigmask = current->blocked;
124 siginitset(&current->blocked, mask); 121 siginitset(&current->blocked, mask);
125 recalc_sigpending(); 122 recalc_sigpending();
126 spin_unlock_irq(&current->sighand->siglock); 123 spin_unlock_irq(&current->sighand->siglock);
127 124
128 regs->rax = -EINTR; 125 current->state = TASK_INTERRUPTIBLE;
129 while (1) { 126 schedule();
130 current->state = TASK_INTERRUPTIBLE; 127 set_thread_flag(TIF_RESTORE_SIGMASK);
131 schedule(); 128 return -ERESTARTNOHAND;
132 if (do_signal(regs, &saveset))
133 return -EINTR;
134 }
135} 129}
136 130
137asmlinkage long 131asmlinkage long
@@ -508,11 +502,11 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
508 current->comm, current->pid, frame, regs->rip, frame->pretcode); 502 current->comm, current->pid, frame, regs->rip, frame->pretcode);
509#endif 503#endif
510 504
511 return 1; 505 return 0;
512 506
513give_sigsegv: 507give_sigsegv:
514 force_sigsegv(sig, current); 508 force_sigsegv(sig, current);
515 return 0; 509 return -EFAULT;
516} 510}
517 511
518int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, 512int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -595,7 +589,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
595 regs->ss = __USER32_DS; 589 regs->ss = __USER32_DS;
596 590
597 set_fs(USER_DS); 591 set_fs(USER_DS);
598 regs->eflags &= ~TF_MASK; 592 regs->eflags &= ~TF_MASK;
599 if (test_thread_flag(TIF_SINGLESTEP)) 593 if (test_thread_flag(TIF_SINGLESTEP))
600 ptrace_notify(SIGTRAP); 594 ptrace_notify(SIGTRAP);
601 595
@@ -604,9 +598,9 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
604 current->comm, current->pid, frame, regs->rip, frame->pretcode); 598 current->comm, current->pid, frame, regs->rip, frame->pretcode);
605#endif 599#endif
606 600
607 return 1; 601 return 0;
608 602
609give_sigsegv: 603give_sigsegv:
610 force_sigsegv(sig, current); 604 force_sigsegv(sig, current);
611 return 0; 605 return -EFAULT;
612} 606}
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)