> > report_reap is covered with the utrace_detached_reap() stub.  Every other
> > callback uses start_callback(), i.e. calls report_quiesce first.
> > utrace_detached_quiesce() returns UTRACE_DETACH,
> 
> Assuming ->report_quiesce() will be called.
> 
> Suppose that, say, engine->flags == UTRACE_EVENT(EXEC) (no QUIESCE).
> 
>       1. start_callback() reads want = engine->flags (== EXEC)
> 
>       2. mark_engine_detached() sets engine->ops = &utrace_detached_ops
> 
>       3. start_callback() gets ops = utrace_detached_ops

Right, good point.

> OK, instead of filling utrace_detached_ops{} we can change start_callback()
> 
>       - if (want & UTRACE_EVENT(QUIESCE)) {
>       + if ((want & UTRACE_EVENT(QUIESCE)) || ops == detached_ops) {

If we're going to have a special-case check for &utrace_detached_ops, then
it can just short-circuit entirely and there is no need for any callbacks
in utrace_detached_ops.  (Then we might even use NULL or (void *)-1l
instead of &utrace_detached_ops.)  All it needs to do is:

        report->detaches = true;
        utrace->reporting = NULL;
        return NULL;

> In particular, I'd like to think if we can simplify this somehow.
> Say, avoid the barriers somewhere, or avoid changing engine->flags in
> mark_engine_detached().

Yeah.  The original idea of changing engine->flags was just to make sure it
had QUIESCE so that it would be noticed and detached on any next callback
run, not just one that happened to be for the events it was previously
tracing (which could be only rare ones, or none but implicit reap).  But if
we have a special case check in start_callback() before even looking at the
flags, then it doesn't matter at all what the flags are.

> I am worried that mark_engine_detached() sets engine->flags, but it
> doesn't add QUIESCE to utrace_flags. I can't convince myself that
> utrace_do_stop() closes all possible races.

Ok.  The worst case races should not be real problems, only delays in the
final engine cleanup.  Any eventual utrace_reset() or reaping will of
course clean it up at some point.

> And, in particular, I don't understand this code in utrace_get_signal:
> 
>               } else if (!(task->utrace_flags & UTRACE_EVENT(QUIESCE))) {
>                       /*
>                        * We only got here to clear utrace->signal_handler.
>                        */
>                       return -1;
>               }
> 
> How so? What if we were called because of utrace_control(INTERRUPT)
> and QUIESCE is not set?

If an engine used UTRACE_INTERRUPT without having first set QUIESCE,
then it has no rightful expectation of getting any callback.


Thanks,
Roland

Reply via email to