aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator')
-rw-r--r--erts/emulator/beam/atom.names7
-rw-r--r--erts/emulator/beam/erl_trace.c65
-rw-r--r--erts/emulator/beam/io.c59
-rw-r--r--erts/emulator/hipe/hipe_bif0.c10
-rw-r--r--erts/emulator/hipe/hipe_x86.c4
-rw-r--r--erts/emulator/nifs/common/erl_tracer_nif.c34
-rw-r--r--erts/emulator/test/distribution_SUITE.erl69
-rw-r--r--erts/emulator/test/tracer_SUITE.erl103
-rw-r--r--erts/emulator/test/tracer_SUITE_data/tracer_test.c4
-rw-r--r--erts/emulator/test/tracer_test.erl4
10 files changed, 249 insertions, 110 deletions
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index 464058535a..badd69856e 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -228,9 +228,6 @@ atom endian
atom env
atom eof
atom eol
-atom exception_from
-atom exception_trace
-atom extended
atom Eq='=:='
atom Eqeq='=='
atom erl_tracer
@@ -243,6 +240,8 @@ atom ets
atom ETS_TRANSFER='ETS-TRANSFER'
atom event
atom exact_reductions
+atom exception_from
+atom exception_trace
atom exclusive
atom exit_status
atom existing
@@ -251,7 +250,9 @@ atom existing_ports
atom existing
atom exiting
atom exports
+atom extended
atom external
+atom extra
atom false
atom fcgi
atom fd
diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c
index ca001fc156..3dca58d60b 100644
--- a/erts/emulator/beam/erl_trace.c
+++ b/erts/emulator/beam/erl_trace.c
@@ -2625,7 +2625,7 @@ static void init_tracer_template(ErtsTracerNif *tnif) {
/* default tracer functions */
tnif->tracers[TRACE_FUN_DEFAULT].name = "trace";
- tnif->tracers[TRACE_FUN_DEFAULT].arity = 6;
+ tnif->tracers[TRACE_FUN_DEFAULT].arity = 5;
tnif->tracers[TRACE_FUN_DEFAULT].cb = NULL;
tnif->tracers[TRACE_FUN_ENABLED].name = "enabled";
@@ -2634,35 +2634,35 @@ static void init_tracer_template(ErtsTracerNif *tnif) {
/* specific tracer functions */
tnif->tracers[TRACE_FUN_T_SEND].name = "trace_send";
- tnif->tracers[TRACE_FUN_T_SEND].arity = 6;
+ tnif->tracers[TRACE_FUN_T_SEND].arity = 5;
tnif->tracers[TRACE_FUN_T_SEND].cb = NULL;
tnif->tracers[TRACE_FUN_T_RECEIVE].name = "trace_receive";
- tnif->tracers[TRACE_FUN_T_RECEIVE].arity = 6;
+ tnif->tracers[TRACE_FUN_T_RECEIVE].arity = 5;
tnif->tracers[TRACE_FUN_T_RECEIVE].cb = NULL;
tnif->tracers[TRACE_FUN_T_CALL].name = "trace_call";
- tnif->tracers[TRACE_FUN_T_CALL].arity = 6;
+ tnif->tracers[TRACE_FUN_T_CALL].arity = 5;
tnif->tracers[TRACE_FUN_T_CALL].cb = NULL;
tnif->tracers[TRACE_FUN_T_SCHED_PROC].name = "trace_running_procs";
- tnif->tracers[TRACE_FUN_T_SCHED_PROC].arity = 6;
+ tnif->tracers[TRACE_FUN_T_SCHED_PROC].arity = 5;
tnif->tracers[TRACE_FUN_T_SCHED_PROC].cb = NULL;
tnif->tracers[TRACE_FUN_T_SCHED_PORT].name = "trace_running_ports";
- tnif->tracers[TRACE_FUN_T_SCHED_PORT].arity = 6;
+ tnif->tracers[TRACE_FUN_T_SCHED_PORT].arity = 5;
tnif->tracers[TRACE_FUN_T_SCHED_PORT].cb = NULL;
tnif->tracers[TRACE_FUN_T_GC].name = "trace_garbage_collection";
- tnif->tracers[TRACE_FUN_T_GC].arity = 6;
+ tnif->tracers[TRACE_FUN_T_GC].arity = 5;
tnif->tracers[TRACE_FUN_T_GC].cb = NULL;
tnif->tracers[TRACE_FUN_T_PROCS].name = "trace_procs";
- tnif->tracers[TRACE_FUN_T_PROCS].arity = 6;
+ tnif->tracers[TRACE_FUN_T_PROCS].arity = 5;
tnif->tracers[TRACE_FUN_T_PROCS].cb = NULL;
tnif->tracers[TRACE_FUN_T_PORTS].name = "trace_ports";
- tnif->tracers[TRACE_FUN_T_PORTS].arity = 6;
+ tnif->tracers[TRACE_FUN_T_PORTS].arity = 5;
tnif->tracers[TRACE_FUN_T_PORTS].cb = NULL;
/* specific enabled functions */
@@ -2834,10 +2834,12 @@ send_to_tracer_nif_raw(Process *c_p, Process *tracee,
Eterm tag, Eterm msg, Eterm extra, Eterm pam_result)
{
if (tnif || (tnif = lookup_tracer_nif(tracer)) != NULL) {
-#define MAP_SIZE 3
- Eterm argv[6], local_heap[3+MAP_SIZE /* values */ + (MAP_SIZE+1 /* keys */)];
+#define MAP_SIZE 4
+ Eterm argv[5], local_heap[3+MAP_SIZE /* values */ + (MAP_SIZE+1 /* keys */)];
flatmap_t *map = (flatmap_t*)(local_heap+(MAP_SIZE+1));
Eterm *map_values = flatmap_get_values(map);
+ Eterm *map_keys = local_heap + 1;
+ Uint map_elem_count = 0;
topt = (tnif->tracers[topt].cb) ? topt : TRACE_FUN_DEFAULT;
ASSERT(topt < NIF_TRACER_TYPES);
@@ -2846,31 +2848,40 @@ send_to_tracer_nif_raw(Process *c_p, Process *tracee,
argv[1] = ERTS_TRACER_STATE(tracer);
argv[2] = t_p_id;
argv[3] = msg;
- argv[4] = extra == THE_NON_VALUE ? am_undefined : extra;
- argv[5] = make_flatmap(map);
+ argv[4] = make_flatmap(map);
map->thing_word = MAP_HEADER_FLATMAP;
- map->size = MAP_SIZE;
- map->keys = TUPLE3(local_heap, am_match_spec_result, am_scheduler_id, am_timestamp);
-
- *map_values++ = pam_result;
- if (tracee_flags & F_TRACE_SCHED_NO)
- *map_values++ = make_small(erts_get_scheduler_id());
- else
- *map_values++ = am_undefined;
+
+ if (extra != THE_NON_VALUE) {
+ map_keys[map_elem_count] = am_extra;
+ map_values[map_elem_count++] = extra;
+ }
+
+ if (pam_result != am_true) {
+ map_keys[map_elem_count] = am_match_spec_result;
+ map_values[map_elem_count++] = pam_result;
+ }
+
+ if (tracee_flags & F_TRACE_SCHED_NO) {
+ map_keys[map_elem_count] = am_scheduler_id;
+ map_values[map_elem_count++] = make_small(erts_get_scheduler_id());
+ }
+ map_keys[map_elem_count] = am_timestamp;
if (tracee_flags & F_NOW_TS)
#ifdef HAVE_ERTS_NOW_CPU
if (erts_cpu_timestamp)
- *map_values++ = am_cpu_timestamp;
+ map_values[map_elem_count++] = am_cpu_timestamp;
else
#endif
- *map_values++ = am_timestamp;
+ map_values[map_elem_count++] = am_timestamp;
else if (tracee_flags & F_STRICT_MON_TS)
- *map_values++ = am_strict_monotonic;
+ map_values[map_elem_count++] = am_strict_monotonic;
else if (tracee_flags & F_MON_TS)
- *map_values++ = am_monotonic;
- else
- *map_values++ = am_undefined;
+ map_values[map_elem_count++] = am_monotonic;
+
+ map->size = map_elem_count;
+ map->keys = make_tuple(local_heap);
+ local_heap[0] = make_arityval(map_elem_count);
#undef MAP_SIZE
erts_nif_call_function(c_p, tracee ? tracee : c_p,
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index 0377f6cb5e..01df5476db 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -938,18 +938,32 @@ int erts_port_handle_xports(Port *prt)
** -2 on type error
*/
-#define SET_VEC(iov, bv, bin, ptr, len, vlen) do { \
- (iov)->iov_base = (ptr); \
- (iov)->iov_len = (len); \
- if (sizeof((iov)->iov_len) < sizeof(len) \
- /* Check if (len) overflowed (iov)->iov_len */ \
- && (iov)->iov_len != (len)) { \
- goto L_overflow; \
- } \
- *(bv)++ = (bin); \
- (iov)++; \
- (vlen)++; \
-} while(0)
+#ifdef DEBUG
+#define MAX_SYSIOVEC_IOVLEN (1ull << (32 - 1))
+#else
+#define MAX_SYSIOVEC_IOVLEN (1ull << (sizeof(((SysIOVec*)0)->iov_len) * 8 - 1))
+#endif
+
+static ERTS_INLINE void
+io_list_to_vec_set_vec(SysIOVec **iov, ErlDrvBinary ***binv,
+ ErlDrvBinary *bin, byte *ptr, Uint len,
+ int *vlen)
+{
+ while (len > MAX_SYSIOVEC_IOVLEN) {
+ (*iov)->iov_base = ptr;
+ (*iov)->iov_len = MAX_SYSIOVEC_IOVLEN;
+ ptr += MAX_SYSIOVEC_IOVLEN;
+ len -= MAX_SYSIOVEC_IOVLEN;
+ (*iov)++;
+ (*vlen)++;
+ *(*binv)++ = bin;
+ }
+ (*iov)->iov_base = ptr;
+ (*iov)->iov_len = len;
+ *(*binv)++ = bin;
+ (*iov)++;
+ (*vlen)++;
+}
static int
io_list_to_vec(Eterm obj, /* io-list */
@@ -960,11 +974,11 @@ io_list_to_vec(Eterm obj, /* io-list */
{
DECLARE_ESTACK(s);
Eterm* objp;
- char *buf = cbin->orig_bytes;
+ byte *buf = (byte*)cbin->orig_bytes;
Uint len = cbin->orig_size;
Uint csize = 0;
int vlen = 0;
- char* cptr = buf;
+ byte* cptr = buf;
goto L_jump_start; /* avoid push */
@@ -1032,15 +1046,17 @@ io_list_to_vec(Eterm obj, /* io-list */
len -= size;
} else {
if (csize != 0) {
- SET_VEC(iov, binv, cbin, cptr, csize, vlen);
+ io_list_to_vec_set_vec(&iov, &binv, cbin,
+ cptr, csize, &vlen);
cptr = buf;
csize = 0;
}
if (pb->flags) {
erts_emasculate_writable_binary(pb);
}
- SET_VEC(iov, binv, Binary2ErlDrvBinary(pb->val),
- pb->bytes+offset, size, vlen);
+ io_list_to_vec_set_vec(
+ &iov, &binv, Binary2ErlDrvBinary(pb->val),
+ pb->bytes+offset, size, &vlen);
}
} else {
ErlHeapBin* hb = (ErlHeapBin *) bptr;
@@ -1060,7 +1076,7 @@ io_list_to_vec(Eterm obj, /* io-list */
}
if (csize != 0) {
- SET_VEC(iov, binv, cbin, cptr, csize, vlen);
+ io_list_to_vec_set_vec(&iov, &binv, cbin, cptr, csize, &vlen);
}
DESTROY_ESTACK(s);
@@ -1086,10 +1102,13 @@ do { \
if (_bitsize != 0) goto L_type_error; \
if (thing_subtag(*binary_val(_real)) == REFC_BINARY_SUBTAG && \
_bitoffs == 0) { \
- b_size += _size; \
+ b_size += _size; \
if (b_size < _size) goto L_overflow_error; \
in_clist = 0; \
- v_size++; \
+ v_size++; \
+ /* If iov_len is smaller then Uint we split the binary into*/ \
+ /* multiple smaller (2GB) elements in the iolist.*/ \
+ v_size += _size / MAX_SYSIOVEC_IOVLEN; \
if (_size >= ERL_SMALL_IO_BIN_LIMIT) { \
p_in_clist = 0; \
p_v_size++; \
diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c
index 4063cbf306..58b5be3906 100644
--- a/erts/emulator/hipe/hipe_bif0.c
+++ b/erts/emulator/hipe/hipe_bif0.c
@@ -418,6 +418,8 @@ BIF_RETTYPE hipe_bifs_enter_code_2(BIF_ALIST_2)
BIF_RET(make_tuple(hp));
}
+#define IS_POWER_OF_TWO(Val) (((Val) > 0) && (((Val) & ((Val)-1)) == 0))
+
/*
* Allocate memory for arbitrary non-Erlang data.
*/
@@ -427,16 +429,18 @@ BIF_RETTYPE hipe_bifs_alloc_data_2(BIF_ALIST_2)
void *block;
if (is_not_small(BIF_ARG_1) || is_not_small(BIF_ARG_2) ||
- (align = unsigned_val(BIF_ARG_1),
- align != sizeof(long) && align != sizeof(double)))
+ (align = unsigned_val(BIF_ARG_1), !IS_POWER_OF_TWO(align)))
BIF_ERROR(BIF_P, BADARG);
nrbytes = unsigned_val(BIF_ARG_2);
if (nrbytes == 0)
BIF_RET(make_small(0));
block = erts_alloc(ERTS_ALC_T_HIPE, nrbytes);
- if ((unsigned long)block & (align-1))
+ if ((unsigned long)block & (align-1)) {
fprintf(stderr, "%s: erts_alloc(%lu) returned %p which is not %lu-byte aligned\r\n",
__FUNCTION__, (unsigned long)nrbytes, block, (unsigned long)align);
+ erts_free(ERTS_ALC_T_HIPE, block);
+ BIF_ERROR(BIF_P, EXC_NOTSUP);
+ }
BIF_RET(address_to_term(block, BIF_P));
}
diff --git a/erts/emulator/hipe/hipe_x86.c b/erts/emulator/hipe/hipe_x86.c
index 3d25646231..5f6c8c200e 100644
--- a/erts/emulator/hipe/hipe_x86.c
+++ b/erts/emulator/hipe/hipe_x86.c
@@ -37,7 +37,7 @@
void hipe_patch_load_fe(Uint32 *address, Uint32 value)
{
/* address points to a disp32 or imm32 operand */
- *address = value;
+ *address += value;
}
int hipe_patch_insn(void *address, Uint32 value, Eterm type)
@@ -54,7 +54,7 @@ int hipe_patch_insn(void *address, Uint32 value, Eterm type)
default:
return -1;
}
- *(Uint32*)address = value;
+ *(Uint32*)address += value;
return 0;
}
diff --git a/erts/emulator/nifs/common/erl_tracer_nif.c b/erts/emulator/nifs/common/erl_tracer_nif.c
index 6dddc80607..c0cc48ff42 100644
--- a/erts/emulator/nifs/common/erl_tracer_nif.c
+++ b/erts/emulator/nifs/common/erl_tracer_nif.c
@@ -45,7 +45,7 @@ static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ErlNifFunc nif_funcs[] = {
{"enabled", 3, enabled},
- {"trace", 6, trace}
+ {"trace", 5, trace}
};
@@ -57,6 +57,7 @@ ERL_NIF_INIT(erl_tracer, nif_funcs, load, NULL, upgrade, unload)
ATOM_DECL(cpu_timestamp); \
ATOM_DECL(discard); \
ATOM_DECL(exception_from); \
+ ATOM_DECL(extra); \
ATOM_DECL(match_spec_result); \
ATOM_DECL(monotonic); \
ATOM_DECL(ok); \
@@ -76,8 +77,7 @@ ERL_NIF_INIT(erl_tracer, nif_funcs, load, NULL, upgrade, unload)
ATOM_DECL(gc_minor_start); \
ATOM_DECL(gc_minor_end); \
ATOM_DECL(gc_major_start); \
- ATOM_DECL(gc_major_end); \
- ATOM_DECL(undefined);
+ ATOM_DECL(gc_major_end);
#define ATOM_DECL(A) static ERL_NIF_TERM atom_##A
ATOMS
@@ -154,11 +154,6 @@ static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
Tracee :: pid() || port() || undefined,
Msg :: term(),
Opts :: map()) -> ignored().
- -spec trace(Tag :: atom(), TracerState :: pid() | port(),
- Tracee :: pid() || port() || undefined,
- Msg :: term(),
- Extra :: term(),
- Opts :: map()) -> ignored().
*/
static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
@@ -167,7 +162,8 @@ static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ErlNifPort to_port;
size_t tt_sz = 0;
int is_port = 0;
- ASSERT(argc == 6);
+ size_t opts_sz = 0;
+ ASSERT(argc == 5);
if (!enif_get_local_pid(env, argv[1], &to_pid)) {
if (!enif_get_local_port(env, argv[1], &to_port)) {
@@ -179,12 +175,17 @@ static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
is_port = 1;
}
- if (!enif_is_identical(argv[4], atom_undefined)) {
+ opts = argv[4];
+
+ if (!enif_get_map_size(env, opts, &opts_sz))
+ opts_sz = 0;
+
+ if (opts_sz && enif_get_map_value(env, opts, atom_extra, &value)) {
tt[tt_sz++] = atom_trace;
tt[tt_sz++] = argv[2];
tt[tt_sz++] = argv[0];
tt[tt_sz++] = argv[3];
- tt[tt_sz++] = argv[4];
+ tt[tt_sz++] = value;
} else {
if (enif_is_identical(argv[0], atom_seq_trace)) {
tt[tt_sz++] = atom_seq_trace;
@@ -198,21 +199,16 @@ static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
}
}
- opts = argv[5];
- if (enif_get_map_value(env, opts, atom_match_spec_result,
- &value)
- && !enif_is_identical(value, atom_true)) {
+ if (opts_sz && enif_get_map_value(env, opts, atom_match_spec_result, &value)) {
tt[tt_sz++] = value;
}
- if (enif_get_map_value(env, opts, atom_scheduler_id, &value)
- && !enif_is_identical(value, atom_undefined)) {
+ if (opts_sz && enif_get_map_value(env, opts, atom_scheduler_id, &value)) {
tt[tt_sz++] = value;
}
- if (enif_get_map_value(env, opts, atom_timestamp, &value)
- && !enif_is_identical(value, atom_undefined)) {
+ if (opts_sz && enif_get_map_value(env, opts, atom_timestamp, &value)) {
ERL_NIF_TERM ts;
if (enif_is_identical(value, atom_monotonic)) {
ErlNifTime mon = enif_monotonic_time(ERL_NIF_NSEC);
diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl
index d0096fb1bc..26780f6017 100644
--- a/erts/emulator/test/distribution_SUITE.erl
+++ b/erts/emulator/test/distribution_SUITE.erl
@@ -55,7 +55,8 @@
bad_dist_ext_receive/1,
bad_dist_ext_process_info/1,
bad_dist_ext_control/1,
- bad_dist_ext_connection_id/1]).
+ bad_dist_ext_connection_id/1,
+ start_epmd_false/1, epmd_module/1]).
%% Internal exports.
-export([sender/3, receiver2/2, dummy_waiter/0, dead_process/0,
@@ -64,6 +65,9 @@
dist_evil_parallel_receiver/0,
sendersender/4, sendersender2/4]).
+%% epmd_module exports
+-export([start_link/0, register_node/2, port_please/2]).
+
suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap, {minutes, 4}}].
@@ -76,7 +80,8 @@ all() ->
{group, trap_bif}, {group, dist_auto_connect},
dist_parallel_send, atom_roundtrip, unicode_atom_roundtrip, atom_roundtrip_r15b,
contended_atom_cache_entry, contended_unicode_atom_cache_entry,
- bad_dist_structure, {group, bad_dist_ext}].
+ bad_dist_structure, {group, bad_dist_ext},
+ start_epmd_false, epmd_module].
groups() ->
[{bulk_send, [], [bulk_send_small, bulk_send_big, bulk_send_bigbig]},
@@ -1881,6 +1886,66 @@ dmsg_ext(Term) ->
dmsg_bad_atom_cache_ref() ->
[$R, 137].
+start_epmd_false(Config) when is_list(Config) ->
+ %% Start a node with the option -start_epmd false.
+ {ok, OtherNode} = start_node(start_epmd_false, "-start_epmd false"),
+ %% We should be able to ping it, as epmd was started by us:
+ pong = net_adm:ping(OtherNode),
+ stop_node(OtherNode),
+
+ ok.
+
+epmd_module(Config) when is_list(Config) ->
+ %% We need a relay node to test this, since the test node uses the
+ %% standard epmd module.
+ Sock1 = start_relay_node(epmd_module_node1, "-epmd_module " ++ ?MODULE_STRING),
+ Node1 = inet_rpc_nodename(Sock1),
+ %% Ask what port it's listening on - it won't have registered with
+ %% epmd.
+ {ok, {ok, Port1}} = do_inet_rpc(Sock1, application, get_env, [kernel, dist_listen_port]),
+
+ %% Start a second node, passing the port number as a secret
+ %% argument.
+ Sock2 = start_relay_node(epmd_module_node2, "-epmd_module " ++ ?MODULE_STRING
+ ++ " -other_node_port " ++ integer_to_list(Port1)),
+ Node2 = inet_rpc_nodename(Sock2),
+ %% Node 1 can't ping node 2
+ {ok, pang} = do_inet_rpc(Sock1, net_adm, ping, [Node2]),
+ {ok, []} = do_inet_rpc(Sock1, erlang, nodes, []),
+ {ok, []} = do_inet_rpc(Sock2, erlang, nodes, []),
+ %% But node 2 can ping node 1
+ {ok, pong} = do_inet_rpc(Sock2, net_adm, ping, [Node1]),
+ {ok, [Node2]} = do_inet_rpc(Sock1, erlang, nodes, []),
+ {ok, [Node1]} = do_inet_rpc(Sock2, erlang, nodes, []),
+
+ stop_relay_node(Sock2),
+ stop_relay_node(Sock1).
+
+%% epmd_module functions:
+
+start_link() ->
+ ignore.
+
+register_node(_Name, Port) ->
+ %% Save the port number we're listening on.
+ application:set_env(kernel, dist_listen_port, Port),
+ Creation = rand:uniform(3),
+ {ok, Creation}.
+
+port_please(_Name, _Ip) ->
+ case init:get_argument(other_node_port) of
+ error ->
+ %% None specified. Default to 42.
+ Port = 42,
+ Version = 5,
+ {port, Port, Version};
+ {ok, [[PortS]]} ->
+ %% Port number given on command line.
+ Port = list_to_integer(PortS),
+ Version = 5,
+ {port, Port, Version}
+ end.
+
%%% Utilities
timestamp() ->
diff --git a/erts/emulator/test/tracer_SUITE.erl b/erts/emulator/test/tracer_SUITE.erl
index 20fb7e475e..9eb55c9af3 100644
--- a/erts/emulator/test/tracer_SUITE.erl
+++ b/erts/emulator/test/tracer_SUITE.erl
@@ -28,9 +28,9 @@
init_per_group/2,end_per_group/2, init_per_testcase/2,
end_per_testcase/2]).
-export([load/1, unload/1, reload/1, invalid_tracers/1]).
--export([send/1, recv/1, spawn/1, exit/1, link/1, unlink/1,
- getting_linked/1, getting_unlinked/1, register/1, unregister/1,
- in/1, out/1, gc_start/1, gc_end/1]).
+-export([send/1, recv/1, call/1, call_return/1, spawn/1, exit/1,
+ link/1, unlink/1, getting_linked/1, getting_unlinked/1,
+ register/1, unregister/1, in/1, out/1, gc_start/1, gc_end/1]).
suite() -> [{ct_hooks,[ts_install_cth]},
{timetrap, {minutes, 1}}].
@@ -39,9 +39,9 @@ all() ->
[load, unload, reload, invalid_tracers, {group, basic}].
groups() ->
- [{ basic, [], [send, recv, spawn, exit, link, unlink, getting_linked,
- getting_unlinked, register, unregister, in, out,
- gc_start, gc_end]}].
+ [{ basic, [], [send, recv, call, call_return, spawn, exit,
+ link, unlink, getting_linked, getting_unlinked,
+ register, unregister, in, out, gc_start, gc_end]}].
init_per_suite(Config) ->
erlang:trace_pattern({'_','_','_'}, false, [local]),
@@ -223,8 +223,8 @@ send(_Config) ->
Expect = fun(Pid, State, EOpts) ->
receive
Msg ->
- {send, State, Pid, ok, Self, Opts} = Msg,
- check_opts(EOpts, Opts)
+ {send, State, Pid, ok, Opts} = Msg,
+ check_opts(EOpts, Opts, Self)
end
end,
test(send, Tc, Expect).
@@ -239,13 +239,59 @@ recv(_Config) ->
Expect = fun(Pid, State, EOpts) ->
receive
Msg ->
- {'receive', State, Pid, ok, undefined, Opts} = Msg,
+ {'receive', State, Pid, ok, Opts} = Msg,
check_opts(EOpts, Opts)
end
end,
test('receive', Tc, Expect, false).
+call(_Config) ->
+
+ Self = self(),
+ Tc = fun(Pid) ->
+ Pid ! fun() -> call_test(Self), Self ! ok end,
+ receive ok -> ok after 100 -> ct:fail(timeout) end
+ end,
+
+ erlang:trace_pattern({?MODULE, call_test, 1}, [], [local]),
+
+ Expect = fun(Pid, State, EOpts) ->
+ receive
+ Msg ->
+ {call, State, Pid, {?MODULE, call_test, [Self]}, Opts} = Msg,
+ check_opts(EOpts, Opts)
+ end
+ end,
+ test(call, Tc, Expect).
+
+call_return(_Config) ->
+
+ Self = self(),
+ Tc = fun(Pid) ->
+ Pid ! fun() -> call_test(undefined), Self ! ok end,
+ receive ok -> ok after 100 -> ct:fail(timeout) end
+ end,
+
+ 1 = erlang:trace_pattern({?MODULE, call_test, 1}, [{'_',[],[{return_trace}]}], [local]),
+
+ Expect = fun(Pid, State, EOpts) ->
+ receive
+ CallMsg ->
+ {call, State, Pid, {?MODULE, call_test, [undefined]}, COpts} = CallMsg,
+ check_opts(EOpts, COpts)
+ end,
+ receive
+ RetMsg ->
+ {return_from, State, Pid, {?MODULE, call_test, 1}, ROpts} = RetMsg,
+ check_opts(EOpts, ROpts, undefined)
+ end
+ end,
+ test(call, Tc, Expect).
+
+call_test(Arg) ->
+ Arg.
+
spawn(_Config) ->
Tc = fun(Pid) ->
@@ -256,9 +302,8 @@ spawn(_Config) ->
fun(Pid, State, EOpts) ->
receive
Msg ->
- {spawn, State, Pid, NewPid,
- {lists,seq,[1,10]}, Opts} = Msg,
- check_opts(EOpts, Opts),
+ {spawn, State, Pid, NewPid, Opts} = Msg,
+ check_opts(EOpts, Opts, {lists,seq,[1,10]}),
true = is_pid(NewPid) andalso NewPid /= Pid
end
end,
@@ -274,7 +319,7 @@ exit(_Config) ->
fun(Pid, State, EOpts) ->
receive
Msg ->
- {exit, State, Pid, normal, undefined, Opts} = Msg,
+ {exit, State, Pid, normal, Opts} = Msg,
check_opts(EOpts, Opts)
end
end,
@@ -295,7 +340,7 @@ link(_Config) ->
fun(Pid, State, EOpts) ->
receive
Msg ->
- {link, State, Pid, NewPid, undefined, Opts} = Msg,
+ {link, State, Pid, NewPid, Opts} = Msg,
check_opts(EOpts, Opts),
true = is_pid(NewPid) andalso NewPid /= Pid
end
@@ -318,7 +363,7 @@ unlink(_Config) ->
fun(Pid, State, EOpts) ->
receive
Msg ->
- {unlink, State, Pid, NewPid, undefined, Opts} = Msg,
+ {unlink, State, Pid, NewPid, Opts} = Msg,
check_opts(EOpts, Opts),
true = is_pid(NewPid) andalso NewPid /= Pid
end
@@ -340,7 +385,7 @@ getting_linked(_Config) ->
fun(Pid, State, EOpts) ->
receive
Msg ->
- {getting_linked, State, Pid, NewPid, undefined, Opts} = Msg,
+ {getting_linked, State, Pid, NewPid, Opts} = Msg,
check_opts(EOpts, Opts),
true = is_pid(NewPid) andalso NewPid /= Pid
end
@@ -364,7 +409,7 @@ getting_unlinked(_Config) ->
fun(Pid, State, EOpts) ->
receive
Msg ->
- {getting_unlinked, State, Pid, NewPid, undefined, Opts} = Msg,
+ {getting_unlinked, State, Pid, NewPid, Opts} = Msg,
check_opts(EOpts, Opts),
true = is_pid(NewPid) andalso NewPid /= Pid
end
@@ -386,7 +431,7 @@ register(_Config) ->
fun(Pid, State, EOpts) ->
receive
Msg ->
- {register, State, Pid, ?MODULE, undefined, Opts} = Msg,
+ {register, State, Pid, ?MODULE, Opts} = Msg,
check_opts(EOpts, Opts)
end
end,
@@ -407,7 +452,7 @@ unregister(_Config) ->
fun(Pid, State, EOpts) ->
receive
Msg ->
- {unregister, State, Pid, ?MODULE, undefined, Opts} = Msg,
+ {unregister, State, Pid, ?MODULE, Opts} = Msg,
check_opts(EOpts, Opts)
end
end,
@@ -427,8 +472,7 @@ in(_Config) ->
N = (fun F(N) ->
receive
Msg ->
- {in, State, Pid, _,
- undefined, Opts} = Msg,
+ {in, State, Pid, _, Opts} = Msg,
check_opts(EOpts, Opts),
F(N+1)
after 0 -> N
@@ -452,8 +496,7 @@ out(_Config) ->
N = (fun F(N) ->
receive
Msg ->
- {out, State, Pid, _,
- undefined, Opts} = Msg,
+ {out, State, Pid, _, Opts} = Msg,
check_opts(EOpts, Opts),
F(N+1)
after 0 -> N
@@ -477,7 +520,7 @@ gc_start(_Config) ->
fun(Pid, State, EOpts) ->
receive
Msg ->
- {gc_major_start, State, Pid, _, undefined, Opts} = Msg,
+ {gc_major_start, State, Pid, _, Opts} = Msg,
check_opts(EOpts, Opts)
end
end,
@@ -497,7 +540,7 @@ gc_end(_Config) ->
fun(Pid, State, EOpts) ->
receive
Msg ->
- {gc_major_end, State, Pid, _, undefined, Opts} = Msg,
+ {gc_major_end, State, Pid, _, Opts} = Msg,
check_opts(EOpts, Opts)
end
end,
@@ -513,9 +556,7 @@ test(Event, TraceFlag, Tc, Expect, Removes) ->
test(Event, TraceFlag, Tc, Expect, _Removes, Dies) ->
ComplexState = {fun() -> ok end, <<0:(128*8)>>},
- Opts = #{ timestamp => undefined,
- scheduler_id => undefined,
- match_spec_result => true },
+ Opts = #{ },
%% Test that trace works
State1 = {#{ Event => trace }, self(), ComplexState},
@@ -540,8 +581,8 @@ test(Event, TraceFlag, Tc, Expect, _Removes, Dies) ->
Tc(Pid1T),
ok = trace_delivered(Pid1T),
- Expect(Pid1T, State1, Opts#{ scheduler_id := number,
- timestamp := timestamp}),
+ Expect(Pid1T, State1, Opts#{ scheduler_id => number,
+ timestamp => timestamp}),
receive M11T -> ct:fail({unexpected, M11T}) after 0 -> ok end,
if not Dies ->
{flags, [scheduler_id, TraceFlag, timestamp]}
@@ -568,6 +609,8 @@ test(Event, TraceFlag, Tc, Expect, _Removes, Dies) ->
ok.
+check_opts(E, O, Extra) ->
+ check_opts(E#{ extra => Extra }, O).
check_opts(#{ scheduler_id := number } = E, #{ scheduler_id := N } = O)
when is_integer(N) ->
E1 = maps:remove(scheduler_id, E),
diff --git a/erts/emulator/test/tracer_SUITE_data/tracer_test.c b/erts/emulator/test/tracer_SUITE_data/tracer_test.c
index 908f35da9c..a26bb33600 100644
--- a/erts/emulator/test/tracer_SUITE_data/tracer_test.c
+++ b/erts/emulator/test/tracer_SUITE_data/tracer_test.c
@@ -36,7 +36,7 @@ static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ErlNifFunc nif_funcs[] = {
{"enabled", 3, enabled},
- {"trace", 6, trace}
+ {"trace", 5, trace}
};
ERL_NIF_INIT(tracer_test, nif_funcs, load, NULL, upgrade, unload)
@@ -100,7 +100,7 @@ static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ErlNifPid self, to;
ERL_NIF_TERM *tuple, msg;
const ERL_NIF_TERM *state_tuple;
- ASSERT(argc == 6);
+ ASSERT(argc == 5);
enif_get_tuple(env, argv[1], &state_arity, &state_tuple);
diff --git a/erts/emulator/test/tracer_test.erl b/erts/emulator/test/tracer_test.erl
index d4778f4531..1da80bfe31 100644
--- a/erts/emulator/test/tracer_test.erl
+++ b/erts/emulator/test/tracer_test.erl
@@ -24,14 +24,14 @@
%%% Test tracer
%%%
--export([enabled/3, trace/6]).
+-export([enabled/3, trace/5]).
-export([load/1, load/2]).
-on_load(load/0).
enabled(_, _, _) ->
erlang:nif_error(nif_not_loaded).
-trace(_, _, _, _, _, _) ->
+trace(_, _, _, _, _) ->
erlang:nif_error(nif_not_loaded).
load() ->