diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-26 16:07:55 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-26 16:07:55 -0400 |
commit | b278240839e20fa9384ea430df463b367b90e04e (patch) | |
tree | f99f0c8cdd4cc7f177cd75440e6bd181cded7fb3 /arch/x86_64/kernel/signal.c | |
parent | dd77a4ee0f3981693d4229aa1d57cea9e526ff47 (diff) | |
parent | 3f75f42d7733e73aca5c78326489efd4189e0111 (diff) |
Merge branch 'for-linus' of git://one.firstfloor.org/home/andi/git/linux-2.6
* 'for-linus' of git://one.firstfloor.org/home/andi/git/linux-2.6: (225 commits)
[PATCH] Don't set calgary iommu as default y
[PATCH] i386/x86-64: New Intel feature flags
[PATCH] x86: Add a cumulative thermal throttle event counter.
[PATCH] i386: Make the jiffies compares use the 64bit safe macros.
[PATCH] x86: Refactor thermal throttle processing
[PATCH] Add 64bit jiffies compares (for use with get_jiffies_64)
[PATCH] Fix unwinder warning in traps.c
[PATCH] x86: Allow disabling early pci scans with pci=noearly or disallowing conf1
[PATCH] x86: Move direct PCI scanning functions out of line
[PATCH] i386/x86-64: Make all early PCI scans dependent on CONFIG_PCI
[PATCH] Don't leak NT bit into next task
[PATCH] i386/x86-64: Work around gcc bug with noreturn functions in unwinder
[PATCH] Fix some broken white space in ia32_signal.c
[PATCH] Initialize argument registers for 32bit signal handlers.
[PATCH] Remove all traces of signal number conversion
[PATCH] Don't synchronize time reading on single core AMD systems
[PATCH] Remove outdated comment in x86-64 mmconfig code
[PATCH] Use string instructions for Core2 copy/clear
[PATCH] x86: - restore i8259A eoi status on resume
[PATCH] i386: Split multi-line printk in oops output.
...
Diffstat (limited to 'arch/x86_64/kernel/signal.c')
-rw-r--r-- | arch/x86_64/kernel/signal.c | 87 |
1 files changed, 35 insertions, 52 deletions
diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c index 28161170fb0a..49ec324cd141 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 | { |
@@ -308,11 +277,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
308 | #endif | 277 | #endif |
309 | 278 | ||
310 | /* Set up registers for signal handler */ | 279 | /* Set up registers for signal handler */ |
311 | { | ||
312 | struct exec_domain *ed = current_thread_info()->exec_domain; | ||
313 | if (unlikely(ed && ed->signal_invmap && sig < 32)) | ||
314 | sig = ed->signal_invmap[sig]; | ||
315 | } | ||
316 | regs->rdi = sig; | 280 | regs->rdi = sig; |
317 | /* In case the signal handler was declared without prototypes */ | 281 | /* In case the signal handler was declared without prototypes */ |
318 | regs->rax = 0; | 282 | regs->rax = 0; |
@@ -341,11 +305,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); | 305 | current->comm, current->pid, frame, regs->rip, frame->pretcode); |
342 | #endif | 306 | #endif |
343 | 307 | ||
344 | return 1; | 308 | return 0; |
345 | 309 | ||
346 | give_sigsegv: | 310 | give_sigsegv: |
347 | force_sigsegv(sig, current); | 311 | force_sigsegv(sig, current); |
348 | return 0; | 312 | return -EFAULT; |
349 | } | 313 | } |
350 | 314 | ||
351 | /* | 315 | /* |
@@ -408,7 +372,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
408 | #endif | 372 | #endif |
409 | ret = setup_rt_frame(sig, ka, info, oldset, regs); | 373 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |
410 | 374 | ||
411 | if (ret) { | 375 | if (ret == 0) { |
412 | spin_lock_irq(¤t->sighand->siglock); | 376 | spin_lock_irq(¤t->sighand->siglock); |
413 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 377 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
414 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 378 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
@@ -425,11 +389,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 | 389 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
426 | * mistake. | 390 | * mistake. |
427 | */ | 391 | */ |
428 | int do_signal(struct pt_regs *regs, sigset_t *oldset) | 392 | static void do_signal(struct pt_regs *regs) |
429 | { | 393 | { |
430 | struct k_sigaction ka; | 394 | struct k_sigaction ka; |
431 | siginfo_t info; | 395 | siginfo_t info; |
432 | int signr; | 396 | int signr; |
397 | sigset_t *oldset; | ||
433 | 398 | ||
434 | /* | 399 | /* |
435 | * We want the common case to go fast, which | 400 | * We want the common case to go fast, which |
@@ -438,9 +403,11 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
438 | * if so. | 403 | * if so. |
439 | */ | 404 | */ |
440 | if (!user_mode(regs)) | 405 | if (!user_mode(regs)) |
441 | return 1; | 406 | return; |
442 | 407 | ||
443 | if (!oldset) | 408 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
409 | oldset = ¤t->saved_sigmask; | ||
410 | else | ||
444 | oldset = ¤t->blocked; | 411 | oldset = ¤t->blocked; |
445 | 412 | ||
446 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 413 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
@@ -454,30 +421,46 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
454 | set_debugreg(current->thread.debugreg7, 7); | 421 | set_debugreg(current->thread.debugreg7, 7); |
455 | 422 | ||
456 | /* Whee! Actually deliver the signal. */ | 423 | /* Whee! Actually deliver the signal. */ |
457 | return handle_signal(signr, &info, &ka, oldset, regs); | 424 | if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { |
425 | /* a signal was successfully delivered; the saved | ||
426 | * sigmask will have been stored in the signal frame, | ||
427 | * and will be restored by sigreturn, so we can simply | ||
428 | * clear the TIF_RESTORE_SIGMASK flag */ | ||
429 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
430 | } | ||
431 | return; | ||
458 | } | 432 | } |
459 | 433 | ||
460 | /* Did we come from a system call? */ | 434 | /* Did we come from a system call? */ |
461 | if ((long)regs->orig_rax >= 0) { | 435 | if ((long)regs->orig_rax >= 0) { |
462 | /* Restart the system call - no handlers present */ | 436 | /* Restart the system call - no handlers present */ |
463 | long res = regs->rax; | 437 | long res = regs->rax; |
464 | if (res == -ERESTARTNOHAND || | 438 | switch (res) { |
465 | res == -ERESTARTSYS || | 439 | case -ERESTARTNOHAND: |
466 | res == -ERESTARTNOINTR) { | 440 | case -ERESTARTSYS: |
441 | case -ERESTARTNOINTR: | ||
467 | regs->rax = regs->orig_rax; | 442 | regs->rax = regs->orig_rax; |
468 | regs->rip -= 2; | 443 | regs->rip -= 2; |
469 | } | 444 | break; |
470 | if (regs->rax == (unsigned long)-ERESTART_RESTARTBLOCK) { | 445 | case -ERESTART_RESTARTBLOCK: |
471 | regs->rax = test_thread_flag(TIF_IA32) ? | 446 | regs->rax = test_thread_flag(TIF_IA32) ? |
472 | __NR_ia32_restart_syscall : | 447 | __NR_ia32_restart_syscall : |
473 | __NR_restart_syscall; | 448 | __NR_restart_syscall; |
474 | regs->rip -= 2; | 449 | regs->rip -= 2; |
450 | break; | ||
475 | } | 451 | } |
476 | } | 452 | } |
477 | return 0; | 453 | |
454 | /* if there's no signal to deliver, we just put the saved sigmask | ||
455 | back. */ | ||
456 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
457 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
458 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
459 | } | ||
478 | } | 460 | } |
479 | 461 | ||
480 | void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, __u32 thread_info_flags) | 462 | void |
463 | do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) | ||
481 | { | 464 | { |
482 | #ifdef DEBUG_SIG | 465 | #ifdef DEBUG_SIG |
483 | printk("do_notify_resume flags:%x rip:%lx rsp:%lx caller:%lx pending:%lx\n", | 466 | printk("do_notify_resume flags:%x rip:%lx rsp:%lx caller:%lx pending:%lx\n", |
@@ -491,8 +474,8 @@ void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, __u32 thread_info_ | |||
491 | } | 474 | } |
492 | 475 | ||
493 | /* deal with pending signal delivery */ | 476 | /* deal with pending signal delivery */ |
494 | if (thread_info_flags & _TIF_SIGPENDING) | 477 | if (thread_info_flags & (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK)) |
495 | do_signal(regs,oldset); | 478 | do_signal(regs); |
496 | } | 479 | } |
497 | 480 | ||
498 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where) | 481 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where) |