diff options
author | Andi Kleen <ak@suse.de> | 2006-09-26 04:52:26 -0400 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2006-09-26 04:52:26 -0400 |
commit | 1d001df19d5323e642ba8ac821c713675ebccd82 (patch) | |
tree | 6eec46bca129524fc6e9ee55772a3943ff091a2f /arch/x86_64 | |
parent | 3adbbcce9a49b900d4cc118cdccfdefa78bf1afb (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.c | 28 | ||||
-rw-r--r-- | arch/x86_64/kernel/signal.c | 82 |
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 | ||
115 | asmlinkage long | 115 | asmlinkage long |
116 | sys32_sigsuspend(int history0, int history1, old_sigset_t mask, | 116 | sys32_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(¤t->sighand->siglock); | 119 | spin_lock_irq(¤t->sighand->siglock); |
123 | saveset = current->blocked; | 120 | current->saved_sigmask = current->blocked; |
124 | siginitset(¤t->blocked, mask); | 121 | siginitset(¤t->blocked, mask); |
125 | recalc_sigpending(); | 122 | recalc_sigpending(); |
126 | spin_unlock_irq(¤t->sighand->siglock); | 123 | spin_unlock_irq(¤t->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 | ||
137 | asmlinkage long | 131 | asmlinkage 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 | ||
513 | give_sigsegv: | 507 | give_sigsegv: |
514 | force_sigsegv(sig, current); | 508 | force_sigsegv(sig, current); |
515 | return 0; | 509 | return -EFAULT; |
516 | } | 510 | } |
517 | 511 | ||
518 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 512 | int 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 | ||
609 | give_sigsegv: | 603 | give_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 | ||
40 | asmlinkage long | 40 | asmlinkage long |
41 | sys_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(¤t->sighand->siglock); | ||
54 | saveset = current->blocked; | ||
55 | current->blocked = newset; | ||
56 | recalc_sigpending(); | ||
57 | spin_unlock_irq(¤t->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 | |||
71 | asmlinkage long | ||
72 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | 41 | sys_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 | ||
346 | give_sigsegv: | 315 | give_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(¤t->sighand->siglock); | 381 | spin_lock_irq(¤t->sighand->siglock); |
413 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 382 | sigorsets(¤t->blocked,¤t->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 | */ |
428 | int do_signal(struct pt_regs *regs, sigset_t *oldset) | 397 | static 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 = ¤t->saved_sigmask; | ||
415 | else | ||
444 | oldset = ¤t->blocked; | 416 | oldset = ¤t->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, ¤t->saved_sigmask, NULL); | ||
464 | } | ||
478 | } | 465 | } |
479 | 466 | ||
480 | void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, __u32 thread_info_flags) | 467 | void |
468 | do_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 | ||
498 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where) | 486 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where) |