diff options
-rw-r--r-- | arch/mips/kernel/irixsig.c | 55 |
1 files changed, 40 insertions, 15 deletions
diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c index e6f40609ba6a..052ea15f1e80 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,14 +186,27 @@ 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 (!oldset) | 191 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
192 | oldset = ¤t->saved_sigmask; | ||
193 | else | ||
190 | oldset = ¤t->blocked; | 194 | oldset = ¤t->blocked; |
191 | 195 | ||
192 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 196 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
193 | if (signr > 0) | 197 | if (signr > 0) { |
194 | 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 | } | ||
195 | 210 | ||
196 | /* | 211 | /* |
197 | * Who's code doesn't conform to the restartable syscall convention | 212 | * Who's code doesn't conform to the restartable syscall convention |
@@ -204,8 +219,21 @@ asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs) | |||
204 | regs->regs[2] == ERESTARTNOINTR) { | 219 | regs->regs[2] == ERESTARTNOINTR) { |
205 | regs->cp0_epc -= 8; | 220 | regs->cp0_epc -= 8; |
206 | } | 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 | } | ||
228 | |||
229 | /* | ||
230 | * If there's no signal to deliver, we just put the saved sigmask | ||
231 | * back | ||
232 | */ | ||
233 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
234 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
235 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
207 | } | 236 | } |
208 | return 0; | ||
209 | } | 237 | } |
210 | 238 | ||
211 | asmlinkage void | 239 | asmlinkage void |
@@ -409,7 +437,7 @@ asmlinkage int irix_sigprocmask(int how, irix_sigset_t __user *new, | |||
409 | 437 | ||
410 | asmlinkage int irix_sigsuspend(struct pt_regs *regs) | 438 | asmlinkage int irix_sigsuspend(struct pt_regs *regs) |
411 | { | 439 | { |
412 | sigset_t saveset, newset; | 440 | sigset_t newset; |
413 | sigset_t __user *uset; | 441 | sigset_t __user *uset; |
414 | 442 | ||
415 | uset = (sigset_t __user *) regs->regs[4]; | 443 | uset = (sigset_t __user *) regs->regs[4]; |
@@ -418,18 +446,15 @@ asmlinkage int irix_sigsuspend(struct pt_regs *regs) | |||
418 | sigdelsetmask(&newset, ~_BLOCKABLE); | 446 | sigdelsetmask(&newset, ~_BLOCKABLE); |
419 | 447 | ||
420 | spin_lock_irq(¤t->sighand->siglock); | 448 | spin_lock_irq(¤t->sighand->siglock); |
421 | saveset = current->blocked; | 449 | current->saved_sigmask = current->blocked; |
422 | current->blocked = newset; | 450 | current->blocked = newset; |
423 | recalc_sigpending(); | 451 | recalc_sigpending(); |
424 | spin_unlock_irq(¤t->sighand->siglock); | 452 | spin_unlock_irq(¤t->sighand->siglock); |
425 | 453 | ||
426 | regs->regs[2] = -EINTR; | 454 | current->state = TASK_INTERRUPTIBLE; |
427 | while (1) { | 455 | schedule(); |
428 | current->state = TASK_INTERRUPTIBLE; | 456 | set_thread_flag(TIF_RESTORE_SIGMASK); |
429 | schedule(); | 457 | return -ERESTARTNOHAND; |
430 | if (do_irix_signal(&saveset, regs)) | ||
431 | return -EINTR; | ||
432 | } | ||
433 | } | 458 | } |
434 | 459 | ||
435 | /* hate hate hate... */ | 460 | /* hate hate hate... */ |