Q: ->attaching && REPORT_CALLBACKS()

Roland McGrath roland at redhat.com
Thu Mar 12 05:12:46 UTC 2009


> But not vise versa. I misunderstood the comment as if the new engine
> should not be notified if it is attached by another task while target
> is inside callback.

That is indeed what happens in that case.  But that one is not a
specific "should not", it's just what happens to be true given what we
say about the "asynchronous" attach case in general.  That is, that an
"asynchronous" attach + set_events makes no guarantees about how
instantly you start to get event reports.  It might be as long as the
time it takes to get back to user mode from whereever the thread is
now, or the time it takes it to process an interrupt and then get back
to user mode.  It's like you did "thread->events |= events" but there
has not been any kind of memory barrier--it might see it or might not,
until you do something affirmative to make sure (i.e. put it through
UTRACE_STOP, or else get some other callback you're sure happens after
your utrace_set_events call).

For this purpose an "asynchronous attach" means one by a third task (not
the thread itself or the creator during its report_clone), and done when
that third task did not already have some engine that completed a UTRACE_STOP.

This applies even if it is literally synchronous, i.e. if a callback
arranged for the third task to do the attach and set_events and then
blocked waiting for the third task to report its success, we'd call this an
"asynchronous attach" because it didn't synchronize using UTRACE_STOP.

> Still can't understand... If (say) ->report_exec() attaches the new
> engine to the same task and does utrace_set_events(EXEC), then it looks
> logical the new engine gets the notification too. But OK, I agree, either
> way is correct, and perhaps the current behaviour is more intuitive.

As you can see in the cited thread, that's what I thought too.  Jim
convinced me that the (new) current behavior is more useful.  The most
important thing to me is that it's clearly specified one way or the
other for the synchronous case.  It's obviously straightforward to do:

	report_exec(engine, ...)
	{
		new_engine = utrace_attach_task(current, &new_ops);
		utrace_set_events(new_engine, UTRACE_EVENT(EXEC));
		new_ops.report_exec(new_engine, ...);
	}

if you want one of your own callback functions to get another call
there.  OTOH, it's much more cumbersome to make the report_exec
callback used by your new engine keep flags and whatnot to distinguish
the first exec event that preceded that engine's setup from the next
one (which is what the new engine is really there to respond to).

Jim's use seems fairly representative of situations where this might
come up.  He's concerned with the EXEC event as the "old address space
is gone, new one is here" event.  It's also the "my name changed"
event that may be triggering a new tracing setup.  The former use just
wants report_exec to do "wipe out our state and go away" stuff.  The
latter use might want to set up a new incarnation of that sort of
tracing setup--a new engine whose report_exec callback does clean up.
It's obvious how the new engine getting its "clean up now" callback
immediately as a consequence of where the call to set it up came from
is not helpful.  I'm sure this sort of scenario will not be unique
either to Jim's work or to EXEC callbacks in particular.

> But this means that "When target == current it would be safe just to call
> splice_attaching() right here" part of the comment is not right, no?
> Except for report_reap() target == current.

It would be "safe", meaning it doesn't have race problems like the
target != current case does for touching ->attached here.  That's what
the comment says (and that's what the code used to do).  The reason we
don't do it (any more) is the explicit choice for API semantics, not
any implementation reason (in the implementation it is indeed an
obvious optimization if you are understanding the code).  That's why
the comment is there.

> Yes, yes, I see. But I meant another case. Suppose that the debugger D
> attaches to T and does
> 
> 	engine = utrace_attach_task(T, ...);
> 	utrace_set_events(T, engine, XXX);
> 
> It is possible that ->report_xxx() is called before utrace_set_events()
> completes. But afaics currently this is not a problem.

As far as the API guarantees are concerned, there is no "completes".
When you call utrace_set_events, it becomes possible your callbacks
get made.  The return value (a failure return, not -EINPROGRESS) can
say that you are now sure no callback was made or will be.  But when
you called, you wanted it to be possible.  If you didn't, then you
should have made sure it was fully stopped via UTRACE_STOP before you
called utrace_set_events.


Thanks,
Roland




More information about the utrace-devel mailing list