diff options
Diffstat (limited to 'arch/mips/kernel/irixsig.c')
| -rw-r--r-- | arch/mips/kernel/irixsig.c | 63 |
1 files changed, 44 insertions, 19 deletions
diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c index 676e868d26fb..2132485caa74 100644 --- a/arch/mips/kernel/irixsig.c +++ b/arch/mips/kernel/irixsig.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | 17 | ||
| 18 | #include <asm/ptrace.h> | 18 | #include <asm/ptrace.h> |
| 19 | #include <asm/uaccess.h> | 19 | #include <asm/uaccess.h> |
| 20 | #include <asm/unistd.h> | ||
| 20 | 21 | ||
| 21 | #undef DEBUG_SIG | 22 | #undef DEBUG_SIG |
| 22 | 23 | ||
| @@ -172,11 +173,12 @@ static inline int handle_signal(unsigned long sig, siginfo_t *info, | |||
| 172 | return ret; | 173 | return ret; |
| 173 | } | 174 | } |
| 174 | 175 | ||
| 175 | asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs) | 176 | void do_irix_signal(struct pt_regs *regs) |
| 176 | { | 177 | { |
| 177 | struct k_sigaction ka; | 178 | struct k_sigaction ka; |
| 178 | siginfo_t info; | 179 | siginfo_t info; |
| 179 | int signr; | 180 | int signr; |
| 181 | sigset_t *oldset; | ||
| 180 | 182 | ||
| 181 | /* | 183 | /* |
| 182 | * We want the common case to go fast, which is why we may in certain | 184 | * We want the common case to go fast, which is why we may in certain |
| @@ -184,19 +186,28 @@ asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs) | |||
| 184 | * if so. | 186 | * if so. |
| 185 | */ | 187 | */ |
| 186 | if (!user_mode(regs)) | 188 | if (!user_mode(regs)) |
| 187 | return 1; | 189 | return; |
| 188 | 190 | ||
| 189 | if (try_to_freeze()) | 191 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
| 190 | goto no_signal; | 192 | oldset = ¤t->saved_sigmask; |
| 191 | 193 | else | |
| 192 | if (!oldset) | ||
| 193 | oldset = ¤t->blocked; | 194 | oldset = ¤t->blocked; |
| 194 | 195 | ||
| 195 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 196 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
| 196 | if (signr > 0) | 197 | if (signr > 0) { |
| 197 | return handle_signal(signr, &info, &ka, oldset, regs); | 198 | /* Whee! Actually deliver the signal. */ |
| 199 | if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { | ||
| 200 | /* a signal was successfully delivered; the saved | ||
| 201 | * sigmask will have been stored in the signal frame, | ||
| 202 | * and will be restored by sigreturn, so we can simply | ||
| 203 | * clear the TIF_RESTORE_SIGMASK flag */ | ||
| 204 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
| 205 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 206 | } | ||
| 207 | |||
| 208 | return; | ||
| 209 | } | ||
| 198 | 210 | ||
| 199 | no_signal: | ||
| 200 | /* | 211 | /* |
| 201 | * Who's code doesn't conform to the restartable syscall convention | 212 | * Who's code doesn't conform to the restartable syscall convention |
| 202 | * dies here!!! The li instruction, a single machine instruction, | 213 | * dies here!!! The li instruction, a single machine instruction, |
| @@ -208,8 +219,22 @@ no_signal: | |||
| 208 | regs->regs[2] == ERESTARTNOINTR) { | 219 | regs->regs[2] == ERESTARTNOINTR) { |
| 209 | regs->cp0_epc -= 8; | 220 | regs->cp0_epc -= 8; |
| 210 | } | 221 | } |
| 222 | if (regs->regs[2] == ERESTART_RESTARTBLOCK) { | ||
| 223 | regs->regs[2] = __NR_restart_syscall; | ||
| 224 | regs->regs[7] = regs->regs[26]; | ||
| 225 | regs->cp0_epc -= 4; | ||
| 226 | } | ||
| 227 | regs->regs[0] = 0; /* Don't deal with this again. */ | ||
| 228 | } | ||
| 229 | |||
| 230 | /* | ||
| 231 | * If there's no signal to deliver, we just put the saved sigmask | ||
| 232 | * back | ||
| 233 | */ | ||
| 234 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
| 235 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 236 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
| 211 | } | 237 | } |
| 212 | return 0; | ||
| 213 | } | 238 | } |
| 214 | 239 | ||
| 215 | asmlinkage void | 240 | asmlinkage void |
| @@ -298,6 +323,9 @@ struct sigact_irix5 { | |||
| 298 | int _unused0[2]; | 323 | int _unused0[2]; |
| 299 | }; | 324 | }; |
| 300 | 325 | ||
| 326 | #define SIG_SETMASK32 256 /* Goodie from SGI for BSD compatibility: | ||
| 327 | set only the low 32 bit of the sigset. */ | ||
| 328 | |||
| 301 | #ifdef DEBUG_SIG | 329 | #ifdef DEBUG_SIG |
| 302 | static inline void dump_sigact_irix5(struct sigact_irix5 *p) | 330 | static inline void dump_sigact_irix5(struct sigact_irix5 *p) |
| 303 | { | 331 | { |
| @@ -413,7 +441,7 @@ asmlinkage int irix_sigprocmask(int how, irix_sigset_t __user *new, | |||
| 413 | 441 | ||
| 414 | asmlinkage int irix_sigsuspend(struct pt_regs *regs) | 442 | asmlinkage int irix_sigsuspend(struct pt_regs *regs) |
| 415 | { | 443 | { |
| 416 | sigset_t saveset, newset; | 444 | sigset_t newset; |
| 417 | sigset_t __user *uset; | 445 | sigset_t __user *uset; |
| 418 | 446 | ||
| 419 | uset = (sigset_t __user *) regs->regs[4]; | 447 | uset = (sigset_t __user *) regs->regs[4]; |
| @@ -422,18 +450,15 @@ asmlinkage int irix_sigsuspend(struct pt_regs *regs) | |||
| 422 | sigdelsetmask(&newset, ~_BLOCKABLE); | 450 | sigdelsetmask(&newset, ~_BLOCKABLE); |
| 423 | 451 | ||
| 424 | spin_lock_irq(¤t->sighand->siglock); | 452 | spin_lock_irq(¤t->sighand->siglock); |
| 425 | saveset = current->blocked; | 453 | current->saved_sigmask = current->blocked; |
| 426 | current->blocked = newset; | 454 | current->blocked = newset; |
| 427 | recalc_sigpending(); | 455 | recalc_sigpending(); |
| 428 | spin_unlock_irq(¤t->sighand->siglock); | 456 | spin_unlock_irq(¤t->sighand->siglock); |
| 429 | 457 | ||
| 430 | regs->regs[2] = -EINTR; | 458 | current->state = TASK_INTERRUPTIBLE; |
| 431 | while (1) { | 459 | schedule(); |
| 432 | current->state = TASK_INTERRUPTIBLE; | 460 | set_thread_flag(TIF_RESTORE_SIGMASK); |
| 433 | schedule(); | 461 | return -ERESTARTNOHAND; |
| 434 | if (do_irix_signal(&saveset, regs)) | ||
| 435 | return -EINTR; | ||
| 436 | } | ||
| 437 | } | 462 | } |
| 438 | 463 | ||
| 439 | /* hate hate hate... */ | 464 | /* hate hate hate... */ |
