aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/doc/src/erl.xml18
-rw-r--r--erts/doc/src/erl_tracer.xml96
-rw-r--r--erts/doc/src/init.xml5
-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
-rw-r--r--erts/etc/common/erlexec.c21
-rw-r--r--erts/preloaded/ebin/erl_tracer.beambin2112 -> 2200 bytes
-rw-r--r--erts/preloaded/src/erl_tracer.erl14
16 files changed, 344 insertions, 169 deletions
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
index 2fae3bfb1f..5d5bfb141f 100644
--- a/erts/doc/src/erl.xml
+++ b/erts/doc/src/erl.xml
@@ -338,7 +338,8 @@
<seealso marker="kernel:net_kernel">net_kernel(3)</seealso>.
It is also ensured that <c><![CDATA[epmd]]></c> runs on the current host
before Erlang is started. See
- <seealso marker="epmd">epmd(1)</seealso>.</p>
+ <seealso marker="epmd">epmd(1)</seealso> and the
+ <seealso marker="#start_epmd"><c>-start_epmd</c></seealso> option.</p>
<p>The name of the node will be <c><![CDATA[Name@Host]]></c>, where
<c><![CDATA[Host]]></c> is the fully qualified host name of the current
host. For short names, use the <c><![CDATA[-sname]]></c> flag instead.</p>
@@ -463,6 +464,21 @@
flag and those running with the <c><![CDATA[-name]]></c> flag, as node
names must be unique in distributed Erlang systems.</p>
</item>
+ <tag><marker id="start_epmd"/><c>-start_epmd true | false</c></tag>
+ <item>
+
+ <p>Specifies whether Erlang should start
+ <seealso marker="epmd">epmd</seealso> on startup. By default
+ this is <c>true</c>, but if you prefer to start epmd
+ manually, set this to <c>false</c>.</p>
+
+ <p>This only applies if Erlang is started as a distributed node,
+ i.e. if <c>-name</c> or <c>-sname</c> is specified. Otherwise,
+ epmd is not started even if <c>-start_epmd true</c> is given.</p>
+
+ <p>Note that a distributed node will fail to start if epmd is
+ not running.</p>
+ </item>
<tag><marker id="smp"/><c><![CDATA[-smp [enable|auto|disable]]]></c></tag>
<item>
<p><c>-smp enable</c> and <c>-smp</c> starts the Erlang runtime
diff --git a/erts/doc/src/erl_tracer.xml b/erts/doc/src/erl_tracer.xml
index d4c8bbad31..7841fdfd63 100644
--- a/erts/doc/src/erl_tracer.xml
+++ b/erts/doc/src/erl_tracer.xml
@@ -67,7 +67,7 @@
<desc>
<p>The different trace tags that the tracer will be called with.
Each trace tag is described in greater detail in
- <seealso marker="#Module:trace/6">Module:trace/6</seealso>
+ <seealso marker="#Module:trace/5">Module:trace/5</seealso>
</p>
</desc>
</datatype>
@@ -84,14 +84,18 @@
<p>The options for the tracee.</p>
<taglist>
<tag><c>timestamp</c></tag>
- <item>If not set to <c>undefined</c>, the tracer has been requested to
- include a timestamp.</item>
+ <item>If set the tracer has been requested to include a timestamp.</item>
+ <tag><c>extra</c></tag>
+ <item>If set the tracepoint has included additonal data about
+ the trace event. What the additional data is depends on which
+ <c>TraceTag</c> has been triggered. The <c>extra</c> trace data
+ corresponds to the fifth elemnt in the trace tuples described in
+ <seealso marker="erlang#trace_3_trace_messages">erlang:trace/3</seealso>.</item>
<tag><c>match_spec_result</c></tag>
- <item>If not set to <c>true</c>, the tracer has been requested to
- include the output of a match specification that was run.</item>
+ <item>If set the tracer has been requested to include the output
+ of a match specification that was run.</item>
<tag><c>scheduler_id</c></tag>
- <item>Set to a number if the scheduler id is to be included by the tracer.
- Otherwise it is set to <c>undefined</c>.</item>
+ <item>Set the scheduler id is to be included by the tracer.</item>
</taglist>
</desc>
</datatype>
@@ -115,23 +119,23 @@
<taglist>
<tag><seealso marker="#Module:enabled/3"><c>Module:enabled/3</c></seealso></tag>
<item>Mandatory</item>
- <tag><seealso marker="#Module:trace/6"><c>Module:trace/6</c></seealso></tag>
+ <tag><seealso marker="#Module:trace/5"><c>Module:trace/5</c></seealso></tag>
<item>Mandatory</item>
<tag><seealso marker="#Module:enabled_procs/3"><c>Module:enabled_procs/3</c></seealso></tag>
<item>Optional</item>
- <tag><seealso marker="#Module:trace_procs/6"><c>Module:trace_procs/6</c></seealso></tag>
+ <tag><seealso marker="#Module:trace_procs/5"><c>Module:trace_procs/5</c></seealso></tag>
<item>Optional</item>
<tag><seealso marker="#Module:enabled_ports/3"><c>Module:enabled_ports/3</c></seealso></tag>
<item>Optional</item>
- <tag><seealso marker="#Module:trace_ports/6"><c>Module:trace_ports/6</c></seealso></tag>
+ <tag><seealso marker="#Module:trace_ports/5"><c>Module:trace_ports/5</c></seealso></tag>
<item>Optional</item>
<tag><seealso marker="#Module:enabled_running_ports/3"><c>Module:enabled_running_ports/3</c></seealso></tag>
<item>Optional</item>
- <tag><seealso marker="#Module:trace_running_ports/6"><c>Module:trace_running_ports/6</c></seealso></tag>
+ <tag><seealso marker="#Module:trace_running_ports/5"><c>Module:trace_running_ports/5</c></seealso></tag>
<item>Optional</item>
<tag><seealso marker="#Module:enabled_running_procs/3"><c>Module:enabled_running_procs/3</c></seealso></tag>
<item>Optional</item>
- <tag><seealso marker="#Module:trace_running_procs/6"><c>Module:trace_running_procs/6</c></seealso></tag>
+ <tag><seealso marker="#Module:trace_running_procs/5"><c>Module:trace_running_procs/5</c></seealso></tag>
<item>Optional</item>
</taglist>
@@ -166,14 +170,13 @@
</desc>
</func>
<func>
- <name>Module:trace(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <name>Module:trace(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
<type>
<v>TraceTag = <seealso marker="#type-trace_tag">trace_tag()</seealso></v>
<v>TracerState = term()</v>
<v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
<v>FirstTraceTerm = term()</v>
- <v>SecondTraceTerm = term() | undefined</v>
<v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
<v>Result = ok</v>
</type>
@@ -182,17 +185,17 @@
the <seealso marker="#Module:enabled/3">Module:enabled/3</seealso>
callback returned <c>trace</c>. In it any side effects needed by
the tracer should be done. The tracepoint payload is located in
- the <c>FirstTraceTerm</c> and <c>SecondTraceTerm</c>. The content
- of the TraceTerms depends on which <c>TraceTag</c> has been triggered.
- The <c>FirstTraceTerm</c> and <c>SecondTraceTerm</c> correspond to the
- fourth and fifth slot in the trace tuples described in
+ the <c>TraceTerm</c>. The content of the TraceTerm depends on which
+ <c>TraceTag</c> has been triggered.
+ The <c>TraceTerm</c> corresponds to the
+ fourth element in the trace tuples described in
<seealso marker="erlang#trace_3_trace_messages">erlang:trace/3</seealso>.
- If the tuple only has four elements, <c>SecondTraceTerm</c> will be
- <c>undefined</c>.</p>
+ If the trace tuple has five elements, the fifth element will be sent as
+ the <c>extra</c> value in the <c>Opts</c> maps.</p>
</desc>
</func>
<func>
- <name name="trace">Module:trace(seq_trace, TracerState, Label, SeqTraceInfo, undefined, Opts) -> Result</name>
+ <name name="trace">Module:trace(seq_trace, TracerState, Label, SeqTraceInfo, Opts) -> Result</name>
<fsummary>Check if a sequence trace event should be generated.</fsummary>
<type>
<v>TracerState = term()</v>
@@ -228,14 +231,13 @@
</func>
<func>
- <name>Module:trace_procs(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <name>Module:trace_procs(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
<type>
<v>TraceTag = <seealso marker="#type-trace_tag_procs">trace_tag()</seealso></v>
<v>TracerState = term()</v>
<v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
<v>FirstTraceTerm = term()</v>
- <v>SecondTraceTerm = term() | undefined</v>
<v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
<v>Result = ok</v>
</type>
@@ -243,7 +245,7 @@
<p>This callback will be called when a tracepoint is triggered and
the <seealso marker="#Module:enabled_procs/3">Module:enabled_procs/3</seealso>
callback returned <c>trace</c>.</p>
- <p>If <c>trace_procs/6</c> is not defined <c>trace/6</c> will be called instead.</p>
+ <p>If <c>trace_procs/5</c> is not defined <c>trace/5</c> will be called instead.</p>
</desc>
</func>
@@ -265,14 +267,13 @@
</func>
<func>
- <name>Module:trace_ports(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <name>Module:trace_ports(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
<type>
<v>TraceTag = <seealso marker="#type-trace_tag_ports">trace_tag()</seealso></v>
<v>TracerState = term()</v>
<v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
<v>FirstTraceTerm = term()</v>
- <v>SecondTraceTerm = term() | undefined</v>
<v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
<v>Result = ok</v>
</type>
@@ -280,7 +281,7 @@
<p>This callback will be called when a tracepoint is triggered and
the <seealso marker="#Module:enabled_ports/3">Module:enabled_ports/3</seealso>
callback returned <c>trace</c>.</p>
- <p>If <c>trace_ports/6</c> is not defined <c>trace/6</c> will be called instead.</p>
+ <p>If <c>trace_ports/5</c> is not defined <c>trace/5</c> will be called instead.</p>
</desc>
</func>
@@ -302,14 +303,13 @@
</func>
<func>
- <name>Module:trace_running_procs(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <name>Module:trace_running_procs(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
<type>
<v>TraceTag = <seealso marker="#type-trace_tag_running_procs">trace_tag_running_procs()</seealso></v>
<v>TracerState = term()</v>
<v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
<v>FirstTraceTerm = term()</v>
- <v>SecondTraceTerm = term() | undefined</v>
<v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
<v>Result = ok</v>
</type>
@@ -317,7 +317,7 @@
<p>This callback will be called when a tracepoint is triggered and
the <seealso marker="#Module:enabled_running_procs/3">Module:enabled_running_procs/3</seealso>
callback returned <c>trace</c>.</p>
- <p>If <c>trace_running_procs/6</c> is not defined <c>trace/6</c> will be called instead.</p>
+ <p>If <c>trace_running_procs/5</c> is not defined <c>trace/5</c> will be called instead.</p>
</desc>
</func>
@@ -339,14 +339,13 @@
</func>
<func>
- <name>Module:trace_running_ports(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <name>Module:trace_running_ports(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
<type>
<v>TraceTag = <seealso marker="#type-trace_tag_running_ports">trace_tag_running_ports()</seealso></v>
<v>TracerState = term()</v>
<v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
<v>FirstTraceTerm = term()</v>
- <v>SecondTraceTerm = term() | undefined</v>
<v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
<v>Result = ok</v>
</type>
@@ -354,7 +353,7 @@
<p>This callback will be called when a tracepoint is triggered and
the <seealso marker="#Module:enabled_running_ports/3">Module:enabled_running_ports/3</seealso>
callback returned <c>trace</c>.</p>
- <p>If <c>trace_running_ports/6</c> is not defined <c>trace/6</c> will be called instead.</p>
+ <p>If <c>trace_running_ports/5</c> is not defined <c>trace/5</c> will be called instead.</p>
</desc>
</func>
@@ -376,14 +375,13 @@
</func>
<func>
- <name>Module:trace_call(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <name>Module:trace_call(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
<type>
<v>TraceTag = <seealso marker="#type-trace_tag_call">trace_tag_call()</seealso></v>
<v>TracerState = term()</v>
<v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
<v>FirstTraceTerm = term()</v>
- <v>SecondTraceTerm = term() | undefined</v>
<v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
<v>Result = ok</v>
</type>
@@ -391,7 +389,7 @@
<p>This callback will be called when a tracepoint is triggered and
the <seealso marker="#Module:enabled_call/3">Module:enabled_call/3</seealso>
callback returned <c>trace</c>.</p>
- <p>If <c>trace_call/6</c> is not defined <c>trace/6</c> will be called instead.</p>
+ <p>If <c>trace_call/5</c> is not defined <c>trace/5</c> will be called instead.</p>
</desc>
</func>
@@ -413,14 +411,13 @@
</func>
<func>
- <name>Module:trace_send(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <name>Module:trace_send(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
<type>
<v>TraceTag = <seealso marker="#type-trace_tag_send">trace_tag_send()</seealso></v>
<v>TracerState = term()</v>
<v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
<v>FirstTraceTerm = term()</v>
- <v>SecondTraceTerm = term() | undefined</v>
<v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
<v>Result = ok</v>
</type>
@@ -428,7 +425,7 @@
<p>This callback will be called when a tracepoint is triggered and
the <seealso marker="#Module:enabled_send/3">Module:enabled_send/3</seealso>
callback returned <c>trace</c>.</p>
- <p>If <c>trace_send/6</c> is not defined <c>trace/6</c> will be called instead.</p>
+ <p>If <c>trace_send/5</c> is not defined <c>trace/5</c> will be called instead.</p>
</desc>
</func>
@@ -450,14 +447,13 @@
</func>
<func>
- <name>Module:trace_receive(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <name>Module:trace_receive(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
<type>
<v>TraceTag = <seealso marker="#type-trace_tag_receive">trace_tag_receive()</seealso></v>
<v>TracerState = term()</v>
<v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
<v>FirstTraceTerm = term()</v>
- <v>SecondTraceTerm = term() | undefined</v>
<v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
<v>Result = ok</v>
</type>
@@ -465,7 +461,7 @@
<p>This callback will be called when a tracepoint is triggered and
the <seealso marker="#Module:enabled_receive/3">Module:enabled_receive/3</seealso>
callback returned <c>trace</c>.</p>
- <p>If <c>trace_receive/6</c> is not defined <c>trace/6</c> will be called instead.</p>
+ <p>If <c>trace_receive/5</c> is not defined <c>trace/5</c> will be called instead.</p>
</desc>
</func>
@@ -487,14 +483,13 @@
</func>
<func>
- <name>Module:trace_garbage_collection(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <name>Module:trace_garbage_collection(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
<type>
<v>TraceTag = <seealso marker="#type-trace_tag_gc">trace_tag_gc()</seealso></v>
<v>TracerState = term()</v>
<v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
<v>FirstTraceTerm = term()</v>
- <v>SecondTraceTerm = term() | undefined</v>
<v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
<v>Result = ok</v>
</type>
@@ -502,7 +497,7 @@
<p>This callback will be called when a tracepoint is triggered and
the <seealso marker="#Module:enabled_garbage_collection/3">Module:enabled_garbage_collection/3</seealso>
callback returned <c>trace</c>.</p>
- <p>If <c>trace_garbage_collection/6</c> is not defined <c>trace/6</c> will be called instead.</p>
+ <p>If <c>trace_garbage_collection/5</c> is not defined <c>trace/5</c> will be called instead.</p>
</desc>
</func>
@@ -543,7 +538,7 @@ ok
<pre>
-module(erl_msg_tracer).
--export([enabled/3, trace/6, load/0]).
+-export([enabled/3, trace/5, load/0]).
load() ->
erlang:load_nif("erl_msg_tracer", []).
@@ -551,7 +546,7 @@ load() ->
enabled(_, _, _) ->
error.
-trace(_, _, _,_, _, _) ->
+trace(_, _, _,_, _) ->
error.
</pre>
<p>erl_msg_tracer.c</p>
@@ -569,7 +564,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(erl_msg_tracer, nif_funcs, load, NULL, upgrade, unload)
@@ -632,9 +627,8 @@ static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
* argv[0]: TraceTag, should only be 'send'
* argv[1]: TracerState, process to send {argv[2], argv[4]} to
* argv[2]: Tracee
- * argv[3]: Message, ignored
- * argv[4]: Recipient
- * argv[5]: Options, ignored
+ * argv[3]: Recipient
+ * argv[4]: Options, ignored
*/
static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
diff --git a/erts/doc/src/init.xml b/erts/doc/src/init.xml
index 84a5aea335..878a33c9ca 100644
--- a/erts/doc/src/init.xml
+++ b/erts/doc/src/init.xml
@@ -241,6 +241,11 @@
marker="kernel:code">code(3)</seealso>.</p>
</item>
+ <tag><c>-epmd_module Module</c></tag>
+ <item>
+ <p>Specifies the module to use for registration and lookup of
+ node names. Defaults to <c>erl_epmd</c>.</p>
+ </item>
<tag><c>-eval Expr</c></tag>
<item>
<p>Scans, parses and evaluates an arbitrary expression
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() ->
diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c
index 42da05b1f7..2b2e0e480a 100644
--- a/erts/etc/common/erlexec.c
+++ b/erts/etc/common/erlexec.c
@@ -195,6 +195,7 @@ static char *plusz_val_switches[] = {
#endif
void usage(const char *switchname);
+static void usage_format(char *format, ...);
void start_epmd(char *epmd);
void error(char* format, ...);
@@ -795,6 +796,24 @@ int main(int argc, char **argv)
get_start_erl_data((char *) NULL);
}
#endif
+ else if (strcmp(argv[i], "-start_epmd") == 0) {
+ if (i+1 >= argc)
+ usage("-start_epmd");
+
+ if (strcmp(argv[i+1], "true") == 0) {
+ /* The default */
+ no_epmd = 0;
+ }
+ else if (strcmp(argv[i+1], "false") == 0) {
+ no_epmd = 1;
+ }
+ else
+ usage_format("Expected boolean argument for \'-start_epmd\'.\n");
+
+ add_arg(argv[i]);
+ add_arg(argv[i+1]);
+ i++;
+ }
else
add_arg(argv[i]);
@@ -1173,7 +1192,7 @@ usage_aux(void)
"]"
#endif
"] "
- "[-make] [-man [manopts] MANPAGE] [-x] [-emu_args] "
+ "[-make] [-man [manopts] MANPAGE] [-x] [-emu_args] [-start_epmd BOOLEAN] "
"[-args_file FILENAME] [+A THREADS] [+a SIZE] [+B[c|d|i]] [+c [BOOLEAN]] "
"[+C MODE] [+h HEAP_SIZE_OPTION] [+K BOOLEAN] "
"[+l] [+M<SUBSWITCH> <ARGUMENT>] [+P MAX_PROCS] [+Q MAX_PORTS] "
diff --git a/erts/preloaded/ebin/erl_tracer.beam b/erts/preloaded/ebin/erl_tracer.beam
index 69804540c9..22286ed221 100644
--- a/erts/preloaded/ebin/erl_tracer.beam
+++ b/erts/preloaded/ebin/erl_tracer.beam
Binary files differ
diff --git a/erts/preloaded/src/erl_tracer.erl b/erts/preloaded/src/erl_tracer.erl
index fe15812535..c810069d17 100644
--- a/erts/preloaded/src/erl_tracer.erl
+++ b/erts/preloaded/src/erl_tracer.erl
@@ -1,6 +1,6 @@
-module(erl_tracer).
--export([enabled/3, trace/6, on_load/0]).
+-export([enabled/3, trace/5, on_load/0]).
-type tracee() :: port() | pid() | undefined.
@@ -26,9 +26,9 @@
| trace_tag_running_ports()
| trace_tag_gc().
--type trace_opts() :: #{ match_spec_result => true | term(),
- scheduler_id => undefined | non_neg_integer(),
- timestamp => undefined | timestamp | cpu_timestamp |
+-type trace_opts() :: #{ extra => term(), match_spec_result => term(),
+ scheduler_id => non_neg_integer(),
+ timestamp => timestamp | cpu_timestamp |
monotonic | strict_monotonic }.
-type tracer_state() :: term().
@@ -41,6 +41,9 @@ on_load() ->
%%% NIF placeholders
%%%
+%% This suppression is needed as trace_tag gets collapsed to atom()
+-dialyzer({no_contracts, enabled/3}).
+
-spec enabled(Tag :: trace_status,
TracerState :: tracer_state(),
Tracee :: tracee()) ->
@@ -56,8 +59,7 @@ enabled(_, _, _) ->
TracerState :: tracer_state(),
Tracee :: tracee(),
Msg :: term(),
- Extra :: term(),
Opts :: trace_opts()) -> any().
-trace(_, _, _, _, _, _) ->
+trace(_, _, _, _, _) ->
erlang:nif_error(nif_not_loaded).