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);