[DTrace-devel] [PATCH 06/13] Add provider-dependent struct in dt_probe_t

Kris Van Hees kris.van.hees at oracle.com
Wed Jul 8 20:36:30 PDT 2020


On Wed, Jul 08, 2020 at 10:38:18AM -0700, Eugene Loh wrote:
> On 07/07/2020 11:02 PM, Kris Van Hees wrote:
> 
> > On Tue, Jul 07, 2020 at 10:11:44PM -0700, Eugene Loh wrote:
> >> On 07/06/2020 02:50 PM, Kris Van Hees wrote:
> >>> On Wed, Jul 01, 2020 at 10:41:11PM -0400, eugene.loh at oracle.com wrote:
> >>>> From: Eugene Loh <eugene.loh at oracle.com>
> >>>>
> >>>> The dt_probe_t struct had members like event_id and event_fd.
> >>>> This made sense for the providers we were supporting, since they
> >>>> were all tracepoint-like.  For future providers, however, those
> >>>> members might not make sense and others will be needed.  Therefore,
> >>>> replace event_id and event_fd with an opaque pointer to a
> >>>> provider-dependent struct.
> >>>>
> >>>> Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
> >>>>
> >>>> diff --git a/libdtrace/dt_probe.c b/libdtrace/dt_probe.c
> >>>> index be407dd2..496ba11e 100644
> >>>> --- a/libdtrace/dt_probe.c
> >>>> +++ b/libdtrace/dt_probe.c
> >>>> @@ -505,6 +505,7 @@ dt_probe_destroy(dt_probe_t *prp)
> >>>>    
> >>>>    	if (prp->prov && prp->prov->impl && prp->prov->impl->probe_fini)
> >>>>    		prp->prov->impl->probe_fini(dtp, prp);
> >>>> +	dt_free(dtp, prp->prv_data);
> >>> OK
> >>>
> >>>>    
> >>>>    	dt_node_list_free(&prp->nargs);
> >>>>    	dt_node_list_free(&prp->xargs);
> >>>> @@ -665,7 +666,8 @@ dt_probe_tag(dt_probe_t *prp, uint_t argn, dt_node_t *dnp)
> >>>>    }
> >>>>    
> >>>>    dt_probe_t *
> >>>> -dt_probe_insert(dtrace_hdl_t *dtp, dt_provider_t *prov, const char *prv,
> >>>> +dt_probe_insert(dtrace_hdl_t *dtp, dt_provider_t *prov, const void *prv_data,
> >>>> +		const char *prv,
> >>>>    		const char *mod, const char *fun, const char *prb)
> >>> Please move the prv_data to the end of the argument list, which is more
> >>> consistent with other code that supports opaque pointers.  It also shows its
> >>> status as auxilliary information rather than being mixed with the elements
> >>> that are part of the generic probe.  And perhaps name it datap since that is
> >>> the name you used for the provider-specific data variable in other places.
> >>>
> >>> I would also modify dt_probe_insert() to free datap (if not NULL) if the probe
> >>> cannot be created.  That avoids needing to have each caller check if the probe
> >>> got created, and if not, free datap.
> 
> Maybe this is beside the point but FWIW with all tp providers using the 
> new tp_probe_insert(), there are much fewer callers of dt_probe_insert() 
> than there were before.  FWIW.

That is ok.  Number of callers isn't really relevant here - even if there was
just one caller, dt_probe_insert() would need to exist to do the work of
creating a new probe and inserting it into the hashtables.

> >> I don't think this really works.  The datap points to provider-specific
> >> stuff.  It might even point to memory that contains pointers to other
> >> things.  So the provider needs to free datap.
> >>
> >> Another option is that the provider only allocates datap but doesn't set
> >> up the memory to which datap points, doing that only once the probe has
> >> been inserted.  But then if there is a problem with initializing the
> >> memory to which datap points, would we want to delete the probe we just
> >> inserted?  We do not yet have a good function for that (deleting one
> >> probe, vs cleaning them all up at the end... e.g., never do we decrement
> >> dt_probe_id).
> >>
> >> Anyhow, one can shoehorn the change you're talking about, but it strikes
> >> me as pretty ugly.
> >>
> >>> You already do a freeing of the datap in
> >>> dt_probr_destroy() so doing it in dt_probe_insert() as well (when needed) is
> >>> OK.
> >> Well, no.  I mean, yes, there is a free(datap) in dt_probe_destroy(),
> >> but it comes right after calling the provider-specific fini() function.
> >> So, do we want dt_probe_insert(), called by a provider, to then call a
> >> provider-specific callback we need to define?  My head is spinning just
> >> thinking of the back-and-forth.
> > If we anticipate that the provider-specific data will contains pointers to
> > other memory blocks that would need to be cleaned up along with it (I cannot
> > really think of a need for that in any provider we're planning to support but
> > it might turn out to be needed)
> 
> What about the profile provider?  For profile-n probes, we have 
> something on each CPU.  So we end up with an array of file descriptors, 
> one per CPU.  datap points to (among other things) a pointer to such an 
> array.

The probe_fini() function performs the cleanup of the provider specific data,
incuding freeing the fds array, and then dt_probe_destroy() can still do the
free of the datap.

> > then we will be needing a function to destroy
> > the provider-specific data anyhow.
> 
> Right.  The probe_fini() function.  Just seems funny to me to have the 
> provider call dt_probe_insert(), which calls back to the provider, then 
> returns to dt_probe_insert(), and then back to the provider.  
> Nevertheless, just calling probe_fini(dtp,prp) here simply doesn't work 
> since it takes a prp argument;  meanwhile, the particular case we're 
> discussing here is when we are unable to create a prp.

Indeed, you would need a function that performs the datap cleanup, and that
gets called from dt_probe_insert() when the probe cannot be created and from
probe_fini() when the probe is being destroyed.

> > I think it is safe right now to just have
> > dt_probe_insert() do it (similar to dt_probe_destroy())
> >
> > The fact that the one in dt_probe_destroy() comes after calling a probe_fini()
> > (if one exists) is not really a good argument.  You wouldn't want the fini()
> > to do the cleanup of stuff referenced from datap and then have datap free'd
> > by dt_probe_destroy().
> 
> Why wouldn't I?
> 
> Actually, let's just assume we won't agree on the woulds and shoulds.  
> Let's just figure out some way that works.  I don't care if it seems 
> unnecessarily convoluted to me;  if I can implement it, I will.  If I 
> understand what you're proposing:
> 
> *)  introduce a new provider-specific function ("data_free" maybe?) that 
> takes a datap and
> frees resources it points to as well as freeing datap itself

probe_destroy(dtrace_hdl_t *dtp, void *datap)

> *)  have dt_probe_insert() try to form a prp;  if it cannot, it will 
> call the new function and then return a NULL prp
> 
> *)  change probe_fini() to take advantage of the new function
> 
> Do I understand correctly?  If that's what you're proposing, I will 
> implement it.

Yes.

> > If you envision more complex datap variants where there
> > is additional allocated data, then we really need to have a function to handle
> > the freeing of datap and related structures.  And that can then be called from
> > dt_probe_insert() if the probe creation fails.
> >
> > I still think a plan free of datap in dt_probe_insert() suffices for now, and
> > we can always implement a function to do the freeing later if it turns out to
> > be necessary.  Right now it seems to be a bit of over-engineering.
> >
> >>> The caller can count on the fact that if the probe could not be created,
> >>> datap is no longer valid.
> 
> _______________________________________________
> DTrace-devel mailing list
> DTrace-devel at oss.oracle.com
> https://oss.oracle.com/mailman/listinfo/dtrace-devel



More information about the DTrace-devel mailing list