diff options
Diffstat (limited to 'arch/mips/kernel/signal32.c')
| -rw-r--r-- | arch/mips/kernel/signal32.c | 74 |
1 files changed, 43 insertions, 31 deletions
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 8a8b8dd90417..237cd8a2cd32 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | * for more details. | 4 | * for more details. |
| 5 | * | 5 | * |
| 6 | * Copyright (C) 1991, 1992 Linus Torvalds | 6 | * Copyright (C) 1991, 1992 Linus Torvalds |
| 7 | * Copyright (C) 1994 - 2000 Ralf Baechle | 7 | * Copyright (C) 1994 - 2000, 2006 Ralf Baechle |
| 8 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. | 8 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. |
| 9 | */ | 9 | */ |
| 10 | #include <linux/cache.h> | 10 | #include <linux/cache.h> |
| @@ -106,8 +106,6 @@ typedef struct compat_siginfo { | |||
| 106 | 106 | ||
| 107 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 107 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
| 108 | 108 | ||
| 109 | extern int do_signal32(sigset_t *oldset, struct pt_regs *regs); | ||
| 110 | |||
| 111 | /* 32-bit compatibility types */ | 109 | /* 32-bit compatibility types */ |
| 112 | 110 | ||
| 113 | #define _NSIG_BPW32 32 | 111 | #define _NSIG_BPW32 32 |
| @@ -198,7 +196,7 @@ __attribute_used__ noinline static int | |||
| 198 | _sys32_sigsuspend(nabi_no_regargs struct pt_regs regs) | 196 | _sys32_sigsuspend(nabi_no_regargs struct pt_regs regs) |
| 199 | { | 197 | { |
| 200 | compat_sigset_t *uset; | 198 | compat_sigset_t *uset; |
| 201 | sigset_t newset, saveset; | 199 | sigset_t newset; |
| 202 | 200 | ||
| 203 | uset = (compat_sigset_t *) regs.regs[4]; | 201 | uset = (compat_sigset_t *) regs.regs[4]; |
| 204 | if (get_sigset(&newset, uset)) | 202 | if (get_sigset(&newset, uset)) |
| @@ -206,19 +204,15 @@ _sys32_sigsuspend(nabi_no_regargs struct pt_regs regs) | |||
| 206 | sigdelsetmask(&newset, ~_BLOCKABLE); | 204 | sigdelsetmask(&newset, ~_BLOCKABLE); |
| 207 | 205 | ||
| 208 | spin_lock_irq(¤t->sighand->siglock); | 206 | spin_lock_irq(¤t->sighand->siglock); |
| 209 | saveset = current->blocked; | 207 | current->saved_sigmask = current->blocked; |
| 210 | current->blocked = newset; | 208 | current->blocked = newset; |
| 211 | recalc_sigpending(); | 209 | recalc_sigpending(); |
| 212 | spin_unlock_irq(¤t->sighand->siglock); | 210 | spin_unlock_irq(¤t->sighand->siglock); |
| 213 | 211 | ||
| 214 | regs.regs[2] = EINTR; | 212 | current->state = TASK_INTERRUPTIBLE; |
| 215 | regs.regs[7] = 1; | 213 | schedule(); |
| 216 | while (1) { | 214 | set_thread_flag(TIF_RESTORE_SIGMASK); |
| 217 | current->state = TASK_INTERRUPTIBLE; | 215 | return -ERESTARTNOHAND; |
| 218 | schedule(); | ||
| 219 | if (do_signal32(&saveset, ®s)) | ||
| 220 | return -EINTR; | ||
| 221 | } | ||
| 222 | } | 216 | } |
| 223 | 217 | ||
| 224 | save_static_function(sys32_rt_sigsuspend); | 218 | save_static_function(sys32_rt_sigsuspend); |
| @@ -226,8 +220,8 @@ __attribute_used__ noinline static int | |||
| 226 | _sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) | 220 | _sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) |
| 227 | { | 221 | { |
| 228 | compat_sigset_t *uset; | 222 | compat_sigset_t *uset; |
| 229 | sigset_t newset, saveset; | 223 | sigset_t newset; |
| 230 | size_t sigsetsize; | 224 | size_t sigsetsize; |
| 231 | 225 | ||
| 232 | /* XXX Don't preclude handling different sized sigset_t's. */ | 226 | /* XXX Don't preclude handling different sized sigset_t's. */ |
| 233 | sigsetsize = regs.regs[5]; | 227 | sigsetsize = regs.regs[5]; |
| @@ -240,19 +234,15 @@ _sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) | |||
| 240 | sigdelsetmask(&newset, ~_BLOCKABLE); | 234 | sigdelsetmask(&newset, ~_BLOCKABLE); |
| 241 | 235 | ||
| 242 | spin_lock_irq(¤t->sighand->siglock); | 236 | spin_lock_irq(¤t->sighand->siglock); |
| 243 | saveset = current->blocked; | 237 | current->saved_sigmask = current->blocked; |
| 244 | current->blocked = newset; | 238 | current->blocked = newset; |
| 245 | recalc_sigpending(); | 239 | recalc_sigpending(); |
| 246 | spin_unlock_irq(¤t->sighand->siglock); | 240 | spin_unlock_irq(¤t->sighand->siglock); |
| 247 | 241 | ||
| 248 | regs.regs[2] = EINTR; | 242 | current->state = TASK_INTERRUPTIBLE; |
| 249 | regs.regs[7] = 1; | 243 | schedule(); |
| 250 | while (1) { | 244 | set_thread_flag(TIF_RESTORE_SIGMASK); |
| 251 | current->state = TASK_INTERRUPTIBLE; | 245 | return -ERESTARTNOHAND; |
| 252 | schedule(); | ||
| 253 | if (do_signal32(&saveset, ®s)) | ||
| 254 | return -EINTR; | ||
| 255 | } | ||
| 256 | } | 246 | } |
| 257 | 247 | ||
| 258 | asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act, | 248 | asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act, |
| @@ -783,7 +773,7 @@ static inline int handle_signal(unsigned long sig, siginfo_t *info, | |||
| 783 | regs->regs[2] = EINTR; | 773 | regs->regs[2] = EINTR; |
| 784 | break; | 774 | break; |
| 785 | case ERESTARTSYS: | 775 | case ERESTARTSYS: |
| 786 | if(!(ka->sa.sa_flags & SA_RESTART)) { | 776 | if (!(ka->sa.sa_flags & SA_RESTART)) { |
| 787 | regs->regs[2] = EINTR; | 777 | regs->regs[2] = EINTR; |
| 788 | break; | 778 | break; |
| 789 | } | 779 | } |
| @@ -810,9 +800,10 @@ static inline int handle_signal(unsigned long sig, siginfo_t *info, | |||
| 810 | return ret; | 800 | return ret; |
| 811 | } | 801 | } |
| 812 | 802 | ||
| 813 | int do_signal32(sigset_t *oldset, struct pt_regs *regs) | 803 | void do_signal32(struct pt_regs *regs) |
| 814 | { | 804 | { |
| 815 | struct k_sigaction ka; | 805 | struct k_sigaction ka; |
| 806 | sigset_t *oldset; | ||
| 816 | siginfo_t info; | 807 | siginfo_t info; |
| 817 | int signr; | 808 | int signr; |
| 818 | 809 | ||
| @@ -822,17 +813,30 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs) | |||
| 822 | * if so. | 813 | * if so. |
| 823 | */ | 814 | */ |
| 824 | if (!user_mode(regs)) | 815 | if (!user_mode(regs)) |
| 825 | return 1; | 816 | return; |
| 826 | 817 | ||
| 827 | if (try_to_freeze()) | 818 | if (try_to_freeze()) |
| 828 | goto no_signal; | 819 | goto no_signal; |
| 829 | 820 | ||
| 830 | if (!oldset) | 821 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
| 822 | oldset = ¤t->saved_sigmask; | ||
| 823 | else | ||
| 831 | oldset = ¤t->blocked; | 824 | oldset = ¤t->blocked; |
| 832 | 825 | ||
| 833 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 826 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
| 834 | if (signr > 0) | 827 | if (signr > 0) { |
| 835 | return handle_signal(signr, &info, &ka, oldset, regs); | 828 | /* Whee! Actually deliver the signal. */ |
| 829 | if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { | ||
| 830 | /* | ||
| 831 | * A signal was successfully delivered; the saved | ||
| 832 | * sigmask will have been stored in the signal frame, | ||
| 833 | * and will be restored by sigreturn, so we can simply | ||
| 834 | * clear the TIF_RESTORE_SIGMASK flag. | ||
| 835 | */ | ||
| 836 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
| 837 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 838 | } | ||
| 839 | } | ||
| 836 | 840 | ||
| 837 | no_signal: | 841 | no_signal: |
| 838 | /* | 842 | /* |
| @@ -853,7 +857,15 @@ no_signal: | |||
| 853 | regs->cp0_epc -= 4; | 857 | regs->cp0_epc -= 4; |
| 854 | } | 858 | } |
| 855 | } | 859 | } |
| 856 | return 0; | 860 | |
| 861 | /* | ||
| 862 | * If there's no signal to deliver, we just put the saved sigmask | ||
| 863 | * back | ||
| 864 | */ | ||
| 865 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
| 866 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 867 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
| 868 | } | ||
| 857 | } | 869 | } |
| 858 | 870 | ||
| 859 | asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 *act, | 871 | asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 *act, |
