Move the code which clears SIGNAL_STOP_STOPPED under "if (force_wakeup)". Change ptrace_detach() accordingly. See also the next patch which cleanups/fixes ptrace_wake_up().
Upstream logic: if detach is explicit, we should always wakeup the tracee, otherwise (exit_ptrace() path) we rely on ptrace_untrace() which checks SIGNAL_STOP_STOPPED. utrace-ptrace: ptrace_detach(sig) checks valid_signal(sig) to detect the explicit detach and passes "bool voluntary" to ptrace_wake_up(). both upstream and utrace-ptrace are racy (but these races are different), hopefully utrace-ptrace is not worse. And of course this all is not right and should be fixed, but we seem to agree this should be fixed later, when utrace-ptrace is merged. In my opinion, from now utrace-ptrace is close enough to upstream wrt stop/wakeup oddities. It passes all tests which upstream passes, plus it passes detach-stopped which fails with upstream kernel. This is because utrace_get_signal() sets SIGNAL_STOP_DEQUEUED when it returns a sig_kernel_stop() signal. This logic is not exactly right, but I think it is better than nothing. IOW: afaics we don't need additional functional changes in this area before submitting utrace-ptrace. Of course, it is easy to detect the difference in behaviour and perhaps we will have "it breaks my app" reports, but I don't think we should try hard to be more bug-compatible before V1. What do you think? --- kernel/ptrace.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) --- PU/kernel/ptrace.c~90_DETACH_CK_IMPLICIT 2009-10-13 19:55:25.000000000 +0200 +++ PU/kernel/ptrace.c 2009-10-14 13:18:45.000000000 +0200 @@ -82,7 +82,8 @@ static int ptrace_attach_task(struct tas static void ptrace_abort_attach(struct task_struct *tracee); static void ptrace_wake_up(struct task_struct *tracee, struct utrace_engine *engine, - enum utrace_resume_action action); + enum utrace_resume_action action, + bool force_wakeup); static struct utrace_engine *ptrace_lookup_engine(struct task_struct *tracee) { @@ -92,8 +93,9 @@ static struct utrace_engine *ptrace_look static void ptrace_detach_task(struct task_struct *tracee, int sig) { - struct utrace_engine *engine = ptrace_lookup_engine(tracee); + bool voluntary = valid_signal(sig); enum utrace_resume_action action = UTRACE_DETACH; + struct utrace_engine *engine = ptrace_lookup_engine(tracee); if (unlikely(IS_ERR(engine))) return; @@ -104,12 +106,12 @@ static void ptrace_detach_task(struct ta switch (get_stop_event(context)) { case PTRACE_EVENT_SYSCALL_ENTRY: case PTRACE_EVENT_SYSCALL_EXIT: - if (valid_signal(sig)) + if (voluntary) send_sig_info(sig, SEND_SIG_PRIV, tracee); break; case PTRACE_EVENT_SIGNAL: - if (valid_signal(sig)) + if (voluntary) context->signr = sig; context->resume = UTRACE_DETACH; action = UTRACE_RESUME; @@ -117,7 +119,7 @@ static void ptrace_detach_task(struct ta } } - ptrace_wake_up(tracee, engine, action); + ptrace_wake_up(tracee, engine, action, voluntary); utrace_engine_put(engine); } @@ -944,15 +946,18 @@ void ptrace_notify_stop(struct task_stru static void ptrace_wake_up( struct task_struct *tracee, struct utrace_engine *engine, - enum utrace_resume_action action) + enum utrace_resume_action action, + bool force_wakeup) { - unsigned long flags; + if (force_wakeup) { + unsigned long flags; - /* preserve the compatibility bug */ - if (!lock_task_sighand(tracee, &flags)) - return; - tracee->signal->flags &= ~SIGNAL_STOP_STOPPED; - unlock_task_sighand(tracee, &flags); + /* preserve the compatibility bug */ + if (!lock_task_sighand(tracee, &flags)) + return; + tracee->signal->flags &= ~SIGNAL_STOP_STOPPED; + unlock_task_sighand(tracee, &flags); + } // XXX: FIXME!!! racy. tracee->exit_code = 0; @@ -1012,7 +1017,7 @@ static void do_ptrace_resume(struct utra } context->resume = action; - ptrace_wake_up(tracee, engine, action); + ptrace_wake_up(tracee, engine, action, true); } static int ptrace_resume(struct utrace_engine *engine,