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 | |
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>
-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 41d4a5f93284..b6be705c2a3e 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 | } |