[DTrace-devel] [PATCH 12/47] Implementation of the exit() action

Kris Van Hees kris.van.hees at oracle.com
Sun May 3 20:17:01 PDT 2020


The exit() action is quite instrumental to the use of DTrace because it
allows a tracing script to terminate the tracing session.

Because exit() must be able to signal that trace data processing is
done, dt_consume_one(), dt_consume_cpu(), and dt_consume() have been
updated to return a dtrace_workstatus_t value to indicate whether
processing of trace data is to continue (DTRACE_WORKSTATUS_OKAY),
is done (DTRACE_WORKSTATUS_DONE), or whether an error occurred
(DTRACE_WORKSTATUS_ERROR).

Orabug: 31220520
Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
Reviewed-by: Kris Van Hees <kris.van.hees at oracle.com>
Reviewed-by: Eugene Loh <eugene.loh at oracle.com>
---
 libdtrace/dt_cg.c                             | 10 +++--
 libdtrace/dt_consume.c                        | 37 ++++++++++++-------
 libdtrace/dt_work.c                           | 11 +-----
 .../actions/exit/err.D_PROTO_LEN.noarg.d      | 19 ++++++++++
 .../actions/exit/err.D_PROTO_LEN.noarg.r      |  2 +
 test/unittest/actions/exit/err.fail.d         | 19 ++++++++++
 test/unittest/actions/exit/err.fail.r         |  1 +
 test/unittest/actions/exit/tst.success.d      | 19 ++++++++++
 test/unittest/actions/exit/tst.success.r      |  1 +
 9 files changed, 94 insertions(+), 25 deletions(-)
 create mode 100644 test/unittest/actions/exit/err.D_PROTO_LEN.noarg.d
 create mode 100644 test/unittest/actions/exit/err.D_PROTO_LEN.noarg.r
 create mode 100644 test/unittest/actions/exit/err.fail.d
 create mode 100644 test/unittest/actions/exit/err.fail.r
 create mode 100644 test/unittest/actions/exit/tst.success.d
 create mode 100644 test/unittest/actions/exit/tst.success.r

diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 538960c9..39ba1f6d 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -42,7 +42,7 @@ static void dt_cg_node(dt_node_t *, dt_irlist_t *, dt_regset_t *);
  * output data buffer, and then store the next address location in %r9.
  *
  * In the epilogue, we then need to submit (%r9 - 4) as source address of our
- * data buffer.
+ * data buffer and add 4 to the record size..
  */
 static void
 dt_cg_prologue(dt_pcb_t *pcb)
@@ -166,6 +166,7 @@ dt_cg_epilogue(dt_pcb_t *pcb)
 	 *		mov %r4, %r9
 	 *		add %r4, -4
 	 *		mov %r5, pcb->pcb_bufoff
+	 *		add %r4, 4
 	 *		call bpf_perf_event_output
 	 *		mov %r0, 0
 	 */
@@ -180,6 +181,8 @@ dt_cg_epilogue(dt_pcb_t *pcb)
 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
 	instr = BPF_MOV_IMM(BPF_REG_5, pcb->pcb_bufoff);
 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+	instr = BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 4);
+	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
 	instr = BPF_CALL_HELPER(BPF_FUNC_perf_event_output);
 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
 
@@ -362,11 +365,12 @@ dt_cg_act_exit(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
 	dt_cg_node(dnp->dn_args, &pcb->pcb_ir, pcb->pcb_regs);
 
 	off = dt_rec_add(pcb->pcb_hdl, dt_cg_fill_gap, DTRACEACT_EXIT,
-			 sizeof(uint64_t), sizeof(uint64_t), NULL,
+			 sizeof(uint32_t), sizeof(uint32_t), NULL,
 			 DT_ACT_EXIT);
 
-	instr = BPF_STORE(BPF_DW, BPF_REG_9, off, BPF_REG_0);	/* FIXME */
+	instr = BPF_STORE(BPF_W, BPF_REG_9, off, dnp->dn_args->dn_reg);
 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+	dt_regset_free(pcb->pcb_regs, dnp->dn_args->dn_reg);
 }
 
 static void
diff --git a/libdtrace/dt_consume.c b/libdtrace/dt_consume.c
index 60a16b70..a47ebf33 100644
--- a/libdtrace/dt_consume.c
+++ b/libdtrace/dt_consume.c
@@ -2254,10 +2254,10 @@ nextepid:
 	return (dt_handle_cpudrop(dtp, cpu, DTRACEDROP_PRINCIPAL, drops));
 }
 #else
-int
+dtrace_workstatus_t
 dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, int cpu, char *buf,
 	       dtrace_consume_probe_f *efunc, dtrace_consume_rec_f *rfunc,
-	       int flow, int quiet, dtrace_epid_t last, void *arg)
+	       int flow, int quiet, dtrace_epid_t *last, void *arg)
 {
 	char				*data = buf;
 	struct perf_event_header	*hdr;
@@ -2270,6 +2270,7 @@ dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, int cpu, char *buf,
 		char			*ptr = data;
 		uint32_t		size, epid, tag;
 		int			i;
+		int			done = 0;
 		dtrace_probedata_t	pdat;
 
 		/*
@@ -2319,7 +2320,7 @@ dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, int cpu, char *buf,
 			return rval;
 
 		if (flow)
-			dt_flowindent(dtp, &pdat, last, DTRACE_EPIDNONE);
+			dt_flowindent(dtp, &pdat, *last, DTRACE_EPIDNONE);
 
 		rval = (*efunc)(&pdat, arg);
 
@@ -2345,6 +2346,8 @@ dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, int cpu, char *buf,
 			dtrace_recdesc_t	*rec;
 
 			rec = &pdat.dtpda_ddesc->dtdd_recs[i];
+			if (rec->dtrd_action == DTRACEACT_EXIT)
+				done = 1;
 
 			pdat.dtpda_data = data + rec->dtrd_offset;
 			rval = (*rfunc)(&pdat, rec, arg);
@@ -2371,7 +2374,9 @@ dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, int cpu, char *buf,
 		 */
 		rval = (*rfunc)(&pdat, NULL, arg);
 
-		return epid;
+		*last = epid;
+
+		return done ? DTRACE_WORKSTATUS_DONE : DTRACE_WORKSTATUS_OKAY;
 	} else if (hdr->type == PERF_RECORD_LOST) {
 		uint64_t	lost;
 
@@ -2386,9 +2391,9 @@ dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, int cpu, char *buf,
 		lost = *(uint64_t *)(data + sizeof(uint64_t));
 
 		/* FIXME: To be implemented */
-		return -1;
+		return DTRACE_WORKSTATUS_ERROR;
 	} else
-		return -1;
+		return DTRACE_WORKSTATUS_ERROR;
 }
 
 int
@@ -2406,6 +2411,7 @@ dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, dt_peb_t *peb,
 	dt_pebset_t			*pebset = dtp->dt_pebset;
 	uint64_t			data_size = pebset->data_size;
 	int				flow, quiet;
+	dtrace_workstatus_t		rval = DTRACE_WORKSTATUS_OKAY;
 
 	flow = (dtp->dt_options[DTRACEOPT_FLOWINDENT] != DTRACEOPT_UNSET);
 	quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET);
@@ -2450,15 +2456,18 @@ dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, dt_peb_t *peb,
 				event = dst;
 			}
 
-			last = dt_consume_one(dtp, fp, cpu, event, efunc, rfunc,
-					      flow, quiet, last, arg);
+			rval = dt_consume_one(dtp, fp, cpu, event, efunc, rfunc,
+					      flow, quiet, &last, arg);
+			if (rval != DTRACE_WORKSTATUS_OKAY)
+				return rval;
+
 			tail += hdr->size;
 		} while (tail != head);
 
 		ring_buffer_write_tail(rb_page, tail);
 	}
 
-	return 0;
+	return DTRACE_WORKSTATUS_OKAY;
 }
 #endif
 
@@ -2666,7 +2675,7 @@ dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, dtrace_bufdesc_t *buf,
 	return (rval);
 }
 
-int
+dtrace_workstatus_t
 dtrace_consume(dtrace_hdl_t *dtp, FILE *fp,
     dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg)
 {
@@ -2779,8 +2788,10 @@ dtrace_consume(dtrace_hdl_t *dtp, FILE *fp,
 	timeout /= NANOSEC / MILLISEC;
 	cnt = epoll_wait(dtp->dt_poll_fd, events, dtp->dt_conf.numcpus,
 			 timeout);
-	if (cnt < 0)
-		return dt_set_errno(dtp, errno);
+	if (cnt < 0) {
+		dt_set_errno(dtp, errno);
+		return DTRACE_WORKSTATUS_ERROR;
+	}
 
 	/*
 	 * Loop over the buffers that have data available, and process them one
@@ -2795,6 +2806,6 @@ dtrace_consume(dtrace_hdl_t *dtp, FILE *fp,
 			return rval;
 	}
 
-	return 0;
+	return DTRACE_WORKSTATUS_OKAY;
 #endif
 }
diff --git a/libdtrace/dt_work.c b/libdtrace/dt_work.c
index 7889ba78..4e8cf111 100644
--- a/libdtrace/dt_work.c
+++ b/libdtrace/dt_work.c
@@ -1,6 +1,6 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
@@ -337,13 +337,6 @@ dtrace_workstatus_t
 dtrace_work(dtrace_hdl_t *dtp, FILE *fp, dtrace_consume_probe_f *pfunc,
 	    dtrace_consume_rec_f *rfunc, void *arg)
 {
-	dtrace_workstatus_t	rval;
-
-	rval = DTRACE_WORKSTATUS_OKAY;
-
-	if (dtrace_consume(dtp, fp, pfunc, rfunc, arg) == -1)
-		return DTRACE_WORKSTATUS_ERROR;
-
-	return rval;
+	return dtrace_consume(dtp, fp, pfunc, rfunc, arg);
 }
 #endif
diff --git a/test/unittest/actions/exit/err.D_PROTO_LEN.noarg.d b/test/unittest/actions/exit/err.D_PROTO_LEN.noarg.d
new file mode 100644
index 00000000..dbe3f96b
--- /dev/null
+++ b/test/unittest/actions/exit/err.D_PROTO_LEN.noarg.d
@@ -0,0 +1,19 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The exit() action requires an argument.
+ *
+ * SECTION: Actions and Subroutines/exit()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	exit();
+}
diff --git a/test/unittest/actions/exit/err.D_PROTO_LEN.noarg.r b/test/unittest/actions/exit/err.D_PROTO_LEN.noarg.r
new file mode 100644
index 00000000..db1e1510
--- /dev/null
+++ b/test/unittest/actions/exit/err.D_PROTO_LEN.noarg.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/exit/err.D_PROTO_LEN.noarg.d: [D_PROTO_LEN] line 18: exit( ) prototype mismatch: 0 args passed, 1 expected
diff --git a/test/unittest/actions/exit/err.fail.d b/test/unittest/actions/exit/err.fail.d
new file mode 100644
index 00000000..046d1637
--- /dev/null
+++ b/test/unittest/actions/exit/err.fail.d
@@ -0,0 +1,19 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: Calling exit(n) indicates failures if n is not 0.
+ *
+ * SECTION: Actions and Subroutines/exit()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	exit(1);
+}
diff --git a/test/unittest/actions/exit/err.fail.r b/test/unittest/actions/exit/err.fail.r
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/unittest/actions/exit/err.fail.r
@@ -0,0 +1 @@
+
diff --git a/test/unittest/actions/exit/tst.success.d b/test/unittest/actions/exit/tst.success.d
new file mode 100644
index 00000000..1e95d1dd
--- /dev/null
+++ b/test/unittest/actions/exit/tst.success.d
@@ -0,0 +1,19 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: Calling exit(0) indicates success.
+ *
+ * SECTION: Actions and Subroutines/exit()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	exit(0);
+}
diff --git a/test/unittest/actions/exit/tst.success.r b/test/unittest/actions/exit/tst.success.r
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/unittest/actions/exit/tst.success.r
@@ -0,0 +1 @@
+
-- 
2.26.0




More information about the DTrace-devel mailing list