On 06/23, Roland McGrath wrote:
>
> > OK. But then perhaps UTRACE_STICKY_STOP makes sense even without the
> > races we discussed. It can simplify the cooperation in this case.
>
> The only cooperation methods we should consider are those that cover all
> their races.
>
> > Yes. Let's consider the concrete example. The tracee is going to
> > stop and calls utrace_stop(). Before it takes utrace->lock and
> > sets state = TASK_TRACED, the debugger does utrace_control(DETACH).
> >
> > In this case utrace_stop() shouldn't stop, otherwise nobody will
> > ever wake it up. That is why we clear this bit in ->utrace_flags
> > to provoke utrace_reset() which will check carefully the tracee
> > has an engine with ENGINE_STOP.
>
> Right.  I agree this race seems to apply to all kinds of resumption, not
> just detach.  The question for the non-detach cases is what kind of
> guarantee the utrace API is claiming to provide.  For detach it matters
> strongly because the "loser" of the race is gone and there is no way for
> it to be responsible for cleaning up the fallout.
>
> For non-detach cases, the picture is more hazy.  The conclusions on what
> matters might be different if we have utrace_wake_up() or equivalent.
>
> Off hand I think it does matter today insofar as it violates the
> documented guarantees of the utrace_barrier API.  If utrace_barrier
> returns 0 it is said to mean that, "Any effect of its return value (such
> as %UTRACE_STOP) has already been applied to @engine."  So e.g. if you
> get a wake-up sent by your callback before it returns UTRACE_STOP, and
> then call utrace_barrier followed by utrace_control(,,UTRACE_RESUME),
> then you should be guaranteed that your resumption cleared the
> callback's stop.

Not sure I understand how this connects to utrace_wake_up().

If a callback can return return UTRACE_STOP due to the "extern"
reason, then we can do nothing to cancel this UTRACE_STOP reliably.
I meant something like

        // say, engine->data->please_stop = false;
        instruct_the_tracee_to_not_return_UTRACE_STOP();

        utrace_barrier();
        utrace_control(UTRACE_RESUME);

> Another example, you call utrace_set_events and disable some events,
> including all the ones for which your callbacks ever return UTRACE_STOP.
> If that returns 0, or then you call utrace_barrier and it returns 0,
> then you know that either it was already stopped before you called
> utrace_set_events, or that it's not stopped now.  In either case, you
> know that utrace_control(,,UTRACE_RESUME) ensures that it's no longer
> stopped.  (That is, "stopped by your engine"--it of course might still
> be stopped by a different engine.)

Yes, this is close to my example above.

Well. This reminds me the old and unfinished discussion about utrace_barrier()
and memory barriers.

At least with the current implementation, I'm afraid that "->reporting = NULL"
in finish_callback() can fool the tracer. Unless finish_callback_report()
takes utrace->lock to change flags/ops. Of course, this is pure theoretical.

> > > For the new API idea, I was talking about something like a 
> > > utrace_wake_up()
> > > call.
> >
> > Now I don't understand you again...
> >
> > The 1st question: should the new API help us to kill ptrace_notify_stop()
> > in utrace_stop() ?
>
> Ideally yes.  This might still have to be some other kind of special case,
> we'll have to figure that out.  That would be survivable if it's necessary.
> The wait_chldexit wakeup would be covered by what we're discussing, it's
> just another wait_queue_head_t.  The signal sending is more problematic.

Yes, the signal sending is problematic, but wait_chldexit also looks
problematic. How can utrace_wake_up() know which wait_queue_head_t should
be used for wake up?

> But I wanted first to contemplate what API would cover new code cleanly
> written.  The dismal old ptrace signal/wait synchronization might always be
> a difficult outlying case.

OK.

> > Hmm... After the previous email I thought that this utrace_wake_up()
> > or whatever shouldn't be visible outside of utrace.c.
>
> I'm sorry if I was not clear.  I have been talking entirely about new
> utrace API features, not internals.  This is a discussion for your
> engine-writer hat more than your utrace-maintainer hat.  I'm only
> mentioning any utrace implementation details to elucidate what is
> realistic or problematic to consider for the new API features.

OK, let's forget about "internal" utrace problems like the spinning
inside utrace_barriers().

> > Or. Do you literally mean something like
> >
> >     utrace_wait_for_event();                // for debugger
> >     utrace_wake_up();                       // for tracee
> >
> > which should (at least) cover all races with exit/detach/etc ?
>
> I meant utrace_wake_up(wait_queue_head_t *) used in place of wake_up()
> inside a utrace callback.  The waiter (tracer) side would use normal
> <linux/wait.h> interfaces (wait_event macro, etc.).

Sorry Roland, I have the blind spot here.

Let's talk about API visible to engine writers. Which arguments
should utrace_wake_up() have, wait_queue_head_t ? When this
helper should be used by engine writers?

Sure, the tracer and tracee can have many reasons to synchronize.
They can engine->data to place wait_queue_head_t. Or they can
use another wq. I still can't understand what a simple wrapper
on top of __wake_up() can buy us.

I am sure I am missing something important and simple her.

Oleg.

Reply via email to