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 | } |