Both utrace and ptrace can want the same thread to be quiescent, in this
case its state is TASK_TRACED | TASK_UTRACED. And this also means that
this task must not run unless both utrace and ptrace resume it.

Change wake_up_quiescent(p, state) to do "p->state &= ~state" and return
false unless there is no more "quiescent" bits in task->state.

Signed-off-by: Oleg Nesterov <o...@redhat.com>
---
 kernel/signal.c |   15 +++++++++++++++
 1 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/kernel/signal.c b/kernel/signal.c
index a7979ad..57552e6 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -651,11 +651,26 @@ void signal_wake_up(struct task_struct *t, int resume)
                kick_process(t);
 }
 
+#define STATE_QUIESCENT        (__TASK_STOPPED | __TASK_TRACED | 
__TASK_UTRACED)
 /*
  * wakes up the STOPPED/TRACED task, must be called with ->siglock held.
  */
 int wake_up_quiescent(struct task_struct *p, unsigned int state)
 {
+       unsigned int quiescent = (p->state & STATE_QUIESCENT);
+
+       WARN_ON(state & ~(STATE_QUIESCENT | TASK_INTERRUPTIBLE));
+
+       if (quiescent) {
+               state &= ~TASK_INTERRUPTIBLE;
+               if ((quiescent & ~state) != 0) {
+                       p->state &= ~state;
+                       WARN_ON(!(p->state & STATE_QUIESCENT));
+                       WARN_ON(!(p->state & TASK_WAKEKILL));
+                       return 0;
+               }
+       }
+
        return wake_up_state(p, state);
 }
 
-- 
1.5.5.1


Reply via email to