[DTrace-devel] [PATCH] The exit() action must set the activity state to DRAINING

Eugene Loh eugene.loh at oracle.com
Fri Sep 4 21:43:07 PDT 2020


On 09/02/2020 01:56 PM, Kris Van Hees wrote:

> Now that activity state is supported, the exit() action needs to move
> the activity state to DRAINING to prevent further probe firings from
> being processed.

I don't understand this patch.  In a previous patch, we told END to 
short circuit if the activity state is not ACTIVE.  So, if exit() 
changes the activity state to DRAINING, then END will not execute its 
clause.  That seems wrong.

Consider:

     # dtrace -n 'BEGIN {exit(0)} END{trace(1234)}'
     dtrace: description 'BEGIN ' matched 2 probes
CPU     ID                    FUNCTION:NAME

Okay, now what?  With DTv1:

       7      1                           :BEGIN
       7      2                             :END      1234

Both probes fire and report.  Good.  What about DTv2?  Well, with your 
new patch:

       1      1                           :BEGIN

while before your patch:

       1      1                           :BEGIN
       1      1                           :BEGIN

Grrr.  Very confusing.  Let me throw in a quick hack just so we can make 
sense of what's going on.  In dt_consume.c:

     @@ -2535,10 +2535,11 @@ dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, 
int cpu, dt_peb_t *peb,
                  rval = dt_consume_one(dtp, fp, cpu, event, &pdat,
                                efunc, rfunc, flow, quiet, &last,
                                arg);
     +            tail += hdr->size;
     +            ring_buffer_write_tail(rb_page, tail);
     +
                  if (rval != DTRACE_WORKSTATUS_OKAY)
                      return rval;
     -
     -            tail += hdr->size;
              } while (tail != head);

              ring_buffer_write_tail(rb_page, tail);

That's just to clean up the reporting of the last probe.  Okay, so 
hacked, I get (with your patch):

       1      1                           :BEGIN

while before your patch:

       1      1                           :BEGIN
       1      2                             :END        1234

I can imagine your "Wow, that's a lot of writing just to say it's 
wrong."  Sorry, I'm trying to think these things out.  It seems to me 
your patch breaks things by exit() disabling the ERROR probe's clause.

As you say, patches should include tests.  I do not know what tests were 
done here.  The patch does not indicate any tests.

> Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
> ---
>   libdtrace/dt_cg.c | 48 +++++++++++++++++++++++++++++++++++++++++++++--
>   1 file changed, 46 insertions(+), 2 deletions(-)
>
> diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
> index 01e8707f..d289e02b 100644
> --- a/libdtrace/dt_cg.c
> +++ b/libdtrace/dt_cg.c
> @@ -674,7 +674,9 @@ dt_cg_act_discard(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
>   }
>   
>   /*
> - * Signal that tracing should be terminated with the given return code.
> + * Signal that tracing should be terminated with the given return code.  This
> + * action also forces the activity state to be set to DRAINING to signal that
> + * tracing is ending.
>    *
>    * Stores:
>    *	integer (4 bytes)		-- return code
> @@ -682,12 +684,54 @@ dt_cg_act_discard(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
>   static void
>   dt_cg_act_exit(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
>   {
> -	struct bpf_insn	instr;
>   	dt_irlist_t	*dlp = &pcb->pcb_ir;
> +	dt_ident_t	*state = dt_dlib_get_map(pcb->pcb_hdl, "state");
> +	struct bpf_insn	instr;
>   	uint_t		off;
>   
> +	/* Evaluate the exit code expression. */
>   	dt_cg_node(dnp->dn_args, &pcb->pcb_ir, pcb->pcb_regs);
>   
> +	/*
> +	 * Force the activity state to DRAINING.
> +	 *
> +	 *	key = DT_STATE_ACTIVITY;// stw [%fp + DT_STK_SPILL(0)],
> +	 *				//		DT_STATE_ACTIVITY
> +	 *	val = DT_ACTIVITY_DRAINING;
> +	 *				// stw [%fp + DT_STK_SPILL(1)],
> +	 *				//		DT_ACTIVITY_DRAINING
> +	 *	rc = bpf_map_update_elem(&state, &key, &val, BPF_ANY);
> +	 *				// lddw %r1, &state
> +	 *				// mov %r2, %fp
> +	 *				// add %r2, DT_STK_SPILL(0)
> +	 *				// mov %r3, %fp
> +	 *				// add %r3, DT_STK_SPILL(1)
> +	 *				// mov %r4, BPF_ANY
> +	 *				// call bpf_map_update_elem
> +	 *				//     (%r1 ... %r5 clobbered)
> +	 *				//     (%r0 = map value)
> +	 */
> +	instr = BPF_STORE_IMM(BPF_W, BPF_REG_FP, DT_STK_SPILL(0),
> +			      DT_STATE_ACTIVITY);
> +	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
> +	instr = BPF_STORE_IMM(BPF_W, BPF_REG_FP, DT_STK_SPILL(1),
> +			      DT_ACTIVITY_DRAINING);
> +	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
> +	dt_cg_xsetx(dlp, state, DT_LBL_NONE, BPF_REG_1, state->di_id);
> +	instr = BPF_MOV_REG(BPF_REG_2, BPF_REG_FP);
> +	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
> +	instr = BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, DT_STK_SPILL(0));
> +	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
> +	instr = BPF_MOV_REG(BPF_REG_3, BPF_REG_FP);
> +	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
> +	instr = BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, DT_STK_SPILL(1));
> +	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
> +	instr = BPF_MOV_IMM(BPF_REG_4, BPF_ANY);
> +	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
> +	instr = BPF_CALL_HELPER(BPF_FUNC_map_update_elem);
> +	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
> +
> +	/* Record the exit code. */
>   	off = dt_rec_add(pcb->pcb_hdl, dt_cg_fill_gap, DTRACEACT_EXIT,
>   			 sizeof(uint32_t), sizeof(uint32_t), NULL,
>   			 DT_ACT_EXIT);




More information about the DTrace-devel mailing list