[PATCH 12/33] introduce ptrace_signal_wake_up()

Oleg Nesterov oleg at redhat.com
Mon Nov 21 20:01:59 UTC 2011


Add the new helper, ptrace_signal_wake_up(), change ptrace.c/signal.c
to use it instead of signal_wake_up() to wake up a STOPPED/TRACED task.

The new helper does almost the same, except:

	- it doesn't use the TASK_WAKEKILL bit to wake up the TRACED
	  or STOPPED task, it uses __TASK_STOPPED | __TASK_TRACED
	  explicitly. This is what ptrace actually wants, it should
	  never wake up a TASK_KILLABLE task.

	  This should be cleanuped upatream, signal_wake_up() should
	  take the state as an argument, not a boolean. Until then
	  we add a new static helper.

	- it uses wake_up_quiescent() instead of wake_up_state().

Thereafter every change from STOPPED/TRACED to RUNNING is done via
wake_up_quiescent().

Signed-off-by: Oleg Nesterov <oleg at redhat.com>
---
 include/linux/ptrace.h |    1 +
 kernel/ptrace.c        |   20 ++++++++++++++++----
 kernel/signal.c        |    2 +-
 3 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index 800f113..6d9282a 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -113,6 +113,7 @@
 #include <linux/compiler.h>		/* For unlikely.  */
 #include <linux/sched.h>		/* For struct task_struct.  */
 
+extern void ptrace_signal_wake_up(struct task_struct *p, int quiescent);
 
 extern long arch_ptrace(struct task_struct *child, long request,
 			unsigned long addr, unsigned long data);
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 8439ef1..a464ab5 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -25,6 +25,18 @@
 #include <linux/hw_breakpoint.h>
 #include <linux/cn_proc.h>
 
+void ptrace_signal_wake_up(struct task_struct *p, int quiescent)
+{
+	unsigned int state;
+
+	set_tsk_thread_flag(p, TIF_SIGPENDING);
+
+	state = TASK_INTERRUPTIBLE;
+	if (quiescent)
+		state |= (__TASK_STOPPED | __TASK_TRACED);
+	if (!wake_up_quiescent(p, state))
+		kick_process(p);
+}
 
 static int ptrace_trapping_sleep_fn(void *flags)
 {
@@ -106,7 +118,7 @@ void __ptrace_unlink(struct task_struct *child)
 	 * TASK_KILLABLE sleeps.
 	 */
 	if (child->jobctl & JOBCTL_STOP_PENDING || task_is_traced(child))
-		signal_wake_up(child, task_is_traced(child));
+		ptrace_signal_wake_up(child, task_is_traced(child));
 
 	spin_unlock(&child->sighand->siglock);
 }
@@ -296,7 +308,7 @@ static int ptrace_attach(struct task_struct *task, long request,
 	 */
 	if (task_is_stopped(task) &&
 	    task_set_jobctl_pending(task, JOBCTL_TRAP_STOP | JOBCTL_TRAPPING))
-		signal_wake_up(task, 1);
+		ptrace_signal_wake_up(task, 1);
 
 	spin_unlock(&task->sighand->siglock);
 
@@ -731,7 +743,7 @@ int ptrace_request(struct task_struct *child, long request,
 		 * tracee into STOP.
 		 */
 		if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP)))
-			signal_wake_up(child, child->jobctl & JOBCTL_LISTENING);
+			ptrace_signal_wake_up(child, child->jobctl & JOBCTL_LISTENING);
 
 		unlock_task_sighand(child, &flags);
 		ret = 0;
@@ -757,7 +769,7 @@ int ptrace_request(struct task_struct *child, long request,
 			 * start of this trap and now.  Trigger re-trap.
 			 */
 			if (child->jobctl & JOBCTL_TRAP_NOTIFY)
-				signal_wake_up(child, true);
+				ptrace_signal_wake_up(child, true);
 			ret = 0;
 		}
 		unlock_task_sighand(child, &flags);
diff --git a/kernel/signal.c b/kernel/signal.c
index 99a6008..7a47a93 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -854,7 +854,7 @@ static void ptrace_trap_notify(struct task_struct *t)
 	assert_spin_locked(&t->sighand->siglock);
 
 	task_set_jobctl_pending(t, JOBCTL_TRAP_NOTIFY);
-	signal_wake_up(t, t->jobctl & JOBCTL_LISTENING);
+	ptrace_signal_wake_up(t, t->jobctl & JOBCTL_LISTENING);
 }
 
 /*
-- 
1.5.5.1



More information about the kernel mailing list