diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-01 14:53:44 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-01 14:53:44 -0400 |
commit | 86c47b70f62a7072d441ba212aab33c2f82627c2 (patch) | |
tree | d03988bd2226966352bb7f3c2e82ff545353d2c4 /kernel | |
parent | 1193755ac6328ad240ba987e6ec41d5e8baf0680 (diff) | |
parent | 44fbbb3dc687c9709a6f2236197316e5c79ab1eb (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull third pile of signal handling patches from Al Viro:
"This time it's mostly helpers and conversions to them; there's a lot
of stuff remaining in the tree, but that'll either go in -rc2
(isolated bug fixes, ideally via arch maintainers' trees) or will sit
there until the next cycle."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal:
x86: get rid of calling do_notify_resume() when returning to kernel mode
blackfin: check __get_user() return value
whack-a-mole with TIF_FREEZE
FRV: Optimise the system call exit path in entry.S [ver #2]
FRV: Shrink TIF_WORK_MASK [ver #2]
FRV: Prevent syscall exit tracing and notify_resume at end of kernel exceptions
new helper: signal_delivered()
powerpc: get rid of restore_sigmask()
most of set_current_blocked() callers want SIGKILL/SIGSTOP removed from set
set_restore_sigmask() is never called without SIGPENDING (and never should be)
TIF_RESTORE_SIGMASK can be set only when TIF_SIGPENDING is set
don't call try_to_freeze() from do_signal()
pull clearing RESTORE_SIGMASK into block_sigmask()
sh64: failure to build sigframe != signal without handler
openrisc: tracehook_signal_handler() is supposed to be called on success
new helper: sigmask_to_save()
new helper: restore_saved_sigmask()
new helpers: {clear,test,test_and_clear}_restore_sigmask()
HAVE_RESTORE_SIGMASK is defined on all architectures now
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/signal.c | 48 |
1 files changed, 31 insertions, 17 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 08dfbd748cd2..677102789cf2 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -2368,24 +2368,34 @@ relock: | |||
2368 | } | 2368 | } |
2369 | 2369 | ||
2370 | /** | 2370 | /** |
2371 | * block_sigmask - add @ka's signal mask to current->blocked | 2371 | * signal_delivered - |
2372 | * @ka: action for @signr | 2372 | * @sig: number of signal being delivered |
2373 | * @signr: signal that has been successfully delivered | 2373 | * @info: siginfo_t of signal being delivered |
2374 | * @ka: sigaction setting that chose the handler | ||
2375 | * @regs: user register state | ||
2376 | * @stepping: nonzero if debugger single-step or block-step in use | ||
2374 | * | 2377 | * |
2375 | * This function should be called when a signal has succesfully been | 2378 | * This function should be called when a signal has succesfully been |
2376 | * delivered. It adds the mask of signals for @ka to current->blocked | 2379 | * delivered. It updates the blocked signals accordingly (@ka->sa.sa_mask |
2377 | * so that they are blocked during the execution of the signal | 2380 | * is always blocked, and the signal itself is blocked unless %SA_NODEFER |
2378 | * handler. In addition, @signr will be blocked unless %SA_NODEFER is | 2381 | * is set in @ka->sa.sa_flags. Tracing is notified. |
2379 | * set in @ka->sa.sa_flags. | ||
2380 | */ | 2382 | */ |
2381 | void block_sigmask(struct k_sigaction *ka, int signr) | 2383 | void signal_delivered(int sig, siginfo_t *info, struct k_sigaction *ka, |
2384 | struct pt_regs *regs, int stepping) | ||
2382 | { | 2385 | { |
2383 | sigset_t blocked; | 2386 | sigset_t blocked; |
2384 | 2387 | ||
2388 | /* A signal was successfully delivered, and the | ||
2389 | saved sigmask was stored on the signal frame, | ||
2390 | and will be restored by sigreturn. So we can | ||
2391 | simply clear the restore sigmask flag. */ | ||
2392 | clear_restore_sigmask(); | ||
2393 | |||
2385 | sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask); | 2394 | sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask); |
2386 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 2395 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
2387 | sigaddset(&blocked, signr); | 2396 | sigaddset(&blocked, sig); |
2388 | set_current_blocked(&blocked); | 2397 | set_current_blocked(&blocked); |
2398 | tracehook_signal_handler(sig, info, ka, regs, stepping); | ||
2389 | } | 2399 | } |
2390 | 2400 | ||
2391 | /* | 2401 | /* |
@@ -2518,7 +2528,16 @@ static void __set_task_blocked(struct task_struct *tsk, const sigset_t *newset) | |||
2518 | * It is wrong to change ->blocked directly, this helper should be used | 2528 | * It is wrong to change ->blocked directly, this helper should be used |
2519 | * to ensure the process can't miss a shared signal we are going to block. | 2529 | * to ensure the process can't miss a shared signal we are going to block. |
2520 | */ | 2530 | */ |
2521 | void set_current_blocked(const sigset_t *newset) | 2531 | void set_current_blocked(sigset_t *newset) |
2532 | { | ||
2533 | struct task_struct *tsk = current; | ||
2534 | sigdelsetmask(newset, sigmask(SIGKILL) | sigmask(SIGSTOP)); | ||
2535 | spin_lock_irq(&tsk->sighand->siglock); | ||
2536 | __set_task_blocked(tsk, newset); | ||
2537 | spin_unlock_irq(&tsk->sighand->siglock); | ||
2538 | } | ||
2539 | |||
2540 | void __set_current_blocked(const sigset_t *newset) | ||
2522 | { | 2541 | { |
2523 | struct task_struct *tsk = current; | 2542 | struct task_struct *tsk = current; |
2524 | 2543 | ||
@@ -2558,7 +2577,7 @@ int sigprocmask(int how, sigset_t *set, sigset_t *oldset) | |||
2558 | return -EINVAL; | 2577 | return -EINVAL; |
2559 | } | 2578 | } |
2560 | 2579 | ||
2561 | set_current_blocked(&newset); | 2580 | __set_current_blocked(&newset); |
2562 | return 0; | 2581 | return 0; |
2563 | } | 2582 | } |
2564 | 2583 | ||
@@ -3132,7 +3151,7 @@ SYSCALL_DEFINE3(sigprocmask, int, how, old_sigset_t __user *, nset, | |||
3132 | return -EINVAL; | 3151 | return -EINVAL; |
3133 | } | 3152 | } |
3134 | 3153 | ||
3135 | set_current_blocked(&new_blocked); | 3154 | __set_current_blocked(&new_blocked); |
3136 | } | 3155 | } |
3137 | 3156 | ||
3138 | if (oset) { | 3157 | if (oset) { |
@@ -3196,7 +3215,6 @@ SYSCALL_DEFINE1(ssetmask, int, newmask) | |||
3196 | int old = current->blocked.sig[0]; | 3215 | int old = current->blocked.sig[0]; |
3197 | sigset_t newset; | 3216 | sigset_t newset; |
3198 | 3217 | ||
3199 | siginitset(&newset, newmask & ~(sigmask(SIGKILL) | sigmask(SIGSTOP))); | ||
3200 | set_current_blocked(&newset); | 3218 | set_current_blocked(&newset); |
3201 | 3219 | ||
3202 | return old; | 3220 | return old; |
@@ -3235,11 +3253,8 @@ SYSCALL_DEFINE0(pause) | |||
3235 | 3253 | ||
3236 | #endif | 3254 | #endif |
3237 | 3255 | ||
3238 | #ifdef HAVE_SET_RESTORE_SIGMASK | ||
3239 | int sigsuspend(sigset_t *set) | 3256 | int sigsuspend(sigset_t *set) |
3240 | { | 3257 | { |
3241 | sigdelsetmask(set, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
3242 | |||
3243 | current->saved_sigmask = current->blocked; | 3258 | current->saved_sigmask = current->blocked; |
3244 | set_current_blocked(set); | 3259 | set_current_blocked(set); |
3245 | 3260 | ||
@@ -3248,7 +3263,6 @@ int sigsuspend(sigset_t *set) | |||
3248 | set_restore_sigmask(); | 3263 | set_restore_sigmask(); |
3249 | return -ERESTARTNOHAND; | 3264 | return -ERESTARTNOHAND; |
3250 | } | 3265 | } |
3251 | #endif | ||
3252 | 3266 | ||
3253 | #ifdef __ARCH_WANT_SYS_RT_SIGSUSPEND | 3267 | #ifdef __ARCH_WANT_SYS_RT_SIGSUSPEND |
3254 | /** | 3268 | /** |