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 Item s are valid:
+ The following Item s 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 Item s 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 Item s 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