From e75fdd38b04896fa6a1ac7b2fdea18ef485c70b3 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 22 Jan 2016 20:10:11 +0100 Subject: erts: Clarify docs for trace_pattern/3 --- erts/doc/src/erlang.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index 423ccdf98f..c7b5ea8867 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -9199,7 +9199,8 @@ timestamp() -> true -

Enables tracing for the matching functions.

+

Enables tracing for the matching functions. + Any match specification is removed.

MatchSpecList -- cgit v1.2.3 From 03afaae12811632cf975586728826af14a634ad1 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 22 Jan 2016 20:12:40 +0100 Subject: erts: Beautify some code with container_of macro --- erts/emulator/beam/erl_bif_trace.c | 11 ++++------- erts/emulator/beam/sys.h | 3 +++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index ff2018aa27..09c82ad206 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -1307,7 +1307,7 @@ erts_set_trace_pattern(Process*p, Eterm* mfa, int specified, for (i = 0; i < n; i++) { BeamInstr* pc = fp[i].pc; - Export* ep = (Export *)(((char *)(pc-3)) - offsetof(Export, code)); + Export* ep = ErtsContainerStruct(pc, Export, code[3]); if (on && !flags.breakpoint) { /* Turn on global call tracing */ @@ -1556,11 +1556,10 @@ install_exp_breakpoints(BpFunctions* f) BpFunction* fp = f->matching; Uint ne = f->matched; Uint i; - Uint offset = offsetof(Export, code) + 3*sizeof(BeamInstr); for (i = 0; i < ne; i++) { BeamInstr* pc = fp[i].pc; - Export* ep = (Export *) (((char *)pc)-offset); + Export* ep = ErtsContainerStruct(pc, Export, code[3]); ep->addressv[code_ix] = pc; } @@ -1573,11 +1572,10 @@ uninstall_exp_breakpoints(BpFunctions* f) BpFunction* fp = f->matching; Uint ne = f->matched; Uint i; - Uint offset = offsetof(Export, code) + 3*sizeof(BeamInstr); for (i = 0; i < ne; i++) { BeamInstr* pc = fp[i].pc; - Export* ep = (Export *) (((char *)pc)-offset); + Export* ep = ErtsContainerStruct(pc, Export, code[3]); if (ep->addressv[code_ix] != pc) { continue; @@ -1594,11 +1592,10 @@ clean_export_entries(BpFunctions* f) BpFunction* fp = f->matching; Uint ne = f->matched; Uint i; - Uint offset = offsetof(Export, code) + 3*sizeof(BeamInstr); for (i = 0; i < ne; i++) { BeamInstr* pc = fp[i].pc; - Export* ep = (Export *) (((char *)pc)-offset); + Export* ep = ErtsContainerStruct(pc, Export, code[3]); if (ep->addressv[code_ix] == pc) { continue; diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index 748fba15c7..dda3ba565c 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -92,6 +92,9 @@ #define ErtsInArea(ptr,start,nbytes) \ ((UWord)((char*)(ptr) - (char*)(start)) < (nbytes)) +#define ErtsContainerStruct(ptr, type, member) \ + (type *)((char *)(1 ? (ptr) : &((type *)0)->member) - offsetof(type, member)) + #if defined (__WIN32__) # include "erl_win_sys.h" #else -- cgit v1.2.3 From 9791998defa447e4620da250bbddacb3c8edc02e Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 22 Jan 2016 20:15:24 +0100 Subject: erts: Rename struct type as is trips up my editor symbol tagging. --- erts/emulator/hipe/hipe_bif0.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index 48cfafb8c5..4063cbf306 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -533,13 +533,13 @@ BIF_RETTYPE hipe_bifs_merge_term_1(BIF_ALIST_1) BIF_RET(val); } -struct mfa { +struct mfa_t { Eterm mod; Eterm fun; Uint ari; }; -static int term_to_mfa(Eterm term, struct mfa *mfa) +static int term_to_mfa(Eterm term, struct mfa_t *mfa) { Eterm mod, fun, a; Uint ari; @@ -597,7 +597,7 @@ static Uint *hipe_find_emu_address(Eterm mod, Eterm name, unsigned int arity) Uint *hipe_bifs_find_pc_from_mfa(Eterm term) { - struct mfa mfa; + struct mfa_t mfa; if (!term_to_mfa(term, &mfa)) return NULL; @@ -617,7 +617,7 @@ BIF_RETTYPE hipe_bifs_set_native_address_3(BIF_ALIST_3) Eterm *pc; void *address; int is_closure; - struct mfa mfa; + struct mfa_t mfa; switch (BIF_ARG_3) { case am_false: @@ -1225,7 +1225,7 @@ void hipe_mfa_set_trampoline(Eterm m, Eterm f, unsigned int arity, void *trampol BIF_RETTYPE hipe_bifs_set_funinfo_native_address_3(BIF_ALIST_3) { - struct mfa mfa; + struct mfa_t mfa; void *address; int is_exported; @@ -1247,7 +1247,7 @@ BIF_RETTYPE hipe_bifs_set_funinfo_native_address_3(BIF_ALIST_3) BIF_RETTYPE hipe_bifs_invalidate_funinfo_native_addresses_1(BIF_ALIST_1) { Eterm lst; - struct mfa mfa; + struct mfa_t mfa; struct hipe_mfa_info *p; hipe_mfa_info_table_rwlock(); @@ -1416,7 +1416,7 @@ BIF_RETTYPE hipe_find_na_or_make_stub(BIF_ALIST_3) BIF_RETTYPE hipe_bifs_find_na_or_make_stub_2(BIF_ALIST_2) { - struct mfa mfa; + struct mfa_t mfa; void *address; int is_remote; @@ -1518,9 +1518,9 @@ struct ref { */ BIF_RETTYPE hipe_bifs_add_ref_2(BIF_ALIST_2) { - struct mfa callee; + struct mfa_t callee; Eterm *tuple; - struct mfa caller; + struct mfa_t caller; void *address; void *trampoline; unsigned int flags; @@ -1597,7 +1597,7 @@ BIF_RETTYPE hipe_bifs_add_ref_2(BIF_ALIST_2) */ BIF_RETTYPE hipe_bifs_mark_referred_from_1(BIF_ALIST_1) /* get_refs_from */ { - struct mfa mfa; + struct mfa_t mfa; const struct hipe_mfa_info *p; struct ref *ref; @@ -1649,7 +1649,7 @@ static void hipe_purge_all_refs(void) BIF_RETTYPE hipe_bifs_remove_refs_from_1(BIF_ALIST_1) { - struct mfa mfa; + struct mfa_t mfa; struct hipe_mfa_info *caller_mfa, *callee_mfa; struct hipe_mfa_info_list *refers_to, *tmp_refers_to; struct ref **prev, *ref; @@ -1703,7 +1703,7 @@ BIF_RETTYPE hipe_bifs_remove_refs_from_1(BIF_ALIST_1) */ BIF_RETTYPE hipe_bifs_redirect_referred_from_1(BIF_ALIST_1) { - struct mfa mfa; + struct mfa_t mfa; struct hipe_mfa_info *p; struct ref **prev, *ref; int is_remote, res; -- cgit v1.2.3 From af2a4c5a40c62da775caa92df5164fbee08b9245 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 2 Feb 2016 17:30:51 +0100 Subject: erts: Rename constants in enum erts_break_op with uppercase for constants and why not call them 'RESTART' and 'PAUSE' as the API. --- erts/emulator/beam/beam_bp.c | 6 +++--- erts/emulator/beam/beam_bp.h | 8 ++++---- erts/emulator/beam/erl_bif_trace.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c index 2ee98ed7b5..c4b9259d64 100644 --- a/erts/emulator/beam/beam_bp.c +++ b/erts/emulator/beam/beam_bp.c @@ -1432,7 +1432,7 @@ set_function_break(BeamInstr *pc, Binary *match_spec, Uint break_flags, g = (GenericBp *) pc[-4]; if (g == 0) { int i; - if (count_op == erts_break_reset || count_op == erts_break_stop) { + if (count_op == ERTS_BREAK_RESTART || count_op == ERTS_BREAK_PAUSE) { /* Do not insert a new breakpoint */ return; } @@ -1456,7 +1456,7 @@ set_function_break(BeamInstr *pc, Binary *match_spec, Uint break_flags, MatchSetUnref(bp->meta_ms); bp_meta_unref(bp->meta_tracer); } else if (common & ERTS_BPF_COUNT) { - if (count_op == erts_break_stop) { + if (count_op == ERTS_BREAK_PAUSE) { bp->flags &= ~ERTS_BPF_COUNT_ACTIVE; } else { bp->flags |= ERTS_BPF_COUNT_ACTIVE; @@ -1468,7 +1468,7 @@ set_function_break(BeamInstr *pc, Binary *match_spec, Uint break_flags, BpDataTime* bdt = bp->time; Uint i = 0; - if (count_op == erts_break_stop) { + if (count_op == ERTS_BREAK_PAUSE) { bp->flags &= ~ERTS_BPF_TIME_TRACE_ACTIVE; } else { bp->flags |= ERTS_BPF_TIME_TRACE_ACTIVE; diff --git a/erts/emulator/beam/beam_bp.h b/erts/emulator/beam/beam_bp.h index bb171be8a6..fc17f95b5d 100644 --- a/erts/emulator/beam/beam_bp.h +++ b/erts/emulator/beam/beam_bp.h @@ -86,10 +86,10 @@ typedef struct generic_bp { #endif enum erts_break_op{ - erts_break_nop = 0, /* Must be false */ - erts_break_set = !0, /* Must be true */ - erts_break_reset, - erts_break_stop + ERTS_BREAK_NOP = 0, /* Must be false */ + ERTS_BREAK_SET = !0, /* Must be true */ + ERTS_BREAK_RESTART, + ERTS_BREAK_PAUSE }; typedef Uint32 ErtsBpIndex; diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index 09c82ad206..ef01aa3340 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -137,10 +137,10 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) on = 1; } else if (Pattern == am_restart) { match_prog_set = NULL; - on = erts_break_reset; + on = ERTS_BREAK_RESTART; } else if (Pattern == am_pause) { match_prog_set = NULL; - on = erts_break_stop; + on = ERTS_BREAK_PAUSE; } else if ((match_prog_set = erts_match_set_compile(p, Pattern)) != NULL) { MatchSetRef(match_prog_set); on = 1; -- cgit v1.2.3 From 4a4475dea3ab0daf29f9a49ce845fa062387362a Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 3 Mar 2016 19:34:50 +0100 Subject: erts: Add match spec for send trace --- erts/emulator/beam/beam_bp.c | 5 +- erts/emulator/beam/erl_bif_trace.c | 57 +++++++++++++++++ erts/emulator/beam/erl_trace.c | 59 +++++++++++++----- erts/emulator/beam/erl_trace.h | 8 +++ erts/emulator/test/trace_SUITE.erl | 123 ++++++++++++++++++++++++++++++++----- 5 files changed, 220 insertions(+), 32 deletions(-) diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c index c4b9259d64..1e30e8d8d1 100644 --- a/erts/emulator/beam/beam_bp.c +++ b/erts/emulator/beam/beam_bp.c @@ -248,7 +248,10 @@ erts_bp_match_export(BpFunctions* f, Eterm mfa[3], int specified) void erts_bp_free_matched_functions(BpFunctions* f) { - Free(f->matching); + if (f->matching) { + Free(f->matching); + } + else ASSERT(f->matched == 0); } void diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index ef01aa3340..6b5bb2f889 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -68,6 +68,9 @@ static struct { /* Protected by code write permission */ static Eterm trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist); +static void +erts_set_trace_send_pattern(Process*, Binary*, int on); + #ifdef ERTS_SMP static void smp_bp_finisher(void* arg); #endif @@ -85,14 +88,23 @@ static void install_exp_breakpoints(BpFunctions* f); static void uninstall_exp_breakpoints(BpFunctions* f); static void clean_export_entries(BpFunctions* f); +ErtsTracingEvent erts_send_tracing[ERTS_NUM_BP_IX]; + void erts_bif_trace_init(void) { + int i; + erts_default_trace_pattern_is_on = 0; erts_default_match_spec = NULL; erts_default_meta_match_spec = NULL; erts_default_trace_pattern_flags = erts_trace_pattern_flags_off; erts_default_meta_tracer = erts_tracer_nil; + + for (i=0; i ERTS_BREAK_SET) { + goto error; + } + erts_set_trace_send_pattern(p, match_prog_set, on); + matches = 1; } + error: MatchSetUnref(match_prog_set); UnUseTmpHeap(3,p); @@ -1467,6 +1486,43 @@ erts_set_trace_pattern(Process*p, Eterm* mfa, int specified, return matches; } +void +erts_set_trace_send_pattern(Process*p, Binary* match_spec, int on) +{ + ErtsTracingEvent* st = &erts_send_tracing[erts_staging_bp_ix()]; + + MatchSetUnref(st->match_spec); + + st->on = on; + st->match_spec = match_spec; + MatchSetRef(match_spec); + + finish_bp.current = 1; /* prepare phase not needed for send trace */ + finish_bp.install = on; + finish_bp.e.matched = 0; + finish_bp.e.matching = NULL; + finish_bp.f.matched = 0; + finish_bp.f.matching = NULL; + +#ifndef ERTS_SMP + while (erts_finish_breakpointing()) { + /* Empty loop body */ + } +#endif +} + +static void +consolidate_send_tracing(void) +{ + ErtsTracingEvent* src = &erts_send_tracing[erts_active_bp_ix()]; + ErtsTracingEvent* dst = &erts_send_tracing[erts_staging_bp_ix()]; + + MatchSetUnref(dst->match_spec); + dst->on = src->on; + dst->match_spec = src->match_spec; + MatchSetRef(dst->match_spec); +} + int erts_finish_breakpointing(void) { @@ -1542,6 +1598,7 @@ erts_finish_breakpointing(void) erts_consolidate_bp_data(&finish_bp.f, 1); erts_bp_free_matched_functions(&finish_bp.e); erts_bp_free_matched_functions(&finish_bp.f); + consolidate_send_tracing(); return 0; default: ASSERT(0); diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index 56899f574a..e8516cd09c 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -394,7 +394,8 @@ static ERTS_INLINE int send_to_tracer_nif(Process *c_p, ErtsPTabElementCommon *t_p, Eterm t_p_id, ErtsTracerNif *tnif, enum ErtsTracerOpt topt, - Eterm tag, Eterm msg, Eterm extra); + Eterm tag, Eterm msg, Eterm extra, + Eterm pam_result); static ERTS_INLINE Eterm call_enabled_tracer(Process *c_p, const ErtsTracer tracer, ErtsTracerNif **tnif_ref, @@ -786,7 +787,7 @@ trace_sched_aux(Process *p, ErtsProcLocks locks, Eterm what) } send_to_tracer_nif(p, &p->common, p->common.id, tnif, TRACE_FUN_T_SCHED_PROC, - what, tmp, THE_NON_VALUE); + what, tmp, THE_NON_VALUE, am_true); } /* Send {trace_ts, Pid, What, {Mod, Func, Arity}, Timestamp} @@ -811,9 +812,31 @@ trace_send(Process *p, Eterm to, Eterm msg) { Eterm operation = am_send; ErtsTracerNif *tnif = NULL; + ErtsTracingEvent* te; + Eterm pam_result; ASSERT(ARE_TRACE_FLAGS_ON(p, F_TRACE_SEND)); + te = &erts_send_tracing[erts_active_bp_ix()]; + if (!te->on) { + return; + } + if (te->match_spec) { + Eterm args[2]; + Uint32 return_flags; + args[0] = to; + args[1] = msg; + pam_result = erts_match_set_run(p, te->match_spec, args, 2, + ERTS_PAM_TMP_RESULT, &return_flags); + if (is_non_value(pam_result) + || pam_result == am_false + || (ERTS_TRACE_FLAGS(p) & F_TRACE_SILENT)) { + erts_match_set_release_result(p); + return; + } + } else + pam_result = am_true; + if (is_internal_pid(to)) { if (!erts_proc_lookup(to)) goto send_to_non_existing_process; @@ -825,9 +848,11 @@ trace_send(Process *p, Eterm to, Eterm msg) } if (is_tracer_enabled(p, ERTS_PROC_LOCK_MAIN, &p->common, &tnif, - TRACE_FUN_E_SEND, operation)) + TRACE_FUN_E_SEND, operation)) { send_to_tracer_nif(p, &p->common, p->common.id, tnif, TRACE_FUN_T_SEND, - operation, msg, to); + operation, msg, to, pam_result); + } + erts_match_set_release_result(p); } /* Send {trace_ts, Pid, receive, Msg, Timestamp} @@ -841,7 +866,7 @@ trace_receive(Process *c_p, Eterm msg) TRACE_FUN_E_RECEIVE, am_receive)) send_to_tracer_nif(NULL, &c_p->common, c_p->common.id, tnif, TRACE_FUN_T_RECEIVE, - am_receive, msg, THE_NON_VALUE); + am_receive, msg, THE_NON_VALUE, am_true); } int @@ -963,7 +988,7 @@ erts_trace_return_to(Process *p, BeamInstr *pc) } send_to_tracer_nif(p, &p->common, p->common.id, NULL, TRACE_FUN_T_CALL, - am_return_to, mfa, THE_NON_VALUE); + am_return_to, mfa, THE_NON_VALUE, am_true); } @@ -1289,7 +1314,7 @@ trace_proc(Process *c_p, ErtsProcLocks c_p_locks, if (is_tracer_enabled(c_p, c_p_locks, &t_p->common, &tnif, TRACE_FUN_E_PROCS, what)) send_to_tracer_nif(c_p, &t_p->common, t_p->common.id, tnif, TRACE_FUN_T_PROCS, - what, data, THE_NON_VALUE); + what, data, THE_NON_VALUE, am_true); } @@ -1315,7 +1340,7 @@ trace_proc_spawn(Process *p, Eterm what, Eterm pid, mfa = TUPLE3(hp, mod, func, args); hp += 4; send_to_tracer_nif(p, &p->common, p->common.id, tnif, TRACE_FUN_T_PROCS, - what, pid, mfa); + what, pid, mfa, am_true); } } @@ -1365,7 +1390,7 @@ trace_gc(Process *p, Eterm what, Uint size) msg = CONS(hp, tup, msg); hp += 2; send_to_tracer_nif(p, &p->common, p->common.id, tnif, TRACE_FUN_T_GC, - what, msg, am_undefined); + what, msg, am_undefined, am_true); } } @@ -1780,7 +1805,7 @@ trace_port_open(Port *p, Eterm calling_pid, Eterm drv_name) { ERTS_SMP_CHK_NO_PROC_LOCKS; if (is_tracer_enabled(NULL, 0, &p->common, &tnif, TRACE_FUN_E_PORTS, am_open)) send_to_tracer_nif(NULL, &p->common, p->common.id, tnif, TRACE_FUN_T_PORTS, - am_open, calling_pid, drv_name); + am_open, calling_pid, drv_name, am_true); } /* Sends trace message: @@ -1799,7 +1824,7 @@ trace_port(Port *t_p, Eterm what, Eterm data) { ERTS_SMP_CHK_NO_PROC_LOCKS; if (is_tracer_enabled(NULL, 0, &t_p->common, &tnif, TRACE_FUN_E_PORTS, what)) send_to_tracer_nif(NULL, &t_p->common, t_p->common.id, tnif, TRACE_FUN_T_PORTS, - what, data, THE_NON_VALUE); + what, data, THE_NON_VALUE, am_true); } @@ -1936,7 +1961,7 @@ trace_port_receive(Port *t_p, Eterm caller, Eterm what, ...) data = TUPLE2(hp, caller, data); send_to_tracer_nif(NULL, &t_p->common, t_p->common.id, tnif, TRACE_FUN_T_RECEIVE, - am_receive, data, THE_NON_VALUE); + am_receive, data, THE_NON_VALUE, am_true); if (bptr && erts_refc_dectest(&bptr->refc, 1) == 0) erts_bin_free(bptr); @@ -1959,7 +1984,7 @@ trace_port_send(Port *t_p, Eterm receiver, Eterm msg, int exists) ERTS_SMP_CHK_NO_PROC_LOCKS; if (is_tracer_enabled(NULL, 0, &t_p->common, &tnif, TRACE_FUN_E_SEND, op)) send_to_tracer_nif(NULL, &t_p->common, t_p->common.id, tnif, TRACE_FUN_T_SEND, - op, msg, receiver); + op, msg, receiver, am_true); } void trace_port_send_binary(Port *t_p, Eterm to, Eterm what, char *bin, Sint sz) @@ -1988,7 +2013,7 @@ void trace_port_send_binary(Port *t_p, Eterm to, Eterm what, char *bin, Sint sz) hp += 3; send_to_tracer_nif(NULL, &t_p->common, t_p->common.id, tnif, TRACE_FUN_T_SEND, - am_send, msg, to); + am_send, msg, to, am_true); if (bptr && erts_refc_dectest(&bptr->refc, 1) == 0) erts_bin_free(bptr); @@ -2019,7 +2044,7 @@ trace_sched_ports_where(Port *t_p, Eterm what, Eterm where) { if (is_tracer_enabled(NULL, 0, &t_p->common, &tnif, TRACE_FUN_E_SCHED_PORT, what)) send_to_tracer_nif(NULL, &t_p->common, t_p->common.id, tnif, TRACE_FUN_T_SCHED_PORT, - what, where, THE_NON_VALUE); + what, where, THE_NON_VALUE, am_true); } /* Port profiling */ @@ -2842,7 +2867,7 @@ send_to_tracer_nif_raw(Process *c_p, Process *tracee, static ERTS_INLINE int send_to_tracer_nif(Process *c_p, ErtsPTabElementCommon *t_p, Eterm t_p_id, ErtsTracerNif *tnif, enum ErtsTracerOpt topt, - Eterm tag, Eterm msg, Eterm extra) + Eterm tag, Eterm msg, Eterm extra, Eterm pam_result) { #if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK) if (c_p) { @@ -2862,7 +2887,7 @@ send_to_tracer_nif(Process *c_p, ErtsPTabElementCommon *t_p, is_internal_pid(t_p->id) ? (Process*)t_p : NULL, t_p->tracer, t_p->trace_flags, t_p_id, tnif, topt, tag, msg, extra, - am_true); + pam_result); } static ERTS_INLINE Eterm diff --git a/erts/emulator/beam/erl_trace.h b/erts/emulator/beam/erl_trace.h index 9a007e62ec..e8e968c0cf 100644 --- a/erts/emulator/beam/erl_trace.h +++ b/erts/emulator/beam/erl_trace.h @@ -220,4 +220,12 @@ ERTS_DECLARE_DUMMY(erts_tracer_nil) = NIL; && erts_is_tracer_proc_enabled(PROC, ERTS_PROC_LOCK_MAIN, \ &(PROC)->common, am_trace_status)) +typedef struct +{ + int on; + struct binary* match_spec; +} ErtsTracingEvent; + +extern ErtsTracingEvent erts_send_tracing[]; + #endif /* ERL_TRACE_H__ */ diff --git a/erts/emulator/test/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl index b7f312635e..c8cc0fc6e8 100644 --- a/erts/emulator/test/trace_SUITE.erl +++ b/erts/emulator/test/trace_SUITE.erl @@ -255,30 +255,111 @@ send_trace(Config) when is_list(Config) -> %% Check that a message sent to another process is traced. 1 = erlang:trace(Sender, true, [send]), + F1 = fun (Pat) -> + set_trace_pattern(send, Pat, []), + Sender ! {send_please, Receiver, to_receiver}, + {trace, Sender, send, to_receiver, Receiver} = receive_first_trace(), + receive_nothing() + end, + lists:foreach(F1, [no, + [{[Receiver,to_receiver],[],[]}], + [{['_','_'],[],[]}], + [{['$1','_'],[{is_pid,'$1'}],[]}], + [{['_','$1'],[{is_atom,'$1'}],[]}], + true]), + + %% Test {message, Msg} + F1m = fun ({Pat, Msg}) -> + set_trace_pattern(send, Pat, []), + Sender ! {send_please, Receiver, to_receiver}, + {trace, Sender, send, to_receiver, Receiver, Msg} = receive_first_trace(), + receive_nothing() + end, + lists:foreach(F1m, [{[{['_','_'],[],[{message, 4711}]}], 4711}, + {[{['_','_'],[],[{message, "4711"}]}], "4711"} + ]), + + %% Test {message, {process_dump}} + set_trace_pattern(send, [{['_','_'],[],[{message, {process_dump}}]}], []), Sender ! {send_please, Receiver, to_receiver}, - {trace, Sender, send, to_receiver, Receiver} = receive_first_trace(), + {trace, Sender, send, to_receiver, Receiver, ProcDump} = receive_first_trace(), + true = is_binary(ProcDump), receive_nothing(), + %% Same test with false match spec + F2 = fun (Pat) -> + set_trace_pattern(send, Pat, []), + Sender ! {send_please, Receiver, to_receiver}, + receive_nothing() + end, + lists:foreach(F2, [[{[Sender,to_receiver],[],[]}], + [{[Receiver,nomatch],[],[]}], + [{['$1','_'],[{is_atom,'$1'}],[]}], + [{['_','$1'],[{is_pid,'$1'}],[]}], + false, + [{['_','_'],[],[{message,false}]}], + [{['_','_'],[],[{silent,true}]}]]), + erlang:trace_pattern(send, true, []), + erlang:trace(Sender, false, [silent]), + %% Check that a message sent to another registered process is traced. register(?MODULE,Receiver), - Sender ! {send_please, ?MODULE, to_receiver}, - {trace, Sender, send, to_receiver, ?MODULE} = receive_first_trace(), - receive_nothing(), + F3 = fun (Pat) -> + set_trace_pattern(send, Pat, []), + Sender ! {send_please, ?MODULE, to_receiver}, + {trace, Sender, send, to_receiver, ?MODULE} = receive_first_trace(), + receive_nothing() + end, + lists:foreach(F3, [no, + [{[?MODULE,to_receiver],[],[]}], + [{['_','_'],[],[]}], + [{['$1','_'],[{is_atom,'$1'}],[]}], + [{['_','$1'],[{is_atom,'$1'}],[]}], + true]), + %% Again with false match spec + F4 = fun (Pat) -> + set_trace_pattern(send, Pat, []), + Sender ! {send_please, ?MODULE, to_receiver}, + receive_nothing() + end, + lists:foreach(F4, [[{[nomatch,to_receiver],[],[]}], + [{[?MODULE,nomatch],[],[]}], + [{['$1','_'],[{is_pid,'$1'}],[]}], + [{['_','$1'],[{is_pid,'$1'}],[]}], + [{['_','_'],[],[{message,false}]}], + [{['_','_'],[],[{silent,true}]}] + ]), unregister(?MODULE), + erlang:trace_pattern(send, true, []), + erlang:trace(Sender, false, [silent]), %% Check that a message sent to this process is traced. - Sender ! {send_please, self(), to_myself}, - receive to_myself -> ok end, - Self = self(), - {trace, Sender, send, to_myself, Self} = receive_first_trace(), - receive_nothing(), + F5 = fun (Pat) -> + set_trace_pattern(send, Pat, []), + Sender ! {send_please, self(), to_myself}, + receive to_myself -> ok end, + Self = self(), + {trace, Sender, send, to_myself, Self} = receive_first_trace(), + receive_nothing() + end, + lists:foreach(F5, [no, + [{[self(),to_myself],[],[]}], + [{['_','_'],[],[]}], + true]), %% Check that a message sent to dead process is traced. {Pid,Ref} = spawn_monitor(fun() -> ok end), receive {'DOWN',Ref,_,_,_} -> ok end, - Sender ! {send_please, Pid, to_dead}, - {trace, Sender, send_to_non_existing_process, to_dead, Pid} = receive_first_trace(), - receive_nothing(), + F6 = fun (Pat) -> + set_trace_pattern(send, Pat, []), + Sender ! {send_please, Pid, to_dead}, + {trace, Sender, send_to_non_existing_process, to_dead, Pid} = receive_first_trace(), + receive_nothing() + end, + lists:foreach(F6, [no, + [{[Pid,to_dead],[],[]}], + [{['_','_'],[],[]}], + true]), %% Check that a message sent to unknown registrated process is traced. BadargSender = fun_spawn(fun sender/0), @@ -299,8 +380,22 @@ send_trace(Config) when is_list(Config) -> Sender ! {send_please, self(), to_myself_again}, receive to_myself_again -> ok end, receive_nothing(), + + {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [global])), + {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [local])), + {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [meta])), + {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [{meta,self()}])), + {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [call_count])), + {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [call_time])), + {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, restart, [])), + {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, pause, [])), + + %% Done. ok. +set_trace_pattern(_, no, _) -> 0; +set_trace_pattern(MSA, Pat, Flg) -> erlang:trace_pattern(MSA, Pat, Flg). + %% Test trace(Pid, How, [procs]). procs_trace(Config) when is_list(Config) -> Name = list_to_atom(atom_to_list(?MODULE)++"_procs_trace"), @@ -1441,8 +1536,8 @@ receive_nothing() -> receive Any -> ct:fail({unexpected_message, Any}) - after 200 -> - ok + after 100 -> + ok end. -- cgit v1.2.3 From 3261d580be2263b7b4b70ec3c7670a5de963e91c Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 4 Mar 2016 19:25:38 +0100 Subject: erts: Remove multi scheduler blocking in match specs for enable_trace and disable_trace operations. Instead seize needed locks while updating trace flags. --- erts/emulator/beam/erl_db_util.c | 51 +++++++++++++--------------------------- 1 file changed, 16 insertions(+), 35 deletions(-) diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index 76b96637ae..a1f458038e 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -1758,7 +1758,6 @@ Eterm db_prog_match(Process *c_p, Binary *bprog, Eterm (*bif)(Process*, ...); Eterm bif_args[3]; int fail_label; - int atomic_trace; #ifdef DMC_DEBUG Uint *heap_fence; Uint *stack_fence; @@ -1776,28 +1775,6 @@ Eterm db_prog_match(Process *c_p, Binary *bprog, current_scheduled = esdp->current_process; /* SMP: psp->scheduler_data is set by get_match_pseudo_process */ - atomic_trace = 0; -#define BEGIN_ATOMIC_TRACE(p) \ - do { \ - if (! atomic_trace) { \ - erts_refc_inc(&bprog->refc, 2); \ - erts_smp_proc_unlock((p), ERTS_PROC_LOCK_MAIN); \ - erts_smp_thr_progress_block(); \ - atomic_trace = !0; \ - } \ - } while (0) -#define END_ATOMIC_TRACE(p) \ - do { \ - if (atomic_trace) { \ - erts_smp_thr_progress_unblock(); \ - erts_smp_proc_lock((p), ERTS_PROC_LOCK_MAIN); \ - if (erts_refc_dectest(&bprog->refc, 0) == 0) {\ - erts_bin_free(bprog); \ - } \ - atomic_trace = 0; \ - } \ - } while (0) - #ifdef DMC_DEBUG save_op = 0; heap_fence = (Eterm*)((char*) mpsp->u.heap + prog->stack_offset) - 1; @@ -2334,8 +2311,9 @@ restart: break; case matchEnableTrace: if ( (n = erts_trace_flag2bit(esp[-1]))) { - BEGIN_ATOMIC_TRACE(c_p); + erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); set_tracee_flags(c_p, ERTS_TRACER(c_p), 0, n); + erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); esp[-1] = am_true; } else { esp[-1] = FAIL_TERM; @@ -2345,18 +2323,22 @@ restart: n = erts_trace_flag2bit((--esp)[-1]); esp[-1] = FAIL_TERM; if (n) { - BEGIN_ATOMIC_TRACE(c_p); - if ( (tmpp = get_proc(c_p, 0, esp[0], 0))) { + if ( (tmpp = get_proc(c_p, ERTS_PROC_LOCK_MAIN, esp[0], ERTS_PROC_LOCKS_ALL))) { /* Always take over the tracer of the current process */ set_tracee_flags(tmpp, ERTS_TRACER(c_p), 0, n); - esp[-1] = am_true; + if (tmpp == c_p) + erts_smp_proc_unlock(tmpp, ERTS_PROC_LOCKS_ALL_MINOR); + else + erts_smp_proc_unlock(tmpp, ERTS_PROC_LOCKS_ALL); + esp[-1] = am_true; } } break; case matchDisableTrace: if ( (n = erts_trace_flag2bit(esp[-1]))) { - BEGIN_ATOMIC_TRACE(c_p); + erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); set_tracee_flags(c_p, ERTS_TRACER(c_p), n, 0); + erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); esp[-1] = am_true; } else { esp[-1] = FAIL_TERM; @@ -2366,11 +2348,14 @@ restart: n = erts_trace_flag2bit((--esp)[-1]); esp[-1] = FAIL_TERM; if (n) { - BEGIN_ATOMIC_TRACE(c_p); - if ( (tmpp = get_proc(c_p, 0, esp[0], 0))) { + if ( (tmpp = get_proc(c_p, ERTS_PROC_LOCK_MAIN, esp[0], ERTS_PROC_LOCKS_ALL))) { /* Always take over the tracer of the current process */ set_tracee_flags(tmpp, ERTS_TRACER(c_p), n, 0); - esp[-1] = am_true; + if (tmpp == c_p) + erts_smp_proc_unlock(tmpp, ERTS_PROC_LOCKS_ALL_MINOR); + else + erts_smp_proc_unlock(tmpp, ERTS_PROC_LOCKS_ALL); + esp[-1] = am_true; } } break; @@ -2508,13 +2493,9 @@ success: esdp->current_process = current_scheduled; - END_ATOMIC_TRACE(c_p); - return ret; #undef FAIL #undef FAIL_TERM -#undef BEGIN_ATOMIC_TRACE -#undef END_ATOMIC_TRACE } -- cgit v1.2.3 From 8b2906d9974decf9e8bab24a8f753ba81a025410 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 15 Mar 2016 19:53:42 +0100 Subject: erts: Add matchspec to 'receive' trace --- erts/emulator/beam/beam_emu.c | 2 +- erts/emulator/beam/erl_bif_trace.c | 40 ++++++++++++++--------- erts/emulator/beam/erl_db.c | 3 +- erts/emulator/beam/erl_db_util.c | 62 ++++++++++++++++++++++++------------ erts/emulator/beam/erl_db_util.h | 3 +- erts/emulator/beam/erl_message.c | 37 +++++++++++---------- erts/emulator/beam/erl_trace.c | 48 ++++++++++++++++++++++------ erts/emulator/beam/erl_trace.h | 19 +++++------ erts/emulator/beam/global.h | 4 ++- erts/emulator/hipe/hipe_native_bif.c | 2 +- erts/emulator/test/trace_SUITE.erl | 20 ++++++++++++ 11 files changed, 166 insertions(+), 74 deletions(-) diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 72526bca5e..7eecd059a5 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -2166,7 +2166,7 @@ void process_main(void) PreFetch(0, next); if (IS_TRACED_FL(c_p, F_TRACE_RECEIVE)) { - trace_receive(c_p, am_timeout); + trace_receive(c_p, c_p, am_timeout, NULL); } if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) { save_calls(c_p, &exp_timeout); diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index 6b5bb2f889..7b21ff0110 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -68,8 +68,8 @@ static struct { /* Protected by code write permission */ static Eterm trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist); -static void -erts_set_trace_send_pattern(Process*, Binary*, int on); +static int +erts_set_tracing_event_pattern(Eterm event, Binary*, int on); #ifdef ERTS_SMP static void smp_bp_finisher(void* arg); @@ -89,6 +89,7 @@ static void uninstall_exp_breakpoints(BpFunctions* f); static void clean_export_entries(BpFunctions* f); ErtsTracingEvent erts_send_tracing[ERTS_NUM_BP_IX]; +ErtsTracingEvent erts_receive_tracing[ERTS_NUM_BP_IX]; void erts_bif_trace_init(void) @@ -104,6 +105,8 @@ erts_bif_trace_init(void) for (i=0; i ERTS_BREAK_SET) { goto error; } - erts_set_trace_send_pattern(p, match_prog_set, on); - matches = 1; + matches = erts_set_tracing_event_pattern(MFA, match_prog_set, on); } - error: MatchSetUnref(match_prog_set); UnUseTmpHeap(3,p); @@ -1486,10 +1487,17 @@ erts_set_trace_pattern(Process*p, Eterm* mfa, int specified, return matches; } -void -erts_set_trace_send_pattern(Process*p, Binary* match_spec, int on) +int +erts_set_tracing_event_pattern(Eterm event, Binary* match_spec, int on) { - ErtsTracingEvent* st = &erts_send_tracing[erts_staging_bp_ix()]; + ErtsBpIndex ix = erts_staging_bp_ix(); + ErtsTracingEvent* st; + + switch (event) { + case am_send: st = &erts_send_tracing[ix]; break; + case am_receive: st = &erts_receive_tracing[ix]; break; + default: return -1; + } MatchSetUnref(st->match_spec); @@ -1497,7 +1505,7 @@ erts_set_trace_send_pattern(Process*p, Binary* match_spec, int on) st->match_spec = match_spec; MatchSetRef(match_spec); - finish_bp.current = 1; /* prepare phase not needed for send trace */ + finish_bp.current = 1; /* prepare phase not needed for event trace */ finish_bp.install = on; finish_bp.e.matched = 0; finish_bp.e.matching = NULL; @@ -1509,13 +1517,14 @@ erts_set_trace_send_pattern(Process*p, Binary* match_spec, int on) /* Empty loop body */ } #endif + return 1; } static void -consolidate_send_tracing(void) +consolidate_event_tracing(ErtsTracingEvent te[]) { - ErtsTracingEvent* src = &erts_send_tracing[erts_active_bp_ix()]; - ErtsTracingEvent* dst = &erts_send_tracing[erts_staging_bp_ix()]; + ErtsTracingEvent* src = &te[erts_active_bp_ix()]; + ErtsTracingEvent* dst = &te[erts_staging_bp_ix()]; MatchSetUnref(dst->match_spec); dst->on = src->on; @@ -1529,7 +1538,7 @@ erts_finish_breakpointing(void) ERTS_SMP_LC_ASSERT(erts_has_code_write_permission()); /* - * Memory barriers will be issued for all processes *before* + * Memory barriers will be issued for all schedulers *before* * each of the stages below. (Unless the other schedulers * are blocked, in which case memory barriers will be issued * when they are awaken.) @@ -1598,7 +1607,8 @@ erts_finish_breakpointing(void) erts_consolidate_bp_data(&finish_bp.f, 1); erts_bp_free_matched_functions(&finish_bp.e); erts_bp_free_matched_functions(&finish_bp.f); - consolidate_send_tracing(); + consolidate_event_tracing(erts_send_tracing); + consolidate_event_tracing(erts_receive_tracing); return 0; default: ASSERT(0); diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c index 615d23402b..acaca54e9a 100644 --- a/erts/emulator/beam/erl_db.c +++ b/erts/emulator/beam/erl_db.c @@ -2833,7 +2833,8 @@ BIF_RETTYPE ets_match_spec_run_r_3(BIF_ALIST_3) BIF_TRAP3(bif_export[BIF_ets_match_spec_run_r_3], BIF_P,lst,BIF_ARG_2,ret); } - res = db_prog_match(BIF_P, mp, CAR(list_val(lst)), NULL, 0, + res = db_prog_match(BIF_P, BIF_P, + mp, CAR(list_val(lst)), NULL, 0, ERTS_PAM_COPY_RESULT, &dummy); if (is_value(res)) { hp = HAlloc(BIF_P, 2); diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index a1f458038e..72d59df813 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -1202,14 +1202,16 @@ done: return ret; } -Eterm erts_match_set_run(Process *p, Binary *mpsp, +Eterm erts_match_set_run(Process *c_p, + Process *self, + Binary *mpsp, Eterm *args, int num_args, enum erts_pam_run_flags in_flags, Uint32 *return_flags) { Eterm ret; - ret = db_prog_match(p, mpsp, NIL, args, num_args, + ret = db_prog_match(c_p, self, mpsp, NIL, args, num_args, in_flags, return_flags); #if defined(HARDDEBUG) if (is_non_value(ret)) { @@ -1234,7 +1236,8 @@ static Eterm erts_match_set_run_ets(Process *p, Binary *mpsp, { Eterm ret; - ret = db_prog_match(p, mpsp, args, NULL, num_args, + ret = db_prog_match(p, p, + mpsp, args, NULL, num_args, ERTS_PAM_COPY_RESULT, return_flags); #if defined(HARDDEBUG) @@ -1730,7 +1733,9 @@ static Eterm dpm_array_to_list(Process *psp, Eterm *arr, int arity) ** the parameter 'arity' is only used if 'term' is actually an array, ** i.e. 'DCOMP_TRACE' was specified */ -Eterm db_prog_match(Process *c_p, Binary *bprog, +Eterm db_prog_match(Process *c_p, + Process *self, + Binary *bprog, Eterm term, Eterm *termp, int arity, @@ -1746,7 +1751,7 @@ Eterm db_prog_match(Process *c_p, Binary *bprog, UWord *pc = prog->text; Eterm *ehp; Eterm ret; - Uint n = 0; /* To avoid warning. */ + Uint n; int i; unsigned do_catch; ErtsMatchPseudoProcess *mpsp; @@ -1764,6 +1769,8 @@ Eterm db_prog_match(Process *c_p, Binary *bprog, Uint save_op; #endif /* DMC_DEBUG */ + ERTS_UNDEF(n,0); + mpsp = get_match_pseudo_process(c_p, prog->heap_size); psp = &mpsp->process; @@ -2233,7 +2240,7 @@ restart: pc += n; break; case matchSelf: - *esp++ = c_p->common.id; + *esp++ = self->common.id; break; case matchWaste: --esp; @@ -2243,6 +2250,7 @@ restart: break; case matchProcessDump: { erts_dsprintf_buf_t *dsbufp = erts_create_tmp_dsbuf(0); + ASSERT(c_p == self); print_process_info(ERTS_PRINT_DSBUF, (void *) dsbufp, c_p); *esp++ = new_binary(build_proc, (byte *)dsbufp->str, dsbufp->str_len); @@ -2261,14 +2269,16 @@ restart: *return_flags |= MATCH_SET_EXCEPTION_TRACE; *esp++ = am_true; break; - case matchIsSeqTrace: + case matchIsSeqTrace: + ASSERT(c_p == self); if (have_seqtrace(SEQ_TRACE_TOKEN(c_p))) *esp++ = am_true; else *esp++ = am_false; break; case matchSetSeqToken: - t = erts_seq_trace(c_p, esp[-1], esp[-2], 0); + ASSERT(c_p == self); + t = erts_seq_trace(c_p, esp[-1], esp[-2], 0); if (is_non_value(t)) { esp[-2] = FAIL_TERM; } else { @@ -2276,7 +2286,8 @@ restart: } --esp; break; - case matchSetSeqTokenFake: + case matchSetSeqTokenFake: + ASSERT(c_p == self); t = seq_trace_fake(c_p, esp[-1]); if (is_non_value(t)) { esp[-2] = FAIL_TERM; @@ -2285,7 +2296,8 @@ restart: } --esp; break; - case matchGetSeqToken: + case matchGetSeqToken: + ASSERT(c_p == self); if (have_no_seqtrace(SEQ_TRACE_TOKEN(c_p))) *esp++ = NIL; else { @@ -2309,7 +2321,8 @@ restart: ASSERT(is_immed(ehp[5])); } break; - case matchEnableTrace: + case matchEnableTrace: + ASSERT(c_p == self); if ( (n = erts_trace_flag2bit(esp[-1]))) { erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); set_tracee_flags(c_p, ERTS_TRACER(c_p), 0, n); @@ -2319,7 +2332,8 @@ restart: esp[-1] = FAIL_TERM; } break; - case matchEnableTrace2: + case matchEnableTrace2: + ASSERT(c_p == self); n = erts_trace_flag2bit((--esp)[-1]); esp[-1] = FAIL_TERM; if (n) { @@ -2334,7 +2348,8 @@ restart: } } break; - case matchDisableTrace: + case matchDisableTrace: + ASSERT(c_p == self); if ( (n = erts_trace_flag2bit(esp[-1]))) { erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); set_tracee_flags(c_p, ERTS_TRACER(c_p), n, 0); @@ -2344,7 +2359,8 @@ restart: esp[-1] = FAIL_TERM; } break; - case matchDisableTrace2: + case matchDisableTrace2: + ASSERT(c_p == self); n = erts_trace_flag2bit((--esp)[-1]); esp[-1] = FAIL_TERM; if (n) { @@ -2359,7 +2375,8 @@ restart: } } break; - case matchCaller: + case matchCaller: + ASSERT(c_p == self); if (!(c_p->cp) || !(cp = find_function_from_pc(c_p->cp))) { *esp++ = am_undefined; } else { @@ -2371,7 +2388,8 @@ restart: ehp[3] = make_small((Uint) cp[2]); } break; - case matchSilent: + case matchSilent: + ASSERT(c_p == self); --esp; if (in_flags & ERTS_PAM_IGNORE_TRACE_SILENT) break; @@ -2386,7 +2404,8 @@ restart: erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); } break; - case matchTrace2: + case matchTrace2: + ASSERT(c_p == self); { /* disable enable */ Uint d_flags = 0, e_flags = 0; /* process trace flags */ @@ -2418,7 +2437,8 @@ restart: ERTS_TRACER_CLEAR(&tracer); } break; - case matchTrace3: + case matchTrace3: + ASSERT(c_p == self); { /* disable enable */ Uint d_flags = 0, e_flags = 0; /* process trace flags */ @@ -5080,7 +5100,8 @@ static Eterm match_spec_test(Process *p, Eterm against, Eterm spec, int trace) } save_cp = p->cp; p->cp = NULL; - res = erts_match_set_run(p, mps, arr, n, + res = erts_match_set_run(p, p, + mps, arr, n, ERTS_PAM_COPY_RESULT|ERTS_PAM_IGNORE_TRACE_SILENT, &ret_flags); p->cp = save_cp; @@ -5163,7 +5184,8 @@ Eterm db_match_dbterm(DbTableCommon* tb, Process* c_p, Binary* bprog, obj = db_alloc_tmp_uncompressed(tb, obj); } - res = db_prog_match(c_p, bprog, make_tuple(obj->tpl), NULL, 0, + res = db_prog_match(c_p, c_p, + bprog, make_tuple(obj->tpl), NULL, 0, ERTS_PAM_COPY_RESULT|ERTS_PAM_CONTIGUOUS_TUPLE, &dummy); if (is_value(res) && hpp!=NULL) { diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h index 5d7946a525..c3eb82a44a 100644 --- a/erts/emulator/beam/erl_db_util.h +++ b/erts/emulator/beam/erl_db_util.h @@ -435,7 +435,8 @@ Binary *db_match_compile(Eterm *matchexpr, Eterm *guards, Eterm db_match_dbterm(DbTableCommon* tb, Process* c_p, Binary* bprog, int all, DbTerm* obj, Eterm** hpp, Uint extra); -Eterm db_prog_match(Process *p, Binary *prog, Eterm term, +Eterm db_prog_match(Process *p, Process *self, + Binary *prog, Eterm term, Eterm *termp, int arity, enum erts_pam_run_flags in_flags, Uint32 *return_flags /* Zeroed on enter */); diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c index 9beff52835..ee8a7702ce 100644 --- a/erts/emulator/beam/erl_message.c +++ b/erts/emulator/beam/erl_message.c @@ -32,6 +32,7 @@ #include "erl_process.h" #include "erl_binary.h" #include "dtrace-wrapper.h" +#include "beam_bp.h" ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(message_ref, ErtsMessageRef, @@ -369,11 +370,12 @@ static Sint queue_messages(Process *c_p, Process* receiver, erts_aint32_t *receiver_state, - ErtsProcLocks *receiver_locks, + ErtsProcLocks receiver_locks, ErtsMessage* first, ErtsMessage** last, Uint len) { + ErtsTracingEvent* te; Sint res; int locked_msgq = 0; erts_aint32_t state; @@ -386,12 +388,12 @@ queue_messages(Process *c_p, #ifdef ERTS_SMP #ifdef ERTS_ENABLE_LOCK_CHECK ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(receiver) < ERTS_PROC_LOCK_MSGQ || - *receiver_locks == erts_proc_lc_my_proc_locks(receiver)); + receiver_locks == erts_proc_lc_my_proc_locks(receiver)); #endif - if (!(*receiver_locks & ERTS_PROC_LOCK_MSGQ)) { + if (!(receiver_locks & ERTS_PROC_LOCK_MSGQ)) { if (erts_smp_proc_trylock(receiver, ERTS_PROC_LOCK_MSGQ) == EBUSY) { - ErtsProcLocks need_locks = ERTS_PROC_LOCK_MSGQ; + ErtsProcLocks need_locks; if (receiver_state) state = *receiver_state; @@ -400,10 +402,11 @@ queue_messages(Process *c_p, if (state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_PENDING_EXIT)) goto exiting; - if (*receiver_locks & ERTS_PROC_LOCK_STATUS) { - erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_STATUS); - need_locks |= ERTS_PROC_LOCK_STATUS; + need_locks = receiver_locks & (ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE); + if (need_locks) { + erts_smp_proc_unlock(receiver, need_locks); } + need_locks |= ERTS_PROC_LOCK_MSGQ; erts_smp_proc_lock(receiver, need_locks); } locked_msgq = 1; @@ -426,7 +429,7 @@ queue_messages(Process *c_p, res = receiver->msg.len; #ifdef ERTS_SMP - if (*receiver_locks & ERTS_PROC_LOCK_MAIN) { + if (receiver_locks & ERTS_PROC_LOCK_MAIN) { /* * We move 'in queue' to 'private queue' and place * message at the end of 'private queue' in order @@ -445,7 +448,10 @@ queue_messages(Process *c_p, LINK_MESSAGE(receiver, first, last, len); } - if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE)) { + if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE) + && (te = &erts_receive_tracing[erts_active_bp_ix()], + te->on)) { + ErtsMessage *msg = first; #ifdef USE_VM_PROBES @@ -468,19 +474,18 @@ queue_messages(Process *c_p, tok_label, tok_lastcnt, tok_serial); } #endif - while (msg) { - trace_receive(receiver, ERL_MESSAGE_TERM(msg)); + trace_receive(c_p, receiver, ERL_MESSAGE_TERM(msg), te); msg = msg->next; } } - - if (locked_msgq) + if (locked_msgq) { erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ); + } #ifdef ERTS_SMP - erts_proc_notify_new_message(receiver, *receiver_locks); + erts_proc_notify_new_message(receiver, receiver_locks); #else erts_proc_notify_new_message(receiver, 0); ERTS_HOLE_CHECK(receiver); @@ -496,7 +501,7 @@ queue_message(Process *c_p, ErtsMessage* mp, Eterm msg) { ERL_MESSAGE_TERM(mp) = msg; - return queue_messages(c_p, receiver, receiver_state, receiver_locks, + return queue_messages(c_p, receiver, receiver_state, *receiver_locks, mp, &mp->next, 1 ); } @@ -512,7 +517,7 @@ Sint erts_queue_messages(Process* receiver, ErtsProcLocks *receiver_locks, ErtsMessage* first, ErtsMessage** last, Uint len) { - return queue_messages(NULL, receiver, NULL, receiver_locks, + return queue_messages(NULL, receiver, NULL, *receiver_locks, first, last, len); } diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index e8516cd09c..755deda9c1 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -238,7 +238,6 @@ write_timestamp(ErtsTraceTimeStamp *tsp, Eterm **hpp) } #ifdef ERTS_SMP -#define PATCH_TS_SIZE(p) patch_ts_size(TFLGS_TS_TYPE(p)) static ERTS_INLINE Uint patch_ts_size(int ts_type) @@ -258,7 +257,7 @@ patch_ts_size(int ts_type) return 0; } } -#endif +#endif /* ERTS_SMP */ /* * Write a timestamp. The timestamp MUST be the last @@ -826,7 +825,8 @@ trace_send(Process *p, Eterm to, Eterm msg) Uint32 return_flags; args[0] = to; args[1] = msg; - pam_result = erts_match_set_run(p, te->match_spec, args, 2, + pam_result = erts_match_set_run(p, p, + te->match_spec, args, 2, ERTS_PAM_TMP_RESULT, &return_flags); if (is_non_value(pam_result) || pam_result == am_false @@ -859,14 +859,43 @@ trace_send(Process *p, Eterm to, Eterm msg) * or {trace, Pid, receive, Msg} */ void -trace_receive(Process *c_p, Eterm msg) +trace_receive(Process *c_p, + Process* receiver, + Eterm msg, ErtsTracingEvent* te) { ErtsTracerNif *tnif = NULL; - if (is_tracer_enabled(NULL, 0, &c_p->common, &tnif, - TRACE_FUN_E_RECEIVE, am_receive)) - send_to_tracer_nif(NULL, &c_p->common, c_p->common.id, + Eterm pam_result; + + if (!te) { + te = &erts_receive_tracing[erts_active_bp_ix()]; + if (!te->on) + return; + } + + if (te->match_spec) { + Eterm args[2]; + Uint32 return_flags; + args[0] = am_undefined; /* ToDo: from who? */ + args[1] = msg; + pam_result = erts_match_set_run(c_p, receiver, + te->match_spec, args, 2, + ERTS_PAM_TMP_RESULT, &return_flags); + if (is_non_value(pam_result) + || pam_result == am_false + || (ERTS_TRACE_FLAGS(receiver) & F_TRACE_SILENT)) { + erts_match_set_release_result(c_p); + return; + } + } else + pam_result = am_true; + + if (is_tracer_enabled(NULL, 0, &receiver->common, &tnif, + TRACE_FUN_E_RECEIVE, am_receive)) { + send_to_tracer_nif(NULL, &receiver->common, receiver->common.id, tnif, TRACE_FUN_T_RECEIVE, - am_receive, msg, THE_NON_VALUE, am_true); + am_receive, msg, THE_NON_VALUE, pam_result); + } + erts_match_set_release_result(c_p); } int @@ -1226,7 +1255,8 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, may remove it, and we still want to generate a trace message */ erts_tracer_update(&pre_ms_tracer, *tracer); tracer = &pre_ms_tracer; - pam_result = erts_match_set_run(p, match_spec, args, arity, + pam_result = erts_match_set_run(p, p, + match_spec, args, arity, ERTS_PAM_TMP_RESULT, &return_flags); if (is_non_value(pam_result)) { erts_match_set_release_result(p); diff --git a/erts/emulator/beam/erl_trace.h b/erts/emulator/beam/erl_trace.h index e8e968c0cf..040aa296a1 100644 --- a/erts/emulator/beam/erl_trace.h +++ b/erts/emulator/beam/erl_trace.h @@ -56,6 +56,15 @@ struct binary; +typedef struct +{ + int on; + struct binary* match_spec; +} ErtsTracingEvent; + +extern ErtsTracingEvent erts_send_tracing[]; +extern ErtsTracingEvent erts_receive_tracing[]; + /* erl_bif_trace.c */ Eterm erl_seq_trace_info(Process *p, Eterm arg1); void erts_system_monitor_clear(Process *c_p); @@ -91,7 +100,7 @@ void erts_send_sys_msg_proc(Eterm, Eterm, Eterm, ErlHeapFragment *); #endif void trace_send(Process*, Eterm, Eterm); -void trace_receive(Process *, Eterm); +void trace_receive(Process*, Process*, Eterm, ErtsTracingEvent*); Uint32 erts_call_trace(Process *p, BeamInstr mfa[], struct binary *match_spec, Eterm* args, int local, ErtsTracer *tracer); void erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, @@ -220,12 +229,4 @@ ERTS_DECLARE_DUMMY(erts_tracer_nil) = NIL; && erts_is_tracer_proc_enabled(PROC, ERTS_PROC_LOCK_MAIN, \ &(PROC)->common, am_trace_status)) -typedef struct -{ - int on; - struct binary* match_spec; -} ErtsTracingEvent; - -extern ErtsTracingEvent erts_send_tracing[]; - #endif /* ERL_TRACE_H__ */ diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index a7bc990deb..916c6277c1 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -1493,7 +1493,9 @@ enum erts_pam_run_flags { ERTS_PAM_CONTIGUOUS_TUPLE=4, ERTS_PAM_IGNORE_TRACE_SILENT=8 }; -extern Eterm erts_match_set_run(Process *p, Binary *mpsp, +extern Eterm erts_match_set_run(Process *p, + Process *self, + Binary *mpsp, Eterm *args, int num_args, enum erts_pam_run_flags in_flags, Uint32 *return_flags); diff --git a/erts/emulator/hipe/hipe_native_bif.c b/erts/emulator/hipe/hipe_native_bif.c index 00b572029a..d8076a3e02 100644 --- a/erts/emulator/hipe/hipe_native_bif.c +++ b/erts/emulator/hipe/hipe_native_bif.c @@ -601,7 +601,7 @@ void hipe_clear_timeout(Process *c_p) } #endif if (IS_TRACED_FL(c_p, F_TRACE_RECEIVE)) { - trace_receive(c_p, am_timeout); + trace_receive(c_p, c_p, am_timeout, NULL); } c_p->flags &= ~F_TIMO; JOIN_MESSAGE(c_p); diff --git a/erts/emulator/test/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl index c8cc0fc6e8..7eb52dcdeb 100644 --- a/erts/emulator/test/trace_SUITE.erl +++ b/erts/emulator/test/trace_SUITE.erl @@ -94,6 +94,26 @@ receive_trace(Config) when is_list(Config) -> {trace, Receiver, 'receive', Hello2} = receive_first_trace(), receive_nothing(), + %% Test 'receive' with matchspec + F1 = fun ({Pat, IsMatching}) -> + set_trace_pattern('receive', Pat, []), + Receiver ! Hello, + case IsMatching of + true -> + {trace, Receiver, 'receive', Hello} = receive_first_trace(); + false -> + ok + end, + receive_nothing() + end, + lists:foreach(F1, [{no, true}, + {[{[undefined,"Unexpected"],[],[]}], false}, + {[{['_','_'],[],[]}], true}, + {[{['$1','_'],[{is_integer,'$1'}],[]}], false}, + {[{['_','$1'],[{is_tuple,'$1'}],[]}], true}, + {false, false}, + {true, true}]), + %% Another process should not be able to trace Receiver. Intruder = fun_spawn(fun() -> erlang:trace(Receiver, true, ['receive']) end), {'EXIT', Intruder, {badarg, _}} = receive_first(), -- cgit v1.2.3 From 5cb62b003d082c5a32ef5b12a89d872a317fd05f Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 17 Mar 2016 16:35:08 +0100 Subject: erts: Add matchspec restrictions for 'receive' trace and non-call-trace. This is the easy way out to avoid difficult locking scenarios when accessing tracing flags on another process. --- erts/emulator/beam/erl_bif_trace.c | 13 ++- erts/emulator/beam/erl_db_util.c | 223 ++++++++++++++++--------------------- erts/emulator/beam/erl_db_util.h | 5 + erts/emulator/beam/global.h | 2 +- erts/emulator/test/trace_SUITE.erl | 25 ++++- 5 files changed, 131 insertions(+), 137 deletions(-) diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index 7b21ff0110..c604053caa 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -156,11 +156,14 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) } else if (Pattern == am_pause) { match_prog_set = NULL; on = ERTS_BREAK_PAUSE; - } else if ((match_prog_set = erts_match_set_compile(p, Pattern)) != NULL) { - MatchSetRef(match_prog_set); - on = 1; - } else{ - goto error; + } else { + match_prog_set = erts_match_set_compile(p, Pattern, MFA); + if (match_prog_set) { + MatchSetRef(match_prog_set); + on = 1; + } else{ + goto error; + } } is_global = 0; diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index 72d59df813..ae2cc40bfa 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -123,6 +123,9 @@ do { \ #define TermWords(t) (((t) / (sizeof(UWord)/sizeof(Eterm))) + !!((t) % (sizeof(UWord)/sizeof(Eterm)))) +#define add_dmc_err(EINFO, STR, VAR, TERM, SEV) \ + vadd_dmc_err(EINFO, SEV, VAR, STR, TERM) + static ERTS_INLINE Process * get_proc(Process *cp, Uint32 cp_locks, Eterm id, Uint32 id_locks) @@ -889,11 +892,7 @@ void db_match_dis(Binary *prog); #define TRACE /* Nothing */ #define FENCE_PATTERN_SIZE 0 #endif -static void add_dmc_err(DMCErrInfo *err_info, - char *str, - int variable, - Eterm term, - DMCErrorSeverity severity); +static void vadd_dmc_err(DMCErrInfo*, DMCErrorSeverity, int var, const char *str, ...); static Eterm dpm_array_to_list(Process *psp, Eterm *arr, int arity); @@ -989,12 +988,16 @@ Eterm erts_match_set_get_source(Binary *mpsp) } /* This one is for the tracing */ -Binary *erts_match_set_compile(Process *p, Eterm matchexpr) { +Binary *erts_match_set_compile(Process *p, Eterm matchexpr, Eterm MFA) { Binary *bin; Uint sz; Eterm *hp; + Uint flags = DCOMP_TRACE; + + if (is_tuple(MFA)) flags |= DCOMP_CALL_TRACE; + if (MFA != am_receive) flags |= DCOMP_ALLOW_TRACE_OPS; - bin = db_match_set_compile(p, matchexpr, DCOMP_TRACE); + bin = db_match_set_compile(p, matchexpr, flags); if (bin != NULL) { MatchProg *prog = Binary2MatchProg(bin); sz = size_object(matchexpr); @@ -1124,8 +1127,8 @@ Eterm db_match_set_lint(Process *p, Eterm matchexpr, Uint flags) int i; if (!is_list(matchexpr)) { - add_dmc_err(err_info, "Match programs are not in a list.", - -1, 0UL, dmcError); + add_dmc_err(err_info, "Match programs are not in a list.", + -1, 0UL, dmcError); goto done; } num_heads = 0; @@ -1133,9 +1136,8 @@ Eterm db_match_set_lint(Process *p, Eterm matchexpr, Uint flags) ++num_heads; if (l != NIL) { /* proper list... */ - add_dmc_err(err_info, "Match programs are not in a proper " - "list.", - -1, 0UL, dmcError); + add_dmc_err(err_info, "Match programs are not in a proper list.", + -1, 0UL, dmcError); goto done; } @@ -3260,20 +3262,20 @@ int erts_db_is_compiled_ms(Eterm term) ** Utility to add an error */ -static void add_dmc_err(DMCErrInfo *err_info, - char *str, - int variable, - Eterm term, - DMCErrorSeverity severity) +static void vadd_dmc_err(DMCErrInfo *err_info, + DMCErrorSeverity severity, + int variable, + const char *str, + ...) { + DMCError *e; + va_list args; + va_start(args, str); + + /* Linked in in reverse order, to ease the formatting */ - DMCError *e = erts_alloc(ERTS_ALC_T_DB_DMC_ERROR, sizeof(DMCError)); - if (term != 0UL) { - erts_snprintf(e->error_string, DMC_ERR_STR_LEN, str, term); - } else { - strncpy(e->error_string, str, DMC_ERR_STR_LEN); - e->error_string[DMC_ERR_STR_LEN] ='\0'; - } + e = erts_alloc(ERTS_ALC_T_DB_DMC_ERROR, sizeof(DMCError)); + erts_vsnprintf(e->error_string, DMC_ERR_STR_LEN, str, args); e->variable = variable; e->severity = severity; e->next = err_info->first; @@ -3283,8 +3285,11 @@ static void add_dmc_err(DMCErrInfo *err_info, err_info->first = e; if (severity >= dmcError) err_info->error_added = 1; + + va_end(args); } + /* ** Handle one term in the match expression (not the guard) */ @@ -3483,24 +3488,21 @@ static void do_emit_constant(DMCContext *context, DMC_STACK_TYPE(UWord) *text, context->stack_need = context->stack_used; } -#define RETURN_ERROR_X(String, X, Y, ContextP, ConstantF) \ -do { \ -if ((ContextP)->err_info != NULL) { \ - (ConstantF) = 0; \ - add_dmc_err((ContextP)->err_info, String, X, Y, dmcError); \ - return retOk; \ -} else \ - return retFail; \ -} while(0) +#define RETURN_ERROR_X(VAR, ContextP, ConstantF, String, ARG) \ + (((ContextP)->err_info != NULL) \ + ? ((ConstantF) = 0, \ + vadd_dmc_err((ContextP)->err_info, dmcError, VAR, String, ARG), \ + retOk) \ + : retFail) #define RETURN_ERROR(String, ContextP, ConstantF) \ - RETURN_ERROR_X(String, -1, 0UL, ContextP, ConstantF) + return RETURN_ERROR_X(-1, ContextP, ConstantF, String, 0) #define RETURN_VAR_ERROR(String, N, ContextP, ConstantF) \ - RETURN_ERROR_X(String, N, 0UL, ContextP, ConstantF) + return RETURN_ERROR_X(N, ContextP, ConstantF, String, 0) #define RETURN_TERM_ERROR(String, T, ContextP, ConstantF) \ - RETURN_ERROR_X(String, -1, T, ContextP, ConstantF) + return RETURN_ERROR_X(-1, ContextP, ConstantF, String, T) #define WARNING(String, ContextP) \ add_dmc_err((ContextP)->err_info, String, -1, 0UL, dmcWarning) @@ -3766,7 +3768,7 @@ static DMCRet dmc_variable(DMCContext *context, Uint n = db_is_variable(t); if (n >= heap->vars_used || !heap->vars[n].is_bound) { - RETURN_VAR_ERROR("Variable $%d is unbound.", n, context, *constant); + RETURN_VAR_ERROR("Variable $%%d is unbound.", n, context, *constant); } dmc_add_pushv_variant(context, heap, text, n); @@ -4098,7 +4100,30 @@ static DMCRet dmc_exception_trace(DMCContext *context, return retOk; } - +static int check_trace(const char* op, + DMCContext *context, + int *constant, + int need_cflags, + int allow_in_guard, + DMCRet* retp) +{ + if (!(context->cflags & DCOMP_TRACE)) { + *retp = RETURN_ERROR_X(-1, context, *constant, "Special form '%s' " + "used in wrong dialect.", op); + return 0; + } + if ((context->cflags & need_cflags) != need_cflags) { + *retp = RETURN_ERROR_X(-1, context, *constant, "Special form '%s' " + "not allow for this trace event.", op); + return 0; + } + if (context->is_guard && !allow_in_guard) { + *retp = RETURN_ERROR_X(-1, context, *constant, "Special form '%s' " + "called in guard context.", op); + return 0; + } + return 1; +} static DMCRet dmc_is_seq_trace(DMCContext *context, DMCHeap *heap, @@ -4108,12 +4133,11 @@ static DMCRet dmc_is_seq_trace(DMCContext *context, { Eterm *p = tuple_val(t); Uint a = arityval(*p); + DMCRet ret; - if (!(context->cflags & DCOMP_TRACE)) { - RETURN_ERROR("Special form 'is_seq_trace' used in wrong dialect.", - context, - *constant); - } + if (!check_trace("is_seq_trace", context, constant, DCOMP_ALLOW_TRACE_OPS, 1, &ret)) + return ret; + if (a != 1) { RETURN_TERM_ERROR("Special form 'is_seq_trace' called with " "arguments in %T.", t, context, *constant); @@ -4137,16 +4161,8 @@ static DMCRet dmc_set_seq_token(DMCContext *context, DMCRet ret; int c; - - if (!(context->cflags & DCOMP_TRACE)) { - RETURN_ERROR("Special form 'set_seq_token' used in wrong dialect.", - context, - *constant); - } - if (context->is_guard) { - RETURN_ERROR("Special form 'set_seq_token' called in " - "guard context.", context, *constant); - } + if (!check_trace("set_seq_trace", context, constant, DCOMP_ALLOW_TRACE_OPS, 0, &ret)) + return ret; if (a != 3) { RETURN_TERM_ERROR("Special form 'set_seq_token' called with wrong " @@ -4183,16 +4199,11 @@ static DMCRet dmc_get_seq_token(DMCContext *context, { Eterm *p = tuple_val(t); Uint a = arityval(*p); + DMCRet ret; + + if (!check_trace("get_seq_token", context, constant, DCOMP_ALLOW_TRACE_OPS, 0, &ret)) + return ret; - if (!(context->cflags & DCOMP_TRACE)) { - RETURN_ERROR("Special form 'get_seq_token' used in wrong dialect.", - context, - *constant); - } - if (context->is_guard) { - RETURN_ERROR("Special form 'get_seq_token' called in " - "guard context.", context, *constant); - } if (a != 1) { RETURN_TERM_ERROR("Special form 'get_seq_token' called with " "arguments in %T.", t, context, @@ -4256,16 +4267,10 @@ static DMCRet dmc_process_dump(DMCContext *context, { Eterm *p = tuple_val(t); Uint a = arityval(*p); - - if (!(context->cflags & DCOMP_TRACE)) { - RETURN_ERROR("Special form 'process_dump' used in wrong dialect.", - context, - *constant); - } - if (context->is_guard) { - RETURN_ERROR("Special form 'process_dump' called in " - "guard context.", context, *constant); - } + DMCRet ret; + + if (!check_trace("process_dump", context, constant, DCOMP_ALLOW_TRACE_OPS, 0, &ret)) + return ret; if (a != 1) { RETURN_TERM_ERROR("Special form 'process_dump' called with " @@ -4289,17 +4294,8 @@ static DMCRet dmc_enable_trace(DMCContext *context, DMCRet ret; int c; - - if (!(context->cflags & DCOMP_TRACE)) { - RETURN_ERROR("Special form 'enable_trace' used in wrong dialect.", - context, - *constant); - } - if (context->is_guard) { - RETURN_ERROR("Special form 'enable_trace' called in guard context.", - context, - *constant); - } + if (!check_trace("enable_trace", context, constant, DCOMP_ALLOW_TRACE_OPS, 0, &ret)) + return ret; switch (a) { case 2: @@ -4348,18 +4344,9 @@ static DMCRet dmc_disable_trace(DMCContext *context, Uint a = arityval(*p); DMCRet ret; int c; - - if (!(context->cflags & DCOMP_TRACE)) { - RETURN_ERROR("Special form 'disable_trace' used in wrong dialect.", - context, - *constant); - } - if (context->is_guard) { - RETURN_ERROR("Special form 'disable_trace' called in guard context.", - context, - *constant); - } + if (!check_trace("disable_trace", context, constant, DCOMP_ALLOW_TRACE_OPS, 0, &ret)) + return ret; switch (a) { case 2: @@ -4409,17 +4396,8 @@ static DMCRet dmc_trace(DMCContext *context, DMCRet ret; int c; - - if (!(context->cflags & DCOMP_TRACE)) { - RETURN_ERROR("Special form 'trace' used in wrong dialect.", - context, - *constant); - } - if (context->is_guard) { - RETURN_ERROR("Special form 'trace' called in guard context.", - context, - *constant); - } + if (!check_trace("trace", context, constant, DCOMP_ALLOW_TRACE_OPS, 0, &ret)) + return ret; switch (a) { case 3: @@ -4480,16 +4458,11 @@ static DMCRet dmc_caller(DMCContext *context, { Eterm *p = tuple_val(t); Uint a = arityval(*p); + DMCRet ret; - if (!(context->cflags & DCOMP_TRACE)) { - RETURN_ERROR("Special form 'caller' used in wrong dialect.", - context, - *constant); - } - if (context->is_guard) { - RETURN_ERROR("Special form 'caller' called in " - "guard context.", context, *constant); - } + if (!check_trace("caller", context, constant, + (DCOMP_CALL_TRACE|DCOMP_ALLOW_TRACE_OPS), 0, &ret)) + return ret; if (a != 1) { RETURN_TERM_ERROR("Special form 'caller' called with " @@ -4515,15 +4488,8 @@ static DMCRet dmc_silent(DMCContext *context, DMCRet ret; int c; - if (!(context->cflags & DCOMP_TRACE)) { - RETURN_ERROR("Special form 'silent' used in wrong dialect.", - context, - *constant); - } - if (context->is_guard) { - RETURN_ERROR("Special form 'silent' called in " - "guard context.", context, *constant); - } + if (!check_trace("silent", context, constant, DCOMP_ALLOW_TRACE_OPS, 0, &ret)) + return ret; if (a != 2) { RETURN_TERM_ERROR("Special form 'silent' called with wrong " @@ -5063,11 +5029,14 @@ static Eterm match_spec_test(Process *p, Eterm against, Eterm spec, int trace) return THE_NON_VALUE; } if (trace) { - lint_res = db_match_set_lint(p, spec, DCOMP_TRACE | DCOMP_FAKE_DESTRUCTIVE); - mps = db_match_set_compile(p, spec, DCOMP_TRACE | DCOMP_FAKE_DESTRUCTIVE); + const Uint cflags = (DCOMP_TRACE | DCOMP_FAKE_DESTRUCTIVE | + DCOMP_CALL_TRACE | DCOMP_ALLOW_TRACE_OPS); + lint_res = db_match_set_lint(p, spec, cflags); + mps = db_match_set_compile(p, spec, cflags); } else { - lint_res = db_match_set_lint(p, spec, DCOMP_TABLE | DCOMP_FAKE_DESTRUCTIVE); - mps = db_match_set_compile(p, spec, DCOMP_TABLE | DCOMP_FAKE_DESTRUCTIVE); + const Uint cflags = (DCOMP_TABLE | DCOMP_FAKE_DESTRUCTIVE); + lint_res = db_match_set_lint(p, spec, cflags); + mps = db_match_set_compile(p, spec, cflags); } if (mps == NULL) { diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h index c3eb82a44a..60f7067d70 100644 --- a/erts/emulator/beam/erl_db_util.h +++ b/erts/emulator/beam/erl_db_util.h @@ -425,6 +425,11 @@ typedef struct dmc_err_info { #define DCOMP_FAKE_DESTRUCTIVE ((Uint) 8) /* When this is active, no setting of trace control words or seq_trace tokens will be done. */ +/* Allow lock seizing operations on the tracee and 3rd party processes */ +#define DCOMP_ALLOW_TRACE_OPS ((Uint) 0x10) + +/* This is call trace */ +#define DCOMP_CALL_TRACE ((Uint) 0x20) Binary *db_match_compile(Eterm *matchexpr, Eterm *guards, Eterm *body, int num_matches, diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 916c6277c1..328bfe344c 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -1483,7 +1483,7 @@ do { \ #define MatchSetGetSource(MPSP) erts_match_set_get_source(MPSP) -extern Binary *erts_match_set_compile(Process *p, Eterm matchexpr); +extern Binary *erts_match_set_compile(Process *p, Eterm matchexpr, Eterm MFA); Eterm erts_match_set_lint(Process *p, Eterm matchexpr); extern void erts_match_set_release_result(Process* p); diff --git a/erts/emulator/test/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl index 7eb52dcdeb..de1d292d27 100644 --- a/erts/emulator/test/trace_SUITE.erl +++ b/erts/emulator/test/trace_SUITE.erl @@ -119,10 +119,26 @@ receive_trace(Config) when is_list(Config) -> {'EXIT', Intruder, {badarg, _}} = receive_first(), %% Untrace the process; we should not receive anything. - 1 = erlang:trace(Receiver, false, ['receive']), - Receiver ! {hello, there}, - Receiver ! any_garbage, - receive_nothing(), + ?line 1 = erlang:trace(Receiver, false, ['receive']), + ?line Receiver ! {hello, there}, + ?line Receiver ! any_garbage, + ?line receive_nothing(), + + %% Verify restrictions in matchspec for 'receive' + F2 = fun (Pat) -> {'EXIT', {badarg,_}} = (catch erlang:trace_pattern('receive', Pat, [])) end, + lists:foreach(F2, [[{['_','_'],[],[{message, {process_dump}}]}], + [{['_','_'],[{is_seq_trace}],[]}], + [{['_','_'],[],[{set_seq_token,label,4711}]}], + [{['_','_'],[],[{get_seq_token}]}], + [{['_','_'],[],[{enable_trace,call}]}], + [{['_','_'],[],[{enable_trace,self(),call}]}], + [{['_','_'],[],[{disable_trace,call}]}], + [{['_','_'],[],[{disable_trace,self(),call}]}], + [{['_','_'],[],[{trace,[call],[]}]}], + [{['_','_'],[],[{trace,self(),[],[call]}]}], + [{['_','_'],[],[{caller}]}], + [{['_','_'],[],[{silent,true}]}]]), + ok. %% Tests that receive of a message always happens before a call with @@ -409,6 +425,7 @@ send_trace(Config) when is_list(Config) -> {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [call_time])), {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, restart, [])), {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, pause, [])), + {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, [{['_','_'],[],[{caller}]}], [])), %% Done. ok. -- cgit v1.2.3 From 9627711cc39fd311a573a172e6d0e8a6b55dbd17 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 1 Apr 2016 15:38:16 +0200 Subject: erts: Add Sender in 'receive' trace matchspec All 'EXIT' and monitor messages are sent from 'system' Timeouts are "sent" from 'clock_service' --- erts/emulator/beam/beam_emu.c | 2 +- erts/emulator/beam/bif.c | 2 +- erts/emulator/beam/dist.c | 8 +-- erts/emulator/beam/erl_alloc.c | 2 +- erts/emulator/beam/erl_bif_ddll.c | 2 +- erts/emulator/beam/erl_bif_trace.c | 2 +- erts/emulator/beam/erl_db_util.c | 14 ++++-- erts/emulator/beam/erl_gc.c | 2 +- erts/emulator/beam/erl_hl_timer.c | 8 +-- erts/emulator/beam/erl_message.c | 72 +++++++++++++------------- erts/emulator/beam/erl_message.h | 8 +-- erts/emulator/beam/erl_msacc.c | 2 +- erts/emulator/beam/erl_nif.c | 27 +++++----- erts/emulator/beam/erl_process.c | 10 ++-- erts/emulator/beam/erl_time_sup.c | 2 +- erts/emulator/beam/erl_trace.c | 26 +++++----- erts/emulator/beam/erl_trace.h | 2 +- erts/emulator/beam/io.c | 74 +++++++++++++++------------ erts/emulator/beam/utils.c | 2 +- erts/emulator/hipe/hipe_native_bif.c | 2 +- erts/emulator/test/trace_SUITE.erl | 97 +++++++++++++++++++++++++++++------- 21 files changed, 224 insertions(+), 142 deletions(-) diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 7eecd059a5..aab0baebea 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -2166,7 +2166,7 @@ void process_main(void) PreFetch(0, next); if (IS_TRACED_FL(c_p, F_TRACE_RECEIVE)) { - trace_receive(c_p, c_p, am_timeout, NULL); + trace_receive(c_p, am_clock_service, am_timeout, NULL); } if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) { save_calls(c_p, &exp_timeout); diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index ed5b2983dd..ac77fa96e1 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -611,7 +611,7 @@ erts_queue_monitor_message(Process *p, ref_copy = copy_struct(ref, ref_size, &hp, ohp); tup = TUPLE5(hp, am_DOWN, ref_copy, type, item_copy, reason_copy); - erts_queue_message(p, p_locksp, msgp, tup); + erts_queue_message(p, *p_locksp, msgp, tup, am_system); } static BIF_RETTYPE diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index 52fd57e101..b020f16805 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -397,7 +397,7 @@ static void doit_node_link_net_exits(ErtsLink *lnk, void *vnecp) msgp = erts_alloc_message_heap(rp, &rp_locks, 3, &hp, &ohp); tup = TUPLE2(hp, am_nodedown, name); - erts_queue_message(rp, &rp_locks, msgp, tup); + erts_queue_message(rp, rp_locks, msgp, tup, am_system); } erts_smp_proc_unlock(rp, rp_locks); } @@ -1456,7 +1456,7 @@ int erts_net_message(Port *prt, token = copy_struct(token, token_size, &hp, ohp); } - erts_queue_dist_message(rp, &locks, ede_copy, token); + erts_queue_dist_message(rp, locks, ede_copy, token, from); if (locks) erts_smp_proc_unlock(rp, locks); } @@ -1505,7 +1505,7 @@ int erts_net_message(Port *prt, token = copy_struct(token, token_size, &hp, ohp); } - erts_queue_dist_message(rp, &locks, ede_copy, token); + erts_queue_dist_message(rp, locks, ede_copy, token, tuple[2]); if (locks) erts_smp_proc_unlock(rp, locks); } @@ -3317,7 +3317,7 @@ send_nodes_mon_msg(Process *rp, } ASSERT(hend == hp); - erts_queue_message(rp, rp_locksp, mp, msg); + erts_queue_message(rp, *rp_locksp, mp, msg, am_system); } static void diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index d04977b9ae..3dc12bac51 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -3286,7 +3286,7 @@ reply_alloc_info(void *vair) if (hp != hp_end) erts_shrink_message_heap(&mp, rp, hp_start, hp, hp_end, &msg, 1); - erts_queue_message(rp, &rp_locks, mp, msg); + erts_queue_message(rp, rp_locks, mp, msg, am_system); if (air->req_sched == sched_id) rp_locks &= ~ERTS_PROC_LOCK_MAIN; diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c index 1e2db38442..ef77201544 100644 --- a/erts/emulator/beam/erl_bif_ddll.c +++ b/erts/emulator/beam/erl_bif_ddll.c @@ -1737,7 +1737,7 @@ static void notify_proc(Process *proc, Eterm ref, Eterm driver_name, Eterm type, hp += REF_THING_SIZE; mess = TUPLE5(hp,type,r,am_driver,driver_name,tag); } - erts_queue_message(proc, &rp_locks, mp, mess); + erts_queue_message(proc, rp_locks, mp, mess, am_system); erts_smp_proc_unlock(proc, rp_locks); ERTS_SMP_CHK_NO_PROC_LOCKS; } diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index c604053caa..ffc0afda58 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -2344,7 +2344,7 @@ reply_trace_delivered_all(void *vtdarp) #ifdef ERTS_SMP erts_send_sys_msg_proc(rp->common.id, rp->common.id, msg, bp); #else - erts_queue_message(rp, &rp_locks, mp, msg); + erts_queue_message(rp, rp_locks, mp, msg, am_system); #endif erts_free(ERTS_ALC_T_MISC_AUX_WORK, vtdarp); diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index ae2cc40bfa..7d64529250 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -414,17 +414,19 @@ get_match_pseudo_process(Process *c_p, Uint heap_size) { ErtsMatchPseudoProcess *mpsp; #ifdef ERTS_SMP - mpsp = (ErtsMatchPseudoProcess *) c_p->scheduler_data->match_pseudo_process; + ErtsSchedulerData *esdp = c_p ? c_p->scheduler_data : erts_get_scheduler_data(); + + mpsp = (ErtsMatchPseudoProcess *) esdp->match_pseudo_process; if (mpsp) cleanup_match_pseudo_process(mpsp, 0); else { ASSERT(erts_smp_tsd_get(match_pseudo_process_key) == NULL); mpsp = create_match_pseudo_process(); - c_p->scheduler_data->match_pseudo_process = (void *) mpsp; + esdp->match_pseudo_process = (void *) mpsp; erts_smp_tsd_set(match_pseudo_process_key, (void *) mpsp); } ASSERT(mpsp == erts_smp_tsd_get(match_pseudo_process_key)); - mpsp->process.scheduler_data = c_p->scheduler_data; + mpsp->process.scheduler_data = esdp; #else mpsp = match_pseudo_process; cleanup_match_pseudo_process(mpsp, 0); @@ -1750,7 +1752,7 @@ Eterm db_prog_match(Process *c_p, Eterm *esp; MatchVariable* variables; BeamInstr *cp; - UWord *pc = prog->text; + const UWord *pc = prog->text; Eterm *ehp; Eterm ret; Uint n; @@ -1773,13 +1775,15 @@ Eterm db_prog_match(Process *c_p, ERTS_UNDEF(n,0); + ASSERT(c_p || !(in_flags & ERTS_PAM_COPY_RESULT)); + mpsp = get_match_pseudo_process(c_p, prog->heap_size); psp = &mpsp->process; /* We need to lure the scheduler into believing in the pseudo process, because of floating point exceptions. Do *after* mpsp is set!!! */ - esdp = ERTS_GET_SCHEDULER_DATA_FROM_PROC(c_p); + esdp = ERTS_GET_SCHEDULER_DATA_FROM_PROC(psp); ASSERT(esdp != NULL); current_scheduled = esdp->current_process; /* SMP: psp->scheduler_data is set by get_match_pseudo_process */ diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index df5d0f4918..85a1467a52 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -2924,7 +2924,7 @@ reply_gc_info(void *vgcirp) hpp = &hp; } - erts_queue_message(rp, &rp_locks, mp, msg); + erts_queue_message(rp, rp_locks, mp, msg, am_system); if (gcirp->req_sched == esdp->no) rp_locks &= ~ERTS_PROC_LOCK_MAIN; diff --git a/erts/emulator/beam/erl_hl_timer.c b/erts/emulator/beam/erl_hl_timer.c index 8e201d5711..c418762578 100644 --- a/erts/emulator/beam/erl_hl_timer.c +++ b/erts/emulator/beam/erl_hl_timer.c @@ -1247,8 +1247,8 @@ hlt_bif_timer_timeout(ErtsHLTimer *tmr, Uint32 roflgs) if (!ERTS_PROC_IS_EXITING(proc)) { ErtsMessage *mp = erts_alloc_message(0, NULL); mp->data.heap_frag = tmr->btm.bp; - erts_queue_message(proc, &proc_locks, mp, - tmr->btm.message); + erts_queue_message(proc, proc_locks, mp, + tmr->btm.message, am_clock_service); erts_smp_proc_unlock(proc, ERTS_PROC_LOCKS_MSG_SEND); queued_message = 1; proc_locks &= ~ERTS_PROC_LOCKS_MSG_SEND; @@ -1980,7 +1980,7 @@ access_sched_local_btm(Process *c_p, Eterm pid, ERTS_HLT_ASSERT(hp + (async ? 4 : 3) == hp_end); - erts_queue_message(proc, &proc_locks, mp, msg); + erts_queue_message(proc, proc_locks, mp, msg, am_clock_service); if (c_p) proc_locks &= ~ERTS_PROC_LOCK_MAIN; @@ -2111,7 +2111,7 @@ try_access_sched_remote_btm(ErtsSchedulerData *esdp, msg = TUPLE3(hp, tag, tref, res); - erts_queue_message(c_p, &proc_locks, mp, msg); + erts_queue_message(c_p, proc_locks, mp, msg, am_clock_service); proc_locks &= ~ERTS_PROC_LOCK_MAIN; if (proc_locks) diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c index ee8a7702ce..9bb6e40a11 100644 --- a/erts/emulator/beam/erl_message.c +++ b/erts/emulator/beam/erl_message.c @@ -252,9 +252,10 @@ erts_realloc_shrink_message(ErtsMessage *mp, Uint sz, Eterm *brefs, Uint brefs_s void erts_queue_dist_message(Process *rcvr, - ErtsProcLocks *rcvr_locks, + ErtsProcLocks rcvr_locks, ErtsDistExternal *dist_ext, - Eterm token) + Eterm token, + Eterm from) { ErtsMessage* mp; #ifdef USE_VM_PROBES @@ -266,7 +267,7 @@ erts_queue_dist_message(Process *rcvr, erts_aint_t state; #endif - ERTS_SMP_LC_ASSERT(*rcvr_locks == erts_proc_lc_my_proc_locks(rcvr)); + ERTS_SMP_LC_ASSERT(rcvr_locks == erts_proc_lc_my_proc_locks(rcvr)); mp = erts_alloc_message(0, NULL); mp->data.dist_ext = dist_ext; @@ -281,10 +282,10 @@ erts_queue_dist_message(Process *rcvr, ERL_MESSAGE_TOKEN(mp) = token; #ifdef ERTS_SMP - if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ)) { + if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ)) { if (erts_smp_proc_trylock(rcvr, ERTS_PROC_LOCK_MSGQ) == EBUSY) { ErtsProcLocks need_locks = ERTS_PROC_LOCK_MSGQ; - if (*rcvr_locks & ERTS_PROC_LOCK_STATUS) { + if (rcvr_locks & ERTS_PROC_LOCK_STATUS) { erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_STATUS); need_locks |= ERTS_PROC_LOCK_STATUS; } @@ -294,7 +295,7 @@ erts_queue_dist_message(Process *rcvr, state = erts_smp_atomic32_read_acqb(&rcvr->state); if (state & (ERTS_PSFLG_PENDING_EXIT|ERTS_PSFLG_EXITING)) { - if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ)) + if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ)) erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ); /* Drop message if receiver is exiting or has a pending exit ... */ erts_cleanup_messages(mp); @@ -302,10 +303,13 @@ erts_queue_dist_message(Process *rcvr, else #endif if (IS_TRACED_FL(rcvr, F_TRACE_RECEIVE)) { + if (from == am_Empty) + from = dist_ext->dep->sysname; + /* Ahh... need to decode it in order to trace it... */ - if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ)) + if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ)) erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ); - if (!erts_decode_dist_message(rcvr, *rcvr_locks, mp, 0)) + if (!erts_decode_dist_message(rcvr, rcvr_locks, mp, 0)) erts_free_message(mp); else { Eterm msg = ERL_MESSAGE_TERM(mp); @@ -325,7 +329,7 @@ erts_queue_dist_message(Process *rcvr, tok_label, tok_lastcnt, tok_serial); } #endif - erts_queue_message(rcvr, rcvr_locks, mp, msg); + erts_queue_message(rcvr, rcvr_locks, mp, msg, from); } } else { @@ -352,12 +356,12 @@ erts_queue_dist_message(Process *rcvr, LINK_MESSAGE(rcvr, mp, &mp->next, 1); - if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ)) + if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ)) erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ); erts_proc_notify_new_message(rcvr, #ifdef ERTS_SMP - *rcvr_locks + rcvr_locks #else 0 #endif @@ -367,13 +371,13 @@ erts_queue_dist_message(Process *rcvr, /* Add messages last in message queue */ static Sint -queue_messages(Process *c_p, - Process* receiver, +queue_messages(Process* receiver, erts_aint32_t *receiver_state, ErtsProcLocks receiver_locks, ErtsMessage* first, ErtsMessage** last, - Uint len) + Uint len, + Eterm from) { ErtsTracingEvent* te; Sint res; @@ -475,7 +479,7 @@ queue_messages(Process *c_p, } #endif while (msg) { - trace_receive(c_p, receiver, ERL_MESSAGE_TERM(msg), te); + trace_receive(receiver, from, ERL_MESSAGE_TERM(msg), te); msg = msg->next; } @@ -494,31 +498,31 @@ queue_messages(Process *c_p, } static Sint -queue_message(Process *c_p, - Process* receiver, +queue_message(Process* receiver, erts_aint32_t *receiver_state, - ErtsProcLocks *receiver_locks, - ErtsMessage* mp, Eterm msg) + ErtsProcLocks receiver_locks, + ErtsMessage* mp, Eterm msg, Eterm from) { ERL_MESSAGE_TERM(mp) = msg; - return queue_messages(c_p, receiver, receiver_state, *receiver_locks, - mp, &mp->next, 1 ); + return queue_messages(receiver, receiver_state, receiver_locks, + mp, &mp->next, 1, from); } Sint -erts_queue_message(Process* receiver, ErtsProcLocks *receiver_locks, - ErtsMessage* mp, Eterm msg) +erts_queue_message(Process* receiver, ErtsProcLocks receiver_locks, + ErtsMessage* mp, Eterm msg, Eterm from) { - return queue_message(NULL, receiver, NULL, receiver_locks, mp, msg); + return queue_message(receiver, NULL, receiver_locks, mp, msg, from); } Sint -erts_queue_messages(Process* receiver, ErtsProcLocks *receiver_locks, - ErtsMessage* first, ErtsMessage** last, Uint len) +erts_queue_messages(Process* receiver, ErtsProcLocks receiver_locks, + ErtsMessage* first, ErtsMessage** last, Uint len, + Eterm from) { - return queue_messages(NULL, receiver, NULL, *receiver_locks, - first, last, len); + return queue_messages(receiver, NULL, receiver_locks, + first, last, len, from); } void @@ -835,11 +839,11 @@ erts_send_message(Process* sender, #ifdef USE_VM_PROBES ERL_MESSAGE_DT_UTAG(mp) = utag; #endif - res = queue_message(sender, - receiver, + res = queue_message(receiver, &receiver_state, - receiver_locks, - mp, message); + *receiver_locks, + mp, message, + sender->common.id); BM_SWAP_TIMER(send,system); @@ -896,7 +900,7 @@ erts_deliver_exit_message(Eterm from, Process *to, ErtsProcLocks *to_locksp, seq_trace_output(token, save, SEQ_TRACE_SEND, to->common.id, NULL); temptoken = copy_struct(token, sz_token, &hp, ohp); ERL_MESSAGE_TOKEN(mp) = temptoken; - erts_queue_message(to, to_locksp, mp, save); + erts_queue_message(to, *to_locksp, mp, save, am_system); } else { sz_from = IS_CONST(from) ? 0 : size_object(from); #ifdef SHCOPY_SEND @@ -918,7 +922,7 @@ erts_deliver_exit_message(Eterm from, Process *to, ErtsProcLocks *to_locksp, ? from : copy_struct(from, sz_from, &hp, ohp)); save = TUPLE3(hp, am_EXIT, from_copy, mess); - erts_queue_message(to, to_locksp, mp, save); + erts_queue_message(to, *to_locksp, mp, save, am_system); } } diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h index 608cf552a2..851ac37fda 100644 --- a/erts/emulator/beam/erl_message.h +++ b/erts/emulator/beam/erl_message.h @@ -295,10 +295,10 @@ ErlHeapFragment* new_message_buffer(Uint); ErlHeapFragment* erts_resize_message_buffer(ErlHeapFragment *, Uint, Eterm *, Uint); void free_message_buffer(ErlHeapFragment *); -void erts_queue_dist_message(Process*, ErtsProcLocks*, ErtsDistExternal *, Eterm); -Sint erts_queue_message(Process*, ErtsProcLocks*,ErtsMessage*, Eterm); -Sint erts_queue_messages(Process*, ErtsProcLocks*, - ErtsMessage*, ErtsMessage**, Uint); +void erts_queue_dist_message(Process*, ErtsProcLocks, ErtsDistExternal *, Eterm, Eterm); +Sint erts_queue_message(Process*, ErtsProcLocks,ErtsMessage*, Eterm, Eterm); +Sint erts_queue_messages(Process*, ErtsProcLocks, + ErtsMessage*, ErtsMessage**, Uint, Eterm); void erts_deliver_exit_message(Eterm, Process*, ErtsProcLocks *, Eterm, Eterm); Sint erts_send_message(Process*, Process*, ErtsProcLocks*, Eterm, unsigned); void erts_link_mbuf_to_proc(Process *proc, ErlHeapFragment *bp); diff --git a/erts/emulator/beam/erl_msacc.c b/erts/emulator/beam/erl_msacc.c index d0f305900a..0e625f213b 100644 --- a/erts/emulator/beam/erl_msacc.c +++ b/erts/emulator/beam/erl_msacc.c @@ -257,7 +257,7 @@ static void send_reply(ErtsMsAcc *msacc, ErtsMSAccReq *msaccrp) { if (msacc->unmanaged) erts_mtx_unlock(&msacc->mtx); - erts_queue_message(rp, &rp_locks, msgp, msg); + erts_queue_message(rp, rp_locks, msgp, msg, am_system); if (esdp && msaccrp->req_sched == esdp->no) rp_locks &= ~ERTS_PROC_LOCK_MAIN; diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 941f44b9ec..bd3e7ebe54 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -366,7 +366,7 @@ int erts_flush_trace_messages(Process *c_p, ErtsProcLocks c_p_locks) rp_locks = 0; if (rp->common.id == c_p->common.id) rp_locks = c_p_locks; - erts_queue_messages(rp, &rp_locks, first, last, len); + erts_queue_messages(rp, rp_locks, first, last, len, c_p->common.id); if (rp->common.id == c_p->common.id) rp_locks &= ~c_p_locks; if (rp_locks) @@ -405,7 +405,10 @@ enif_send(ErlNifEnv* env, const ErlNifPid* to_pid, ErlNifEnv* msg_env, ERL_NIF_TERM msg) { struct enif_msg_environment_t* menv = (struct enif_msg_environment_t*)msg_env; - ErtsProcLocks rp_locks = 0, lc_locks = 0, c_p_locks = ERTS_PROC_LOCK_MAIN; + ErtsProcLocks rp_locks = 0; +#ifdef ERTS_SMP + ErtsProcLocks lc_locks = 0; +#endif Process* rp; Process* c_p; ErtsMessage *mp; @@ -417,7 +420,7 @@ enif_send(ErlNifEnv* env, const ErlNifPid* to_pid, if (env != NULL) { c_p = env->proc; if (receiver == c_p->common.id) { - rp_locks = c_p_locks; + rp_locks = ERTS_PROC_LOCK_MAIN; flush_me = 1; } } @@ -470,14 +473,8 @@ enif_send(ErlNifEnv* env, const ErlNifPid* to_pid, if (c_p && IS_TRACED_FL(c_p, F_TRACE_SEND)) trace_send(c_p, receiver, msg); - -#ifndef ERTS_SMP } -#endif - - erts_queue_message(rp, &rp_locks, mp, msg); #ifdef ERTS_SMP - } else { /* This clause is taken when the nif is called in the context of a traced process. We do not know which locks we have @@ -502,8 +499,6 @@ enif_send(ErlNifEnv* env, const ErlNifPid* to_pid, #ifdef ERTS_ENABLE_LOCK_CHECK lc_locks = erts_proc_lc_my_proc_locks(rp); rp_locks |= lc_locks; - if (receiver == c_p->common.id) - c_p_locks |= lc_locks; #endif if (ERTS_FORCE_ENIF_SEND_DELAY() || msgq || rp_locks & ERTS_PROC_LOCK_MSGQ || @@ -532,19 +527,25 @@ enif_send(ErlNifEnv* env, const ErlNifPid* to_pid, msgq->last = &mp->next; erts_smp_proc_unlock(t_p, ERTS_PROC_LOCK_TRACE); } + goto done; } else { erts_smp_proc_unlock(t_p, ERTS_PROC_LOCK_TRACE); rp_locks &= ~ERTS_PROC_LOCK_TRACE; rp_locks |= ERTS_PROC_LOCK_MSGQ; - erts_queue_message(rp, &rp_locks, mp, msg); } } -#endif +#endif /* ERTS_SMP */ + + erts_queue_message(rp, rp_locks, mp, msg, + c_p ? c_p->common.id : am_undefined); +#ifdef ERTS_SMP +done: if (c_p == rp) rp_locks &= ~ERTS_PROC_LOCK_MAIN; if (rp_locks & ~lc_locks) erts_smp_proc_unlock(rp, rp_locks & ~lc_locks); +#endif if (!scheduler) erts_proc_dec_refc(rp); if (flush_me) { diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index d485affa3b..da2559839d 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -1139,7 +1139,7 @@ reply_sched_wall_time(void *vswtrp) hpp = &hp; } - erts_queue_message(rp, &rp_locks, mp, msg); + erts_queue_message(rp, rp_locks, mp, msg, am_system); if (swtrp->req_sched == esdp->no) rp_locks &= ~ERTS_PROC_LOCK_MAIN; @@ -1218,7 +1218,7 @@ reply_system_check(void *vscrp) hpp = &hp; msg = STORE_NC(hpp, ohp, scrp->ref); - erts_queue_message(rp, &rp_locks, mp, msg); + erts_queue_message(rp, rp_locks, mp, msg, am_system); if (scrp->req_sched == esdp->no) rp_locks &= ~ERTS_PROC_LOCK_MAIN; @@ -10010,7 +10010,7 @@ notify_sys_task_executed(Process *c_p, ErtsProcSysTask *st, Eterm st_result) ASSERT(hp_start + hsz == hp); #endif - erts_queue_message(rp, &rp_locks, mp, msg); + erts_queue_message(rp, rp_locks, mp, msg, c_p->common.id); if (c_p == rp) rp_locks &= ~ERTS_PROC_LOCK_MAIN; @@ -11744,7 +11744,7 @@ send_exit_message(Process *to, ErtsProcLocks *to_locksp, mp = erts_alloc_message_heap(to, to_locksp, term_size, &hp, &ohp); mess = copy_struct(exit_term, term_size, &hp, ohp); #endif - erts_queue_message(to, to_locksp, mp, mess); + erts_queue_message(to, *to_locksp, mp, mess, am_system); } else { Eterm temp_token; Uint sz_token; @@ -11765,7 +11765,7 @@ send_exit_message(Process *to, ErtsProcLocks *to_locksp, seq_trace_output(token, mess, SEQ_TRACE_SEND, to->common.id, to); temp_token = copy_struct(token, sz_token, &hp, ohp); ERL_MESSAGE_TOKEN(mp) = temp_token; - erts_queue_message(to, to_locksp, mp, mess); + erts_queue_message(to, *to_locksp, mp, mess, am_system); } } diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index 346404fe2a..fadbd704bd 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -1966,7 +1966,7 @@ send_time_offset_changed_notifications(void *new_offsetp) *patch_refp = ref; ASSERT(hsz == size_object(message_template)); message = copy_struct(message_template, hsz, &hp, ohp); - erts_queue_message(rp, &rp_locks, mp, message); + erts_queue_message(rp, rp_locks, mp, message, am_clock_service); } erts_smp_proc_unlock(rp, rp_locks); } diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index 755deda9c1..682f08f667 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -738,7 +738,7 @@ profile_send(Eterm from, Eterm message) { else msg = copy_struct(message, sz, &hp, &mp->hfrag.off_heap); - erts_queue_message(profile_p, NULL, mp, msg); + erts_queue_message(profile_p, 0, mp, msg, from); } } @@ -859,8 +859,8 @@ trace_send(Process *p, Eterm to, Eterm msg) * or {trace, Pid, receive, Msg} */ void -trace_receive(Process *c_p, - Process* receiver, +trace_receive(Process* receiver, + Eterm from, Eterm msg, ErtsTracingEvent* te) { ErtsTracerNif *tnif = NULL; @@ -875,15 +875,15 @@ trace_receive(Process *c_p, if (te->match_spec) { Eterm args[2]; Uint32 return_flags; - args[0] = am_undefined; /* ToDo: from who? */ + args[0] = from; args[1] = msg; - pam_result = erts_match_set_run(c_p, receiver, + pam_result = erts_match_set_run(NULL, receiver, te->match_spec, args, 2, ERTS_PAM_TMP_RESULT, &return_flags); if (is_non_value(pam_result) || pam_result == am_false || (ERTS_TRACE_FLAGS(receiver) & F_TRACE_SILENT)) { - erts_match_set_release_result(c_p); + erts_match_set_release_result(NULL); return; } } else @@ -895,7 +895,7 @@ trace_receive(Process *c_p, tnif, TRACE_FUN_T_RECEIVE, am_receive, msg, THE_NON_VALUE, pam_result); } - erts_match_set_release_result(c_p); + erts_match_set_release_result(NULL); } int @@ -1483,7 +1483,7 @@ monitor_long_schedule_proc(Process *p, BeamInstr *in_fp, BeamInstr *out_fp, Uint { ErtsMessage *mp = erts_alloc_message(0, NULL); mp->data.heap_frag = bp; - erts_queue_message(monitor_p, NULL, mp, msg); + erts_queue_message(monitor_p, 0, mp, msg, am_system); } #endif } @@ -1548,7 +1548,7 @@ monitor_long_schedule_port(Port *pp, ErtsPortTaskType type, Uint time) { ErtsMessage *mp = erts_alloc_message(0, NULL); mp->data.heap_frag = bp; - erts_queue_message(monitor_p, NULL, mp, msg); + erts_queue_message(monitor_p, 0, mp, msg, am_system); } #endif } @@ -1623,7 +1623,7 @@ monitor_long_gc(Process *p, Uint time) { { ErtsMessage *mp = erts_alloc_message(0, NULL); mp->data.heap_frag = bp; - erts_queue_message(monitor_p, NULL, mp, msg); + erts_queue_message(monitor_p, 0, mp, msg, am_system); } #endif } @@ -1698,7 +1698,7 @@ monitor_large_heap(Process *p) { { ErtsMessage *mp = erts_alloc_message(0, NULL); mp->data.heap_frag = bp; - erts_queue_message(monitor_p, NULL, mp, msg); + erts_queue_message(monitor_p, 0, mp, msg, am_system); } #endif } @@ -1730,7 +1730,7 @@ monitor_generic(Process *p, Eterm type, Eterm spec) { { ErtsMessage *mp = erts_alloc_message(0, NULL); mp->data.heap_frag = bp; - erts_queue_message(monitor_p, NULL, mp, msg); + erts_queue_message(monitor_p, 0, mp, msg, am_system); } #endif @@ -2514,7 +2514,7 @@ sys_msg_dispatcher_func(void *unused) queue_proc_msg: mp = erts_alloc_message(0, NULL); mp->data.heap_frag = smqp->bp; - erts_queue_message(proc,&proc_locks,mp,smqp->msg); + erts_queue_message(proc,proc_locks,mp,smqp->msg,am_system); #ifdef DEBUG_PRINTOUTS erts_fprintf(stderr, "delivered\n"); #endif diff --git a/erts/emulator/beam/erl_trace.h b/erts/emulator/beam/erl_trace.h index 040aa296a1..de4beadb7e 100644 --- a/erts/emulator/beam/erl_trace.h +++ b/erts/emulator/beam/erl_trace.h @@ -100,7 +100,7 @@ void erts_send_sys_msg_proc(Eterm, Eterm, Eterm, ErlHeapFragment *); #endif void trace_send(Process*, Eterm, Eterm); -void trace_receive(Process*, Process*, Eterm, ErtsTracingEvent*); +void trace_receive(Process*, Eterm, Eterm, ErtsTracingEvent*); Uint32 erts_call_trace(Process *p, BeamInstr mfa[], struct binary *match_spec, Eterm* args, int local, ErtsTracer *tracer); void erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index b14ca77a04..1d307ae15e 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -1432,10 +1432,11 @@ finalize_force_imm_drv_call(ErtsTryImmDrvCallState *sp) static ERTS_INLINE void queue_port_sched_op_reply(Process *rp, - ErtsProcLocks *rp_locksp, + ErtsProcLocks rp_locks, ErtsHeapFactory* factory, Uint32 *ref_num, - Eterm msg) + Eterm msg, + Port* prt) { Eterm* hp = erts_produce_heap(factory, ERTS_QUEUE_PORT_SCHED_OP_REPLY_SIZE, 0); Eterm ref; @@ -1448,11 +1449,12 @@ queue_port_sched_op_reply(Process *rp, erts_factory_trim_and_close(factory, &msg, 1); - erts_queue_message(rp, rp_locksp, factory->message, msg); + erts_queue_message(rp, rp_locks, factory->message, msg, + prt ? prt->common.id : am_undefined); } static void -port_sched_op_reply(Eterm to, Uint32 *ref_num, Eterm msg) +port_sched_op_reply(Eterm to, Uint32 *ref_num, Eterm msg, Port* prt) { Process *rp = erts_proc_lookup_raw(to); if (rp) { @@ -1478,10 +1480,11 @@ port_sched_op_reply(Eterm to, Uint32 *ref_num, Eterm msg) factory.off_heap)); queue_port_sched_op_reply(rp, - &rp_locks, + rp_locks, &factory, ref_num, - msg_copy); + msg_copy, + prt); if (rp_locks) erts_smp_proc_unlock(rp, rp_locks); @@ -1651,7 +1654,7 @@ port_badsig(Port *prt, erts_aint32_t state, int op, state, sigdp->flags & ERTS_P2P_SIG_DATA_FLG_BAD_OUTPUT); if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY) - port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg); + port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg, prt); return ERTS_PORT_REDS_BADSIG; } /* port_badsig */ /* bad_port_signal() will @@ -1820,7 +1823,7 @@ port_sig_outputv(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *s } if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY) - port_sched_op_reply(sigdp->caller, sigdp->ref, reply); + port_sched_op_reply(sigdp->caller, sigdp->ref, reply, prt); cleanup_scheduled_outputv(sigdp->u.outputv.evp, sigdp->u.outputv.cbinp); @@ -1928,7 +1931,7 @@ port_sig_output(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *si } if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY) - port_sched_op_reply(sigdp->caller, sigdp->ref, reply); + port_sched_op_reply(sigdp->caller, sigdp->ref, reply, prt); cleanup_scheduled_output(sigdp->u.output.bufp); @@ -2636,7 +2639,7 @@ port_sig_exit(Port *prt, if (sigdp->u.exit.bp) free_message_buffer(sigdp->u.exit.bp); if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY) - port_sched_op_reply(sigdp->caller, sigdp->ref, msg); + port_sched_op_reply(sigdp->caller, sigdp->ref, msg, prt); return ERTS_PORT_REDS_EXIT; } @@ -2829,7 +2832,7 @@ port_sig_connect(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *s msg = am_true; } if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY) - port_sched_op_reply(sigdp->caller, sigdp->ref, msg); + port_sched_op_reply(sigdp->caller, sigdp->ref, msg, prt); return ERTS_PORT_REDS_CONNECT; } @@ -2912,7 +2915,7 @@ port_sig_unlink(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *si if (op == ERTS_PROC2PORT_SIG_EXEC) port_unlink(prt, sigdp->u.unlink.from); if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY) - port_sched_op_reply(sigdp->caller, sigdp->ref, am_true); + port_sched_op_reply(sigdp->caller, sigdp->ref, am_true, prt); return ERTS_PORT_REDS_UNLINK; } @@ -3007,7 +3010,7 @@ port_sig_link(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *sigd port_link_failure(sigdp->u.link.port, sigdp->u.link.to); } if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY) - port_sched_op_reply(sigdp->caller, sigdp->ref, am_true); + port_sched_op_reply(sigdp->caller, sigdp->ref, am_true, prt); return ERTS_PORT_REDS_LINK; } @@ -3064,7 +3067,8 @@ init_ack_send_reply(Port *port, Eterm resp) } port_sched_op_reply(port->async_open_port->to, port->async_open_port->ref, - resp); + resp, + port); erts_free(ERTS_ALC_T_PRTSD, port->async_open_port); port->async_open_port = NULL; @@ -3461,7 +3465,7 @@ deliver_result(Port *prt, Eterm sender, Eterm pid, Eterm res) sz_res + 3, &hp, &ohp); res = copy_struct(res, sz_res, &hp, ohp); tuple = TUPLE2(hp, sender, res); - erts_queue_message(rp, &rp_locks, mp, tuple); + erts_queue_message(rp, rp_locks, mp, tuple, sender); if (rp_locks) erts_smp_proc_unlock(rp, rp_locks); @@ -3562,7 +3566,7 @@ static void deliver_read_message(Port* prt, erts_aint32_t state, Eterm to, trace_port_send(prt, to, tuple, 1); ERL_MESSAGE_TOKEN(mp) = am_undefined; - erts_queue_message(rp, &rp_locks, mp, tuple); + erts_queue_message(rp, rp_locks, mp, tuple, prt->common.id); if (rp_locks) erts_smp_proc_unlock(rp, rp_locks); if (!scheduler) @@ -3734,7 +3738,7 @@ deliver_vec_message(Port* prt, /* Port */ trace_port_send(prt, to, tuple, 1); ERL_MESSAGE_TOKEN(mp) = am_undefined; - erts_queue_message(rp, &rp_locks, mp, tuple); + erts_queue_message(rp, rp_locks, mp, tuple, prt->common.id); erts_smp_proc_unlock(rp, rp_locks); if (!scheduler) erts_proc_dec_refc(rp); @@ -4388,10 +4392,11 @@ port_sig_control(Port *prt, &factory.hp, factory.off_heap); queue_port_sched_op_reply(rp, - &rp_locks, + rp_locks, &factory, sigdp->ref, - msg); + msg, + prt); if (rp_locks) erts_smp_proc_unlock(rp, rp_locks); @@ -4402,7 +4407,7 @@ port_sig_control(Port *prt, /* failure */ if (sigdp->caller != ERTS_INVALID_PID) - port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg); + port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg, prt); done: @@ -4739,10 +4744,11 @@ port_sig_call(Port *prt, msg = TUPLE2(hp, am_ok, msg); queue_port_sched_op_reply(rp, - &rp_locks, + rp_locks, &factory, sigdp->ref, - msg); + msg, + prt); if (rp_locks) erts_smp_proc_unlock(rp, rp_locks); @@ -4754,7 +4760,7 @@ port_sig_call(Port *prt, } } - port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg); + port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg, prt); done: @@ -4969,7 +4975,7 @@ port_sig_info(Port *prt, { ASSERT(sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY); if (op != ERTS_PROC2PORT_SIG_EXEC) - port_sched_op_reply(sigdp->caller, sigdp->ref, am_undefined); + port_sched_op_reply(sigdp->caller, sigdp->ref, am_undefined, prt); else { Eterm *hp, *hp_start; Uint hsz; @@ -4995,10 +5001,11 @@ port_sig_info(Port *prt, mp->data.heap_frag = bp; erts_factory_selfcontained_message_init(&factory, mp, hp); queue_port_sched_op_reply(rp, - &rp_locks, + rp_locks, &factory, sigdp->ref, - value); + value, + prt); } if (rp_locks) erts_smp_proc_unlock(rp, rp_locks); @@ -5115,7 +5122,7 @@ reply_io_bytes(void *vreq) msg = TUPLE4(hp, ref, make_small(sched_id), ein, eout); - erts_queue_message(rp, &rp_locks, mp, msg); + erts_queue_message(rp, rp_locks, mp, msg, am_system); if (req->sched_id == sched_id) rp_locks &= ~ERTS_PROC_LOCK_MAIN; @@ -5613,7 +5620,7 @@ void driver_report_exit(ErlDrvPort ix, int status) trace_port_send(prt, pid, tuple, 1); ERL_MESSAGE_TOKEN(mp) = am_undefined; - erts_queue_message(rp, &rp_locks, mp, tuple); + erts_queue_message(rp, rp_locks, mp, tuple, prt->common.id); erts_smp_proc_unlock(rp, rp_locks); if (!scheduler) @@ -6217,15 +6224,20 @@ driver_deliver_term(Port *prt, Eterm to, ErlDrvTermData* data, int len) done: if (res > 0) { + Eterm from = am_undefined; mess = ESTACK_POP(stack); /* get resulting value */ erts_factory_trim_and_close(&factory, &mess, 1); - if (prt && IS_TRACED_FL(prt, F_TRACE_SEND)) - trace_port_send(prt, to, mess, 1); + if (prt) { + if (IS_TRACED_FL(prt, F_TRACE_SEND)) { + trace_port_send(prt, to, mess, 1); + } + from = prt->common.id; + } /* send message */ ERL_MESSAGE_TOKEN(factory.message) = am_undefined; - erts_queue_message(rp, &rp_locks, factory.message, mess); + erts_queue_message(rp, rp_locks, factory.message, mess, from); } else if (res == -2) { /* this clause only happens when we were requested to diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index b280995488..74114626be 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -2298,7 +2298,7 @@ static void do_send_logger_message(Eterm *hp, ErlOffHeap *ohp, ErlHeapFragment * { ErtsMessage *mp = erts_alloc_message(0, NULL); mp->data.heap_frag = bp; - erts_queue_message(p, NULL /* only used for smp build */, mp, message); + erts_queue_message(p, 0, mp, message, am_system); } #endif } diff --git a/erts/emulator/hipe/hipe_native_bif.c b/erts/emulator/hipe/hipe_native_bif.c index d8076a3e02..9c03b3811c 100644 --- a/erts/emulator/hipe/hipe_native_bif.c +++ b/erts/emulator/hipe/hipe_native_bif.c @@ -601,7 +601,7 @@ void hipe_clear_timeout(Process *c_p) } #endif if (IS_TRACED_FL(c_p, F_TRACE_RECEIVE)) { - trace_receive(c_p, c_p, am_timeout, NULL); + trace_receive(c_p, am_clock_service, am_timeout, NULL); } c_p->flags &= ~F_TIMO; JOIN_MESSAGE(c_p); diff --git a/erts/emulator/test/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl index de1d292d27..af35a6d6bf 100644 --- a/erts/emulator/test/trace_SUITE.erl +++ b/erts/emulator/test/trace_SUITE.erl @@ -106,14 +106,69 @@ receive_trace(Config) when is_list(Config) -> end, receive_nothing() end, + From = self(), lists:foreach(F1, [{no, true}, {[{[undefined,"Unexpected"],[],[]}], false}, - {[{['_','_'],[],[]}], true}, - {[{['$1','_'],[{is_integer,'$1'}],[]}], false}, + {[{[From,'_'],[],[]}], true}, + {[{['$1','_'],[{'=/=','$1',From}],[]}], false}, {[{['_','$1'],[{is_tuple,'$1'}],[]}], true}, {false, false}, {true, true}]), + %% Remote messages + OtherName = atom_to_list(?MODULE)++"_receive_trace", + {ok, OtherNode} = start_node(OtherName), + RemoteProc = spawn(OtherNode, ?MODULE, process, [self()]), + io:format("RemoteProc = ~p ~n", [RemoteProc]), + + RemoteProc ! {send_please, Receiver, Hello}, + {trace, Receiver, 'receive', Hello} = receive_first_trace(), + RemoteProc ! {send_please, Receiver, 99}, + {trace, Receiver, 'receive', 99} = receive_first_trace(), + + %% Remote with matchspec + F2 = fun (To, {Pat, IsMatching}) -> + set_trace_pattern('receive', Pat, []), + RemoteProc ! {send_please, To, Hello}, + case IsMatching of + true -> + {trace, Receiver, 'receive', Hello} = receive_first_trace(); + false -> + ok + end, + receive_nothing() + end, + F2(Receiver, {no, true}), + F2(Receiver, {[{[undefined,"Unexpected"],[],[]}], false}), + F2(Receiver, {[{[RemoteProc,'_'],[],[]}], true}), + F2(Receiver, {[{['$1','_'], [{'=/=',{node,'$1'},{node}}], []}], true}), + F2(Receiver, {[{['_','$1'], [{is_tuple,'$1'}], []}], true}), + F2(Receiver, {false, false}), + F2(Receiver, {true, true}), + + %% Remote to named with matchspec + Name = trace_SUITE_receiver, + register(Name, Receiver), + NN = {Name, node()}, + F2(NN, {no, true}), + F2(NN, {[{[undefined,"Unexpected"],[],[]}], false}), + F2(NN, {[{[RemoteProc,'_'],[],[]}], true}), + F2(NN, {[{['$1','_'], [{'=/=',{node,'$1'},{node}}], []}], true}), + F2(NN, {[{['_','$1'], [{is_tuple,'$1'}], []}], true}), + F2(NN, {false, false}), + F2(NN, {true, true}), + + true = stop_node(OtherNode), + + %% Timeout + Receiver ! {set_timeout, 10}, + {trace, Receiver, 'receive', {set_timeout, 10}} = receive_first_trace(), + {trace, Receiver, 'receive', timeout} = receive_first_trace(), + erlang:trace_pattern('receive', [{[clock_service,timeout], [], []}], []), + Receiver ! {set_timeout, 7}, + {trace, Receiver, 'receive', timeout} = receive_first_trace(), + erlang:trace_pattern('receive', true, []), + %% Another process should not be able to trace Receiver. Intruder = fun_spawn(fun() -> erlang:trace(Receiver, true, ['receive']) end), {'EXIT', Intruder, {badarg, _}} = receive_first(), @@ -125,19 +180,19 @@ receive_trace(Config) when is_list(Config) -> ?line receive_nothing(), %% Verify restrictions in matchspec for 'receive' - F2 = fun (Pat) -> {'EXIT', {badarg,_}} = (catch erlang:trace_pattern('receive', Pat, [])) end, - lists:foreach(F2, [[{['_','_'],[],[{message, {process_dump}}]}], - [{['_','_'],[{is_seq_trace}],[]}], - [{['_','_'],[],[{set_seq_token,label,4711}]}], - [{['_','_'],[],[{get_seq_token}]}], - [{['_','_'],[],[{enable_trace,call}]}], - [{['_','_'],[],[{enable_trace,self(),call}]}], - [{['_','_'],[],[{disable_trace,call}]}], - [{['_','_'],[],[{disable_trace,self(),call}]}], - [{['_','_'],[],[{trace,[call],[]}]}], - [{['_','_'],[],[{trace,self(),[],[call]}]}], - [{['_','_'],[],[{caller}]}], - [{['_','_'],[],[{silent,true}]}]]), + F3 = fun (Pat) -> {'EXIT', {badarg,_}} = (catch erlang:trace_pattern('receive', Pat, [])) end, + F3([{['_','_'],[],[{message, {process_dump}}]}]), + F3([{['_','_'],[{is_seq_trace}],[]}]), + F3([{['_','_'],[],[{set_seq_token,label,4711}]}]), + F3([{['_','_'],[],[{get_seq_token}]}]), + F3([{['_','_'],[],[{enable_trace,call}]}]), + F3([{['_','_'],[],[{enable_trace,self(),call}]}]), + F3([{['_','_'],[],[{disable_trace,call}]}]), + F3([{['_','_'],[],[{disable_trace,self(),call}]}]), + F3([{['_','_'],[],[{trace,[call],[]}]}]), + F3([{['_','_'],[],[{trace,self(),[],[call]}]}]), + F3([{['_','_'],[],[{caller}]}]), + F3([{['_','_'],[],[{silent,true}]}]), ok. @@ -568,6 +623,7 @@ dist_procs_trace(Config) when is_list(Config) -> Proc2 ! {unlink_please, Proc1}, {trace, Proc1, getting_unlinked, Proc2} = receive_first_trace(), receive_nothing(), + %% %% exit (with registered name, due to link) Name = list_to_atom(OtherName), @@ -1649,9 +1705,14 @@ sender() -> %% Just consumes messages from its message queue. receiver() -> - receive - _Any -> receiver() - end. + receiver(infinity). + +receiver(Timeout) -> + receiver(receive + {set_timeout, NewTimeout} -> NewTimeout; + _Any -> Timeout + after Timeout -> infinity %% reset + end). %% Works as long as it receives CPU time. Will always be RUNNABLE. -- cgit v1.2.3 From da75310ce8973221ac90fd34f6375bfc17ae751b Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 31 Mar 2016 21:20:24 +0200 Subject: erts: Change receive matchspec to [NodeOrOther, Pid, Msg] --- erts/emulator/beam/erl_trace.c | 17 +++++++--- erts/emulator/test/trace_SUITE.erl | 63 ++++++++++++++++++++++---------------- 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index 682f08f667..be0d2f0939 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -871,14 +871,23 @@ trace_receive(Process* receiver, if (!te->on) return; } + else ASSERT(te->on); if (te->match_spec) { - Eterm args[2]; + Eterm args[3]; Uint32 return_flags; - args[0] = from; - args[1] = msg; + if (is_pid(from)) { + args[0] = pid_node_name(from); + args[1] = from; + } + else { + ASSERT(is_atom(from)); + args[0] = from; /* node name or other atom (e.g 'system') */ + args[1] = am_undefined; + } + args[2] = msg; pam_result = erts_match_set_run(NULL, receiver, - te->match_spec, args, 2, + te->match_spec, args, 3, ERTS_PAM_TMP_RESULT, &return_flags); if (is_non_value(pam_result) || pam_result == am_false diff --git a/erts/emulator/test/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl index af35a6d6bf..1930332691 100644 --- a/erts/emulator/test/trace_SUITE.erl +++ b/erts/emulator/test/trace_SUITE.erl @@ -82,7 +82,6 @@ cpu_timestamp(Config) when is_list(Config) -> receive_trace(Config) when is_list(Config) -> Receiver = fun_spawn(fun receiver/0), - process_flag(trap_exit, true), %% Trace the process; make sure that we receive the trace messages. 1 = erlang:trace(Receiver, true, ['receive']), @@ -107,18 +106,19 @@ receive_trace(Config) when is_list(Config) -> receive_nothing() end, From = self(), + Node = node(), lists:foreach(F1, [{no, true}, - {[{[undefined,"Unexpected"],[],[]}], false}, - {[{[From,'_'],[],[]}], true}, - {[{['$1','_'],[{'=/=','$1',From}],[]}], false}, - {[{['_','$1'],[{is_tuple,'$1'}],[]}], true}, + {[{[Node, undefined,"Unexpected"],[],[]}], false}, + {[{[Node, From,'_'],[],[]}], true}, + {[{[Node, '$1','_'],[{'=/=','$1',From}],[]}], false}, + {[{['$1', '_','_'],[{'=:=','$1',Node}],[]}], true}, {false, false}, {true, true}]), %% Remote messages OtherName = atom_to_list(?MODULE)++"_receive_trace", {ok, OtherNode} = start_node(OtherName), - RemoteProc = spawn(OtherNode, ?MODULE, process, [self()]), + RemoteProc = spawn_link(OtherNode, ?MODULE, process, [self()]), io:format("RemoteProc = ~p ~n", [RemoteProc]), RemoteProc ! {send_please, Receiver, Hello}, @@ -139,10 +139,13 @@ receive_trace(Config) when is_list(Config) -> receive_nothing() end, F2(Receiver, {no, true}), - F2(Receiver, {[{[undefined,"Unexpected"],[],[]}], false}), - F2(Receiver, {[{[RemoteProc,'_'],[],[]}], true}), - F2(Receiver, {[{['$1','_'], [{'=/=',{node,'$1'},{node}}], []}], true}), - F2(Receiver, {[{['_','$1'], [{is_tuple,'$1'}], []}], true}), + F2(Receiver, {[{[OtherNode, undefined,"Unexpected"],[],[]}], false}), + F2(Receiver, {[{[OtherNode, RemoteProc,'_'],[],[]}, + {[OtherNode, undefined,'_'],[],[]}], true}), + F2(Receiver, {[{[OtherNode, '$1','_'], + [{'orelse',{'=:=','$1',undefined},{'=/=',{node,'$1'},{node}}}], + []}], true}), + F2(Receiver, {[{['$1', '_','_'], [{'=:=','$1',OtherNode}], []}], true}), F2(Receiver, {false, false}), F2(Receiver, {true, true}), @@ -151,25 +154,30 @@ receive_trace(Config) when is_list(Config) -> register(Name, Receiver), NN = {Name, node()}, F2(NN, {no, true}), - F2(NN, {[{[undefined,"Unexpected"],[],[]}], false}), - F2(NN, {[{[RemoteProc,'_'],[],[]}], true}), - F2(NN, {[{['$1','_'], [{'=/=',{node,'$1'},{node}}], []}], true}), - F2(NN, {[{['_','$1'], [{is_tuple,'$1'}], []}], true}), + F2(NN, {[{[OtherNode, undefined,"Unexpected"],[],[]}], false}), + F2(NN, {[{[OtherNode, RemoteProc,'_'],[],[]}, + {[OtherNode, undefined,'_'],[],[]}], true}), + F2(NN, {[{[OtherNode, '$1','_'], + [{'orelse',{'=:=','$1',undefined},{'=/=',{node,'$1'},{node}}}], + []}], true}), + F2(NN, {[{['$1', '_','_'], [{'==','$1',OtherNode}], []}], true}), F2(NN, {false, false}), F2(NN, {true, true}), + unlink(RemoteProc), true = stop_node(OtherNode), %% Timeout Receiver ! {set_timeout, 10}, {trace, Receiver, 'receive', {set_timeout, 10}} = receive_first_trace(), {trace, Receiver, 'receive', timeout} = receive_first_trace(), - erlang:trace_pattern('receive', [{[clock_service,timeout], [], []}], []), + erlang:trace_pattern('receive', [{[clock_service,undefined,timeout], [], []}], []), Receiver ! {set_timeout, 7}, {trace, Receiver, 'receive', timeout} = receive_first_trace(), erlang:trace_pattern('receive', true, []), %% Another process should not be able to trace Receiver. + process_flag(trap_exit, true), Intruder = fun_spawn(fun() -> erlang:trace(Receiver, true, ['receive']) end), {'EXIT', Intruder, {badarg, _}} = receive_first(), @@ -181,18 +189,19 @@ receive_trace(Config) when is_list(Config) -> %% Verify restrictions in matchspec for 'receive' F3 = fun (Pat) -> {'EXIT', {badarg,_}} = (catch erlang:trace_pattern('receive', Pat, [])) end, - F3([{['_','_'],[],[{message, {process_dump}}]}]), - F3([{['_','_'],[{is_seq_trace}],[]}]), - F3([{['_','_'],[],[{set_seq_token,label,4711}]}]), - F3([{['_','_'],[],[{get_seq_token}]}]), - F3([{['_','_'],[],[{enable_trace,call}]}]), - F3([{['_','_'],[],[{enable_trace,self(),call}]}]), - F3([{['_','_'],[],[{disable_trace,call}]}]), - F3([{['_','_'],[],[{disable_trace,self(),call}]}]), - F3([{['_','_'],[],[{trace,[call],[]}]}]), - F3([{['_','_'],[],[{trace,self(),[],[call]}]}]), - F3([{['_','_'],[],[{caller}]}]), - F3([{['_','_'],[],[{silent,true}]}]), + WC = ['_','_','_'], + F3([{WC,[],[{message, {process_dump}}]}]), + F3([{WC,[{is_seq_trace}],[]}]), + F3([{WC,[],[{set_seq_token,label,4711}]}]), + F3([{WC,[],[{get_seq_token}]}]), + F3([{WC,[],[{enable_trace,call}]}]), + F3([{WC,[],[{enable_trace,self(),call}]}]), + F3([{WC,[],[{disable_trace,call}]}]), + F3([{WC,[],[{disable_trace,self(),call}]}]), + F3([{WC,[],[{trace,[call],[]}]}]), + F3([{WC,[],[{trace,self(),[],[call]}]}]), + F3([{WC,[],[{caller}]}]), + F3([{WC,[],[{silent,true}]}]), ok. -- cgit v1.2.3 From 36e9d73aa08930ddf3e3587addfb9a647a41b3e7 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 6 Apr 2016 15:05:10 +0200 Subject: erts: Add docs for trace_pattern with 'send' and 'receive' --- erts/doc/src/erlang.xml | 140 ++++++++++++++++++++++++++++++++++++++++-- erts/preloaded/src/erlang.erl | 10 ++- 2 files changed, 142 insertions(+), 8 deletions(-) diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index c7b5ea8867..f88d05cdc3 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -9124,27 +9124,155 @@ timestamp() -> - Sets trace patterns for global call tracing. + Sets trace patterns for call, send or 'receive' tracing.

The same as - erlang:trace_pattern(MFA, MatchSpec, []), + erlang:trace_pattern(Event, MatchSpec, []), retained for backward compatibility.

- + + Sets trace pattern for message sending. + +

Sets trace pattern for message sending. + Must be combined with + erlang:trace/3 + to set the send trace flag for one or more processes. + By default all messages, sent from send traced processes, + are traced. Use erlang:trace_pattern/3 to limit + traced send events based on the message content, the sender + and/or the receiver.

+

Argument MatchSpec can take the + following forms:

+ + MatchSpecList + +

A list of match specifications. The matching is done + on the list [Receiver, Msg]. Receiver + is the process or port identity of the receiver and + Msg is the message term. The pid of the sending + process can be accessed with the guard function + self/0. An empty list is the same as true. + See the users guide section + Match Specifications in Erlang + for more information.

+
+ true + +

Enables tracing for all sent messages (from send + traced processes). Any match specification is + removed. This is the default.

+
+ false + +

Disables tracing for all sent messages. + Any match specification is removed.

+
+
+

Argument FlagList must be [] + for send tracing.

+

The return value is always 1.

+

Example; only trace messages to a specific process Pid:

+
+> erlang:trace_pattern(send, [{[Pid, '_'],[],[]}], []).
+1
+

Only trace messages matching {reply, _}:

+
+> erlang:trace_pattern(send, [{['_', {reply,'_'}],[],[]}], []).
+1
+

Only trace messages sent to the sender itself:

+
+> erlang:trace_pattern(send, [{['$1', '_'],[{'=:=','$1',{self}}],[]}], []).
+1
+

Only trace messages sent to other nodes:

+
+> erlang:trace_pattern(send, [{['$1', '_'],[{'=/=',{node,'$1'},{node}}],[]}], []).
+1
+

A match specification for send trace can use + all guard and body functions except caller.

+
+
+ + + + Sets trace pattern for tracing of message receiving. + +

+

Sets trace pattern for message receiving. + Must be combined with + erlang:trace/3 + to set the 'receive' trace flag for one or more processes. + By default all messages, received by 'receive' traced processes, + are traced. Use erlang:trace_pattern/3 to limit + traced receive events based on the message content, the sender + and/or the receiver.

+

Argument MatchSpec can take the + following forms:

+ + MatchSpecList + +

A list of match specifications. The matching is done + on the list [Node, Sender, Msg]. Node + is the node name of the sender. Sender is the + process or port identity of the sender, or the atom + undefined if the sender is not known (which may + be the case for remote senders). Msg is the + message term. The pid of the receiving process can be + accessed with the guard function self/0. An empty + list is the same as true. See the users guide section + Match Specifications in Erlang + for more information.

+
+ true + +

Enables tracing for all received messages (to 'receive' + traced processes). Any match specification is + removed. This is the default.

+
+ false + +

Disables tracing for all sent messages. + Any match specification is removed.

+
+
+

Argument FlagList must be [] + for receive tracing.

+

The return value is always 1.

+

Example; only trace messages from a specific process Pid:

+
+> erlang:trace_pattern('receive', [{['_',Pid, '_'],[],[]}], []).
+1
+

Only trace messages matching {reply, _}:

+
+> erlang:trace_pattern('receive', [{['_','_', {reply,'_'}],[],[]}], []).
+1
+

Only trace messages from other nodes:

+
+> erlang:trace_pattern('receive', [{['$1', '_', '_'],[{'=/=','$1',{node}}],[]}], []).
+1
+

A match specification for 'receive' trace can + use all guard and body functions except caller, + is_seq_trace, get_seq_token, set_seq_token, enable_trace, + disable_trace, trace, silent and process_dump.

+
+
+ + + Sets trace patterns for tracing of function calls. -

Enables or disables call tracing for - one or more functions. Must be combined with +

Enables or disables call tracing for one or more functions. + Must be combined with erlang:trace/3 - to set the call trace flag for one or more processes.

+ to set the call trace flag + for one or more processes.

Conceptually, call tracing works as follows. Inside the Erlang Virtual Machine, a set of processes and a set of functions are to be traced. If a traced process diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 20a64e81b4..d09958032b 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2381,7 +2381,7 @@ tl(_List) -> [{[term()] | '_' ,[term()],[term()]}]. -spec erlang:trace_pattern(MFA, MatchSpec) -> non_neg_integer() when - MFA :: trace_pattern_mfa(), + MFA :: trace_pattern_mfa() | send | 'receive', MatchSpec :: (MatchSpecList :: trace_match_spec()) | boolean() | restart @@ -2403,7 +2403,13 @@ trace_pattern(MFA, MatchSpec) -> call_count | call_time. --spec erlang:trace_pattern(MFA, MatchSpec, FlagList) -> non_neg_integer() when +-spec erlang:trace_pattern(send, MatchSpec, []) -> non_neg_integer() when + MatchSpec :: (MatchSpecList :: trace_match_spec()) + | boolean(); + ('receive', MatchSpec, []) -> non_neg_integer() when + MatchSpec :: (MatchSpecList :: trace_match_spec()) + | boolean(); + (MFA, MatchSpec, FlagList) -> non_neg_integer() when MFA :: trace_pattern_mfa(), MatchSpec :: (MatchSpecList :: trace_match_spec()) | boolean() -- cgit v1.2.3 From 14b81c60f0c6403e9371be420a6df4d414180c68 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 29 Apr 2016 17:50:18 +0200 Subject: erts: Fix PAM to be callable from non-scheduler thread also simplified the interface to to run PAM from trace --- erts/emulator/beam/erl_db_util.c | 73 ++++++++++++++++++++++++---------------- erts/emulator/beam/erl_trace.c | 61 +++++++++++++++------------------ erts/emulator/beam/global.h | 22 ++++++++---- 3 files changed, 88 insertions(+), 68 deletions(-) diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index 7d64529250..051c107d1f 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -414,19 +414,27 @@ get_match_pseudo_process(Process *c_p, Uint heap_size) { ErtsMatchPseudoProcess *mpsp; #ifdef ERTS_SMP - ErtsSchedulerData *esdp = c_p ? c_p->scheduler_data : erts_get_scheduler_data(); + ErtsSchedulerData *esdp; + + esdp = c_p ? c_p->scheduler_data : erts_get_scheduler_data(); + + mpsp = esdp ? esdp->match_pseudo_process : + (ErtsMatchPseudoProcess*) erts_smp_tsd_get(match_pseudo_process_key); - mpsp = (ErtsMatchPseudoProcess *) esdp->match_pseudo_process; - if (mpsp) + if (mpsp) { + ASSERT(mpsp == erts_smp_tsd_get(match_pseudo_process_key)); + ASSERT(mpsp->process.scheduler_data == esdp); cleanup_match_pseudo_process(mpsp, 0); + } else { ASSERT(erts_smp_tsd_get(match_pseudo_process_key) == NULL); mpsp = create_match_pseudo_process(); - esdp->match_pseudo_process = (void *) mpsp; + if (esdp) { + esdp->match_pseudo_process = (void *) mpsp; + } + mpsp->process.scheduler_data = esdp; erts_smp_tsd_set(match_pseudo_process_key, (void *) mpsp); } - ASSERT(mpsp == erts_smp_tsd_get(match_pseudo_process_key)); - mpsp->process.scheduler_data = esdp; #else mpsp = match_pseudo_process; cleanup_match_pseudo_process(mpsp, 0); @@ -1206,32 +1214,37 @@ done: return ret; } -Eterm erts_match_set_run(Process *c_p, - Process *self, - Binary *mpsp, - Eterm *args, int num_args, - enum erts_pam_run_flags in_flags, - Uint32 *return_flags) +/* Returns + * am_false if no match or + * if {message,false} has been called, + * am_true if {message,_} has NOT been called or + * if {message,true} has been called, + * Msg if {message,Msg} has been called. + * + * If return value is_not_immed + * then erts_match_set_release_result_trace() must be called to release it. + */ +Eterm erts_match_set_run_trace(Process *c_p, + Process *self, + Binary *mpsp, + Eterm *args, int num_args, + enum erts_pam_run_flags in_flags, + Uint32 *return_flags) { Eterm ret; ret = db_prog_match(c_p, self, mpsp, NIL, args, num_args, in_flags, return_flags); -#if defined(HARDDEBUG) - if (is_non_value(ret)) { - erts_fprintf(stderr, "Failed\n"); - } else { - erts_fprintf(stderr, "Returning : %T\n", ret); + + ASSERT(!(is_non_value(ret) && *return_flags)); + + if (is_non_value(ret) || ret == am_false) { + erts_match_set_release_result(c_p); + return am_false; } -#endif + if (is_immed(ret)) + erts_match_set_release_result(c_p); return ret; - /* Returns - * THE_NON_VALUE if no match - * am_false if {message,false} has been called, - * am_true if {message,_} has not been called or - * if {message,true} has been called, - * Msg if {message,Msg} has been called. - */ } static Eterm erts_match_set_run_ets(Process *p, Binary *mpsp, @@ -1774,6 +1787,7 @@ Eterm db_prog_match(Process *c_p, #endif /* DMC_DEBUG */ ERTS_UNDEF(n,0); + ERTS_UNDEF(current_scheduled,NULL); ASSERT(c_p || !(in_flags & ERTS_PAM_COPY_RESULT)); @@ -1784,8 +1798,8 @@ Eterm db_prog_match(Process *c_p, because of floating point exceptions. Do *after* mpsp is set!!! */ esdp = ERTS_GET_SCHEDULER_DATA_FROM_PROC(psp); - ASSERT(esdp != NULL); - current_scheduled = esdp->current_process; + if (esdp) + current_scheduled = esdp->current_process; /* SMP: psp->scheduler_data is set by get_match_pseudo_process */ #ifdef DMC_DEBUG @@ -2517,7 +2531,8 @@ success: } #endif - esdp->current_process = current_scheduled; + if (esdp) + esdp->current_process = current_scheduled; return ret; #undef FAIL @@ -5073,7 +5088,7 @@ static Eterm match_spec_test(Process *p, Eterm against, Eterm spec, int trace) } save_cp = p->cp; p->cp = NULL; - res = erts_match_set_run(p, p, + res = erts_match_set_run_trace(p, p, mps, arr, n, ERTS_PAM_COPY_RESULT|ERTS_PAM_IGNORE_TRACE_SILENT, &ret_flags); diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index be0d2f0939..9f3341537d 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -825,13 +825,13 @@ trace_send(Process *p, Eterm to, Eterm msg) Uint32 return_flags; args[0] = to; args[1] = msg; - pam_result = erts_match_set_run(p, p, - te->match_spec, args, 2, - ERTS_PAM_TMP_RESULT, &return_flags); - if (is_non_value(pam_result) - || pam_result == am_false - || (ERTS_TRACE_FLAGS(p) & F_TRACE_SILENT)) { - erts_match_set_release_result(p); + pam_result = erts_match_set_run_trace(p, p, + te->match_spec, args, 2, + ERTS_PAM_TMP_RESULT, &return_flags); + if (pam_result == am_false) + return; + if (ERTS_TRACE_FLAGS(p) & F_TRACE_SILENT) { + erts_match_set_release_result_trace(p, pam_result); return; } } else @@ -850,9 +850,9 @@ trace_send(Process *p, Eterm to, Eterm msg) if (is_tracer_enabled(p, ERTS_PROC_LOCK_MAIN, &p->common, &tnif, TRACE_FUN_E_SEND, operation)) { send_to_tracer_nif(p, &p->common, p->common.id, tnif, TRACE_FUN_T_SEND, - operation, msg, to, pam_result); + operation, msg, to, pam_result); } - erts_match_set_release_result(p); + erts_match_set_release_result_trace(p, pam_result); } /* Send {trace_ts, Pid, receive, Msg, Timestamp} @@ -886,13 +886,13 @@ trace_receive(Process* receiver, args[1] = am_undefined; } args[2] = msg; - pam_result = erts_match_set_run(NULL, receiver, - te->match_spec, args, 3, - ERTS_PAM_TMP_RESULT, &return_flags); - if (is_non_value(pam_result) - || pam_result == am_false - || (ERTS_TRACE_FLAGS(receiver) & F_TRACE_SILENT)) { - erts_match_set_release_result(NULL); + pam_result = erts_match_set_run_trace(NULL, receiver, + te->match_spec, args, 3, + ERTS_PAM_TMP_RESULT, &return_flags); + if (pam_result == am_false) + return; + if (ERTS_TRACE_FLAGS(receiver) & F_TRACE_SILENT) { + erts_match_set_release_result_trace(NULL, pam_result); return; } } else @@ -904,7 +904,7 @@ trace_receive(Process* receiver, tnif, TRACE_FUN_T_RECEIVE, am_receive, msg, THE_NON_VALUE, pam_result); } - erts_match_set_release_result(NULL); + erts_match_set_release_result_trace(NULL, pam_result); } int @@ -1264,21 +1264,14 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, may remove it, and we still want to generate a trace message */ erts_tracer_update(&pre_ms_tracer, *tracer); tracer = &pre_ms_tracer; - pam_result = erts_match_set_run(p, p, - match_spec, args, arity, - ERTS_PAM_TMP_RESULT, &return_flags); - if (is_non_value(pam_result)) { - erts_match_set_release_result(p); - UnUseTmpHeap(ERL_SUB_BIN_SIZE,p); - ERTS_TRACER_CLEAR(&pre_ms_tracer); - return 0; - } + pam_result = erts_match_set_run_trace(p, p, + match_spec, args, arity, + ERTS_PAM_TMP_RESULT, &return_flags); } if (tracee_flags == &meta_flags) { /* Meta trace */ if (pam_result == am_false) { - erts_match_set_release_result(p); UnUseTmpHeap(ERL_SUB_BIN_SIZE,p); ERTS_TRACER_CLEAR(&pre_ms_tracer); return return_flags; @@ -1286,13 +1279,12 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, } else { /* Non-meta trace */ if (*tracee_flags & F_TRACE_SILENT) { - erts_match_set_release_result(p); + erts_match_set_release_result_trace(p, pam_result); UnUseTmpHeap(ERL_SUB_BIN_SIZE,p); ERTS_TRACER_CLEAR(&pre_ms_tracer); return 0; } if (pam_result == am_false) { - erts_match_set_release_result(p); UnUseTmpHeap(ERL_SUB_BIN_SIZE,p); ERTS_TRACER_CLEAR(&pre_ms_tracer); return return_flags; @@ -1328,11 +1320,14 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, * Build the trace tuple and send it to the port. */ send_to_tracer_nif_raw(p, NULL, *tracer, *tracee_flags, p->common.id, - tnif, TRACE_FUN_T_CALL, am_call, mfa_tuple, THE_NON_VALUE, pam_result); - erts_match_set_release_result(p); + tnif, TRACE_FUN_T_CALL, am_call, mfa_tuple, + THE_NON_VALUE, pam_result); - if (match_spec && tracer == &pre_ms_tracer) - ERTS_TRACER_CLEAR(&pre_ms_tracer); + if (match_spec) { + erts_match_set_release_result_trace(p, pam_result); + if (tracer == &pre_ms_tracer) + ERTS_TRACER_CLEAR(&pre_ms_tracer); + } return return_flags; } diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 328bfe344c..baa0a201d1 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -1486,6 +1486,16 @@ do { \ extern Binary *erts_match_set_compile(Process *p, Eterm matchexpr, Eterm MFA); Eterm erts_match_set_lint(Process *p, Eterm matchexpr); extern void erts_match_set_release_result(Process* p); +ERTS_GLB_INLINE void erts_match_set_release_result_trace(Process* p, Eterm); + +#if ERTS_GLB_INLINE_INCL_FUNC_DEF +ERTS_GLB_INLINE +void erts_match_set_release_result_trace(Process* p, Eterm pam_result) +{ + if (is_not_immed(pam_result)) + erts_match_set_release_result(p); +} +#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ enum erts_pam_run_flags { ERTS_PAM_TMP_RESULT=1, @@ -1493,12 +1503,12 @@ enum erts_pam_run_flags { ERTS_PAM_CONTIGUOUS_TUPLE=4, ERTS_PAM_IGNORE_TRACE_SILENT=8 }; -extern Eterm erts_match_set_run(Process *p, - Process *self, - Binary *mpsp, - Eterm *args, int num_args, - enum erts_pam_run_flags in_flags, - Uint32 *return_flags); +extern Eterm erts_match_set_run_trace(Process *p, + Process *self, + Binary *mpsp, + Eterm *args, int num_args, + enum erts_pam_run_flags in_flags, + Uint32 *return_flags); extern Eterm erts_match_set_get_source(Binary *mpsp); extern void erts_match_prog_foreach_offheap(Binary *b, void (*)(ErlOffHeap *, void *), -- cgit v1.2.3 From d0ffd5c2a84d15d94dcbc8bac98d527bfc1d4a3c Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 2 May 2016 12:29:25 +0200 Subject: erts: Fix missing type in doc for trace_pattern --- erts/doc/src/erlang.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index f88d05cdc3..f42923a009 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -9137,6 +9137,7 @@ timestamp() -> Sets trace pattern for message sending. +

Sets trace pattern for message sending. Must be combined with @@ -9200,6 +9201,7 @@ timestamp() -> Sets trace pattern for tracing of message receiving. +

Sets trace pattern for message receiving. -- cgit v1.2.3 From 6197aa2498bcb35e331c9112a70635f55047bf26 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 2 May 2016 18:40:10 +0200 Subject: erts: Fix bug in trace_pattern for 'on_load' 'on_load' is a call trace. --- erts/emulator/beam/erl_db_util.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index 051c107d1f..95b1cd0148 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -1002,10 +1002,14 @@ Binary *erts_match_set_compile(Process *p, Eterm matchexpr, Eterm MFA) { Binary *bin; Uint sz; Eterm *hp; - Uint flags = DCOMP_TRACE; + Uint flags; - if (is_tuple(MFA)) flags |= DCOMP_CALL_TRACE; - if (MFA != am_receive) flags |= DCOMP_ALLOW_TRACE_OPS; + switch (MFA) { + case am_receive: flags = DCOMP_TRACE; break; + case am_send: flags = DCOMP_TRACE | DCOMP_ALLOW_TRACE_OPS; break; + default: + flags = DCOMP_TRACE | DCOMP_CALL_TRACE | DCOMP_ALLOW_TRACE_OPS; + } bin = db_match_set_compile(p, matchexpr, flags); if (bin != NULL) { -- cgit v1.2.3 From 54172674e71caf7da7a0b069c9bd92543e4f705d Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 4 May 2016 14:45:05 +0200 Subject: erts: Add send and 'receive' to trace_info/2 to obtain match specs --- erts/doc/src/erlang.xml | 33 ++++++++++++++++++++----------- erts/emulator/beam/erl_bif_trace.c | 40 ++++++++++++++++++++++++++++++++++++++ erts/emulator/test/trace_SUITE.erl | 5 ++++- erts/preloaded/src/erlang.erl | 8 ++++---- 4 files changed, 70 insertions(+), 16 deletions(-) diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index f42923a009..5af4f0bd66 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -9015,16 +9015,16 @@ timestamp() -> -

Returns trace information about a port, process or function.

-

To get information about a port or process, - PidPortOrFunc is to +

Returns trace information about a port, process, function or event.

+

To get information about a port or process, + PidPortFuncEvent is to be a process identifier (pid), port identifier or one of the atoms new, new_processes, new_ports. The atom new or new_processes means that the default trace state for processes to be created is returned. The atom new_ports means that the default trace state for ports to be created is returned.

-

The following Items are valid:

+

The following Items are valid for ports and processes:

flags @@ -9048,12 +9048,15 @@ timestamp() -> value is [].

-

To get information about a function, PidPortOrFunc is to +

To get information about a function, PidPortFuncEvent is to be the three-element tuple {Module, Function, Arity} or the atom on_load. No wild cards are allowed. Returns undefined if the function does not exist, or - false if the function is not traced.

-

The following Items are valid::

+ false if the function is not traced. If PidPortFuncEvent + is on_load, the information returned refers to + the default value for code that will be loaded.

+ +

The following Items are valid for functions:

traced @@ -9112,13 +9115,21 @@ timestamp() -> is active for this function.

+

To get information about an event, PidPortFuncEvent is to + be one of the atoms send or 'receive'.

+

The only valid Item for events is:

+ + match_spec + +

Returns the match specification for this event, if it + has one, or true if no match specification has been + set.

+
+

The return value is {Item, Value}, where Value is the requested information as described earlier. If a pid for a dead process was given, or the name of a non-existing function, Value is undefined.

-

If PidPortOrFunc is on_load, the information - returned refers to the default value for code that will be - loaded.

@@ -9237,7 +9248,7 @@ timestamp() ->
false -

Disables tracing for all sent messages. +

Disables tracing for all received messages. Any match specification is removed.

diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index ffc0afda58..b65c0e303f 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -81,6 +81,8 @@ static void new_seq_trace_token(Process* p); /* help func for seq_trace_2*/ static Eterm trace_info_pid(Process* p, Eterm pid_spec, Eterm key); static Eterm trace_info_func(Process* p, Eterm pid_spec, Eterm key); static Eterm trace_info_on_load(Process* p, Eterm key); +static Eterm trace_info_event(Process* p, Eterm event, Eterm key); + static void reset_bif_trace(void); static void setup_bif_trace(void); @@ -814,6 +816,8 @@ Eterm trace_info_2(BIF_ALIST_2) if (What == am_on_load) { res = trace_info_on_load(p, Key); + } else if (What == am_send || What == am_receive) { + res = trace_info_event(p, What, Key); } else if (is_atom(What) || is_pid(What) || is_port(What)) { res = trace_info_pid(p, What, Key); } else if (is_tuple(What)) { @@ -1303,6 +1307,42 @@ trace_info_on_load(Process* p, Eterm key) } } +static Eterm +trace_info_event(Process* p, Eterm event, Eterm key) +{ + ErtsTracingEvent* te; + Eterm retval; + Eterm* hp; + + switch (event) { + case am_send: te = erts_send_tracing; break; + case am_receive: te = erts_receive_tracing; break; + default: + goto error; + } + + if (key != am_match_spec) + goto error; + + te = &te[erts_active_bp_ix()]; + + if (te->on) { + if (!te->match_spec) + retval = am_true; + else + retval = copy_object(MatchSetGetSource(te->match_spec), p); + } + else + retval = am_false; + + hp = HAlloc(p, 3); + return TUPLE2(hp, key, retval); + + error: + BIF_ERROR(p, BADARG); +} + + #undef FUNC_TRACE_NOEXIST #undef FUNC_TRACE_UNTRACED #undef FUNC_TRACE_GLOBAL_TRACE diff --git a/erts/emulator/test/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl index 1930332691..3d7cb41fc0 100644 --- a/erts/emulator/test/trace_SUITE.erl +++ b/erts/emulator/test/trace_SUITE.erl @@ -495,7 +495,10 @@ send_trace(Config) when is_list(Config) -> ok. set_trace_pattern(_, no, _) -> 0; -set_trace_pattern(MSA, Pat, Flg) -> erlang:trace_pattern(MSA, Pat, Flg). +set_trace_pattern(MFA, Pat, Flg) -> + R = erlang:trace_pattern(MFA, Pat, Flg), + {match_spec, Pat} = erlang:trace_info(MFA, match_spec), + R. %% Test trace(Pid, How, [procs]). procs_trace(Config) when is_list(Config) -> diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index d09958032b..90fd536b15 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1749,16 +1749,16 @@ trace_delivered(_Tracee) -> erlang:nif_error(undefined). %% trace_info/2 --spec erlang:trace_info(PidPortOrFunc, Item) -> Res when - PidPortOrFunc :: pid() | port() | new | new_processes | new_ports - | {Module, Function, Arity} | on_load, +-spec erlang:trace_info(PidPortFuncEvent, Item) -> Res when + PidPortFuncEvent :: pid() | port() | new | new_processes | new_ports + | {Module, Function, Arity} | on_load | send | 'receive', Module :: module(), Function :: atom(), Arity :: arity(), Item :: flags | tracer | traced | match_spec | meta | meta_match_spec | call_count | call_time | all, Res :: trace_info_return(). -trace_info(_PidPortOrFunc, _Item) -> +trace_info(_PidPortFuncEvent, _Item) -> erlang:nif_error(undefined). %% trunc/1 -- cgit v1.2.3 From bc274db5918286eae72acc8050a12ad6d6fe05bf Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 4 May 2016 14:55:24 +0200 Subject: runtime_tools: Add dbg functions tpe/2 and ctpe/1 To set/clear match specs for send and receive trace. 'e' for Event as we might want to add match specs for other trace events (proc exit,link,ulink,...). --- lib/runtime_tools/src/dbg.erl | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/lib/runtime_tools/src/dbg.erl b/lib/runtime_tools/src/dbg.erl index d5ff874206..b29bc42a8e 100644 --- a/lib/runtime_tools/src/dbg.erl +++ b/lib/runtime_tools/src/dbg.erl @@ -20,6 +20,7 @@ -module(dbg). -export([p/1,p/2,c/3,c/4,i/0,start/0,stop/0,stop_clear/0,tracer/0, tracer/2, tracer/3, get_tracer/0, get_tracer/1, tp/2, tp/3, tp/4, + tpe/2, ctpe/1, ctp/0, ctp/1, ctp/2, ctp/3, tpl/2, tpl/3, tpl/4, ctpl/0, ctpl/1, ctpl/2, ctpl/3, ctpg/0, ctpg/1, ctpg/2, ctpg/3, ltp/0, wtp/1, rtp/1, dtp/0, dtp/1, n/1, cn/1, ln/0, h/0, h/1]). @@ -128,7 +129,12 @@ tpl(Module, Pattern) when is_atom(Module) -> do_tp({Module, '_', '_'}, Pattern, [local]); tpl({_Module, _Function, _Arity} = X, Pattern) -> do_tp(X,Pattern,[local]). -do_tp({_Module, _Function, _Arity} = X, Pattern, Flags) + +tpe(Event, Pattern) when Event =:= send; + Event =:= 'receive' -> + do_tp(Event, Pattern, []). + +do_tp(X, Pattern, Flags) when is_integer(Pattern); is_atom(Pattern) -> case ets:lookup(get_pattern_table(), Pattern) of @@ -137,17 +143,16 @@ do_tp({_Module, _Function, _Arity} = X, Pattern, Flags) _ -> {error, unknown_pattern} end; -do_tp({Module, _Function, _Arity} = X, Pattern, Flags) when is_list(Pattern) -> +do_tp(X, Pattern, Flags) when is_list(Pattern) -> Nodes = req(get_nodes), - case Module of - '_' -> - ok; - M when is_atom(M) -> + case X of + {M,_,_} when is_atom(M) -> %% Try to load M on all nodes lists:foreach(fun(Node) -> rpc:call(Node, M, module_info, []) end, - Nodes) + Nodes); + _ -> ok end, case lint_tp(Pattern) of {ok,_} -> @@ -163,9 +168,9 @@ do_tp({Module, _Function, _Arity} = X, Pattern, Flags) when is_list(Pattern) -> end. %% All nodes are handled the same way - also the local node if it is traced -do_tp_on_nodes(Nodes, MFA, P, Flags) -> +do_tp_on_nodes(Nodes, X, P, Flags) -> lists:map(fun(Node) -> - case rpc:call(Node,erlang,trace_pattern,[MFA,P, Flags]) of + case rpc:call(Node,erlang,trace_pattern,[X,P, Flags]) of N when is_integer(N) -> {matched, Node, N}; Else -> @@ -210,6 +215,7 @@ ctpg(Module) when is_atom(Module) -> do_ctp({Module, '_', '_'}, [global]); ctpg({_Module, _Function, _Arity} = X) -> do_ctp(X,[global]). + do_ctp({Module, Function, Arity},[]) -> do_ctp({Module, Function, Arity},[global]), do_ctp({Module, Function, Arity},[local]); @@ -217,6 +223,11 @@ do_ctp({_Module, _Function, _Arity}=MFA,Flags) -> Nodes = req(get_nodes), {ok,do_tp_on_nodes(Nodes,MFA,false,Flags)}. +ctpe(Event) when Event =:= send; + Event =:= 'receive' -> + Nodes = req(get_nodes), + {ok,do_tp_on_nodes(Nodes,Event,false,[])}. + %% %% ltp() -> ok %% List saved and built-in trace patterns. -- cgit v1.2.3 From e8fa9bb9e4c9bbd38371dc47791fd4c1f3d932ff Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 4 May 2016 14:55:45 +0200 Subject: runtime_tools: Add send tpe testcase --- lib/runtime_tools/test/dbg_SUITE.erl | 81 ++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/lib/runtime_tools/test/dbg_SUITE.erl b/lib/runtime_tools/test/dbg_SUITE.erl index 9c9d6ca352..db4aad7341 100644 --- a/lib/runtime_tools/test/dbg_SUITE.erl +++ b/lib/runtime_tools/test/dbg_SUITE.erl @@ -22,6 +22,7 @@ %% Test functions -export([all/0, suite/0, big/1, tiny/1, simple/1, message/1, distributed/1, port/1, + send/1, ip_port/1, file_port/1, file_port2/1, file_port_schedfix/1, ip_port_busy/1, wrap_port/1, wrap_port_time/1, with_seq_trace/1, dead_suspend/1, local_trace/1, @@ -39,6 +40,7 @@ suite() -> all() -> [big, tiny, simple, message, distributed, port, ip_port, + send, file_port, file_port2, file_port_schedfix, ip_port_busy, wrap_port, wrap_port_time, with_seq_trace, dead_suspend, local_trace, saved_patterns, tracer_exit_on_stop, @@ -151,6 +153,74 @@ message(Config) when is_list(Config) -> {trace,S,call,{dbg,ln,[]},S}] = flush(), ok. +send(Config) when is_list(Config) -> + {ok, _} = start(), + try + S = self(), + Rcvr = spawn_link(fun F() -> + receive M -> + S ! M, + F() + end + end), + + {ok, [{matched, _, 1}]} = dbg:p(Rcvr, send), + R1 = Rcvr ! make_ref(), + receive R1 -> ok end, + [{trace, Rcvr, send, R1, S}] = flush(), + + {ok, [{matched, _node, 1}, {saved, 1}]} = dbg:tpe(send, [{[S,'_'],[],[]}]), + R2 = Rcvr ! make_ref(), + receive R2 -> ok end, + [{trace, Rcvr, send, R2, S}] = flush(), + + {ok, [{matched, _node, 1}, {saved, 2}]} = + dbg:tpe(send, [{['$1','_'],[{'==','$1',{self}}],[]}]), + R3 = Rcvr ! make_ref(), + receive R3 -> ok end, + [] = flush(), + + {ok, [{matched, _node, 1}, {saved, 3}]} = + dbg:tpe(send, [{['_','_'],[{'==',Rcvr,{self}}],[]}]), + R4 = Rcvr ! make_ref(), + receive R4 -> ok end, + [{trace, Rcvr, send, R4, S}] = flush(), + + {ok, [{matched, _node, 1}, {saved, 4}]} = + dbg:tpe(send, [{['_','_'],[{'==',Rcvr,{self}}],[{message, hello}]}]), + R5 = Rcvr ! make_ref(), + receive R5 -> ok end, + [{trace, Rcvr, send, R5, S, hello}] = flush(), + + {ok, [{matched, _node, 1}, {saved, 2}]} = dbg:tpe(send, 2), + R6 = Rcvr ! make_ref(), + receive R6 -> ok end, + [] = flush(), + + {ok, [{matched, _node, 1}]} = dbg:ctpe(send), + R7 = Rcvr ! make_ref(), + receive R7 -> ok end, + [{trace, Rcvr, send, R7, S, hello}] = flush(), + + R8 = make_ref(), + {ok, [{matched, _node, 1}, {saved, 5}]} = + dbg:tpe(send, [{['_','$2'],[{'==',R8,{element, 1, {element, 2, '$2'}}}], + [{message, hello}]}]), + Msg1 = Rcvr ! {test, {R8}, <<0:(8*1024)>>}, + receive Msg1 -> ok end, + [{trace, Rcvr, send, Msg1, S, hello}] = flush(), + + R9 = make_ref(), + Msg2 = Rcvr ! {test, {R9}, <<0:(8*1024)>>}, + receive Msg2 -> ok end, + [] = flush(), + + ok + + after + stop() + end. + %% Simple test of distributed tracing distributed(Config) when is_list(Config) -> {ok, _} = start(), @@ -859,6 +929,17 @@ flush(Acc) -> Acc end. +flush_trace() -> + flush_trace([]). +flush_trace(Acc) -> + receive + X when element(1,X) =:= trace; + element(1,X) =:= trace_ts + -> flush_trace(Acc ++ [X]) + after 1000 -> + Acc + end. + start() -> stop(), dbg:tracer(process, {fun myhandler/2, self()}). -- cgit v1.2.3 From 9265763bafb2e744a42693686a14fa214ebef261 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 3 May 2016 14:50:48 +0200 Subject: runtime_tools: more dbg send trace pattern tests --- lib/runtime_tools/test/dbg_SUITE.erl | 152 +++++++++++++++++++++-------------- 1 file changed, 91 insertions(+), 61 deletions(-) diff --git a/lib/runtime_tools/test/dbg_SUITE.erl b/lib/runtime_tools/test/dbg_SUITE.erl index db4aad7341..4374141157 100644 --- a/lib/runtime_tools/test/dbg_SUITE.erl +++ b/lib/runtime_tools/test/dbg_SUITE.erl @@ -155,65 +155,76 @@ message(Config) when is_list(Config) -> send(Config) when is_list(Config) -> {ok, _} = start(), + Node = start_slave(), + rpc:call(Node, code, add_patha, + [filename:join(proplists:get_value(data_dir, Config), "..")]), try - S = self(), - Rcvr = spawn_link(fun F() -> - receive M -> - S ! M, - F() - end - end), + Echo = fun F() -> + receive {From, M} -> + From ! M, + F() + end + end, + Rcvr = spawn_link(Echo), + RemoteRcvr = spawn_link(Node, Echo), {ok, [{matched, _, 1}]} = dbg:p(Rcvr, send), - R1 = Rcvr ! make_ref(), - receive R1 -> ok end, - [{trace, Rcvr, send, R1, S}] = flush(), - {ok, [{matched, _node, 1}, {saved, 1}]} = dbg:tpe(send, [{[S,'_'],[],[]}]), - R2 = Rcvr ! make_ref(), - receive R2 -> ok end, - [{trace, Rcvr, send, R2, S}] = flush(), + send_test(Rcvr, make_ref(), true), + + %% Test that the test case process is the receiving process + send_test(Rcvr, [{[self(),'_'],[],[]}]), + %% Test that self() is not the receiving process {ok, [{matched, _node, 1}, {saved, 2}]} = dbg:tpe(send, [{['$1','_'],[{'==','$1',{self}}],[]}]), - R3 = Rcvr ! make_ref(), - receive R3 -> ok end, - [] = flush(), - - {ok, [{matched, _node, 1}, {saved, 3}]} = - dbg:tpe(send, [{['_','_'],[{'==',Rcvr,{self}}],[]}]), - R4 = Rcvr ! make_ref(), - receive R4 -> ok end, - [{trace, Rcvr, send, R4, S}] = flush(), - - {ok, [{matched, _node, 1}, {saved, 4}]} = - dbg:tpe(send, [{['_','_'],[{'==',Rcvr,{self}}],[{message, hello}]}]), - R5 = Rcvr ! make_ref(), - receive R5 -> ok end, - [{trace, Rcvr, send, R5, S, hello}] = flush(), - - {ok, [{matched, _node, 1}, {saved, 2}]} = dbg:tpe(send, 2), - R6 = Rcvr ! make_ref(), - receive R6 -> ok end, - [] = flush(), + send_test(Rcvr, make_ref(), false), + + %% Test that self() is the sending process + send_test(Rcvr, [{['_','_'],[{'==',Rcvr,{self}}],[]}]), + + %% Test attaching a message + send_test(Rcvr, [{['_','_'],[{'==',Rcvr,{self}}],[{message, hello}]}], + make_ref(), hello), + + %% Test using a saved trace pattern + send_test(Rcvr, 2, make_ref(), false), + %% Test clearing of trace pattern {ok, [{matched, _node, 1}]} = dbg:ctpe(send), - R7 = Rcvr ! make_ref(), - receive R7 -> ok end, - [{trace, Rcvr, send, R7, S, hello}] = flush(), - - R8 = make_ref(), - {ok, [{matched, _node, 1}, {saved, 5}]} = - dbg:tpe(send, [{['_','$2'],[{'==',R8,{element, 1, {element, 2, '$2'}}}], - [{message, hello}]}]), - Msg1 = Rcvr ! {test, {R8}, <<0:(8*1024)>>}, - receive Msg1 -> ok end, - [{trace, Rcvr, send, Msg1, S, hello}] = flush(), - - R9 = make_ref(), - Msg2 = Rcvr ! {test, {R9}, <<0:(8*1024)>>}, - receive Msg2 -> ok end, - [] = flush(), + send_test(Rcvr, make_ref(), true), + + %% Test complex message inspection + Ref = make_ref(), + send_test(Rcvr, + [{['_','$2'],[{'==',Ref,{element,1,{element,2,'$2'}}}],[]}], + {test, {Ref}, <<0:(8*1024)>>}, true), + + send_test(Rcvr, {test, {make_ref()}, <<0:(8*1024)>>}, false), + + %% Test send to remote process + remote_send_test(Rcvr, RemoteRcvr, [], make_ref(), true), + + remote_send_test(Rcvr, RemoteRcvr, + [{['$1','_'],[{'==',{node, '$1'},{node}}],[]}], + make_ref(), false), + + remote_send_test(Rcvr, RemoteRcvr, + [{['$1','_'],[{'==',{node, '$1'},Node}],[]}], + make_ref(), true), + + %% Test that distributed dbg works + dbg:tracer(Node, process, {fun myhandler/2, self()}), + Rcvr2 = spawn_link(Echo), + RemoteRcvr2 = spawn_link(Node, Echo), + dbg:p(Rcvr2, [send]), + dbg:p(RemoteRcvr2, [send]), + dbg:tpe(send, [{['_', hej],[],[]}]), + + send_test(Rcvr2, make_ref(), false), + send_test(RemoteRcvr2, make_ref(), false), + send_test(Rcvr2, hej, true), + send_test(RemoteRcvr2, hej, true), ok @@ -221,6 +232,36 @@ send(Config) when is_list(Config) -> stop() end. +send_test(Pid, Pattern, Msg, TraceEvent) -> + {ok, [{matched, _, _}, _]} = dbg:tpe(send, Pattern), + send_test(Pid, Msg, TraceEvent). +send_test(Pid, Pattern) -> + send_test(Pid, Pattern, make_ref(), true). +send_test(Pid, Msg, TraceEvent) -> + S = self(), + Pid ! {S, Msg}, + receive Msg -> ok end, + send_test_rcv(Pid, Msg, S, TraceEvent). + +remote_send_test(Pid, RPid, Pattern, Msg, TraceEvent) -> + dbg:tpe(send, Pattern), + TMsg = {self(), Msg}, + Pid ! {RPid, TMsg}, + receive Msg -> ok end, + send_test_rcv(Pid, TMsg, RPid, TraceEvent). + +send_test_rcv(Pid, Msg, S, TraceEvent) -> + case flush() of + [] when not TraceEvent -> + ok; + [{trace, Pid, send, Msg, S}] when TraceEvent -> + ok; + [{trace, Pid, send, Msg, S, Message}] when TraceEvent == Message -> + ok; + Else -> + ct:fail({got_unexpected_message, Else}) + end. + %% Simple test of distributed tracing distributed(Config) when is_list(Config) -> {ok, _} = start(), @@ -929,17 +970,6 @@ flush(Acc) -> Acc end. -flush_trace() -> - flush_trace([]). -flush_trace(Acc) -> - receive - X when element(1,X) =:= trace; - element(1,X) =:= trace_ts - -> flush_trace(Acc ++ [X]) - after 1000 -> - Acc - end. - start() -> stop(), dbg:tracer(process, {fun myhandler/2, self()}). -- cgit v1.2.3 From ce0e097aaa206922bcb59babbd28a0e0355b59f8 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 3 May 2016 15:24:59 +0200 Subject: runtime_tools: Add dbg tests for receive trace patterns --- lib/runtime_tools/test/dbg_SUITE.erl | 115 ++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 2 deletions(-) diff --git a/lib/runtime_tools/test/dbg_SUITE.erl b/lib/runtime_tools/test/dbg_SUITE.erl index 4374141157..4b32696aa5 100644 --- a/lib/runtime_tools/test/dbg_SUITE.erl +++ b/lib/runtime_tools/test/dbg_SUITE.erl @@ -22,7 +22,7 @@ %% Test functions -export([all/0, suite/0, big/1, tiny/1, simple/1, message/1, distributed/1, port/1, - send/1, + send/1, recv/1, ip_port/1, file_port/1, file_port2/1, file_port_schedfix/1, ip_port_busy/1, wrap_port/1, wrap_port_time/1, with_seq_trace/1, dead_suspend/1, local_trace/1, @@ -40,7 +40,7 @@ suite() -> all() -> [big, tiny, simple, message, distributed, port, ip_port, - send, + send, recv, file_port, file_port2, file_port_schedfix, ip_port_busy, wrap_port, wrap_port_time, with_seq_trace, dead_suspend, local_trace, saved_patterns, tracer_exit_on_stop, @@ -262,6 +262,117 @@ send_test_rcv(Pid, Msg, S, TraceEvent) -> ct:fail({got_unexpected_message, Else}) end. +recv(Config) when is_list(Config) -> + {ok, _} = start(), + Node = start_slave(), + rpc:call(Node, code, add_patha, + [filename:join(proplists:get_value(data_dir, Config), "..")]), + try + Echo = fun F() -> + receive {From, M} -> + From ! M, + F() + end + end, + Rcvr = spawn_link(Echo), + RemoteRcvr = spawn_link(Node, Echo), + + {ok, [{matched, _, 1}]} = dbg:p(Rcvr, 'receive'), + + recv_test(Rcvr, make_ref(), true), + + %% Test that the test case process is the sending process + recv_test(Rcvr, [{[node(), self(), '_'],[],[]}]), + + %% Test that self() is the not sending process + {ok, [{matched, _node, 1}, {saved, 2}]} = + dbg:tpe('receive', [{[node(), '$1','_'],[{'==','$1',{self}}],[]}]), + recv_test(Rcvr, make_ref(), false), + + %% Test that self() is the receiving process + recv_test(Rcvr, [{'_',[{'==',Rcvr,{self}}],[]}]), + + %% Test attaching a message + recv_test(Rcvr, [{'_',[{'==',Rcvr,{self}}],[{message, hello}]}], + make_ref(), hello), + + %% Test using a saved trace pattern + recv_test(Rcvr, 2, make_ref(), false), + + %% Test clearing of trace pattern + {ok, [{matched, _node, 1}]} = dbg:ctpe('receive'), + recv_test(Rcvr, make_ref(), true), + + %% Test complex message inspection + Ref = make_ref(), + recv_test(Rcvr, + [{[node(), '_','$2'],[{'==',Ref,{element,1, + {element,2, + {element,2,'$2'}}}}],[]}], + {test, {Ref}, <<0:(8*1024)>>}, true), + + recv_test(Rcvr, {test, {make_ref()}, <<0:(8*1024)>>}, false), + + %% Test recv to remote process + remote_recv_test(RemoteRcvr, Rcvr, [], make_ref(), true), + + remote_recv_test(RemoteRcvr, Rcvr, + [{['$1',undefined,'_'],[{'==','$1',{node}}],[]}], + make_ref(), false), + + remote_recv_test(RemoteRcvr, Rcvr, + [{['$1',undefined,'_'],[{'==','$1',Node}],[]}], + make_ref(), true), + + %% Test that distributed dbg works + dbg:tracer(Node, process, {fun myhandler/2, self()}), + Rcvr2 = spawn_link(Echo), + RemoteRcvr2 = spawn_link(Node, Echo), + dbg:p(Rcvr2, ['receive']), + dbg:p(RemoteRcvr2, ['receive']), + dbg:tpe('receive', [{[node(), '_', '$1'],[{'==',{element,2,'$1'}, hej}],[]}]), + + recv_test(Rcvr2, make_ref(), false), + recv_test(RemoteRcvr2, make_ref(), false), + recv_test(Rcvr2, hej, true), + recv_test(RemoteRcvr2, hej, true), + + ok + + after + stop() + end. + +recv_test(Pid, Pattern, Msg, TraceEvent) -> + {ok, [{matched, _, _}, _]} = dbg:tpe('receive', Pattern), + recv_test(Pid, Msg, TraceEvent). +recv_test(Pid, Pattern) -> + recv_test(Pid, Pattern, make_ref(), true). +recv_test(Pid, Msg, TraceEvent) -> + S = self(), + Pid ! {S, Msg}, + receive Msg -> ok end, + recv_test_rcv(Pid, {S, Msg}, TraceEvent). + +remote_recv_test(RPid, Pid, Pattern, Msg, TraceEvent) -> + dbg:tpe('receive', Pattern), + TMsg = {self(), Msg}, + RPid ! {Pid, TMsg}, + receive Msg -> ok end, + recv_test_rcv(Pid, TMsg, TraceEvent). + +recv_test_rcv(Pid, Msg, TraceEvent) -> + case flush() of + [] when not TraceEvent -> + ok; + [{trace, Pid, 'receive', Msg}] when TraceEvent -> + ok; + [{trace, Pid, 'receive', Msg, Message}] when TraceEvent == Message -> + ok; + Else -> + ct:fail({got_unexpected_message, Else}) + end. + %% Simple test of distributed tracing distributed(Config) when is_list(Config) -> {ok, _} = start(), -- cgit v1.2.3 From d38d8a4cafe04d7ad63a4d0b168a25eb5e887440 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 4 May 2016 15:58:52 +0200 Subject: Change dbg:ctpe to go back to default i.e enable all send/receive trace. --- lib/runtime_tools/src/dbg.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime_tools/src/dbg.erl b/lib/runtime_tools/src/dbg.erl index b29bc42a8e..1620f52789 100644 --- a/lib/runtime_tools/src/dbg.erl +++ b/lib/runtime_tools/src/dbg.erl @@ -226,7 +226,7 @@ do_ctp({_Module, _Function, _Arity}=MFA,Flags) -> ctpe(Event) when Event =:= send; Event =:= 'receive' -> Nodes = req(get_nodes), - {ok,do_tp_on_nodes(Nodes,Event,false,[])}. + {ok,do_tp_on_nodes(Nodes,Event,true,[])}. %% %% ltp() -> ok -- cgit v1.2.3