diff options
| author | Jesper Nilsson <jesper.nilsson@axis.com> | 2008-01-14 03:55:22 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-01-14 11:52:23 -0500 |
| commit | a4858d4dab4580ec8b1fb7576f91522b6962502c (patch) | |
| tree | d3b356a3f021bdffbef5d3803264b0a25a8bb1ac /arch/cris | |
| parent | 3ea0345be38555c6a1a04ed7e9c015a42e76bd0e (diff) | |
CRIS v10: correct do_signal to fix oops and clean up signal handling in general
This fixes a kernel panic on boot due to do_signal not being compatible
with it's callers.
- do_signal now returns void, and does not have the previous signal set
as a parameter.
- Remove sys_rt_sigsuspend, we can use the common one instead.
- Change sys_sigsuspend to be more like x86, don't call do_signal here.
- handle_signal, setup_frame and setup_rt_frame now return -EFAULT
if we've delivered a segfault, which is used by callers to perform
necessary cleanup.
- Break long lines, correct whitespace and formatting errors.
Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com>
Cc: Mikael Starvik <mikael.starvik@axis.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/cris')
| -rw-r--r-- | arch/cris/arch-v10/kernel/signal.c | 251 |
1 files changed, 112 insertions, 139 deletions
diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c index 41d4a5f932..b6be705c2a 100644 --- a/arch/cris/arch-v10/kernel/signal.c +++ b/arch/cris/arch-v10/kernel/signal.c | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | * | 7 | * |
| 8 | * Ideas also taken from arch/arm. | 8 | * Ideas also taken from arch/arm. |
| 9 | * | 9 | * |
| 10 | * Copyright (C) 2000, 2001 Axis Communications AB | 10 | * Copyright (C) 2000-2007 Axis Communications AB |
| 11 | * | 11 | * |
| 12 | * Authors: Bjorn Wesen (bjornw@axis.com) | 12 | * Authors: Bjorn Wesen (bjornw@axis.com) |
| 13 | * | 13 | * |
| @@ -40,84 +40,30 @@ | |||
| 40 | */ | 40 | */ |
| 41 | #define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->irp -= 2; | 41 | #define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->irp -= 2; |
| 42 | 42 | ||
| 43 | int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs); | 43 | void do_signal(int canrestart, struct pt_regs *regs); |
| 44 | 44 | ||
| 45 | /* | 45 | /* |
| 46 | * Atomically swap in the new signal mask, and wait for a signal. Define | 46 | * Atomically swap in the new signal mask, and wait for a signal. Define |
| 47 | * dummy arguments to be able to reach the regs argument. (Note that this | 47 | * dummy arguments to be able to reach the regs argument. (Note that this |
| 48 | * arrangement relies on old_sigset_t occupying one register.) | 48 | * arrangement relies on old_sigset_t occupying one register.) |
| 49 | */ | 49 | */ |
| 50 | int | 50 | int sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, |
| 51 | sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, | 51 | long srp, struct pt_regs *regs) |
| 52 | long srp, struct pt_regs *regs) | ||
| 53 | { | 52 | { |
| 54 | sigset_t saveset; | ||
| 55 | |||
| 56 | mask &= _BLOCKABLE; | 53 | mask &= _BLOCKABLE; |
| 57 | spin_lock_irq(¤t->sighand->siglock); | 54 | spin_lock_irq(¤t->sighand->siglock); |
| 58 | saveset = current->blocked; | 55 | current->saved_sigmask = current->blocked; |
| 59 | siginitset(¤t->blocked, mask); | 56 | siginitset(¤t->blocked, mask); |
| 60 | recalc_sigpending(); | 57 | recalc_sigpending(); |
| 61 | spin_unlock_irq(¤t->sighand->siglock); | 58 | spin_unlock_irq(¤t->sighand->siglock); |
| 62 | 59 | current->state = TASK_INTERRUPTIBLE; | |
| 63 | regs->r10 = -EINTR; | 60 | schedule(); |
| 64 | while (1) { | 61 | set_thread_flag(TIF_RESTORE_SIGMASK); |
| 65 | current->state = TASK_INTERRUPTIBLE; | 62 | return -ERESTARTNOHAND; |
| 66 | schedule(); | ||
| 67 | if (do_signal(0, &saveset, regs)) | ||
| 68 | /* We will get here twice: once to call the signal | ||
| 69 | handler, then again to return from the | ||
| 70 | sigsuspend system call. When calling the | ||
| 71 | signal handler, R10 holds the signal number as | ||
| 72 | set through do_signal. The sigsuspend call | ||
| 73 | will return with the restored value set above; | ||
| 74 | always -EINTR. */ | ||
| 75 | return regs->r10; | ||
| 76 | } | ||
| 77 | } | 63 | } |
| 78 | 64 | ||
| 79 | /* Define dummy arguments to be able to reach the regs argument. (Note that | 65 | int sys_sigaction(int sig, const struct old_sigaction __user *act, |
| 80 | * this arrangement relies on size_t occupying one register.) | 66 | struct old_sigaction *oact) |
| 81 | */ | ||
| 82 | int | ||
| 83 | sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13, | ||
| 84 | long mof, long srp, struct pt_regs *regs) | ||
| 85 | { | ||
| 86 | sigset_t saveset, newset; | ||
| 87 | |||
| 88 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
| 89 | if (sigsetsize != sizeof(sigset_t)) | ||
| 90 | return -EINVAL; | ||
| 91 | |||
| 92 | if (copy_from_user(&newset, unewset, sizeof(newset))) | ||
| 93 | return -EFAULT; | ||
| 94 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
| 95 | |||
| 96 | spin_lock_irq(¤t->sighand->siglock); | ||
| 97 | saveset = current->blocked; | ||
| 98 | current->blocked = newset; | ||
| 99 | recalc_sigpending(); | ||
| 100 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 101 | |||
| 102 | regs->r10 = -EINTR; | ||
| 103 | while (1) { | ||
| 104 | current->state = TASK_INTERRUPTIBLE; | ||
| 105 | schedule(); | ||
| 106 | if (do_signal(0, &saveset, regs)) | ||
| 107 | /* We will get here twice: once to call the signal | ||
| 108 | handler, then again to return from the | ||
| 109 | sigsuspend system call. When calling the | ||
| 110 | signal handler, R10 holds the signal number as | ||
| 111 | set through do_signal. The sigsuspend call | ||
| 112 | will return with the restored value set above; | ||
| 113 | always -EINTR. */ | ||
| 114 | return regs->r10; | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | int | ||
| 119 | sys_sigaction(int sig, const struct old_sigaction __user *act, | ||
| 120 | struct old_sigaction *oact) | ||
| 121 | { | 67 | { |
| 122 | struct k_sigaction new_ka, old_ka; | 68 | struct k_sigaction new_ka, old_ka; |
| 123 | int ret; | 69 | int ret; |
| @@ -147,8 +93,7 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, | |||
| 147 | return ret; | 93 | return ret; |
| 148 | } | 94 | } |
| 149 | 95 | ||
| 150 | int | 96 | int sys_sigaltstack(const stack_t *uss, stack_t __user *uoss) |
| 151 | sys_sigaltstack(const stack_t *uss, stack_t __user *uoss) | ||
| 152 | { | 97 | { |
| 153 | return do_sigaltstack(uss, uoss, rdusp()); | 98 | return do_sigaltstack(uss, uoss, rdusp()); |
| 154 | } | 99 | } |
| @@ -205,7 +150,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | |||
| 205 | 150 | ||
| 206 | /* TODO: the other ports use regs->orig_XX to disable syscall checks | 151 | /* TODO: the other ports use regs->orig_XX to disable syscall checks |
| 207 | * after this completes, but we don't use that mechanism. maybe we can | 152 | * after this completes, but we don't use that mechanism. maybe we can |
| 208 | * use it now ? | 153 | * use it now ? |
| 209 | */ | 154 | */ |
| 210 | 155 | ||
| 211 | return err; | 156 | return err; |
| @@ -216,7 +161,7 @@ badframe: | |||
| 216 | 161 | ||
| 217 | /* Define dummy arguments to be able to reach the regs argument. */ | 162 | /* Define dummy arguments to be able to reach the regs argument. */ |
| 218 | 163 | ||
| 219 | asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, | 164 | asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, |
| 220 | long srp, struct pt_regs *regs) | 165 | long srp, struct pt_regs *regs) |
| 221 | { | 166 | { |
| 222 | struct sigframe __user *frame = (struct sigframe *)rdusp(); | 167 | struct sigframe __user *frame = (struct sigframe *)rdusp(); |
| @@ -243,7 +188,7 @@ asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, | |||
| 243 | current->blocked = set; | 188 | current->blocked = set; |
| 244 | recalc_sigpending(); | 189 | recalc_sigpending(); |
| 245 | spin_unlock_irq(¤t->sighand->siglock); | 190 | spin_unlock_irq(¤t->sighand->siglock); |
| 246 | 191 | ||
| 247 | if (restore_sigcontext(regs, &frame->sc)) | 192 | if (restore_sigcontext(regs, &frame->sc)) |
| 248 | goto badframe; | 193 | goto badframe; |
| 249 | 194 | ||
| @@ -254,11 +199,11 @@ asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, | |||
| 254 | badframe: | 199 | badframe: |
| 255 | force_sig(SIGSEGV, current); | 200 | force_sig(SIGSEGV, current); |
| 256 | return 0; | 201 | return 0; |
| 257 | } | 202 | } |
| 258 | 203 | ||
| 259 | /* Define dummy arguments to be able to reach the regs argument. */ | 204 | /* Define dummy arguments to be able to reach the regs argument. */ |
| 260 | 205 | ||
| 261 | asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, | 206 | asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, |
| 262 | long mof, long srp, struct pt_regs *regs) | 207 | long mof, long srp, struct pt_regs *regs) |
| 263 | { | 208 | { |
| 264 | struct rt_sigframe __user *frame = (struct rt_sigframe *)rdusp(); | 209 | struct rt_sigframe __user *frame = (struct rt_sigframe *)rdusp(); |
| @@ -282,7 +227,7 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, | |||
| 282 | current->blocked = set; | 227 | current->blocked = set; |
| 283 | recalc_sigpending(); | 228 | recalc_sigpending(); |
| 284 | spin_unlock_irq(¤t->sighand->siglock); | 229 | spin_unlock_irq(¤t->sighand->siglock); |
| 285 | 230 | ||
| 286 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) | 231 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) |
| 287 | goto badframe; | 232 | goto badframe; |
| 288 | 233 | ||
| @@ -294,14 +239,14 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, | |||
| 294 | badframe: | 239 | badframe: |
| 295 | force_sig(SIGSEGV, current); | 240 | force_sig(SIGSEGV, current); |
| 296 | return 0; | 241 | return 0; |
| 297 | } | 242 | } |
| 298 | 243 | ||
| 299 | /* | 244 | /* |
| 300 | * Set up a signal frame. | 245 | * Set up a signal frame. |
| 301 | */ | 246 | */ |
| 302 | 247 | ||
| 303 | static int | 248 | static int setup_sigcontext(struct sigcontext __user *sc, |
| 304 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask) | 249 | struct pt_regs *regs, unsigned long mask) |
| 305 | { | 250 | { |
| 306 | int err = 0; | 251 | int err = 0; |
| 307 | unsigned long usp = rdusp(); | 252 | unsigned long usp = rdusp(); |
| @@ -324,10 +269,11 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned lo | |||
| 324 | return err; | 269 | return err; |
| 325 | } | 270 | } |
| 326 | 271 | ||
| 327 | /* figure out where we want to put the new signal frame - usually on the stack */ | 272 | /* Figure out where we want to put the new signal frame |
| 273 | * - usually on the stack. */ | ||
| 328 | 274 | ||
| 329 | static inline void __user * | 275 | static inline void __user * |
| 330 | get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) | 276 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) |
| 331 | { | 277 | { |
| 332 | unsigned long sp = rdusp(); | 278 | unsigned long sp = rdusp(); |
| 333 | 279 | ||
| @@ -345,15 +291,15 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) | |||
| 345 | } | 291 | } |
| 346 | 292 | ||
| 347 | /* grab and setup a signal frame. | 293 | /* grab and setup a signal frame. |
| 348 | * | 294 | * |
| 349 | * basically we stack a lot of state info, and arrange for the | 295 | * basically we stack a lot of state info, and arrange for the |
| 350 | * user-mode program to return to the kernel using either a | 296 | * user-mode program to return to the kernel using either a |
| 351 | * trampoline which performs the syscall sigreturn, or a provided | 297 | * trampoline which performs the syscall sigreturn, or a provided |
| 352 | * user-mode trampoline. | 298 | * user-mode trampoline. |
| 353 | */ | 299 | */ |
| 354 | 300 | ||
| 355 | static void setup_frame(int sig, struct k_sigaction *ka, | 301 | static int setup_frame(int sig, struct k_sigaction *ka, |
| 356 | sigset_t *set, struct pt_regs * regs) | 302 | sigset_t *set, struct pt_regs *regs) |
| 357 | { | 303 | { |
| 358 | struct sigframe __user *frame; | 304 | struct sigframe __user *frame; |
| 359 | unsigned long return_ip; | 305 | unsigned long return_ip; |
| @@ -401,14 +347,15 @@ static void setup_frame(int sig, struct k_sigaction *ka, | |||
| 401 | 347 | ||
| 402 | wrusp((unsigned long)frame); | 348 | wrusp((unsigned long)frame); |
| 403 | 349 | ||
| 404 | return; | 350 | return 0; |
| 405 | 351 | ||
| 406 | give_sigsegv: | 352 | give_sigsegv: |
| 407 | force_sigsegv(sig, current); | 353 | force_sigsegv(sig, current); |
| 354 | return -EFAULT; | ||
| 408 | } | 355 | } |
| 409 | 356 | ||
| 410 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 357 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
| 411 | sigset_t *set, struct pt_regs * regs) | 358 | sigset_t *set, struct pt_regs *regs) |
| 412 | { | 359 | { |
| 413 | struct rt_sigframe __user *frame; | 360 | struct rt_sigframe __user *frame; |
| 414 | unsigned long return_ip; | 361 | unsigned long return_ip; |
| @@ -443,9 +390,10 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 443 | /* trampoline - the desired return ip is the retcode itself */ | 390 | /* trampoline - the desired return ip is the retcode itself */ |
| 444 | return_ip = (unsigned long)&frame->retcode; | 391 | return_ip = (unsigned long)&frame->retcode; |
| 445 | /* This is movu.w __NR_rt_sigreturn, r9; break 13; */ | 392 | /* This is movu.w __NR_rt_sigreturn, r9; break 13; */ |
| 446 | err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0)); | 393 | err |= __put_user(0x9c5f, (short __user *)(frame->retcode+0)); |
| 447 | err |= __put_user(__NR_rt_sigreturn, (short __user*)(frame->retcode+2)); | 394 | err |= __put_user(__NR_rt_sigreturn, |
| 448 | err |= __put_user(0xe93d, (short __user*)(frame->retcode+4)); | 395 | (short __user *)(frame->retcode+2)); |
| 396 | err |= __put_user(0xe93d, (short __user *)(frame->retcode+4)); | ||
| 449 | } | 397 | } |
| 450 | 398 | ||
| 451 | if (err) | 399 | if (err) |
| @@ -455,73 +403,81 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 455 | 403 | ||
| 456 | /* Set up registers for signal handler */ | 404 | /* Set up registers for signal handler */ |
| 457 | 405 | ||
| 458 | regs->irp = (unsigned long) ka->sa.sa_handler; /* what we enter NOW */ | 406 | /* What we enter NOW */ |
| 459 | regs->srp = return_ip; /* what we enter LATER */ | 407 | regs->irp = (unsigned long) ka->sa.sa_handler; |
| 460 | regs->r10 = sig; /* first argument is signo */ | 408 | /* What we enter LATER */ |
| 461 | regs->r11 = (unsigned long) &frame->info; /* second argument is (siginfo_t *) */ | 409 | regs->srp = return_ip; |
| 462 | regs->r12 = 0; /* third argument is unused */ | 410 | /* First argument is signo */ |
| 463 | 411 | regs->r10 = sig; | |
| 464 | /* actually move the usp to reflect the stacked frame */ | 412 | /* Second argument is (siginfo_t *) */ |
| 465 | 413 | regs->r11 = (unsigned long)&frame->info; | |
| 414 | /* Third argument is unused */ | ||
| 415 | regs->r12 = 0; | ||
| 416 | |||
| 417 | /* Actually move the usp to reflect the stacked frame */ | ||
| 466 | wrusp((unsigned long)frame); | 418 | wrusp((unsigned long)frame); |
| 467 | 419 | ||
| 468 | return; | 420 | return 0; |
| 469 | 421 | ||
| 470 | give_sigsegv: | 422 | give_sigsegv: |
| 471 | force_sigsegv(sig, current); | 423 | force_sigsegv(sig, current); |
| 424 | return -EFAULT; | ||
| 472 | } | 425 | } |
| 473 | 426 | ||
| 474 | /* | 427 | /* |
| 475 | * OK, we're invoking a handler | 428 | * OK, we're invoking a handler |
| 476 | */ | 429 | */ |
| 477 | 430 | ||
| 478 | static inline void | 431 | static inline int handle_signal(int canrestart, unsigned long sig, |
| 479 | handle_signal(int canrestart, unsigned long sig, | 432 | siginfo_t *info, struct k_sigaction *ka, |
| 480 | siginfo_t *info, struct k_sigaction *ka, | 433 | sigset_t *oldset, struct pt_regs *regs) |
| 481 | sigset_t *oldset, struct pt_regs * regs) | ||
| 482 | { | 434 | { |
| 435 | int ret; | ||
| 436 | |||
| 483 | /* Are we from a system call? */ | 437 | /* Are we from a system call? */ |
| 484 | if (canrestart) { | 438 | if (canrestart) { |
| 485 | /* If so, check system call restarting.. */ | 439 | /* If so, check system call restarting.. */ |
| 486 | switch (regs->r10) { | 440 | switch (regs->r10) { |
| 487 | case -ERESTART_RESTARTBLOCK: | 441 | case -ERESTART_RESTARTBLOCK: |
| 488 | case -ERESTARTNOHAND: | 442 | case -ERESTARTNOHAND: |
| 489 | /* ERESTARTNOHAND means that the syscall should only be | 443 | /* ERESTARTNOHAND means that the syscall should |
| 490 | restarted if there was no handler for the signal, and since | 444 | * only be restarted if there was no handler for |
| 491 | we only get here if there is a handler, we don't restart */ | 445 | * the signal, and since we only get here if there |
| 446 | * is a handler, we don't restart */ | ||
| 447 | regs->r10 = -EINTR; | ||
| 448 | break; | ||
| 449 | case -ERESTARTSYS: | ||
| 450 | /* ERESTARTSYS means to restart the syscall if | ||
| 451 | * there is no handler or the handler was | ||
| 452 | * registered with SA_RESTART */ | ||
| 453 | if (!(ka->sa.sa_flags & SA_RESTART)) { | ||
| 492 | regs->r10 = -EINTR; | 454 | regs->r10 = -EINTR; |
| 493 | break; | 455 | break; |
| 494 | 456 | } | |
| 495 | case -ERESTARTSYS: | 457 | /* fallthrough */ |
| 496 | /* ERESTARTSYS means to restart the syscall if there is no | 458 | case -ERESTARTNOINTR: |
| 497 | handler or the handler was registered with SA_RESTART */ | 459 | /* ERESTARTNOINTR means that the syscall should |
| 498 | if (!(ka->sa.sa_flags & SA_RESTART)) { | 460 | * be called again after the signal handler returns. */ |
| 499 | regs->r10 = -EINTR; | 461 | RESTART_CRIS_SYS(regs); |
| 500 | break; | ||
| 501 | } | ||
| 502 | /* fallthrough */ | ||
| 503 | case -ERESTARTNOINTR: | ||
| 504 | /* ERESTARTNOINTR means that the syscall should be called again | ||
| 505 | after the signal handler returns. */ | ||
| 506 | RESTART_CRIS_SYS(regs); | ||
| 507 | } | 462 | } |
| 508 | } | 463 | } |
| 509 | 464 | ||
| 510 | /* Set up the stack frame */ | 465 | /* Set up the stack frame */ |
| 511 | if (ka->sa.sa_flags & SA_SIGINFO) | 466 | if (ka->sa.sa_flags & SA_SIGINFO) |
| 512 | setup_rt_frame(sig, ka, info, oldset, regs); | 467 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |
| 513 | else | 468 | else |
| 514 | setup_frame(sig, ka, oldset, regs); | 469 | ret = setup_frame(sig, ka, oldset, regs); |
| 515 | 470 | ||
| 516 | if (ka->sa.sa_flags & SA_ONESHOT) | 471 | if (ret == 0) { |
| 517 | ka->sa.sa_handler = SIG_DFL; | 472 | spin_lock_irq(¤t->sighand->siglock); |
| 518 | 473 | sigorsets(¤t->blocked, ¤t->blocked, | |
| 519 | spin_lock_irq(¤t->sighand->siglock); | 474 | &ka->sa.sa_mask); |
| 520 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 475 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
| 521 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 476 | sigaddset(¤t->blocked, sig); |
| 522 | sigaddset(¤t->blocked,sig); | 477 | recalc_sigpending(); |
| 523 | recalc_sigpending(); | 478 | spin_unlock_irq(¤t->sighand->siglock); |
| 524 | spin_unlock_irq(¤t->sighand->siglock); | 479 | } |
| 480 | return ret; | ||
| 525 | } | 481 | } |
| 526 | 482 | ||
| 527 | /* | 483 | /* |
| @@ -536,11 +492,12 @@ handle_signal(int canrestart, unsigned long sig, | |||
| 536 | * mode below. | 492 | * mode below. |
| 537 | */ | 493 | */ |
| 538 | 494 | ||
| 539 | int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) | 495 | void do_signal(int canrestart, struct pt_regs *regs) |
| 540 | { | 496 | { |
| 541 | siginfo_t info; | 497 | siginfo_t info; |
| 542 | int signr; | 498 | int signr; |
| 543 | struct k_sigaction ka; | 499 | struct k_sigaction ka; |
| 500 | sigset_t *oldset; | ||
| 544 | 501 | ||
| 545 | /* | 502 | /* |
| 546 | * We want the common case to go fast, which | 503 | * We want the common case to go fast, which |
| @@ -549,16 +506,26 @@ int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) | |||
| 549 | * if so. | 506 | * if so. |
| 550 | */ | 507 | */ |
| 551 | if (!user_mode(regs)) | 508 | if (!user_mode(regs)) |
| 552 | return 1; | 509 | return; |
| 553 | 510 | ||
| 554 | if (!oldset) | 511 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
| 512 | oldset = ¤t->saved_sigmask; | ||
| 513 | else | ||
| 555 | oldset = ¤t->blocked; | 514 | oldset = ¤t->blocked; |
| 556 | 515 | ||
| 557 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 516 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
| 558 | if (signr > 0) { | 517 | if (signr > 0) { |
| 559 | /* Whee! Actually deliver the signal. */ | 518 | /* Whee! Actually deliver the signal. */ |
| 560 | handle_signal(canrestart, signr, &info, &ka, oldset, regs); | 519 | if (handle_signal(canrestart, signr, &info, &ka, |
| 561 | return 1; | 520 | oldset, regs)) { |
| 521 | /* a signal was successfully delivered; the saved | ||
| 522 | * sigmask will have been stored in the signal frame, | ||
| 523 | * and will be restored by sigreturn, so we can simply | ||
| 524 | * clear the TIF_RESTORE_SIGMASK flag */ | ||
| 525 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
| 526 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 527 | } | ||
| 528 | return; | ||
| 562 | } | 529 | } |
| 563 | 530 | ||
| 564 | /* Did we come from a system call? */ | 531 | /* Did we come from a system call? */ |
| @@ -569,10 +536,16 @@ int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) | |||
| 569 | regs->r10 == -ERESTARTNOINTR) { | 536 | regs->r10 == -ERESTARTNOINTR) { |
| 570 | RESTART_CRIS_SYS(regs); | 537 | RESTART_CRIS_SYS(regs); |
| 571 | } | 538 | } |
| 572 | if (regs->r10 == -ERESTART_RESTARTBLOCK){ | 539 | if (regs->r10 == -ERESTART_RESTARTBLOCK) { |
| 573 | regs->r10 = __NR_restart_syscall; | 540 | regs->r10 = __NR_restart_syscall; |
| 574 | regs->irp -= 2; | 541 | regs->irp -= 2; |
| 575 | } | 542 | } |
| 576 | } | 543 | } |
| 577 | return 0; | 544 | |
| 545 | /* if there's no signal to deliver, we just put the saved sigmask | ||
| 546 | * back */ | ||
| 547 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
| 548 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 549 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
| 550 | } | ||
| 578 | } | 551 | } |
