Roland, I left some parts of your message unanswered because I need to think
more about them...

On 03/12, Roland McGrath wrote:
>
> > But, if we enter utrace_report_jctl() with ->stopped == 1, JCTL can be
> > already removed from ->utrace_flags, exactly because ->stopped was true.
>
> I don't follow this.  JCTL is never "removed" from ->utrace_flags, except
> as all event bits are, by utrace_reset().

Yep. And utrace_reset() can be called because ->stopped == 1.

Let me explain. Again, let's suppose D attaches engine E to the target T.

T enters utrace_report_jctl() with ->stopped == 1.

D calls utrace_set_events(events => 0), this removes JCTL from E->flags.

D calls, say, utrace_control(UTRACE_RESUME). Since ->stopped == 1, this
calls utrace_reset() and removes JCTL from T->utrace_flags.

T takes utrace->lock, clears ->stopped, and drops the lock.

D does utrace_control(UTRACE_STOP). This calls utrace_do_stop() which
sees task_is_stopped() && !JCTL, so it sets ->stopped = true.

T calls REPORT() and start_report() hits the (correct) BUG_ON(stopped).

No?

> > This leads to another minor question, how it is possible to enter enter
> > utrace_report_jctl() with ->stopped == 1 ? I think the only possibility
> > it was previously set by another call to utrace_report_jctl(), see below.
>
> There are two ways to enter utrace_report_jctl with ->stopped set.
>
> 1. utrace_report_jctl was called when entering TASK_STOPPED, and set it then.
>    Now utrace_report_jctl is called for the CLD_CONTINUED case, and
>    ->stopped remains set.

this is covered by my guess above,

> 2. utrace_set_events(target, UTRACE_EVENT(JCTL)) was called when target was
>    already in TASK_STOPPED (and really stopped, or at least got past
>    tracehook_notify_jctl before JCTL was set).  It sets ->stopped before
>    adding JCTL to ->utrace_flags,

Yes, thanks. I missed this.

> > SIGNAL_STOP_STOPPED is not reliable, it is possible that the group stop in
> > progress and it is not finished yet.
>
> SIGNAL_STOP_STOPPED should be reliable, as far as it goes.  It will only be
> set if the group stop is complete.

Yes sure. I wasn't clear. I meant, what if SIGNAL_STOP_STOPPED is not set?
This doesn't mean we don't need  __set_current_state(TASK_STOPPED), it is
possible that the group-stop is in progress and ->group_stop_count != 0.

> > But! can't we miss utrace_wakeup() ?
>
> I think you've found something (though not quite the scenario you describe).
>
> > Let's suppose the debugger D attaches the single engine E to the target T.
> >
> >     D does utrace_set_events(JCTL).
> >
> >     T calls do_signal_stop(), tracehook_notify_jctl() sees JCTL and starts
> >     utrace_report_jctl().
> >
> >     D does utrace_set_events(events => 0), this clears E->flags.
> >
> >     T calls REPORT(), nobody needs needs JCTL, finish_report() sees 
> > !->takers
> >     and calls utrace_reset(). It sets ->utrace_flags = 0.
>
> Nope:
>
>                       flags |= engine->flags | UTRACE_EVENT(REAP);

Ah, thanks. Can't understand how I didn't notice this, I checked the
code several times ;)

But as you pointed out,

> So, change your scenario to:
>
>       D does utrace_control(UTRACE_DETACH).
>
> and then this will happen.

Yes.

Oleg.

Reply via email to