[DTrace-devel] [PATCH 14/15] cg: Implement dependent probes
Kris Van Hees
kris.van.hees at oracle.com
Thu Feb 23 07:24:19 UTC 2023
Some providers may wish to implement probes on top of other probes.
This patch provides the concept of dependent probes: probes that use
other probes as their firing mechanism. This is accomplished by
generating a custom trampoline that converts the DTrace context of
the underlying probe into a DTrace context for the dependent probe
and then adding the clauses for the dependent probe to the underlying
probe.
Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
libdtrace/dt_cc.c | 2 ++
libdtrace/dt_cg.c | 46 +++++++++++++++++++++++++++++++++
libdtrace/dt_probe.c | 60 +++++++++++++++++++++++++++++++++++++++-----
libdtrace/dt_probe.h | 7 ++++++
4 files changed, 109 insertions(+), 6 deletions(-)
diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
index bbc203c3..88d7f1fe 100644
--- a/libdtrace/dt_cc.c
+++ b/libdtrace/dt_cc.c
@@ -2119,6 +2119,8 @@ dt_construct(dtrace_hdl_t *dtp, dt_probe_t *prp, uint_t cflags, dt_ident_t *idp)
pcb.pcb_probe = prp;
pcb.pcb_pdesc = prp->desc;
+ yybegin(YYS_DONE);
+
if ((err = setjmp(yypcb->pcb_jmpbuf)) != 0)
goto out;
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 4b619cc7..5837119d 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -499,6 +499,36 @@ dt_cg_tramp_call_clauses(dt_pcb_t *pcb, const dt_probe_t *prp,
(dt_clause_f *)dt_cg_call_clause, &arg);
}
+static int
+dt_cg_add_dependent(dtrace_hdl_t *dtp, dt_probe_t *prp, void *arg)
+{
+ dt_pcb_t *pcb = dtp->dt_pcb;
+ dt_irlist_t *dlp = &pcb->pcb_ir;
+ dt_ident_t *idp = dt_dlib_add_probe_var(pcb->pcb_hdl, prp);
+ dt_probe_t *saved_prp = pcb->pcb_probe;
+ uint_t exitlbl = dt_irlist_label(dlp);
+
+ dt_cg_tramp_save_args(pcb);
+ pcb->pcb_probe = prp;
+ emite(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_7, DMST_PRID, prp->desc->id), idp);
+ if (prp->prov->impl->trampoline != NULL)
+ prp->prov->impl->trampoline(pcb, exitlbl);
+ dt_cg_tramp_call_clauses(pcb, prp, DT_ACTIVITY_ACTIVE);
+
+ pcb->pcb_probe = saved_prp;
+ dt_cg_tramp_restore_args(pcb);
+ emitl(dlp, exitlbl,
+ BPF_NOP());
+
+ return 0;
+}
+
+static void
+dt_cg_tramp_add_dependents(dt_pcb_t *pcb, const dt_probe_t *prp)
+{
+ dt_probe_dependent_iter(pcb->pcb_hdl, prp, dt_cg_add_dependent, NULL);
+}
+
void
dt_cg_tramp_return(dt_pcb_t *pcb)
{
@@ -519,6 +549,22 @@ void
dt_cg_tramp_epilogue(dt_pcb_t *pcb)
{
dt_cg_tramp_call_clauses(pcb, pcb->pcb_probe, DT_ACTIVITY_ACTIVE);
+ /*
+ * For each dependent probe (if any):
+ * 1.1 Call dt_cg_tramp_save_args()
+ * 1.2 Set PRID to the probe ID of the dependent probe
+ * 1.3 Call prp->prov->impl->trampoline()
+ * [ This will generate the pseudo-trampoline that sets
+ * up the arguments for the dependent probe, possibly
+ * based on the arguments of the underllying probe. ]
+ * 1.4 Call dt_cg_tramp_call_clauses() for the dependent probe
+ * 1.1 Call dt_cg_tramp_restore_args()
+ *
+ * Possible iptimization:
+ * Do not call dt_cg_tramp_restore_args() after the last dependent
+ * probe.
+ */
+ dt_cg_tramp_add_dependents(pcb, pcb->pcb_probe);
dt_cg_tramp_return(pcb);
}
diff --git a/libdtrace/dt_probe.c b/libdtrace/dt_probe.c
index e50fc7ba..a5952c57 100644
--- a/libdtrace/dt_probe.c
+++ b/libdtrace/dt_probe.c
@@ -24,10 +24,15 @@
#include <dt_list.h>
#include <dt_bpf.h>
-typedef struct dt_probeclause {
+typedef struct dt_probe_clause {
dt_list_t list;
dt_ident_t *clause;
-} dt_probeclause_t;
+} dt_probe_clause_t;
+
+typedef struct dt_probe_dependent {
+ dt_list_t list;
+ dt_probe_t *probe;
+} dt_probe_dependent_t;
#define DEFINE_HE_FUNCS(id) \
static uint32_t id##_hval(const dt_probe_t *probe) \
@@ -462,7 +467,7 @@ dt_probe_enable(dtrace_hdl_t *dtp, dt_probe_t *prp)
void
dt_probe_destroy(dt_probe_t *prp)
{
- dt_probeclause_t *pcp, *pcp_next;
+ dt_probe_clause_t *pcp, *pcp_next;
dt_probe_instance_t *pip, *pip_next;
dtrace_hdl_t *dtp;
@@ -1321,9 +1326,9 @@ no_mem:
int
dt_probe_add_clause(dtrace_hdl_t *dtp, dt_probe_t *prp, dt_ident_t *idp)
{
- dt_probeclause_t *pcp;
+ dt_probe_clause_t *pcp;
- pcp = dt_zalloc(dtp, sizeof(dt_probeclause_t));;
+ pcp = dt_zalloc(dtp, sizeof(dt_probe_clause_t));;
if (pcp == NULL)
return dt_set_errno(dtp, EDT_NOMEM);
@@ -1345,7 +1350,7 @@ int
dt_probe_clause_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp,
dt_clause_f *func, void *arg)
{
- dt_probeclause_t *pcp;
+ dt_probe_clause_t *pcp;
int rc;
assert(func != NULL);
@@ -1361,6 +1366,49 @@ dt_probe_clause_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp,
return 0;
}
+int
+dt_probe_add_dependent(dtrace_hdl_t *dtp, dt_probe_t *prp, dt_probe_t *dprp)
+{
+ dt_probe_dependent_t *pdp;
+
+ /* Ignore dependent probes already in the list. */
+ for (pdp = dt_list_next(&prp->dependents); pdp != NULL;
+ pdp = dt_list_next(pdp)) {
+ if (pdp->probe == dprp)
+ return 0;
+ }
+
+ pdp = dt_zalloc(dtp, sizeof(dt_probe_dependent_t));;
+ if (pdp == NULL)
+ return dt_set_errno(dtp, EDT_NOMEM);
+
+ pdp->probe = dprp;
+
+ dt_list_append(&prp->dependents, pdp);
+
+ return 0;
+}
+
+int
+dt_probe_dependent_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp,
+ dt_dependent_f *func, void *arg)
+{
+ dt_probe_dependent_t *pdp;
+ int rc;
+
+ assert(func != NULL);
+
+ for (pdp = dt_list_next(&prp->dependents); pdp != NULL;
+ pdp = dt_list_next(pdp)) {
+ rc = func(dtp, pdp->probe, arg);
+
+ if (rc != 0)
+ return rc;
+ }
+
+ return 0;
+}
+
void
dt_probe_init(dtrace_hdl_t *dtp)
{
diff --git a/libdtrace/dt_probe.h b/libdtrace/dt_probe.h
index 6464af55..4b9396a7 100644
--- a/libdtrace/dt_probe.h
+++ b/libdtrace/dt_probe.h
@@ -33,6 +33,7 @@ typedef struct dt_probe_instance {
typedef struct dt_probe {
dt_list_t list; /* prev/next in enablings chain */
dt_list_t clauses; /* clauses to attach */
+ dt_list_t dependents; /* dependenct probes to attach */
const dtrace_probedesc_t *desc; /* probe description (id, name) */
dt_provider_t *prov; /* pointer to containing provider */
struct dt_hentry he_prv; /* provider name htab links */
@@ -90,6 +91,12 @@ typedef int dt_clause_f(dtrace_hdl_t *dtp, dt_ident_t *idp, void *arg);
extern int dt_probe_clause_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp,
dt_clause_f *func, void *arg);
+extern int dt_probe_add_dependent(dtrace_hdl_t *dtp, dt_probe_t *prp,
+ dt_probe_t *idprp);
+typedef int dt_dependent_f(dtrace_hdl_t *dtp, dt_probe_t *prp, void *arg);
+extern int dt_probe_dependent_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp,
+ dt_dependent_f *func, void *arg);
+
extern void dt_probe_init(dtrace_hdl_t *dtp);
extern void dt_probe_detach(dtrace_hdl_t *dtp);
--
2.39.1
More information about the DTrace-devel
mailing list