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... */ |