diff options
Diffstat (limited to 'arch/mips/kernel/signal.c')
| -rw-r--r-- | arch/mips/kernel/signal.c | 88 |
1 files changed, 50 insertions, 38 deletions
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index aaec4785e9a6..c974cc9b30eb 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c | |||
| @@ -39,8 +39,6 @@ | |||
| 39 | 39 | ||
| 40 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 40 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
| 41 | 41 | ||
| 42 | int do_signal(sigset_t *oldset, struct pt_regs *regs); | ||
| 43 | |||
| 44 | /* | 42 | /* |
| 45 | * Atomically swap in the new signal mask, and wait for a signal. | 43 | * Atomically swap in the new signal mask, and wait for a signal. |
| 46 | */ | 44 | */ |
| @@ -50,7 +48,7 @@ save_static_function(sys_sigsuspend); | |||
| 50 | __attribute_used__ noinline static int | 48 | __attribute_used__ noinline static int |
| 51 | _sys_sigsuspend(nabi_no_regargs struct pt_regs regs) | 49 | _sys_sigsuspend(nabi_no_regargs struct pt_regs regs) |
| 52 | { | 50 | { |
| 53 | sigset_t saveset, newset; | 51 | sigset_t newset; |
| 54 | sigset_t __user *uset; | 52 | sigset_t __user *uset; |
| 55 | 53 | ||
| 56 | uset = (sigset_t __user *) regs.regs[4]; | 54 | uset = (sigset_t __user *) regs.regs[4]; |
| @@ -59,19 +57,15 @@ _sys_sigsuspend(nabi_no_regargs struct pt_regs regs) | |||
| 59 | sigdelsetmask(&newset, ~_BLOCKABLE); | 57 | sigdelsetmask(&newset, ~_BLOCKABLE); |
| 60 | 58 | ||
| 61 | spin_lock_irq(¤t->sighand->siglock); | 59 | spin_lock_irq(¤t->sighand->siglock); |
| 62 | saveset = current->blocked; | 60 | current->saved_sigmask = current->blocked; |
| 63 | current->blocked = newset; | 61 | current->blocked = newset; |
| 64 | recalc_sigpending(); | 62 | recalc_sigpending(); |
| 65 | spin_unlock_irq(¤t->sighand->siglock); | 63 | spin_unlock_irq(¤t->sighand->siglock); |
| 66 | 64 | ||
| 67 | regs.regs[2] = EINTR; | 65 | current->state = TASK_INTERRUPTIBLE; |
| 68 | regs.regs[7] = 1; | 66 | schedule(); |
| 69 | while (1) { | 67 | set_thread_flag(TIF_RESTORE_SIGMASK); |
| 70 | current->state = TASK_INTERRUPTIBLE; | 68 | return -ERESTARTNOHAND; |
| 71 | schedule(); | ||
| 72 | if (do_signal(&saveset, ®s)) | ||
| 73 | return -EINTR; | ||
| 74 | } | ||
| 75 | } | 69 | } |
| 76 | #endif | 70 | #endif |
| 77 | 71 | ||
| @@ -79,7 +73,7 @@ save_static_function(sys_rt_sigsuspend); | |||
| 79 | __attribute_used__ noinline static int | 73 | __attribute_used__ noinline static int |
| 80 | _sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) | 74 | _sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) |
| 81 | { | 75 | { |
| 82 | sigset_t saveset, newset; | 76 | sigset_t newset; |
| 83 | sigset_t __user *unewset; | 77 | sigset_t __user *unewset; |
| 84 | size_t sigsetsize; | 78 | size_t sigsetsize; |
| 85 | 79 | ||
| @@ -94,19 +88,15 @@ _sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) | |||
| 94 | sigdelsetmask(&newset, ~_BLOCKABLE); | 88 | sigdelsetmask(&newset, ~_BLOCKABLE); |
| 95 | 89 | ||
| 96 | spin_lock_irq(¤t->sighand->siglock); | 90 | spin_lock_irq(¤t->sighand->siglock); |
| 97 | saveset = current->blocked; | 91 | current->saved_sigmask = current->blocked; |
| 98 | current->blocked = newset; | 92 | current->blocked = newset; |
| 99 | recalc_sigpending(); | 93 | recalc_sigpending(); |
| 100 | spin_unlock_irq(¤t->sighand->siglock); | 94 | spin_unlock_irq(¤t->sighand->siglock); |
| 101 | 95 | ||
| 102 | regs.regs[2] = EINTR; | 96 | current->state = TASK_INTERRUPTIBLE; |
| 103 | regs.regs[7] = 1; | 97 | schedule(); |
| 104 | while (1) { | 98 | set_thread_flag(TIF_RESTORE_SIGMASK); |
| 105 | current->state = TASK_INTERRUPTIBLE; | 99 | return -ERESTARTNOHAND; |
| 106 | schedule(); | ||
| 107 | if (do_signal(&saveset, ®s)) | ||
| 108 | return -EINTR; | ||
| 109 | } | ||
| 110 | } | 100 | } |
| 111 | 101 | ||
| 112 | #ifdef CONFIG_TRAD_SIGNALS | 102 | #ifdef CONFIG_TRAD_SIGNALS |
| @@ -315,11 +305,11 @@ int setup_frame(struct k_sigaction * ka, struct pt_regs *regs, | |||
| 315 | current->comm, current->pid, | 305 | current->comm, current->pid, |
| 316 | frame, regs->cp0_epc, frame->regs[31]); | 306 | frame, regs->cp0_epc, frame->regs[31]); |
| 317 | #endif | 307 | #endif |
| 318 | return 1; | 308 | return 0; |
| 319 | 309 | ||
| 320 | give_sigsegv: | 310 | give_sigsegv: |
| 321 | force_sigsegv(signr, current); | 311 | force_sigsegv(signr, current); |
| 322 | return 0; | 312 | return -EFAULT; |
| 323 | } | 313 | } |
| 324 | #endif | 314 | #endif |
| 325 | 315 | ||
| @@ -375,11 +365,11 @@ int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, | |||
| 375 | current->comm, current->pid, | 365 | current->comm, current->pid, |
| 376 | frame, regs->cp0_epc, regs->regs[31]); | 366 | frame, regs->cp0_epc, regs->regs[31]); |
| 377 | #endif | 367 | #endif |
| 378 | return 1; | 368 | return 0; |
| 379 | 369 | ||
| 380 | give_sigsegv: | 370 | give_sigsegv: |
| 381 | force_sigsegv(signr, current); | 371 | force_sigsegv(signr, current); |
| 382 | return 0; | 372 | return -EFAULT; |
| 383 | } | 373 | } |
| 384 | 374 | ||
| 385 | static inline int handle_signal(unsigned long sig, siginfo_t *info, | 375 | static inline int handle_signal(unsigned long sig, siginfo_t *info, |
| @@ -393,7 +383,7 @@ static inline int handle_signal(unsigned long sig, siginfo_t *info, | |||
| 393 | regs->regs[2] = EINTR; | 383 | regs->regs[2] = EINTR; |
| 394 | break; | 384 | break; |
| 395 | case ERESTARTSYS: | 385 | case ERESTARTSYS: |
| 396 | if(!(ka->sa.sa_flags & SA_RESTART)) { | 386 | if (!(ka->sa.sa_flags & SA_RESTART)) { |
| 397 | regs->regs[2] = EINTR; | 387 | regs->regs[2] = EINTR; |
| 398 | break; | 388 | break; |
| 399 | } | 389 | } |
| @@ -420,9 +410,10 @@ static inline int handle_signal(unsigned long sig, siginfo_t *info, | |||
| 420 | return ret; | 410 | return ret; |
| 421 | } | 411 | } |
| 422 | 412 | ||
| 423 | int do_signal(sigset_t *oldset, struct pt_regs *regs) | 413 | void do_signal(struct pt_regs *regs) |
| 424 | { | 414 | { |
| 425 | struct k_sigaction ka; | 415 | struct k_sigaction ka; |
| 416 | sigset_t *oldset; | ||
| 426 | siginfo_t info; | 417 | siginfo_t info; |
| 427 | int signr; | 418 | int signr; |
| 428 | 419 | ||
| @@ -432,17 +423,31 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) | |||
| 432 | * if so. | 423 | * if so. |
| 433 | */ | 424 | */ |
| 434 | if (!user_mode(regs)) | 425 | if (!user_mode(regs)) |
| 435 | return 1; | 426 | return; |
| 436 | 427 | ||
| 437 | if (try_to_freeze()) | 428 | if (try_to_freeze()) |
| 438 | goto no_signal; | 429 | goto no_signal; |
| 439 | 430 | ||
| 440 | if (!oldset) | 431 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
| 432 | oldset = ¤t->saved_sigmask; | ||
| 433 | else | ||
| 441 | oldset = ¤t->blocked; | 434 | oldset = ¤t->blocked; |
| 442 | 435 | ||
| 436 | |||
| 443 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 437 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
| 444 | if (signr > 0) | 438 | if (signr > 0) { |
| 445 | return handle_signal(signr, &info, &ka, oldset, regs); | 439 | /* Whee! Actually deliver the signal. */ |
| 440 | if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { | ||
| 441 | /* | ||
| 442 | * A signal was successfully delivered; the saved | ||
| 443 | * sigmask will have been stored in the signal frame, | ||
| 444 | * and will be restored by sigreturn, so we can simply | ||
| 445 | * clear the TIF_RESTORE_SIGMASK flag. | ||
| 446 | */ | ||
| 447 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
| 448 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 449 | } | ||
| 450 | } | ||
| 446 | 451 | ||
| 447 | no_signal: | 452 | no_signal: |
| 448 | /* | 453 | /* |
| @@ -463,18 +468,25 @@ no_signal: | |||
| 463 | regs->cp0_epc -= 4; | 468 | regs->cp0_epc -= 4; |
| 464 | } | 469 | } |
| 465 | } | 470 | } |
| 466 | return 0; | 471 | |
| 472 | /* | ||
| 473 | * If there's no signal to deliver, we just put the saved sigmask | ||
| 474 | * back | ||
| 475 | */ | ||
| 476 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
| 477 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 478 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
| 479 | } | ||
| 467 | } | 480 | } |
| 468 | 481 | ||
| 469 | /* | 482 | /* |
| 470 | * notification of userspace execution resumption | 483 | * notification of userspace execution resumption |
| 471 | * - triggered by current->work.notify_resume | 484 | * - triggered by the TIF_WORK_MASK flags |
| 472 | */ | 485 | */ |
| 473 | asmlinkage void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, | 486 | asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, |
| 474 | __u32 thread_info_flags) | 487 | __u32 thread_info_flags) |
| 475 | { | 488 | { |
| 476 | /* deal with pending signal delivery */ | 489 | /* deal with pending signal delivery */ |
| 477 | if (thread_info_flags & _TIF_SIGPENDING) { | 490 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) |
| 478 | current->thread.abi->do_signal(oldset, regs); | 491 | current->thread.abi->do_signal(regs); |
| 479 | } | ||
| 480 | } | 492 | } |
