On 06/21, Roland McGrath wrote:
>
> > I am wondering if there is another way to handle such a race...
> > Suppose we
> >
> >     - add UTRACE_STOP_XXX
> >
> >     - modify utrace_control(UTRACE_STOP_XXX) to do
> >       mark_engine_wants_stop() and nothing more.
>
> utrace_control(current,,UTRACE_STOP) doesn't really do anything more.

It does utrace_do_stop() which sets UTRACE_REPORT/TIF_NOTIFY_RESUME.
Harmless, but makes sense to avoid.

> > Then, probably producer could do
> >
> >     utrace_control(current, UTRACE_STOP_XXX);
> >
> >     slot = book_message_in_buffer(buf);
> >     if (slot < 0)
> >             return UTRACE_STOP_XXX;
> >
> >     ...
> >     return UTRACE_RESUME;
> >
> > Even better, UTRACE_STOP_XXX can live outside of UTRACE_RESUME_MASK.
>
> Right, it doesn't belong in enum utrace_resume_action--it doesn't make
> sense as an argument for utrace_control, for example.  So it could be
> something like a return-value flag bit saying "stop if marked for stop",
> e.g. UTRACE_SINGLESTEP|UTRACE_STICKY_STOP for single-step, unless marked
> to stop, in which case stay stopped.

Yes, this is what I meant. And yes, if UTRACE_STICKY_STOP doesn't
fall into UTRACE_RESUME_MASK utrace_control(enum utrace_resume_action)
shouldn't be used.

OTOH, I am wondering if we can give more power to utrace_control(STOP).
Currently debugger can't stop the tracee unless it cooperates. However, if
the tracee doesn't have UTRACE_EVENT(QUIESCE), then utrace_control(STOP)
works. This is strange.

Stupid question: what if we just remove the clear_engine_wants_stop()
code in finish_callback_report() ?

> So this would fix that race.
> ...
> (But note if there is
> another engine that decides to stop anyway, then we'll have used a
> second CPU and/or ping-pong scheduled to run the tracer thread in
> parallel with a very short amount of work in the tracee before it just
> blocks anyway.)

Hmm. Not sure I understand... Yes, the tracee still can stop if another
tracer demands, but this is fine?

Btw, before I forgot about this. shouldn't utrace_control(UTRACE_RESUME)
remove ENGINE_STOP from ->utrace_flags like DETACH does?

> Here
> what the callback does is wake up the tracer, and return UTRACE_STOP.
>
> For this sort of scenario, it is clearly better by far to have the
> wake_up_tracer() done as late as possible in the sequence.
>
> In the past, Oleg has suggested something very general, like a
> utrace_engine_ops hook that gets called right before schedule().
> I shy away from something like that, since I think it degrades the
> intended property of the API that it make it harder to write truly
> arcane bugs with terrible effects on the system, not easier.  It's
> just too big a sledgehammer to wield above the thinly-protected toes
> of the utrace engine writer.
>
> To avoid something dangerously general, the only real option is to give
> something safely constrained and specific.

> It's straightforward enough to
> come up with something for any single synchronization method.  For
> example, if every need for this kind of synchronization with tracees is
> based on <linux/wait.h> facilities, then we can have a utrace API feature
> whereby a callback can queue up a wait_queue_head_t pointer to be passed
> to wake_up_interruptible_sync() after all the callbacks are done and
> UTRACE_STOP is being performed.  It's probably sufficient to allow one
> pending wake-up per engine, which makes it pretty cheap and simple to
> implement.

Heh. it turns out that I misunderstood you in the past, I thought
you dislike the whole idea of wake_up from utrace_stop().

I agree, the utrace_engine_ops->notify() hook is dangerous. But, it
is simple and allows us to kill utrace_stop()->ptrace_notify_stop().

(yes I understand, this is not only about utrace_stop(), utrace_barrier
 wants notification too).

> It's straightforward enough to
> come up with something for any single synchronization method.

Hmm. Not sure... at least I don't immediately see something simple.

Except, just add wait_queue_head into struct utrace. This way utrace_barrier()
can wait longer than needed if it notices utrace->reporting == engine. Or we
can add it into utrace_engine, in this case utrace_stop() needs
list_for_each(engine, utrace->attached).

Or I misunderstood you again?

Oleg.

Reply via email to