Consider, say, report_syscall_exit(). UTRACE_STOP as a return value is
"useless", we could return UTRACE_REPORT or UTRACE_INTERRUPT instead.

We need to record the fact we want to stop, then ->report_quiesce() or
->report_interrupt() should re-assert UTRACE_STOP.

Introduce context->stopped_code. It will be set by the callback when
we want to stop. Change quiesce/interrupt callbacks to check this flag
and return UTRACE_STOP if it is set.

Another reason for ->stopped_code is that do_wait() needs ->exit_code.
So the new member is not a boolean, the callback should set the correct
code which will be reported to ->parent. Change ptrace_notify_stop()
to set tracee->exit_code = context->stopped_code and clear it.

(this patch adds some forbidden "// XXX" comments to mark the soon to
 be killed code).

---

 kernel/ptrace.c |   37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

--- PU/kernel/ptrace.c~25_CTX_STOP_PENDING      2009-09-07 19:48:41.000000000 
+0200
+++ PU/kernel/ptrace.c  2009-09-07 22:12:41.000000000 +0200
@@ -26,6 +26,8 @@
 
 struct ptrace_context {
        int options;
+
+       int stopped_code;
 };
 
 static inline struct ptrace_context *
@@ -392,6 +394,14 @@ static u32 ptrace_report_signal(u32 acti
                                const struct k_sigaction *orig_ka,
                                struct k_sigaction *return_ka)
 {
+       struct ptrace_context *context = ptrace_context(engine);
+
+       if (context->stopped_code) {
+               action = utrace_signal_action(action);
+               WARN_ON(action != UTRACE_SIGNAL_REPORT);
+               return action | UTRACE_STOP;
+       }
+
        switch (utrace_signal_action(action)) {
        default:
                WARN_ON(ptrace_stop_event(task) && info->si_signo != SIGKILL);
@@ -431,6 +441,11 @@ static u32 ptrace_report_quiesce(u32 act
                                 struct task_struct *task,
                                 unsigned long event)
 {
+       struct ptrace_context *context = ptrace_context(engine);
+
+       if (context->stopped_code)
+               return UTRACE_STOP;
+
        if (event == 0) {
                task->last_siginfo = NULL;
 
@@ -900,6 +915,28 @@ static int ptrace_setsiginfo(struct task
 
 void ptrace_notify_stop(struct task_struct *tracee)
 {
+       struct utrace_engine *engine;
+       struct ptrace_context *context;
+
+       engine = utrace_attach_task(tracee, UTRACE_ATTACH_MATCH_OPS,
+                                   &ptrace_utrace_ops, NULL);
+       if (IS_ERR(engine)) {
+               // XXX: temporary check, wrong with mutlitracing
+               WARN_ON(tracee->state != TASK_RUNNING);
+               return;
+       }
+
+       context = ptrace_context(engine);
+       if (context->stopped_code) {
+               tracee->exit_code = context->stopped_code;
+               context->stopped_code = 0;
+
+               read_lock(&tasklist_lock);
+               do_notify_parent_cldstop(tracee, CLD_TRAPPED);
+               read_unlock(&tasklist_lock);
+       }
+
+       // XXX: will die soon
        if (ptrace_resume_action(tracee) == UTRACE_STOP) {
                read_lock(&tasklist_lock);
                do_notify_parent_cldstop(tracee, CLD_TRAPPED);

Reply via email to