diff options
| author | Oleg Nesterov <oleg@redhat.com> | 2013-01-21 14:47:41 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-01-22 11:50:08 -0500 |
| commit | 910ffdb18a6408e14febbb6e4b6840fd2c928c82 (patch) | |
| tree | 258a215685f2ca2bb11dcd92582e0adafbd83f7b | |
| parent | 9a9284153d965a57edc7162a8e57c14c97f3a935 (diff) | |
ptrace: introduce signal_wake_up_state() and ptrace_signal_wake_up()
Cleanup and preparation for the next change.
signal_wake_up(resume => true) is overused. None of ptrace/jctl callers
actually want to wakeup a TASK_WAKEKILL task, but they can't specify the
necessary mask.
Turn signal_wake_up() into signal_wake_up_state(state), reintroduce
signal_wake_up() as a trivial helper, and add ptrace_signal_wake_up()
which adds __TASK_TRACED.
This way ptrace_signal_wake_up() can work "inside" ptrace_request()
even if the tracee doesn't have the TASK_WAKEKILL bit set.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | include/linux/sched.h | 11 | ||||
| -rw-r--r-- | kernel/ptrace.c | 8 | ||||
| -rw-r--r-- | kernel/signal.c | 14 |
3 files changed, 18 insertions, 15 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h index 6fc8f45de4e9..d2112477ff5e 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
| @@ -2714,7 +2714,16 @@ static inline void thread_group_cputime_init(struct signal_struct *sig) | |||
| 2714 | extern void recalc_sigpending_and_wake(struct task_struct *t); | 2714 | extern void recalc_sigpending_and_wake(struct task_struct *t); |
| 2715 | extern void recalc_sigpending(void); | 2715 | extern void recalc_sigpending(void); |
| 2716 | 2716 | ||
| 2717 | extern void signal_wake_up(struct task_struct *t, int resume_stopped); | 2717 | extern void signal_wake_up_state(struct task_struct *t, unsigned int state); |
| 2718 | |||
| 2719 | static inline void signal_wake_up(struct task_struct *t, bool resume) | ||
| 2720 | { | ||
| 2721 | signal_wake_up_state(t, resume ? TASK_WAKEKILL : 0); | ||
| 2722 | } | ||
| 2723 | static inline void ptrace_signal_wake_up(struct task_struct *t, bool resume) | ||
| 2724 | { | ||
| 2725 | signal_wake_up_state(t, resume ? __TASK_TRACED : 0); | ||
| 2726 | } | ||
| 2718 | 2727 | ||
| 2719 | /* | 2728 | /* |
| 2720 | * Wrappers for p->thread_info->cpu access. No-op on UP. | 2729 | * Wrappers for p->thread_info->cpu access. No-op on UP. |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 612a56126851..62f7c2774b16 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
| @@ -117,7 +117,7 @@ void __ptrace_unlink(struct task_struct *child) | |||
| 117 | * TASK_KILLABLE sleeps. | 117 | * TASK_KILLABLE sleeps. |
| 118 | */ | 118 | */ |
| 119 | if (child->jobctl & JOBCTL_STOP_PENDING || task_is_traced(child)) | 119 | if (child->jobctl & JOBCTL_STOP_PENDING || task_is_traced(child)) |
| 120 | signal_wake_up(child, task_is_traced(child)); | 120 | ptrace_signal_wake_up(child, true); |
| 121 | 121 | ||
| 122 | spin_unlock(&child->sighand->siglock); | 122 | spin_unlock(&child->sighand->siglock); |
| 123 | } | 123 | } |
| @@ -317,7 +317,7 @@ static int ptrace_attach(struct task_struct *task, long request, | |||
| 317 | */ | 317 | */ |
| 318 | if (task_is_stopped(task) && | 318 | if (task_is_stopped(task) && |
| 319 | task_set_jobctl_pending(task, JOBCTL_TRAP_STOP | JOBCTL_TRAPPING)) | 319 | task_set_jobctl_pending(task, JOBCTL_TRAP_STOP | JOBCTL_TRAPPING)) |
| 320 | signal_wake_up(task, 1); | 320 | signal_wake_up_state(task, __TASK_STOPPED); |
| 321 | 321 | ||
| 322 | spin_unlock(&task->sighand->siglock); | 322 | spin_unlock(&task->sighand->siglock); |
| 323 | 323 | ||
| @@ -737,7 +737,7 @@ int ptrace_request(struct task_struct *child, long request, | |||
| 737 | * tracee into STOP. | 737 | * tracee into STOP. |
| 738 | */ | 738 | */ |
| 739 | if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP))) | 739 | if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP))) |
| 740 | signal_wake_up(child, child->jobctl & JOBCTL_LISTENING); | 740 | ptrace_signal_wake_up(child, child->jobctl & JOBCTL_LISTENING); |
| 741 | 741 | ||
| 742 | unlock_task_sighand(child, &flags); | 742 | unlock_task_sighand(child, &flags); |
| 743 | ret = 0; | 743 | ret = 0; |
| @@ -763,7 +763,7 @@ int ptrace_request(struct task_struct *child, long request, | |||
| 763 | * start of this trap and now. Trigger re-trap. | 763 | * start of this trap and now. Trigger re-trap. |
| 764 | */ | 764 | */ |
| 765 | if (child->jobctl & JOBCTL_TRAP_NOTIFY) | 765 | if (child->jobctl & JOBCTL_TRAP_NOTIFY) |
| 766 | signal_wake_up(child, true); | 766 | ptrace_signal_wake_up(child, true); |
| 767 | ret = 0; | 767 | ret = 0; |
| 768 | } | 768 | } |
| 769 | unlock_task_sighand(child, &flags); | 769 | unlock_task_sighand(child, &flags); |
diff --git a/kernel/signal.c b/kernel/signal.c index 53cd5c4d1172..6e97aa6fa32c 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
| @@ -680,23 +680,17 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) | |||
| 680 | * No need to set need_resched since signal event passing | 680 | * No need to set need_resched since signal event passing |
| 681 | * goes through ->blocked | 681 | * goes through ->blocked |
| 682 | */ | 682 | */ |
| 683 | void signal_wake_up(struct task_struct *t, int resume) | 683 | void signal_wake_up_state(struct task_struct *t, unsigned int state) |
| 684 | { | 684 | { |
| 685 | unsigned int mask; | ||
| 686 | |||
| 687 | set_tsk_thread_flag(t, TIF_SIGPENDING); | 685 | set_tsk_thread_flag(t, TIF_SIGPENDING); |
| 688 | |||
| 689 | /* | 686 | /* |
| 690 | * For SIGKILL, we want to wake it up in the stopped/traced/killable | 687 | * TASK_WAKEKILL also means wake it up in the stopped/traced/killable |
| 691 | * case. We don't check t->state here because there is a race with it | 688 | * case. We don't check t->state here because there is a race with it |
| 692 | * executing another processor and just now entering stopped state. | 689 | * executing another processor and just now entering stopped state. |
| 693 | * By using wake_up_state, we ensure the process will wake up and | 690 | * By using wake_up_state, we ensure the process will wake up and |
| 694 | * handle its death signal. | 691 | * handle its death signal. |
| 695 | */ | 692 | */ |
| 696 | mask = TASK_INTERRUPTIBLE; | 693 | if (!wake_up_state(t, state | TASK_INTERRUPTIBLE)) |
| 697 | if (resume) | ||
| 698 | mask |= TASK_WAKEKILL; | ||
| 699 | if (!wake_up_state(t, mask)) | ||
| 700 | kick_process(t); | 694 | kick_process(t); |
| 701 | } | 695 | } |
| 702 | 696 | ||
| @@ -844,7 +838,7 @@ static void ptrace_trap_notify(struct task_struct *t) | |||
| 844 | assert_spin_locked(&t->sighand->siglock); | 838 | assert_spin_locked(&t->sighand->siglock); |
| 845 | 839 | ||
| 846 | task_set_jobctl_pending(t, JOBCTL_TRAP_NOTIFY); | 840 | task_set_jobctl_pending(t, JOBCTL_TRAP_NOTIFY); |
| 847 | signal_wake_up(t, t->jobctl & JOBCTL_LISTENING); | 841 | ptrace_signal_wake_up(t, t->jobctl & JOBCTL_LISTENING); |
| 848 | } | 842 | } |
| 849 | 843 | ||
| 850 | /* | 844 | /* |
