aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/doc/src/erl_nif.xml9
-rw-r--r--erts/doc/src/erl_tracer.xml62
-rw-r--r--erts/doc/src/erts_alloc.xml2
-rw-r--r--erts/doc/src/match_spec.xml149
-rw-r--r--erts/emulator/beam/beam_load.c1
-rw-r--r--erts/emulator/beam/binary.c2
-rw-r--r--erts/emulator/beam/erl_alloc.c30
-rw-r--r--erts/emulator/beam/erl_bif_re.c8
-rw-r--r--erts/emulator/beam/erl_message.h4
-rw-r--r--erts/emulator/beam/erl_nif.c38
-rw-r--r--erts/emulator/beam/erl_nif.h3
-rw-r--r--erts/emulator/beam/erl_nif_api_funcs.h2
-rw-r--r--erts/emulator/beam/erl_process.h4
-rw-r--r--erts/emulator/beam/erl_unicode.c58
-rw-r--r--erts/emulator/beam/global.h2
-rw-r--r--erts/emulator/hipe/hipe_mode_switch.c27
-rw-r--r--erts/emulator/test/alloc_SUITE.erl22
-rw-r--r--erts/emulator/test/nif_SUITE.erl17
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c20
-rw-r--r--erts/emulator/test/port_trace_SUITE.erl44
-rw-r--r--erts/emulator/test/port_trace_SUITE_data/echo_drv.c36
-rw-r--r--erts/epmd/test/epmd_SUITE.erl1205
22 files changed, 918 insertions, 827 deletions
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index fefec3eeb6..33a4fee182 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -1763,6 +1763,15 @@ enif_map_iterator_destroy(env, &iter);
<desc><p>Get the byte size of a resource object <c>obj</c> obtained by
<seealso marker="#enif_alloc_resource">enif_alloc_resource</seealso>.</p></desc>
</func>
+
+ <func><name><ret>int</ret><nametext>enif_snprintf(char *str, size_t size, const char *format, ...)</nametext></name>
+ <fsummary>Format strings and Erlang terms</fsummary>
+ <desc>
+ <p>Similar to <c>snprintf</c> but this format string also accepts <c>"%T"</c> which formats Erlang terms.
+ </p>
+ </desc>
+ </func>
+
<func>
<name><ret>void</ret><nametext>enif_system_info(ErlNifSysInfo *sys_info_ptr, size_t size)</nametext></name>
<fsummary>Get information about the Erlang runtime system</fsummary>
diff --git a/erts/doc/src/erl_tracer.xml b/erts/doc/src/erl_tracer.xml
index 7fd5512b33..d4c8bbad31 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="#trace">Module:trace/6</seealso>
+ <seealso marker="#Module:trace/6">Module:trace/6</seealso>
</p>
</desc>
</datatype>
@@ -81,7 +81,7 @@
<datatype>
<name name="trace_opts" />
<desc>
- <p>The options for the tracee.
+ <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
@@ -93,7 +93,6 @@
<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>
</taglist>
- </p>
</desc>
</datatype>
<datatype>
@@ -114,30 +113,30 @@
<p>The following functions
should be exported from a <c>erl_tracer</c> callback module.</p>
<taglist>
- <tag><seealso marker="#enabled"><c>Module:enabled/3</c></seealso></tag>
+ <tag><seealso marker="#Module:enabled/3"><c>Module:enabled/3</c></seealso></tag>
<item>Mandatory</item>
- <tag><seealso marker="#trace"><c>Module:trace/6</c></seealso></tag>
+ <tag><seealso marker="#Module:trace/6"><c>Module:trace/6</c></seealso></tag>
<item>Mandatory</item>
- <tag><seealso marker="#enabled_procs"><c>Module:enabled_procs/3</c></seealso></tag>
+ <tag><seealso marker="#Module:enabled_procs/3"><c>Module:enabled_procs/3</c></seealso></tag>
<item>Optional</item>
- <tag><seealso marker="#trace_procs"><c>Module:trace_procs/6</c></seealso></tag>
+ <tag><seealso marker="#Module:trace_procs/6"><c>Module:trace_procs/6</c></seealso></tag>
<item>Optional</item>
- <tag><seealso marker="#enabled_ports"><c>Module:enabled_ports/3</c></seealso></tag>
+ <tag><seealso marker="#Module:enabled_ports/3"><c>Module:enabled_ports/3</c></seealso></tag>
<item>Optional</item>
- <tag><seealso marker="#trace_ports"><c>Module:trace_ports/6</c></seealso></tag>
+ <tag><seealso marker="#Module:trace_ports/6"><c>Module:trace_ports/6</c></seealso></tag>
<item>Optional</item>
- <tag><seealso marker="#enabled_running_ports"><c>Module:enabled_running_ports/3</c></seealso></tag>
+ <tag><seealso marker="#Module:enabled_running_ports/3"><c>Module:enabled_running_ports/3</c></seealso></tag>
<item>Optional</item>
- <tag><seealso marker="#trace_running_ports"><c>Module:trace_running_ports/6</c></seealso></tag>
+ <tag><seealso marker="#Module:trace_running_ports/6"><c>Module:trace_running_ports/6</c></seealso></tag>
<item>Optional</item>
- <tag><seealso marker="#enabled_running_procs"><c>Module:enabled_running_procs/3</c></seealso></tag>
+ <tag><seealso marker="#Module:enabled_running_procs/3"><c>Module:enabled_running_procs/3</c></seealso></tag>
<item>Optional</item>
- <tag><seealso marker="#trace_running_procs"><c>Module:trace_running_procs/6</c></seealso></tag>
+ <tag><seealso marker="#Module:trace_running_procs/6"><c>Module:trace_running_procs/6</c></seealso></tag>
<item>Optional</item>
</taglist>
</section>
- <marker id="enabled"></marker>
+
<funcs>
<func>
<name>Module:enabled(TraceTag, TracerState, Tracee) -> Result</name>
@@ -166,7 +165,6 @@
is important that it is both fast and side effect free.</p>
</desc>
</func>
- <marker id="trace"></marker>
<func>
<name>Module:trace(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
@@ -181,7 +179,7 @@
</type>
<desc>
<p>This callback will be called when a tracepoint is triggered and
- the <seealso marker="#enabled">Module:enabled/3</seealso>
+ 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
@@ -212,7 +210,6 @@
</desc>
</func>
- <marker id="enabled_procs"></marker>
<func>
<name>Module:enabled_procs(TraceTag, TracerState, Tracee) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
@@ -230,7 +227,6 @@
</desc>
</func>
- <marker id="trace_procs"></marker>
<func>
<name>Module:trace_procs(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
@@ -245,13 +241,12 @@
</type>
<desc>
<p>This callback will be called when a tracepoint is triggered and
- the <seealso marker="#enabled_procs">Module:enabled_procs/3</seealso>
+ 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>
</desc>
</func>
- <marker id="enabled_ports"></marker>
<func>
<name>Module:enabled_ports(TraceTag, TracerState, Tracee) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
@@ -269,7 +264,6 @@
</desc>
</func>
- <marker id="trace_ports"></marker>
<func>
<name>Module:trace_ports(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
@@ -284,13 +278,12 @@
</type>
<desc>
<p>This callback will be called when a tracepoint is triggered and
- the <seealso marker="#enabled_ports">Module:enabled_ports/3</seealso>
+ 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>
</desc>
</func>
- <marker id="enabled_running_procs"></marker>
<func>
<name>Module:enabled_running_procs(TraceTag, TracerState, Tracee) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
@@ -308,7 +301,6 @@
</desc>
</func>
- <marker id="trace_running_procs"></marker>
<func>
<name>Module:trace_running_procs(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
@@ -323,13 +315,12 @@
</type>
<desc>
<p>This callback will be called when a tracepoint is triggered and
- the <seealso marker="#enabled_running_procs">Module:enabled_running_procs/3</seealso>
+ 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>
</desc>
</func>
- <marker id="enabled_running_ports"></marker>
<func>
<name>Module:enabled_running_ports(TraceTag, TracerState, Tracee) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
@@ -347,7 +338,6 @@
</desc>
</func>
- <marker id="trace_running_ports"></marker>
<func>
<name>Module:trace_running_ports(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
@@ -362,13 +352,12 @@
</type>
<desc>
<p>This callback will be called when a tracepoint is triggered and
- the <seealso marker="#enabled_running_ports">Module:enabled_running_ports/3</seealso>
+ 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>
</desc>
</func>
- <marker id="enabled_call"></marker>
<func>
<name>Module:enabled_call(TraceTag, TracerState, Tracee) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
@@ -386,7 +375,6 @@
</desc>
</func>
- <marker id="trace_call"></marker>
<func>
<name>Module:trace_call(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
@@ -401,13 +389,12 @@
</type>
<desc>
<p>This callback will be called when a tracepoint is triggered and
- the <seealso marker="#enabled_call">Module:enabled_call/3</seealso>
+ 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>
</desc>
</func>
- <marker id="enabled_send"></marker>
<func>
<name>Module:enabled_send(TraceTag, TracerState, Tracee) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
@@ -425,7 +412,6 @@
</desc>
</func>
- <marker id="trace_send"></marker>
<func>
<name>Module:trace_send(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
@@ -440,13 +426,12 @@
</type>
<desc>
<p>This callback will be called when a tracepoint is triggered and
- the <seealso marker="#enabled_send">Module:enabled_send/3</seealso>
+ 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>
</desc>
</func>
- <marker id="enabled_receive"></marker>
<func>
<name>Module:enabled_receive(TraceTag, TracerState, Tracee) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
@@ -464,7 +449,6 @@
</desc>
</func>
- <marker id="trace_receive"></marker>
<func>
<name>Module:trace_receive(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
@@ -479,13 +463,12 @@
</type>
<desc>
<p>This callback will be called when a tracepoint is triggered and
- the <seealso marker="#enabled_receive">Module:enabled_receive/3</seealso>
+ 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>
</desc>
</func>
- <marker id="enabled_garbage_collection"></marker>
<func>
<name>Module:enabled_garbage_collection(TraceTag, TracerState, Tracee) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
@@ -503,7 +486,6 @@
</desc>
</func>
- <marker id="trace_garbage_collection"></marker>
<func>
<name>Module:trace_garbage_collection(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
<fsummary>Check if a trace event should be generated.</fsummary>
@@ -518,7 +500,7 @@
</type>
<desc>
<p>This callback will be called when a tracepoint is triggered and
- the <seealso marker="#enabled_garbage_collection">Module:enabled_garbage_collection/3</seealso>
+ 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>
</desc>
diff --git a/erts/doc/src/erts_alloc.xml b/erts/doc/src/erts_alloc.xml
index 70775b9f0f..9aef1c0b1f 100644
--- a/erts/doc/src/erts_alloc.xml
+++ b/erts/doc/src/erts_alloc.xml
@@ -583,7 +583,7 @@
</taglist>
<p>The following flag is special for <c>exec_alloc</c>:</p>
<taglist>
- <tag><marker id="MIscs"/><c><![CDATA[+MXscs <size in MB>]]></c></tag>
+ <tag><marker id="MXscs"/><c><![CDATA[+MXscs <size in MB>]]></c></tag>
<item>
<c>exec_alloc</c> super carrier size (in MB). The amount of
<em>virtual</em> address space reserved for native executable code
diff --git a/erts/doc/src/match_spec.xml b/erts/doc/src/match_spec.xml
index 3944f24f84..7be3d15de6 100644
--- a/erts/doc/src/match_spec.xml
+++ b/erts/doc/src/match_spec.xml
@@ -33,21 +33,15 @@
<file>match_spec.xml</file>
</header>
<p>A "match specification" (match_spec) is an Erlang term describing a
- small "program" that will try to match something (either the
- parameters to a function as used in the <c><![CDATA[erlang:trace_pattern/2]]></c>
- BIF, or the objects in an ETS table.).
+ small "program" that will try to match something. It can be used
+ to either control tracing with
+ <seealso marker="erlang#trace_pattern/3">erlang:trace_pattern/3</seealso>
+ or to search for objects in an ETS table with for example
+ <seealso marker="stdlib:ets#select/2">ets:select/2</seealso>.
The match_spec in many ways works like a small function in Erlang, but is
interpreted/compiled by the Erlang runtime system to something much more
efficient than calling an Erlang function. The match_spec is also
very limited compared to the expressiveness of real Erlang functions.</p>
- <p>Match specifications are given to the BIF <c><![CDATA[erlang:trace_pattern/2]]></c> to
- execute matching of function arguments as well as to define some actions
- to be taken when the match succeeds (the <c><![CDATA[MatchBody]]></c> part). Match
- specifications can also be used in ETS, to specify objects to be
- returned from an <c><![CDATA[ets:select/2]]></c> call (or other select
- calls). The semantics and restrictions differ slightly when using
- match specifications for tracing and in ETS, the differences are
- defined in a separate paragraph below.</p>
<p>The most notable difference between a match_spec and an Erlang fun is
of course the syntax. Match specifications are Erlang terms, not
Erlang code. A match_spec also has a somewhat strange concept of
@@ -382,6 +376,51 @@
the pid() of the current process.</p>
</section>
+ <marker id="match_target"></marker>
+ <section>
+ <title>Match target</title>
+ <p>Each execution of a match specification is done against
+ a match target term. The format and content of the target term
+ depends on the context in which the match is done. The match
+ target for ETS is always a full table tuple. The match target
+ for call trace is always a list of all function arguments. The
+ match target for event trace depends on the event type, see
+ table below.</p>
+ <table>
+ <row>
+ <cell align="left" valign="middle">Context</cell>
+ <cell align="left" valign="middle">Type</cell>
+ <cell align="left" valign="middle">Match target</cell>
+ <cell align="left" valign="middle">Description</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">ETS</cell>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">{Key, Value1, Value2, ...}</cell>
+ <cell align="left" valign="middle">A table object</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">Trace</cell>
+ <cell align="left" valign="middle">call</cell>
+ <cell align="left" valign="middle">[Arg1, Arg2, ...]</cell>
+ <cell align="left" valign="middle">Function arguments</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">Trace</cell>
+ <cell align="left" valign="middle">send</cell>
+ <cell align="left" valign="middle">[Receiver, Message]</cell>
+ <cell align="left" valign="middle">Receiving process/port and message term</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">Trace</cell>
+ <cell align="left" valign="middle">'receive'</cell>
+ <cell align="left" valign="middle">[Node, Sender, Message]</cell>
+ <cell align="left" valign="middle">Sending node, process/port and message term</cell>
+ </row>
+ <tcaption>Match target depending on context</tcaption>
+ </table>
+ </section>
+
<section>
<title>Variables and literals</title>
<p>Variables take the form <c><![CDATA['$<number>']]></c> where
@@ -396,10 +435,8 @@
<c><![CDATA[MatchCondition]]></c> parts, only variables bound previously may
be used. As a special case, in the
<c><![CDATA[MatchCondition/MatchBody]]></c> parts, the variable <c><![CDATA['$_']]></c>
- expands to the whole expression which matched the
- <c><![CDATA[MatchHead]]></c> (i.e., the whole parameter list to the possibly
- traced function or the whole matching object in the ets table)
- and the variable <c><![CDATA['$$']]></c> expands to a list
+ expands to the whole <seealso marker="#match_target">match target</seealso>
+ term and the variable <c><![CDATA['$$']]></c> expands to a list
of the values of all bound variables in order
(i.e. <c><![CDATA[['$1','$2', ...]]]></c>).
</p>
@@ -480,8 +517,8 @@
<p>For each tuple in the <c><![CDATA[MatchExpression]]></c> list and while no
match has succeeded:</p>
<list type="bulleted">
- <item>Match the <c><![CDATA[MatchHead]]></c> part against the arguments to the
- function,
+ <item>Match the <c><![CDATA[MatchHead]]></c> part against the
+ match target term,
binding the <c><![CDATA['$<number>']]></c> variables (much like in
<c><![CDATA[ets:match/2]]></c>).
If the <c><![CDATA[MatchHead]]></c> cannot match the arguments, the match fails.
@@ -522,13 +559,10 @@
term. The <c><![CDATA[ActionTerm]]></c>'s are executed as in an imperative
language, i.e. for their side effects. Functions with side effects
are also allowed when tracing.</p>
- <p>In ETS the match head is a <c><![CDATA[tuple()]]></c> (or a single match
- variable) while it is a list (or a single match variable) when
- tracing.</p>
</section>
<section>
- <title>ETS Examples</title>
+ <title>Tracing Examples</title>
<p>Match an argument list of three where the first and third arguments
are equal:</p>
<code type="none"><![CDATA[
@@ -585,42 +619,6 @@
parameter list with a single variable is a special case. In all
other cases the <c><![CDATA[MatchHead]]></c> has to be a <em>proper</em> list.
</p>
- <p>Match all objects in an ets table where the first element is
- the atom 'strider' and the tuple arity is 3 and return the whole
- object.</p>
- <code type="none"><![CDATA[
-[{{strider,'_','_'},
- [],
- ['$_']}]
- ]]></code>
- <p>Match all objects in an ets table with arity &gt; 1 and the first
- element is 'gandalf', return element 2.</p>
- <code type="none"><![CDATA[
-[{'$1',
- [{'==', gandalf, {element, 1, '$1'}},{'>=',{size, '$1'},2}],
- [{element,2,'$1'}]}]
- ]]></code>
- <p>In the above example, if the first element had been the key,
- it's much more efficient to match that key in the <c><![CDATA[MatchHead]]></c>
- part than in the <c><![CDATA[MatchConditions]]></c> part. The search space of
- the tables is restricted with regards to the <c><![CDATA[MatchHead]]></c> so
- that only objects with the matching key are searched.
- </p>
- <p>Match tuples of 3 elements where the second element is either
- 'merry' or 'pippin', return the whole objects.</p>
- <code type="none"><![CDATA[
-[{{'_',merry,'_'},
- [],
- ['$_']},
- {{'_',pippin,'_'},
- [],
- ['$_']}]
- ]]></code>
- <p>The function <c><![CDATA[ets:test_ms/2]]></c> can be useful for testing
- complicated ets matches.</p>
- </section>
- <section>
- <title>Tracing Examples</title>
<p>Only generate trace message if trace control word is set to 1:</p>
<code type="none"><![CDATA[
[{'_',
@@ -658,5 +656,42 @@
{'_',[],[]}]
]]></code>
</section>
+
+ <section>
+ <title>ETS Examples</title>
+ <p>Match all objects in an ets table where the first element is
+ the atom 'strider' and the tuple arity is 3 and return the whole
+ object.</p>
+ <code type="none"><![CDATA[
+[{{strider,'_','_'},
+ [],
+ ['$_']}]
+ ]]></code>
+ <p>Match all objects in an ets table with arity &gt; 1 and the first
+ element is 'gandalf', return element 2.</p>
+ <code type="none"><![CDATA[
+[{'$1',
+ [{'==', gandalf, {element, 1, '$1'}},{'>=',{size, '$1'},2}],
+ [{element,2,'$1'}]}]
+ ]]></code>
+ <p>In the above example, if the first element had been the key,
+ it's much more efficient to match that key in the <c><![CDATA[MatchHead]]></c>
+ part than in the <c><![CDATA[MatchConditions]]></c> part. The search space of
+ the tables is restricted with regards to the <c><![CDATA[MatchHead]]></c> so
+ that only objects with the matching key are searched.
+ </p>
+ <p>Match tuples of 3 elements where the second element is either
+ 'merry' or 'pippin', return the whole objects.</p>
+ <code type="none"><![CDATA[
+[{{'_',merry,'_'},
+ [],
+ ['$_']},
+ {{'_',pippin,'_'},
+ [],
+ ['$_']}]
+ ]]></code>
+ <p>The function <c><![CDATA[ets:test_ms/2]]></c> can be useful for testing
+ complicated ets matches.</p>
+ </section>
</chapter>
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index 95489d9a63..0c2743beb2 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -4424,6 +4424,7 @@ gen_get_map_elements(LoaderState* stp, GenOpArg Fail, GenOpArg Src,
int good_hash;
#endif
+ ERTS_UNDEF(hx, 0);
ASSERT(Size.type == TAG_u);
NEW_GENOP(stp, op);
diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c
index cfd8fbe2f5..071a356260 100644
--- a/erts/emulator/beam/binary.c
+++ b/erts/emulator/beam/binary.c
@@ -117,7 +117,7 @@ new_binary(Process *p, byte *buf, Uint len)
* When heap binary is not desired...
*/
-Eterm erts_new_mso_binary(Process *p, byte *buf, int len)
+Eterm erts_new_mso_binary(Process *p, byte *buf, Uint len)
{
ProcBin* pb;
Binary* bptr;
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c
index c367d4162c..3c2c9def3b 100644
--- a/erts/emulator/beam/erl_alloc.c
+++ b/erts/emulator/beam/erl_alloc.c
@@ -137,10 +137,13 @@ static ErtsAllocatorState_t exec_alloc_state;
#endif
static ErtsAllocatorState_t test_alloc_state;
-#define ERTS_ALC_INFO_A_ALLOC_UTIL (ERTS_ALC_A_MAX + 1)
-#define ERTS_ALC_INFO_A_MSEG_ALLOC (ERTS_ALC_A_MAX + 2)
-#define ERTS_ALC_INFO_A_ERTS_MMAP (ERTS_ALC_A_MAX + 3)
-#define ERTS_ALC_INFO_A_MAX ERTS_ALC_INFO_A_ERTS_MMAP
+enum {
+ ERTS_ALC_INFO_A_ALLOC_UTIL = ERTS_ALC_A_MAX + 1,
+ ERTS_ALC_INFO_A_MSEG_ALLOC,
+ ERTS_ALC_INFO_A_ERTS_MMAP,
+ ERTS_ALC_INFO_A_DISABLED_EXEC, /* fake a disabled "exec_alloc" */
+ ERTS_ALC_INFO_A_END
+};
typedef struct {
erts_smp_atomic32_t refc;
@@ -150,7 +153,7 @@ typedef struct {
Process *proc;
Eterm ref;
Eterm ref_heap[REF_THING_SIZE];
- int allocs[ERTS_ALC_INFO_A_MAX - ERTS_ALC_A_MIN + 1 + 1];
+ int allocs[ERTS_ALC_INFO_A_END - ERTS_ALC_A_MIN + 1];
} ErtsAllocInfoReq;
ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(aireq,
@@ -3260,6 +3263,12 @@ reply_alloc_info(void *vair)
am_false);
#endif
break;
+#ifndef ERTS_ALC_A_EXEC
+ case ERTS_ALC_INFO_A_DISABLED_EXEC:
+ alloc_atom = erts_bld_atom(hpp, szp, "exec_alloc");
+ ainfo = erts_bld_tuple2(hpp, szp, alloc_atom, am_false);
+ break;
+#endif
default:
alloc_atom = erts_bld_atom(hpp, szp,
(char *) ERTS_ALC_A2AD(ai));
@@ -3287,7 +3296,8 @@ reply_alloc_info(void *vair)
switch (ai) {
case ERTS_ALC_A_SYSTEM:
case ERTS_ALC_INFO_A_ALLOC_UTIL:
- case ERTS_ALC_INFO_A_ERTS_MMAP:
+ case ERTS_ALC_INFO_A_ERTS_MMAP:
+ case ERTS_ALC_INFO_A_DISABLED_EXEC:
break;
case ERTS_ALC_INFO_A_MSEG_ALLOC:
#if HAVE_ERTS_MSEG && defined(ERTS_SMP)
@@ -3359,7 +3369,7 @@ erts_request_alloc_info(struct process *c_p,
int internal)
{
ErtsAllocInfoReq *air = aireq_alloc();
- Eterm req_ai[ERTS_ALC_INFO_A_MAX+1] = {0};
+ Eterm req_ai[ERTS_ALC_INFO_A_END] = {0};
Eterm alist;
Eterm *hp;
int airix = 0, ai;
@@ -3399,6 +3409,12 @@ erts_request_alloc_info(struct process *c_p,
ai = ERTS_ALC_INFO_A_ERTS_MMAP;
goto save_alloc;
}
+#ifndef ERTS_ALC_A_EXEC
+ if (erts_is_atom_str("exec_alloc", alloc, 0)) {
+ ai = ERTS_ALC_INFO_A_DISABLED_EXEC;
+ goto save_alloc;
+ }
+#endif
if (erts_is_atom_str("alloc_util", alloc, 0)) {
ai = ERTS_ALC_INFO_A_ALLOC_UTIL;
save_alloc:
diff --git a/erts/emulator/beam/erl_bif_re.c b/erts/emulator/beam/erl_bif_re.c
index f4daecd2a4..ff7746ce1d 100644
--- a/erts/emulator/beam/erl_bif_re.c
+++ b/erts/emulator/beam/erl_bif_re.c
@@ -630,9 +630,15 @@ static Eterm build_exec_return(Process *p, int rc, RestartContext *restartp, Ete
}
} else {
ReturnInfo *ri;
- ReturnInfo defri = {RetIndex,0,{0}};
+ ReturnInfo defri;
if (restartp->ret_info == NULL) {
+ /* OpenBSD 5.8 gcc compiler for some reason creates
+ bad code if the above initialization is done
+ inline with the struct. So don't do that. */
+ defri.type = RetIndex;
+ defri.num_spec = 0;
+ defri.v[0] = 0;
ri = &defri;
} else {
ri = restartp->ret_info;
diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h
index 851ac37fda..4493df1c1a 100644
--- a/erts/emulator/beam/erl_message.h
+++ b/erts/emulator/beam/erl_message.h
@@ -112,8 +112,8 @@ typedef struct erl_heap_fragment ErlHeapFragment;
struct erl_heap_fragment {
ErlHeapFragment* next; /* Next heap fragment */
ErlOffHeap off_heap; /* Offset heap data. */
- unsigned alloc_size; /* Size in (half)words of mem */
- unsigned used_size; /* With terms to be moved to heap by GC */
+ Uint alloc_size; /* Size in (half)words of mem */
+ Uint used_size; /* With terms to be moved to heap by GC */
Eterm mem[1]; /* Data */
};
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 8a3007d52a..606b73c7b5 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -96,7 +96,7 @@ void dtrace_nifenv_str(ErlNifEnv *, char *);
#endif
#define MIN_HEAP_FRAG_SZ 200
-static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need, Eterm* hp);
+static Eterm* alloc_heap_heavy(ErlNifEnv* env, size_t need, Eterm* hp);
static ERTS_INLINE int
is_scheduler(void)
@@ -135,7 +135,7 @@ execution_state(ErlNifEnv *env, Process **c_pp, int *schedp)
}
}
-static ERTS_INLINE Eterm* alloc_heap(ErlNifEnv* env, unsigned need)
+static ERTS_INLINE Eterm* alloc_heap(ErlNifEnv* env, size_t need)
{
Eterm* hp = env->hp;
env->hp += need;
@@ -145,7 +145,7 @@ static ERTS_INLINE Eterm* alloc_heap(ErlNifEnv* env, unsigned need)
return alloc_heap_heavy(env, need, hp);
}
-static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need, Eterm* hp)
+static Eterm* alloc_heap_heavy(ErlNifEnv* env, size_t need, Eterm* hp)
{
env->hp = hp;
if (env->heap_frag == NULL) {
@@ -166,7 +166,7 @@ static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need, Eterm* hp)
}
#if SIZEOF_LONG != ERTS_SIZEOF_ETERM
-static ERTS_INLINE void ensure_heap(ErlNifEnv* env, unsigned may_need)
+static ERTS_INLINE void ensure_heap(ErlNifEnv* env, size_t may_need)
{
if (env->hp + may_need > env->hp_end) {
alloc_heap_heavy(env, may_need, env->hp);
@@ -667,6 +667,9 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid,
erts_smp_proc_trylock(rp, ERTS_PROC_LOCK_MSGQ) == EBUSY) {
if (!msgq) {
+#ifdef ERTS_SMP
+ ErtsThrPrgrDelayHandle dhndl;
+#endif
msgq = erts_alloc(ERTS_ALC_T_TRACE_MSG_QUEUE,
sizeof(ErlTraceMessageQueue));
@@ -681,8 +684,15 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid,
erts_smp_proc_unlock(t_p, ERTS_PROC_LOCK_TRACE);
+#ifdef ERTS_SMP
+ if (!scheduler)
+ dhndl = erts_thr_progress_unmanaged_delay();
+#endif
erts_schedule_flush_trace_messages(t_p->common.id);
-
+#ifdef ERTS_SMP
+ if (!scheduler)
+ erts_thr_progress_unmanaged_continue(dhndl);
+#endif
} else {
msgq->len++;
*msgq->last = mp;
@@ -1197,7 +1207,7 @@ Eterm enif_make_sub_binary(ErlNifEnv* env, ERL_NIF_TERM bin_term,
Eterm orig;
Uint offset, bit_offset, bit_size;
#ifdef DEBUG
- unsigned src_size;
+ size_t src_size;
ASSERT(is_binary(bin_term));
src_size = binary_size(bin_term);
@@ -1669,7 +1679,8 @@ int enif_is_process_alive(ErlNifEnv* env, ErlNifPid *proc)
return !!rp;
#else
erts_exit(ERTS_ABORT_EXIT, "enif_is_process_alive: "
- "called from non-scheduler thread");
+ "called from non-scheduler thread "
+ "in non-smp emulator");
return 0;
#endif
}
@@ -1694,7 +1705,8 @@ int enif_is_port_alive(ErlNifEnv *env, ErlNifPort *port)
return !!prt;
#else
erts_exit(ERTS_ABORT_EXIT, "enif_is_port_alive: "
- "called from non-scheduler thread");
+ "called from non-scheduler thread "
+ "in non-smp emulator");
return 0;
#endif
}
@@ -1810,6 +1822,16 @@ int enif_fprintf(void* filep, const char* format, ...)
return ret;
}
+int enif_snprintf(char *buffer, size_t size, const char* format, ...)
+{
+ int ret;
+ va_list arglist;
+ va_start(arglist, format);
+ ret = erts_vsnprintf(buffer, size, format, arglist);
+ va_end(arglist);
+ return ret;
+}
+
/***********************************************************
** Memory managed (GC'ed) "resource" objects **
***********************************************************/
diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h
index 02c82415fd..da7a754757 100644
--- a/erts/emulator/beam/erl_nif.h
+++ b/erts/emulator/beam/erl_nif.h
@@ -49,9 +49,10 @@
** 2.8: 18.0 add enif_has_pending_exception
** 2.9: 18.2 enif_getenv
** 2.10: Time API
+** 2.11: 19.0 enif_snprintf
*/
#define ERL_NIF_MAJOR_VERSION 2
-#define ERL_NIF_MINOR_VERSION 10
+#define ERL_NIF_MINOR_VERSION 11
/*
* The emulator will refuse to load a nif-lib with a major version
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index 1bdac51d1f..b211ab4b16 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -174,6 +174,7 @@ ERL_NIF_API_FUNC_DECL(int, enif_term_to_binary, (ErlNifEnv *env, ERL_NIF_TERM te
ERL_NIF_API_FUNC_DECL(size_t, enif_binary_to_term, (ErlNifEnv *env, const unsigned char* data, size_t sz, ERL_NIF_TERM *term, unsigned int opts));
ERL_NIF_API_FUNC_DECL(int, enif_port_command, (ErlNifEnv *env, const ErlNifPort* to_port, ErlNifEnv *msg_env, ERL_NIF_TERM msg));
ERL_NIF_API_FUNC_DECL(int,enif_is_on_dirty_scheduler,(ErlNifEnv*));
+ERL_NIF_API_FUNC_DECL(int,enif_snprintf,(char * buffer, size_t size, const char *format, ...));
/*
** ADD NEW ENTRIES HERE (before this comment) !!!
@@ -330,6 +331,7 @@ ERL_NIF_API_FUNC_DECL(int,enif_is_on_dirty_scheduler,(ErlNifEnv*));
# define enif_binary_to_term ERL_NIF_API_FUNC_MACRO(enif_binary_to_term)
# define enif_port_command ERL_NIF_API_FUNC_MACRO(enif_port_command)
# define enif_is_on_dirty_scheduler ERL_NIF_API_FUNC_MACRO(enif_is_on_dirty_scheduler)
+# define enif_snprintf ERL_NIF_API_FUNC_MACRO(enif_snprintf)
/*
** ADD NEW ENTRIES HERE (before this comment)
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 2801947613..b44ac442aa 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -960,7 +960,6 @@ struct process {
Uint heap_sz; /* Size of heap in words */
Uint min_heap_size; /* Minimum size of heap (in words). */
Uint min_vheap_size; /* Minimum size of virtual heap (in words). */
- Uint max_heap_size; /* Maximum size of heap (in words). */
#if !defined(NO_FPE_SIGNALS) || defined(HIPE)
volatile unsigned long fp_exception;
@@ -1061,6 +1060,7 @@ struct process {
Eterm *old_hend; /* Heap pointers for generational GC. */
Eterm *old_htop;
Eterm *old_heap;
+ Uint max_heap_size; /* Maximum size of heap (in words). */
Uint16 gen_gcs; /* Number of (minor) generational GCs. */
Uint16 max_gen_gcs; /* Max minor gen GCs before fullsweep. */
ErlOffHeap off_heap; /* Off-heap data updated by copy_struct(). */
@@ -1339,7 +1339,7 @@ ERTS_GLB_INLINE void erts_heap_frag_shrink(Process* p, Eterm* hp)
{
ErlHeapFragment* hf = MBUF(p);
- ASSERT(hf!=NULL && (hp - hf->mem < (unsigned long)hf->alloc_size));
+ ASSERT(hf!=NULL && (hp - hf->mem < hf->alloc_size));
hf->used_size = hp - hf->mem;
}
diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c
index 3c3536c021..bd5e1482fb 100644
--- a/erts/emulator/beam/erl_unicode.c
+++ b/erts/emulator/beam/erl_unicode.c
@@ -55,7 +55,7 @@ static BIF_RETTYPE finalize_list_to_list(Process *p,
Uint num_processed_bytes,
Uint num_bytes_to_process,
Uint num_resulting_chars,
- int state, int left,
+ int state, Sint left,
Eterm tail);
static BIF_RETTYPE characters_to_utf8_trap(BIF_ALIST_3);
static BIF_RETTYPE characters_to_list_trap_1(BIF_ALIST_3);
@@ -173,12 +173,13 @@ static ERTS_INLINE int allowed_iterations(Process *p)
else
return tmp;
}
-static ERTS_INLINE int cost_to_proc(Process *p, int cost)
+
+static ERTS_INLINE void cost_to_proc(Process *p, Sint cost)
{
- int x = (cost / LOOP_FACTOR);
+ Sint x = (cost / LOOP_FACTOR);
BUMP_REDS(p,x);
- return x;
}
+
static ERTS_INLINE int simple_loops_to_common(int cost)
{
int factor = (LOOP_FACTOR_SIMPLE / LOOP_FACTOR);
@@ -243,14 +244,15 @@ static int utf8_len(byte first)
return -1;
}
-static int copy_utf8_bin(byte *target, byte *source, Uint size,
- byte *leftover, int *num_leftovers,
- byte **err_pos, Uint *characters) {
- int copied = 0;
+static Uint copy_utf8_bin(byte *target, byte *source, Uint size,
+ byte *leftover, int *num_leftovers,
+ byte **err_pos, Uint *characters)
+{
+ Uint copied = 0;
if (leftover != NULL && *num_leftovers) {
int need = utf8_len(leftover[0]);
int from_source = need - (*num_leftovers);
- int c;
+ Uint c;
byte *tmp_err_pos = NULL;
ASSERT(need > 0);
ASSERT(from_source > 0);
@@ -502,8 +504,8 @@ L_Again: /* Restart with sublist, old listend was pushed on stack */
}
-static Eterm do_build_utf8(Process *p, Eterm ioterm, int *left, int latin1,
- byte *target, int *pos, Uint *characters, int *err,
+static Eterm do_build_utf8(Process *p, Eterm ioterm, Sint *left, int latin1,
+ byte *target, Uint *pos, Uint *characters, int *err,
byte *leftover, int *num_leftovers)
{
int c;
@@ -573,7 +575,7 @@ static Eterm do_build_utf8(Process *p, Eterm ioterm, int *left, int latin1,
}
if (!latin1) {
- int num;
+ Uint num;
byte *err_pos = NULL;
num = copy_utf8_bin(target + (*pos), bytes,
size, leftover, num_leftovers,&err_pos,characters);
@@ -804,7 +806,7 @@ static int check_leftovers(byte *source, int size)
-static BIF_RETTYPE build_utf8_return(Process *p,Eterm bin,int pos,
+static BIF_RETTYPE build_utf8_return(Process *p,Eterm bin,Uint pos,
Eterm rest_term,int err,
byte *leftover,int num_leftovers,Eterm latin1)
{
@@ -859,8 +861,8 @@ static BIF_RETTYPE characters_to_utf8_trap(BIF_ALIST_3)
#endif
byte* bytes;
Eterm rest_term;
- int left, sleft;
- int pos;
+ Sint left, sleft;
+ Uint pos;
int err;
byte leftover[4]; /* used for temp buffer too,
otherwise 3 bytes would have been enough */
@@ -874,7 +876,7 @@ static BIF_RETTYPE characters_to_utf8_trap(BIF_ALIST_3)
real_bin = binary_val(BIF_ARG_1);
ASSERT(*real_bin == HEADER_PROC_BIN);
#endif
- pos = (int) binary_size(BIF_ARG_1);
+ pos = binary_size(BIF_ARG_1);
bytes = binary_bytes(BIF_ARG_1);
sleft = left = allowed_iterations(BIF_P);
err = 0;
@@ -934,9 +936,9 @@ BIF_RETTYPE unicode_characters_to_binary_2(BIF_ALIST_2)
int latin1;
Eterm bin;
byte *bytes;
- int pos;
+ Uint pos;
int err;
- int left, sleft;
+ Sint left, sleft;
Eterm rest_term, subject;
byte leftover[4]; /* used for temp buffer too, o
therwise 3 bytes would have been enough */
@@ -999,7 +1001,7 @@ BIF_RETTYPE unicode_characters_to_binary_2(BIF_ALIST_2)
byte *t = NULL;
Uint sz = binary_size(bin);
byte *by = erts_get_aligned_binary_bytes(bin,&t);
- int i;
+ Uint i;
erts_printf("<<");
for (i = 0;i < sz; ++i) {
erts_printf((i == sz -1) ? "0x%X" : "0x%X, ", (unsigned) by[i]);
@@ -1007,7 +1009,7 @@ BIF_RETTYPE unicode_characters_to_binary_2(BIF_ALIST_2)
erts_printf(">>: ");
erts_free_aligned_binary_bytes(t);
}
- erts_printf("%d - %d = %d\n",sleft,left,sleft - left);
+ erts_printf("%ld - %ld = %ld\n", sleft, left, sleft - left);
}
#endif
cost_to_proc(BIF_P, sleft - left);
@@ -1015,10 +1017,10 @@ BIF_RETTYPE unicode_characters_to_binary_2(BIF_ALIST_2)
leftover,num_leftovers,BIF_ARG_2);
}
-static BIF_RETTYPE build_list_return(Process *p, byte *bytes, int pos, Uint characters,
+static BIF_RETTYPE build_list_return(Process *p, byte *bytes, Uint pos, Uint characters,
Eterm rest_term, int err,
byte *leftover, int num_leftovers,
- Eterm latin1, int left)
+ Eterm latin1, Sint left)
{
Eterm *hp;
@@ -1070,11 +1072,11 @@ static BIF_RETTYPE characters_to_list_trap_1(BIF_ALIST_3)
{
RestartContext *rc;
byte* bytes;
- int pos;
+ Uint pos;
Uint characters;
int err;
Eterm rest_term;
- int left, sleft;
+ Sint left, sleft;
int latin1 = 0;
byte leftover[4]; /* used for temp buffer too,
@@ -1107,9 +1109,9 @@ BIF_RETTYPE unicode_characters_to_list_2(BIF_ALIST_2)
int latin1;
Uint characters = 0;
byte *bytes;
- int pos;
+ Uint pos;
int err;
- int left, sleft;
+ Sint left, sleft;
Eterm rest_term;
byte leftover[4]; /* used for temp buffer too, o
therwise 3 bytes would have been enough */
@@ -1541,7 +1543,7 @@ static BIF_RETTYPE finalize_list_to_list(Process *p,
Uint num_processed_bytes,
Uint num_bytes_to_process,
Uint num_resulting_chars,
- int state, int left,
+ int state, Sint left,
Eterm tail)
{
Uint num_built; /* characters */
@@ -2016,7 +2018,7 @@ char *erts_convert_filename_to_encoding(Eterm name, char *statbuf, size_t statbu
++need;
}
if (used)
- *used = (Sint) need;
+ *used = need;
if (need+extra > statbuf_size) {
name_buf = (char *) erts_alloc(alloc_type, need+extra);
} else {
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index 1abcc6cbf4..b76b9cd874 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -947,7 +947,7 @@ ERTS_GLB_INLINE Eterm erts_equeue_get(ErtsEQueue *q) {
void erts_emasculate_writable_binary(ProcBin* pb);
Eterm erts_new_heap_binary(Process *p, byte *buf, int len, byte** datap);
-Eterm erts_new_mso_binary(Process*, byte*, int);
+Eterm erts_new_mso_binary(Process*, byte*, Uint);
Eterm new_binary(Process*, byte*, Uint);
Eterm erts_realloc_binary(Eterm bin, size_t size);
diff --git a/erts/emulator/hipe/hipe_mode_switch.c b/erts/emulator/hipe/hipe_mode_switch.c
index f532d3151f..884331e969 100644
--- a/erts/emulator/hipe/hipe_mode_switch.c
+++ b/erts/emulator/hipe/hipe_mode_switch.c
@@ -174,6 +174,33 @@ void hipe_mode_switch_init(void)
make_catch(beam_catches_cons(hipe_beam_pc_throw, BEAM_CATCHES_NIL));
hipe_mfa_info_table_init();
+
+#if (defined(__i386__) || defined(__x86_64__)) && defined(__linux__)
+ /* Verify that the offset of c-p->hipe does not change.
+ The ErLLVM hipe backend depends on it being in a specific
+ position. Kostis et al has promised to fix this in upstream
+ llvm by OTP 20, so it should be possible to remove these asserts
+ after that. */
+ ERTS_CT_ASSERT(sizeof(ErtsPTabElementCommon) ==
+ (sizeof(Eterm) + /* id */
+ sizeof(((ErtsPTabElementCommon*)0)->refc) +
+ sizeof(ErtsTracer) + /* tracer */
+ sizeof(Uint) + /* trace_flags */
+ sizeof(erts_smp_atomic_t) + /* timer */
+ sizeof(((ErtsPTabElementCommon*)0)->u)));
+
+ ERTS_CT_ASSERT(offsetof(Process, hipe) ==
+ (sizeof(ErtsPTabElementCommon) + /* common */
+ sizeof(Eterm*) + /* htop */
+ sizeof(Eterm*) + /* stop */
+ sizeof(Eterm*) + /* heap */
+ sizeof(Eterm*) + /* hend */
+ sizeof(Uint) + /* heap_sz */
+ sizeof(Uint) + /* min_heap_size */
+ sizeof(Uint) + /* min_vheap_size */
+ sizeof(volatile unsigned long))); /* fp_exception */
+#endif
+
}
void hipe_set_call_trap(Uint *bfun, void *nfun, int is_closure)
diff --git a/erts/emulator/test/alloc_SUITE.erl b/erts/emulator/test/alloc_SUITE.erl
index 1f7b499dcb..84cf4921d3 100644
--- a/erts/emulator/test/alloc_SUITE.erl
+++ b/erts/emulator/test/alloc_SUITE.erl
@@ -73,16 +73,32 @@ migration(Cfg) ->
end.
erts_mmap(Config) when is_list(Config) ->
- case os:type() of
- {unix, _} ->
+ case {os:type(), mmsc_flags()} of
+ {{unix,_}, false} ->
[erts_mmap_do(Config, SCO, SCRPM, SCRFSD)
|| SCO <-[true,false], SCRFSD <-[1234,0], SCRPM <- [true,false]];
- {SkipOs,_} ->
+ {{unix,_}, Flags} ->
+ {skipped, Flags};
+ {{SkipOs,_},_} ->
{skipped,
lists:flatten(["Not run on "
| io_lib:format("~p",[SkipOs])])}
end.
+%% Check if there are ERL_FLAGS set that will mess up this test case
+mmsc_flags() ->
+ case mmsc_flags("ERL_FLAGS") of
+ false -> mmsc_flags("ERL_ZFLAGS");
+ Flags -> Flags
+ end.
+mmsc_flags(Env) ->
+ case os:getenv(Env) of
+ false -> false;
+ V -> case string:str(V, "+MMsc") of
+ 0 -> false;
+ P -> Env ++ "=" ++ string:substr(V, P)
+ end
+ end.
erts_mmap_do(Config, SCO, SCRPM, SCRFSD) ->
%% We use the number of schedulers + 1 * approx main carriers size
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index a1e1495480..a0e9f1bad6 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -45,7 +45,8 @@
nif_now_time/1, nif_cpu_time/1, nif_unique_integer/1,
nif_is_process_alive/1, nif_is_port_alive/1,
nif_term_to_binary/1, nif_binary_to_term/1,
- nif_port_command/1
+ nif_port_command/1,
+ nif_snprintf/1
]).
-export([many_args_100/100]).
@@ -79,8 +80,8 @@ all() ->
nif_now_time, nif_cpu_time, nif_unique_integer,
nif_is_process_alive, nif_is_port_alive,
nif_term_to_binary, nif_binary_to_term,
- nif_port_command
- ].
+ nif_port_command,
+ nif_snprintf].
init_per_testcase(_Case, Config) ->
Config.
@@ -1952,9 +1953,18 @@ nif_port_command(Config) ->
port_close(Port),
{'EXIT', {badarg, _}} = (catch port_command_nif(Port, "hello\n")),
+ ok.
+nif_snprintf(Config) ->
+ ensure_lib_loaded(Config),
+ <<"ok",0>> = format_term_nif(3,ok),
+ <<"o",0>> = format_term_nif(2,ok),
+ <<"\"hello world\"",0>> = format_term_nif(14,"hello world"),
+ <<"{{hello,world,-33},3.14",_/binary>> = format_term_nif(50,{{hello,world, -33}, 3.14, self()}),
+ <<"{{hello,world,-33},",0>> = format_term_nif(20,{{hello,world, -33}, 3.14, self()}),
ok.
+
%% The NIFs:
lib_version() -> undefined.
call_history() -> ?nif_stub.
@@ -2015,6 +2025,7 @@ is_port_alive_nif(_) -> ?nif_stub.
term_to_binary_nif(_, _) -> ?nif_stub.
binary_to_term_nif(_, _, _) -> ?nif_stub.
port_command_nif(_, _) -> ?nif_stub.
+format_term_nif(_,_) -> ?nif_stub.
%% maps
is_map_nif(_) -> ?nif_stub.
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index 73073ad59f..13846244d4 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -1998,6 +1998,23 @@ static ERL_NIF_TERM port_command(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
return atom_true;
}
+static ERL_NIF_TERM format_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifBinary obin;
+ unsigned int size;
+
+ if (!enif_get_uint(env, argv[0], &size))
+ return enif_make_badarg(env);
+ if (!enif_alloc_binary(size,&obin))
+ return enif_make_badarg(env);
+
+ if (enif_snprintf((char*)obin.data, (size_t)size, "%T", argv[1]) < 0)
+ return atom_false;
+
+ return enif_make_binary(env,&obin);
+}
+
+
static ErlNifFunc nif_funcs[] =
{
{"lib_version", 0, lib_version},
@@ -2073,7 +2090,8 @@ static ErlNifFunc nif_funcs[] =
{"is_port_alive_nif", 1, is_port_alive},
{"term_to_binary_nif", 2, term_to_binary},
{"binary_to_term_nif", 3, binary_to_term},
- {"port_command_nif", 2, port_command}
+ {"port_command_nif", 2, port_command},
+ {"format_term_nif", 2, format_term}
};
ERL_NIF_INIT(nif_SUITE,nif_funcs,load,reload,upgrade,unload)
diff --git a/erts/emulator/test/port_trace_SUITE.erl b/erts/emulator/test/port_trace_SUITE.erl
index bfdea0761b..5d9a75bcd3 100644
--- a/erts/emulator/test/port_trace_SUITE.erl
+++ b/erts/emulator/test/port_trace_SUITE.erl
@@ -31,7 +31,8 @@
failure_atom/1, failure_posix/1,
failure/1, output_term/1,
driver_output_term/1,
- send_term/1, driver_send_term/1]).
+ send_term/1, driver_send_term/1,
+ driver_remote_send_term/1]).
-define(ECHO_DRV_NOOP, 0).
-define(ECHO_DRV_OUTPUT, 1).
@@ -48,6 +49,7 @@
-define(ECHO_DRV_SEND_TERM, 12).
-define(ECHO_DRV_DRIVER_SEND_TERM, 13).
-define(ECHO_DRV_SAVE_CALLER, 14).
+-define(ECHO_DRV_REMOTE_SEND_TERM, 15).
suite() -> [{ct_hooks,[ts_install_cth]},
{timetrap, {seconds, 30}}].
@@ -60,7 +62,8 @@ all() ->
failure_atom, failure_posix,
failure, output_term,
driver_output_term,
- send_term, driver_send_term].
+ send_term, driver_send_term,
+ driver_remote_send_term].
init_per_suite(Config) ->
Config.
@@ -75,6 +78,13 @@ end_per_group(_GroupName, Config) ->
Config.
+init_per_testcase(driver_remote_send_term, Config) ->
+ case erlang:system_info(smp_support) of
+ false ->
+ {skip,"Only supported on smp systems"};
+ true ->
+ init_per_testcase(driver_remote_send_term_smp, Config)
+ end;
init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
erlang:trace(all, false, [all]),
os:unsetenv("OUTPUTV"),
@@ -543,6 +553,34 @@ driver_send_term(_Config) ->
ok.
+%% Test that driver_send_term from non-scheduler thread does not
+%% generate trace messages.
+driver_remote_send_term(_Config) ->
+
+ Flags = [send],
+ {Prt, S} = trace_and_open(Flags,[binary]),
+
+ erlang:port_command(Prt, <<?ECHO_DRV_REMOTE_SEND_TERM, 123456:32>>),
+ recv({echo, Prt, <<123456:32>>}),
+ [] = flush(),
+
+ Pid = spawn_link(
+ fun() ->
+ erlang:port_command(Prt, <<?ECHO_DRV_SAVE_CALLER>>),
+ S ! ok,
+ receive M -> S ! M end
+ end),
+ recv(ok),
+ erlang:trace(Pid, true, ['receive']),
+
+ erlang:port_command(Prt, <<?ECHO_DRV_REMOTE_SEND_TERM, 123456:32>>),
+ recv({echo, Prt, <<123456:32>>}),
+ [{trace, Pid, 'receive', {echo, Prt, <<123456:32>>}}] = flush(),
+
+ close(Prt, Flags),
+
+ ok.
+
%%%%%%%%%%%%%%%%%%%
%% Helper functions
%%%%%%%%%%%%%%%%%%%
@@ -598,7 +636,7 @@ f(From) ->
end.
recv(Msg) ->
- receive Msg -> ok after 100 -> ct:fail({did_not_get_data,Msg,flush()}) end.
+ receive Msg -> ok after 1000 -> ct:fail({did_not_get_data,Msg,flush()}) end.
load_drv(Config) ->
Path = proplists:get_value(data_dir, Config),
diff --git a/erts/emulator/test/port_trace_SUITE_data/echo_drv.c b/erts/emulator/test/port_trace_SUITE_data/echo_drv.c
index b5ae9389b4..b545523192 100644
--- a/erts/emulator/test/port_trace_SUITE_data/echo_drv.c
+++ b/erts/emulator/test/port_trace_SUITE_data/echo_drv.c
@@ -14,6 +14,13 @@ typedef struct _erl_drv_data {
ErlDrvTermData caller;
} EchoDrvData;
+struct remote_send_term {
+ char *buf;
+ int len;
+ ErlDrvTermData port;
+ ErlDrvTermData caller;
+};
+
#define ECHO_DRV_NOOP 0
#define ECHO_DRV_OUTPUT 1
#define ECHO_DRV_OUTPUT2 2
@@ -29,6 +36,7 @@ typedef struct _erl_drv_data {
#define ECHO_DRV_SEND_TERM 12
#define ECHO_DRV_DRIVER_SEND_TERM 13
#define ECHO_DRV_SAVE_CALLER 14
+#define ECHO_DRV_REMOTE_SEND_TERM 15
/* -------------------------------------------------------------------------
@@ -78,6 +86,8 @@ static ErlDrvEntry echo_drv_entry = {
NULL
};
+static void send_term_thread(void *);
+
/* -------------------------------------------------------------------------
** Entry functions
**/
@@ -200,6 +210,18 @@ static void echo_drv_output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) {
}
break;
}
+ case ECHO_DRV_REMOTE_SEND_TERM:
+ {
+ ErlDrvTid tid;
+ struct remote_send_term *t = malloc(sizeof(struct remote_send_term));
+ t->len = len-1;
+ t->buf = malloc(len-1);
+ t->port = driver_mk_port(port);
+ t->caller = data_p->caller;
+ memcpy(t->buf, buf+1, t->len);
+ erl_drv_thread_create("tmp_thread", &tid, send_term_thread, t, NULL);
+ break;
+ }
case ECHO_DRV_SAVE_CALLER:
data_p->caller = driver_caller(port);
break;
@@ -239,3 +261,17 @@ static ErlDrvSSizeT echo_drv_call(ErlDrvData drv_data,
memcpy(*rbuf, buf+command, len-command);
return len-command;
}
+
+static void send_term_thread(void *a)
+{
+ struct remote_send_term *t = (struct remote_send_term*)a;
+ ErlDrvTermData term[] = {
+ ERL_DRV_ATOM, driver_mk_atom("echo"),
+ ERL_DRV_PORT, t->port,
+ ERL_DRV_BUF2BINARY, (ErlDrvTermData)(t->buf),
+ (ErlDrvTermData)(t->len),
+ ERL_DRV_TUPLE, 3};
+ erl_drv_send_term(t->port, t->caller,
+ term, sizeof(term) / sizeof(ErlDrvTermData));
+ return;
+}
diff --git a/erts/epmd/test/epmd_SUITE.erl b/erts/epmd/test/epmd_SUITE.erl
index 763984267a..0f0a5acde7 100644
--- a/erts/epmd/test/epmd_SUITE.erl
+++ b/erts/epmd/test/epmd_SUITE.erl
@@ -23,64 +23,58 @@
% Timeout for test cases (rather long to work on slow machines)
--define(SHORT_TEST_TIMEOUT, ?t:seconds(30)). % Default
--define(MEDIUM_TEST_TIMEOUT, ?t:minutes(3)).
--define(LONG_TEST_TIMEOUT, ?t:minutes(10)).
+-define(MEDIUM_TEST_TIMEOUT, {minutes,3}).
+-define(LONG_TEST_TIMEOUT, {minutes,10}).
% Delay inserted into code
-define(SHORT_PAUSE, 100).
--define(MEDIUM_PAUSE, ?t:seconds(1)).
--define(LONG_PAUSE, ?t:seconds(5)).
+-define(MEDIUM_PAUSE, 1000).
+-define(LONG_PAUSE, 5000).
% Information about nodes
-record(node_info, {port, node_type, prot, lvsn, hvsn, node_name, extra}).
% Test server specific exports
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- init_per_testcase/2, end_per_testcase/2]).
-
--export(
- [
- register_name/1,
- register_name_ipv6/1,
- register_names_1/1,
- register_names_2/1,
- register_duplicate_name/1,
- unicode_name/1,
- long_unicode_name/1,
- get_port_nr/1,
- slow_get_port_nr/1,
- unregister_others_name_1/1,
- unregister_others_name_2/1,
- register_overflow/1,
- name_with_null_inside/1,
- name_null_terminated/1,
- stupid_names_req/1,
-
- no_data/1,
- one_byte/1,
- two_bytes/1,
- partial_packet/1,
- zero_length/1,
- too_large/1,
- alive_req_too_small_1/1,
- alive_req_too_small_2/1,
- alive_req_too_large/1,
-
- returns_valid_empty_extra/1,
- returns_valid_populated_extra_with_nulls/1,
-
- names_stdout/1,
-
- buffer_overrun_1/1,
- buffer_overrun_2/1,
- no_nonlocal_register/1,
- no_nonlocal_kill/1,
- no_live_killing/1,
-
- socket_reset_before_alive2_reply_is_written/1
- ]).
+-export([all/0, suite/0, groups/0, init_per_testcase/2, end_per_testcase/2]).
+
+-export([register_name/1,
+ register_name_ipv6/1,
+ register_names_1/1,
+ register_names_2/1,
+ register_duplicate_name/1,
+ unicode_name/1,
+ long_unicode_name/1,
+ get_port_nr/1,
+ slow_get_port_nr/1,
+ unregister_others_name_1/1,
+ unregister_others_name_2/1,
+ register_overflow/1,
+ name_with_null_inside/1,
+ name_null_terminated/1,
+ stupid_names_req/1,
+
+ no_data/1,
+ one_byte/1,
+ two_bytes/1,
+ partial_packet/1,
+ zero_length/1,
+ too_large/1,
+ alive_req_too_small_1/1,
+ alive_req_too_small_2/1,
+ alive_req_too_large/1,
+
+ returns_valid_empty_extra/1,
+ returns_valid_populated_extra_with_nulls/1,
+
+ names_stdout/1,
+
+ buffer_overrun_1/1,
+ buffer_overrun_2/1,
+ no_nonlocal_register/1,
+ no_nonlocal_kill/1,
+ no_live_killing/1,
+
+ socket_reset_before_alive2_reply_is_written/1]).
% Port we use for testing
@@ -88,7 +82,7 @@
-define(EPMDARGS,"-packet_timeout 1").
-define(DUMMY_PORT, 1000). % Port number to register
- % not in real use.
+% not in real use.
% Timeouts etc inside test cases. Time is in milliseconds.
-define(CONN_RETRY, 4). % Times to retry connecting
@@ -111,7 +105,9 @@
%% all/1
%%
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap, ?MEDIUM_TEST_TIMEOUT}].
all() ->
[register_name, register_name_ipv6,
@@ -134,105 +130,71 @@ groups() ->
[{buffer_overrun, [],
[buffer_overrun_1, buffer_overrun_2]}].
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
%%
%% Run before and after each test case
%%
init_per_testcase(_Func, Config) ->
- Dog = test_server:timetrap(?MEDIUM_TEST_TIMEOUT),
cleanup(),
- [{watchdog, Dog} | Config].
+ Config.
-end_per_testcase(_Func, Config) ->
+end_per_testcase(_Func, _Config) ->
cleanup(),
- Dog = ?config(watchdog, Config),
- catch test_server:timetrap_cancel(Dog), % We may have canceled already
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-register_name(doc) ->
- ["Register a name"];
-register_name(suite) ->
- [];
+%% Register a name
register_name(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line {ok,Sock} = register_node("foobar"),
- ?line ok = close(Sock), % Unregister
+ ok = epmdrun(),
+ {ok,Sock} = register_node("foobar"),
+ ok = close(Sock), % Unregister
ok.
-register_name_ipv6(doc) ->
- ["Register a name over IPv6"];
-register_name_ipv6(suite) ->
- [];
+%% Register a name over IPv6
register_name_ipv6(Config) when is_list(Config) ->
% Test if the host has an IPv6 loopback address
Res = gen_tcp:listen(0, [inet6, {ip, {0,0,0,0,0,0,0,1}}]),
case Res of
- {ok,LSock} ->
- gen_tcp:close(LSock),
- ?line ok = epmdrun(),
- ?line {ok,Sock} = register_node6("foobar6"),
- ?line ok = close(Sock), % Unregister
- ok;
- _Error ->
- {skip, "Host does not have an IPv6 loopback address"}
+ {ok,LSock} ->
+ gen_tcp:close(LSock),
+ ok = epmdrun(),
+ {ok,Sock} = register_node6("foobar6"),
+ ok = close(Sock), % Unregister
+ ok;
+ _Error ->
+ {skip, "Host does not have an IPv6 loopback address"}
end.
-register_names_1(doc) ->
- ["Register and unregister two nodes"];
-register_names_1(suite) ->
- [];
+%% Register and unregister two nodes
register_names_1(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line {ok,Sock1} = register_node("foobar"),
- ?line {ok,Sock2} = register_node("foozap"),
- ?line ok = close(Sock1), % Unregister
- ?line ok = close(Sock2), % Unregister
+ ok = epmdrun(),
+ {ok,Sock1} = register_node("foobar"),
+ {ok,Sock2} = register_node("foozap"),
+ ok = close(Sock1), % Unregister
+ ok = close(Sock2), % Unregister
ok.
-register_names_2(doc) ->
- ["Register and unregister two nodes"];
-register_names_2(suite) ->
- [];
+%% Register and unregister two nodes
register_names_2(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line {ok,Sock1} = register_node("foobar"),
- ?line {ok,Sock2} = register_node("foozap"),
- ?line ok = close(Sock2), % Unregister
- ?line ok = close(Sock1), % Unregister
+ ok = epmdrun(),
+ {ok,Sock1} = register_node("foobar"),
+ {ok,Sock2} = register_node("foozap"),
+ ok = close(Sock2), % Unregister
+ ok = close(Sock1), % Unregister
ok.
-register_duplicate_name(doc) ->
- ["Two nodes with the same name"];
-register_duplicate_name(suite) ->
- [];
+%% Two nodes with the same name
register_duplicate_name(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line {ok,Sock} = register_node("foobar"),
- ?line error = register_node("foobar"),
- ?line ok = close(Sock), % Unregister
+ ok = epmdrun(),
+ {ok,Sock} = register_node("foobar"),
+ error = register_node("foobar"),
+ ok = close(Sock), % Unregister
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-unicode_name(doc) ->
- ["Check that we can register and lookup a unicode name"];
-unicode_name(suite) ->
- [];
+%% Check that we can register and lookup a unicode name
unicode_name(Config) when is_list(Config) ->
ok = epmdrun(),
NodeName = [16#1f608],
@@ -244,10 +206,7 @@ unicode_name(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-long_unicode_name(doc) ->
- ["Check that we can register and lookup a long unicode name"];
-long_unicode_name(suite) ->
- [];
+%% Check that we can register and lookup a long unicode name
long_unicode_name(Config) when is_list(Config) ->
ok = epmdrun(),
BaseChar = 16#1f600,
@@ -273,101 +232,85 @@ register_node_v2(Port, NodeType, Prot, HVsn, LVsn, Name, Extra) ->
register_node_v2(Addr, Port, NodeType, Prot, HVsn, LVsn, Name, Extra) ->
Req = alive2_req(Port, NodeType, Prot, HVsn, LVsn, Name, Extra),
case send_req(Req, Addr) of
- {ok,Sock} ->
- case recv(Sock,4) of
- {ok, [?EPMD_ALIVE2_RESP,_Res=0,_C0,_C1]} ->
- {ok,Sock};
- Other ->
- test_server:format("recv on sock ~w: ~p~n",
- [Sock,Other]),
- error
- end;
- error ->
- error
+ {ok,Sock} ->
+ case recv(Sock,4) of
+ {ok, [?EPMD_ALIVE2_RESP,_Res=0,_C0,_C1]} ->
+ {ok,Sock};
+ Other ->
+ io:format("recv on sock ~w: ~p~n", [Sock,Other]),
+ error
+ end;
+ error ->
+ error
end.
% Internal function to fetch information about a node
port_please_v2(Name) ->
case send_req([?EPMD_PORT_PLEASE2_REQ,
- binary_to_list(unicode:characters_to_binary(Name))]) of
- {ok,Sock} ->
- case recv_until_sock_closes(Sock) of
- {ok, Resp} ->
- parse_port2_resp(Resp);
- Other ->
- test_server:format("recv on sock ~w: ~p~n",
- [Sock,Other]),
- error
- end;
- error ->
- error
+ binary_to_list(unicode:characters_to_binary(Name))]) of
+ {ok,Sock} ->
+ case recv_until_sock_closes(Sock) of
+ {ok, Resp} ->
+ parse_port2_resp(Resp);
+ Other ->
+ io:format("recv on sock ~w: ~p~n", [Sock,Other]),
+ error
+ end;
+ error ->
+ error
end.
parse_port2_resp(Resp) ->
case list_to_binary(Resp) of
- <<?EPMD_PORT2_RESP,Res,Port:16,NodeType,Prot,HVsn:16,LVsn:16,
- NLen:16,NodeName:NLen/binary,
- ELen:16,Extra:ELen/binary>> when Res =:= 0 ->
- {ok, #node_info{port=Port,node_type=NodeType,prot=Prot,
- hvsn=HVsn,lvsn=LVsn,
- node_name=unicode:characters_to_list(NodeName),
- extra=binary_to_list(Extra)}};
- _Other ->
- test_server:format("invalid port2 resp: ~p~n",
- [Resp]),
- error
+ <<?EPMD_PORT2_RESP,Res,Port:16,NodeType,Prot,HVsn:16,LVsn:16,
+ NLen:16,NodeName:NLen/binary,
+ ELen:16,Extra:ELen/binary>> when Res =:= 0 ->
+ {ok, #node_info{port=Port,node_type=NodeType,prot=Prot,
+ hvsn=HVsn,lvsn=LVsn,
+ node_name=unicode:characters_to_list(NodeName),
+ extra=binary_to_list(Extra)}};
+ _Other ->
+ io:format("invalid port2 resp: ~p~n", [Resp]),
+ error
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-name_with_null_inside(doc) ->
- ["Register a name with a null char in it"];
-name_with_null_inside(suite) ->
- [];
+%% Register a name with a null char in it
name_with_null_inside(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line error = register_node("foo\000bar"),
+ ok = epmdrun(),
+ error = register_node("foo\000bar"),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-name_null_terminated(doc) ->
- ["Register a name with terminating null byte"];
-name_null_terminated(suite) ->
- [];
+%% Register a name with terminating null byte
name_null_terminated(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line error = register_node("foobar\000"),
+ ok = epmdrun(),
+ error = register_node("foobar\000"),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-stupid_names_req(doc) ->
- ["Read names from epmd in a stupid way"];
-stupid_names_req(suite) ->
- [];
+%% Read names from epmd in a stupid way
stupid_names_req(Config) when is_list(Config) ->
- Dog = ?config(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- LongDog = test_server:timetrap(?MEDIUM_TEST_TIMEOUT),
- ?line ok = epmdrun(),
- ?line [FirstConn | Conn] = register_many(1, ?REG_REPEAT_LIM, "foo"),
- ?line unregister_many([FirstConn]),
+ ok = epmdrun(),
+ [FirstConn | Conn] = register_many(1, ?REG_REPEAT_LIM, "foo"),
+ unregister_many([FirstConn]),
sleep(?MEDIUM_PAUSE),
- ?line ok = check_names(Conn),
- ?line ok = unregister_many(Conn),
- test_server:timetrap_cancel(LongDog),
+ ok = check_names(Conn),
+ ok = unregister_many(Conn),
ok.
check_names(Conn) ->
- ?line {ok,Sock} = connect_active(),
- ?line {ok,Reply} = do_get_names(Sock),
- ?line SortConn = lists:sort(Conn),
- ?line SortReply = lists:sort(Reply),
- ?line ok = check_names_cmp(SortConn, SortReply),
+ {ok,Sock} = connect_active(),
+ {ok,Reply} = do_get_names(Sock),
+ SortConn = lists:sort(Conn),
+ SortReply = lists:sort(Reply),
+ ok = check_names_cmp(SortConn, SortReply),
ok.
-
+
% Compare if the result was the same as was registered
@@ -381,43 +324,43 @@ check_names_cmp([{Name,Port,_Sock} | Conn], [{Name,Port} | Reply]) ->
-define(int16(X), [(X bsr 8) band 16#ff, X band 16#ff]).
-define(u32(X1,X2,X3,X4),
- (((X1) bsl 24) bor ((X2) bsl 16) bor ((X3) bsl 8) bor X4)).
+ (((X1) bsl 24) bor ((X2) bsl 16) bor ((X3) bsl 8) bor X4)).
do_get_names(Socket) ->
inet_tcp:send(Socket, [?int16(1),?EPMD_NAMES_REQ]),
receive
- {tcp, Socket, [P0,P1,P2,P3 | T]} ->
- EpmdPort = ?u32(P0,P1,P2,P3),
- if EpmdPort == ?PORT ->
- names_loop(Socket, T, []);
- true ->
- close(Socket),
- {error, address}
- end;
- {tcp_closed, Socket} ->
- {ok, []}
+ {tcp, Socket, [P0,P1,P2,P3 | T]} ->
+ EpmdPort = ?u32(P0,P1,P2,P3),
+ if EpmdPort == ?PORT ->
+ names_loop(Socket, T, []);
+ true ->
+ close(Socket),
+ {error, address}
+ end;
+ {tcp_closed, Socket} ->
+ {ok, []}
end.
names_loop(Socket, Acc, Ps) ->
receive
- {tcp, Socket, Bytes} ->
- {NAcc, NPs} = scan_names(Acc ++ Bytes, Ps),
- names_loop(Socket, NAcc, NPs);
- {tcp_closed, Socket} ->
- {_, NPs} = scan_names(Acc, Ps), % Really needed?
- {ok, NPs}
+ {tcp, Socket, Bytes} ->
+ {NAcc, NPs} = scan_names(Acc ++ Bytes, Ps),
+ names_loop(Socket, NAcc, NPs);
+ {tcp_closed, Socket} ->
+ {_, NPs} = scan_names(Acc, Ps), % Really needed?
+ {ok, NPs}
end.
scan_names(Buf, Ps) ->
case scan_line(Buf, []) of
- {Line, NBuf} ->
- case parse_line(Line) of
- {ok, Entry} ->
- scan_names(NBuf, [Entry | Ps]);
- error ->
- scan_names(NBuf, Ps)
- end;
- [] -> {Buf, Ps}
+ {Line, NBuf} ->
+ case parse_line(Line) of
+ {ok, Entry} ->
+ scan_names(NBuf, [Entry | Ps]);
+ error ->
+ scan_names(NBuf, Ps)
+ end;
+ [] -> {Buf, Ps}
end.
scan_line([$\n | Buf], Line) -> {lists:reverse(Line), Buf};
@@ -426,16 +369,16 @@ scan_line([], _) -> [].
parse_line([$n,$a,$m,$e,$ | Buf0]) ->
case parse_name(Buf0, []) of
- {Name, Buf1} ->
- case Buf1 of
- [$a,$t,$ ,$p,$o,$r,$t,$ | Buf2] ->
- case catch list_to_integer(Buf2) of
- {'EXIT', _} -> error;
- Port -> {ok, {Name, Port}}
- end;
- _ -> error
- end;
- error -> error
+ {Name, Buf1} ->
+ case Buf1 of
+ [$a,$t,$ ,$p,$o,$r,$t,$ | Buf2] ->
+ case catch list_to_integer(Buf2) of
+ {'EXIT', _} -> error;
+ Port -> {ok, {Name, Port}}
+ end;
+ _ -> error
+ end;
+ error -> error
end;
parse_line(_) -> error.
@@ -447,17 +390,11 @@ parse_name([], _Name) -> error.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-get_port_nr(doc) ->
- ["Register a name on a port and ask about port nr"];
-get_port_nr(suite) ->
- [];
+%% Register a name on a port and ask about port nr
get_port_nr(Config) when is_list(Config) ->
port_request([?EPMD_PORT_PLEASE2_REQ,"foo"]).
-slow_get_port_nr(doc) ->
- ["Register with slow write and ask about port nr"];
-slow_get_port_nr(suite) ->
- [];
+%% Register with slow write and ask about port nr
slow_get_port_nr(Config) when is_list(Config) ->
port_request([?EPMD_PORT_PLEASE2_REQ,d,$f,d,$o,d,$o]).
@@ -465,142 +402,127 @@ slow_get_port_nr(Config) when is_list(Config) ->
% Internal function used above
port_request(M) ->
- ?line ok = epmdrun(),
+ ok = epmdrun(),
Port = 1042,
- ?line {ok,RSock} = register_node("foo", Port),
- ?line {ok,Sock} = connect(),
- ?line ok = send(Sock,[size16(M),M]),
- ?line case recv_until_sock_closes(Sock) of
- {ok, Resp} ->
- ?line close(RSock),
- ?line {ok,Rec} = parse_port2_resp(Resp),
- ?line Port = Rec#node_info.port,
- ok;
- Other ->
- ?line close(RSock),
- ?line test_server:format("recv on sock ~w: ~p~n",
- [Sock,Other]),
- ?line throw({error,Other})
- end,
+ {ok,RSock} = register_node("foo", Port),
+ {ok,Sock} = connect(),
+ ok = send(Sock,[size16(M),M]),
+ case recv_until_sock_closes(Sock) of
+ {ok, Resp} ->
+ close(RSock),
+ {ok,Rec} = parse_port2_resp(Resp),
+ Port = Rec#node_info.port,
+ ok;
+ Other ->
+ close(RSock),
+ io:format("recv on sock ~w: ~p~n", [Sock,Other]),
+ throw({error,Other})
+ end,
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-unregister_others_name_1(doc) ->
- ["Unregister name of other node"];
-unregister_others_name_1(suite) ->
- [];
+%% Unregister name of other node
unregister_others_name_1(Config) when is_list(Config) ->
- ?line ok = epmdrun("-relaxed_command_check"),
- ?line {ok,RSock} = register_node("foo"),
- ?line {ok,Sock} = connect(),
+ ok = epmdrun("-relaxed_command_check"),
+ {ok,RSock} = register_node("foo"),
+ {ok,Sock} = connect(),
M = [?EPMD_STOP_REQ,"foo"],
- ?line ok = send(Sock,[size16(M),M]),
+ ok = send(Sock,[size16(M),M]),
R = "STOPPED",
- ?line {ok,R} = recv(Sock,length(R)),
- ?line ok = close(RSock),
+ {ok,R} = recv(Sock,length(R)),
+ ok = close(RSock),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-unregister_others_name_2(doc) ->
- ["Unregister name of other node"];
-unregister_others_name_2(suite) ->
- [];
+%% Unregister name of other node
unregister_others_name_2(Config) when is_list(Config) ->
- ?line ok = epmdrun("-relaxed_command_check"),
- ?line {ok,Sock} = connect(),
+ ok = epmdrun("-relaxed_command_check"),
+ {ok,Sock} = connect(),
M = [?EPMD_STOP_REQ,"xxx42"],
- ?line ok = send(Sock,[size16(M),M]),
+ ok = send(Sock,[size16(M),M]),
R = "NOEXIST",
- ?line {ok,R} = recv(Sock,length(R)),
+ {ok,R} = recv(Sock,length(R)),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-register_overflow(doc) ->
- ["Register too many, clean and redo 10 times"];
-register_overflow(suite) ->
- [];
+%% Register too many, clean and redo 10 times
register_overflow(Config) when is_list(Config) ->
- Dog = ?config(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- LongDog = test_server:timetrap(?LONG_TEST_TIMEOUT),
- ?line ok = epmdrun(),
- ?line Conn = register_many(1, ?REG_REPEAT_LIM, "foo"),
+ ct:timetrap(?LONG_TEST_TIMEOUT),
+ ok = epmdrun(),
+ Conn = register_many(1, ?REG_REPEAT_LIM, "foo"),
Count = length(Conn),
- ?line ok = unregister_many(Conn),
+ ok = unregister_many(Conn),
sleep(?MEDIUM_PAUSE),
- test_server:format("Limit was ~w names, now reg/unreg all 10 times~n",
- [Count]),
- ?line ok = register_repeat(Count),
+ io:format("Limit was ~w names, now reg/unreg all 10 times~n", [Count]),
+ ok = register_repeat(Count),
sleep(?MEDIUM_PAUSE),
- ?line ok = rregister_repeat(Count),
+ ok = rregister_repeat(Count),
sleep(?MEDIUM_PAUSE),
- ?line ok = register_repeat(Count),
+ ok = register_repeat(Count),
sleep(?MEDIUM_PAUSE),
- ?line ok = rregister_repeat(Count),
+ ok = rregister_repeat(Count),
sleep(?MEDIUM_PAUSE),
- ?line ok = register_repeat(Count),
+ ok = register_repeat(Count),
sleep(?MEDIUM_PAUSE),
- ?line ok = rregister_repeat(Count),
+ ok = rregister_repeat(Count),
sleep(?MEDIUM_PAUSE),
- ?line ok = register_repeat(Count),
+ ok = register_repeat(Count),
sleep(?MEDIUM_PAUSE),
- ?line ok = rregister_repeat(Count),
+ ok = rregister_repeat(Count),
sleep(?MEDIUM_PAUSE),
- ?line ok = register_repeat(Count),
+ ok = register_repeat(Count),
sleep(?MEDIUM_PAUSE),
- ?line ok = rregister_repeat(Count),
- test_server:timetrap_cancel(LongDog),
+ ok = rregister_repeat(Count),
ok.
register_repeat(Count) ->
Conn = register_many(1, ?REG_REPEAT_LIM, "foo"),
ok = unregister_many(Conn),
if
- length(Conn) == Count ->
- ok;
- true ->
- error
+ length(Conn) == Count ->
+ ok;
+ true ->
+ error
end.
rregister_repeat(Count) ->
Conn = register_many(1, ?REG_REPEAT_LIM, "foo"),
ok = unregister_many(lists:reverse(Conn)),
if
- length(Conn) == Count ->
- ok;
- true ->
- error
+ length(Conn) == Count ->
+ ok;
+ true ->
+ error
end.
% Return count of successful registrations
register_many(I, N, _Prefix) when I > N ->
- test_server:format("Done with all ~n", []),
+ io:format("Done with all ~n", []),
[];
register_many(I, N, Prefix) ->
Name = gen_name(Prefix, I),
Port = ?DUMMY_PORT + I, % Just make it up
case register_node(Name, Port) of
- {ok,Sock} ->
- [{Name,Port,Sock} | register_many(I + 1, N, Prefix)];
- Any ->
- test_server:format("Can't register: ~w of 1..~w ~w~n",
- [Name,N,Any]),
- []
+ {ok,Sock} ->
+ [{Name,Port,Sock} | register_many(I + 1, N, Prefix)];
+ Any ->
+ test_server:format("Can't register: ~w of 1..~w ~w~n", [Name,N,Any]),
+ []
end.
unregister_many([]) ->
ok;
unregister_many([{Name,_Port,Sock} | Socks]) ->
case close(Sock) of
- ok ->
- unregister_many(Socks);
- Any ->
- test_server:format("Can't unregister: ~w reason ~w~n", [Name,Any]),
- error
+ ok ->
+ unregister_many(Socks);
+ Any ->
+ test_server:format("Can't unregister: ~w reason ~w~n", [Name,Any]),
+ error
end.
gen_name(Str,Int) ->
@@ -608,246 +530,203 @@ gen_name(Str,Int) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-no_data(doc) ->
- ["Open but send no data"];
-no_data(suite) ->
- [];
+%% Open but send no data
no_data(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line {ok,Sock} = connect(),
+ ok = epmdrun(),
+ {ok,Sock} = connect(),
sleep(?LONG_PAUSE),
- ?line closed = recv(Sock,1),
+ closed = recv(Sock,1),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-one_byte(doc) ->
- ["Send one byte only"];
-one_byte(suite) ->
- [];
+%% Send one byte only
one_byte(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line {ok,Sock} = connect(),
- ?line ok = send(Sock,[0]),
+ ok = epmdrun(),
+ {ok,Sock} = connect(),
+ ok = send(Sock,[0]),
sleep(?LONG_PAUSE),
- ?line closed = recv(Sock,1),
+ closed = recv(Sock,1),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-two_bytes(doc) ->
- ["Send packet size only"];
-two_bytes(suite) ->
- [];
+%% Send packet size only
two_bytes(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line {ok,Sock} = connect(),
- ?line ok = send(Sock,[put16(3)]),
+ ok = epmdrun(),
+ {ok,Sock} = connect(),
+ ok = send(Sock,[put16(3)]),
sleep(?LONG_PAUSE),
- ?line closed = recv(Sock,1),
+ closed = recv(Sock,1),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-partial_packet(doc) ->
- ["Got only part of a packet"];
-partial_packet(suite) ->
- [];
+%% Got only part of a packet
partial_packet(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line {ok,Sock} = connect(),
- ?line ok = send(Sock,[put16(100),"only a few bytes"]),
+ ok = epmdrun(),
+ {ok,Sock} = connect(),
+ ok = send(Sock,[put16(100),"only a few bytes"]),
sleep(?LONG_PAUSE),
- ?line closed = recv(Sock,1),
+ closed = recv(Sock,1),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-zero_length(doc) ->
- ["Invalid zero packet size"];
-zero_length(suite) ->
- [];
+%% Invalid zero packet size
zero_length(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line {ok,Sock} = connect(),
- ?line ok = send(Sock,[0,0,0,0,0,0,0,0,0,0]),
+ ok = epmdrun(),
+ {ok,Sock} = connect(),
+ ok = send(Sock,[0,0,0,0,0,0,0,0,0,0]),
sleep(?MEDIUM_PAUSE),
- ?line closed = recv(Sock,1),
+ closed = recv(Sock,1),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-too_large(doc) ->
- ["Invalid large packet"];
-too_large(suite) ->
- [];
+%% Invalid large packet
too_large(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line {ok,Sock} = connect(),
+ ok = epmdrun(),
+ {ok,Sock} = connect(),
Size = 63000,
M = lists:duplicate(Size, $z),
- ?line ok = send(Sock,[put16(Size),M]),
+ ok = send(Sock,[put16(Size),M]),
sleep(?MEDIUM_PAUSE),
% With such a large packet, even the writes can fail as the
% daemon closes before everything is delivered -> econnaborted
case recv(Sock,1) of
- closed -> ok;
- {error,econnaborted} -> ok;
- Other -> exit({unexpected,Other})
+ closed -> ok;
+ {error,econnaborted} -> ok;
+ Other -> exit({unexpected,Other})
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-alive_req_too_small_1(doc) ->
- ["Try to register but not enough data"];
-alive_req_too_small_1(suite) ->
- [];
+%% Try to register but not enough data
alive_req_too_small_1(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line {ok,Sock} = connect(),
+ ok = epmdrun(),
+ {ok,Sock} = connect(),
M = [?EPMD_ALIVE2_REQ, put16(?DUMMY_PORT),$M,0, put16(5),
- put16(5),put16(0)],
- ?line ok = send(Sock, [size16(M), M]),
+ put16(5),put16(0)],
+ ok = send(Sock, [size16(M), M]),
sleep(?MEDIUM_PAUSE),
- ?line closed = recv(Sock,1),
+ closed = recv(Sock,1),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-alive_req_too_small_2(doc) ->
- ["Try to register but not enough data"];
-alive_req_too_small_2(suite) ->
- [];
+%% Try to register but not enough data
alive_req_too_small_2(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line {ok,Sock} = connect(),
+ ok = epmdrun(),
+ {ok,Sock} = connect(),
M = [?EPMD_ALIVE2_REQ, put16(?DUMMY_PORT),$M,0, put16(5),
- put16(5)],
- ?line ok = send(Sock, [size16(M), M]),
+ put16(5)],
+ ok = send(Sock, [size16(M), M]),
sleep(?MEDIUM_PAUSE),
- ?line closed = recv(Sock,1),
+ closed = recv(Sock,1),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-alive_req_too_large(doc) ->
- ["Try to register but node name too large"];
-alive_req_too_large(suite) ->
- [];
+%% Try to register but node name too large
alive_req_too_large(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line {ok,Sock} = connect(),
- L = [
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- ],
+ ok = epmdrun(),
+ {ok,Sock} = connect(),
+ L = ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"],
S = length(lists:flatten(L)),
M = [?EPMD_ALIVE2_REQ, put16(?DUMMY_PORT),$M,0, put16(5),
- put16(5), put16(S),L,put16(0)],
- ?line ok = send(Sock, [size16(M), M]),
+ put16(5), put16(S),L,put16(0)],
+ ok = send(Sock, [size16(M), M]),
sleep(?MEDIUM_PAUSE),
- ?line {ok,[?EPMD_ALIVE2_RESP,1]} = recv(Sock,2),
+ {ok,[?EPMD_ALIVE2_RESP,1]} = recv(Sock,2),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-returns_valid_empty_extra(doc) ->
- ["Check that an empty extra is prefixed by a two byte length"];
-returns_valid_empty_extra(suite) ->
- [];
+%% Check that an empty extra is prefixed by a two byte length
returns_valid_empty_extra(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line {ok,Sock} = register_node_v2(4711, 72, 0, 5, 5, "foo", []),
- ?line {ok,#node_info{extra=[]}} = port_please_v2("foo"),
- ?line ok = close(Sock),
+ ok = epmdrun(),
+ {ok,Sock} = register_node_v2(4711, 72, 0, 5, 5, "foo", []),
+ {ok,#node_info{extra=[]}} = port_please_v2("foo"),
+ ok = close(Sock),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-returns_valid_populated_extra_with_nulls(doc) ->
- ["Check a populated extra with embedded null characters"];
-returns_valid_populated_extra_with_nulls(suite) ->
- [];
+%% Check a populated extra with embedded null characters
returns_valid_populated_extra_with_nulls(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line {ok,Sock} = register_node_v2(4711, 72, 0, 5, 5, "foo", "ABC\000\000"),
- ?line {ok,#node_info{extra="ABC\000\000"}} = port_please_v2("foo"),
- ?line ok = close(Sock),
+ ok = epmdrun(),
+ {ok,Sock} = register_node_v2(4711, 72, 0, 5, 5, "foo", "ABC\000\000"),
+ {ok,#node_info{extra="ABC\000\000"}} = port_please_v2("foo"),
+ ok = close(Sock),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-names_stdout(doc) ->
- ["Test that epmd -names prints registered nodes to stdout"];
-names_stdout(suite) ->
- [];
+%% Test that epmd -names prints registered nodes to stdout
names_stdout(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line {ok,Sock} = register_node("foobar"),
- ?line ok = epmdrun("-names"),
- ?line {ok, Data} = receive {_Port, {data, D}} -> {ok, D}
- after 10000 -> {error, timeout}
- end,
- ?line {match,_} = re:run(Data, "^epmd: up and running", [multiline]),
- ?line {match,_} = re:run(Data, "^name foobar at port", [multiline]),
- ?line ok = close(Sock),
+ ok = epmdrun(),
+ {ok,Sock} = register_node("foobar"),
+ ok = epmdrun("-names"),
+ {ok, Data} = receive {_Port, {data, D}} -> {ok, D}
+ after 10000 -> {error, timeout}
+ end,
+ {match,_} = re:run(Data, "^epmd: up and running", [multiline]),
+ {match,_} = re:run(Data, "^name foobar at port", [multiline]),
+ ok = close(Sock),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-buffer_overrun_1(suite) ->
- [];
-buffer_overrun_1(doc) ->
- ["Test security vulnerability in fake extra lengths in alive2_req"];
+%% Test security vulnerability in fake extra lengths in alive2_req
buffer_overrun_1(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line true = alltrue([hostile(N) || N <- lists:seq(1,10000)]),
+ ok = epmdrun(),
+ true = alltrue([hostile(N) || N <- lists:seq(1,10000)]),
ok.
-buffer_overrun_2(suite) ->
- [];
-buffer_overrun_2(doc) ->
- ["Test security vulnerability in fake extra lengths in alive2_req"];
+
+%% Test security vulnerability in fake extra lengths in alive2_req
buffer_overrun_2(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line [false | Rest] = [hostile2(N) || N <- lists:seq(255*4,10000)],
- ?line true = alltrue(Rest),
+ ok = epmdrun(),
+ [false | Rest] = [hostile2(N) || N <- lists:seq(255*4,10000)],
+ true = alltrue(Rest),
ok.
hostile(N) ->
try
- Bin= <<$x:8,4747:16,$M:8,0:8,5:16,5:16,5:16,"gurka",N:16>>,
- S = size(Bin),
- {ok,E}=connect_sturdy(),
- gen_tcp:send(E,[<<S:16>>,Bin]),
- closed = recv(E,1),
- gen_tcp:close(E),
- true
+ Bin= <<$x:8,4747:16,$M:8,0:8,5:16,5:16,5:16,"gurka",N:16>>,
+ S = size(Bin),
+ {ok,E}=connect_sturdy(),
+ gen_tcp:send(E,[<<S:16>>,Bin]),
+ closed = recv(E,1),
+ gen_tcp:close(E),
+ true
catch
- _:_ ->
- false
+ _:_ ->
+ false
end.
hostile2(N) ->
try
- B2 = list_to_binary(lists:duplicate(N,255)),
- Bin= <<$x:8,4747:16,$M:8,0:8,5:16,5:16,5:16,"gurka",N:16,B2/binary>>,
- S = size(Bin),
- {ok,E}=connect_sturdy(),
- gen_tcp:send(E,[<<S:16>>,Bin]),
- Z = recv(E,2),
- gen_tcp:close(E),
- (Z =:= closed) or (Z =:= {ok, [$y,1]})
+ B2 = list_to_binary(lists:duplicate(N,255)),
+ Bin= <<$x:8,4747:16,$M:8,0:8,5:16,5:16,5:16,"gurka",N:16,B2/binary>>,
+ S = size(Bin),
+ {ok,E}=connect_sturdy(),
+ gen_tcp:send(E,[<<S:16>>,Bin]),
+ Z = recv(E,2),
+ gen_tcp:close(E),
+ (Z =:= closed) or (Z =:= {ok, [$y,1]})
catch
- _A:_B ->
- false
+ _A:_B ->
+ false
end.
alltrue([]) ->
@@ -857,134 +736,124 @@ alltrue([true|T]) ->
alltrue([_|_]) ->
false.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-no_nonlocal_register(suite) ->
- [];
-no_nonlocal_register(doc) ->
- ["Ensure that we cannot register throug a nonlocal connection"];
+
+%% Ensure that we cannot register throug a nonlocal connection
no_nonlocal_register(Config) when is_list(Config) ->
- ?line case {os:find_executable("ssh"),ct:get_config(ssh_proxy_host)} of
- {SSH,Name} when is_list(Name), is_list(SSH) ->
- do_no_nonlocal_register(Config,Name);
- {false,_} ->
- {skip, "No ssh command found to create proxy"};
- _ ->
- {skip, "No ssh_proxy_host configured in ts.config"}
- end.
+ case {os:find_executable("ssh"),ct:get_config(ssh_proxy_host)} of
+ {SSH,Name} when is_list(Name), is_list(SSH) ->
+ do_no_nonlocal_register(Config,Name);
+ {false,_} ->
+ {skip, "No ssh command found to create proxy"};
+ _ ->
+ {skip, "No ssh_proxy_host configured in ts.config"}
+ end.
do_no_nonlocal_register(Config,SSHHost) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line ProxyPort = proxy_port(),
- ?line ok = ssh_proxy(SSHHost,ProxyPort),
+ ok = epmdrun(),
+ ProxyPort = proxy_port(),
+ ok = ssh_proxy(SSHHost,ProxyPort),
Res = try
- ?line Name = "gurka_"
- %++
- %integer_to_list(A1)++"_"++
- %integer_to_list(A2)++"_"++
- %integer_to_list(A3)++"_"++
- %integer_to_list(A4)
- ,
- ?line Bname = list_to_binary(Name),
- ?line NameS = byte_size(Bname),
- ?line Bin= <<$x:8,4747:16,$M:8,0:8,5:16,
- 5:16,NameS:16,Bname/binary,
- 0:16>>,
- ?line S = size(Bin),
- ?line {ok, E} = connect("localhost",ProxyPort,passive),
- ?line gen_tcp:send(E,[<<S:16>>,Bin]),
- ?line closed = recv(E,1),
- ?line gen_tcp:close(E),
- true
- catch
- _:_ ->
- false
- end,
+ Name = "gurka_"
+ %++
+ %integer_to_list(A1)++"_"++
+ %integer_to_list(A2)++"_"++
+ %integer_to_list(A3)++"_"++
+ %integer_to_list(A4)
+ ,
+ Bname = list_to_binary(Name),
+ NameS = byte_size(Bname),
+ Bin= <<$x:8,4747:16,$M:8,0:8,5:16,
+ 5:16,NameS:16,Bname/binary,
+ 0:16>>,
+ S = size(Bin),
+ {ok, E} = connect("localhost",ProxyPort,passive),
+ gen_tcp:send(E,[<<S:16>>,Bin]),
+ closed = recv(E,1),
+ gen_tcp:close(E),
+ true
+ catch
+ _:_ ->
+ false
+ end,
%erlang:display(Res),
true = Res,
ok.
-no_nonlocal_kill(suite) ->
- [];
-no_nonlocal_kill(doc) ->
- ["Ensure that we cannot kill through nonlocal connection"];
+%% Ensure that we cannot kill through nonlocal connection
no_nonlocal_kill(Config) when is_list(Config) ->
- ?line case {os:find_executable("ssh"),ct:get_config(ssh_proxy_host)} of
- {SSH,Name} when is_list(Name), is_list(SSH) ->
- do_no_nonlocal_kill(Config,Name);
- {false,_} ->
- {skip, "No ssh command found to create proxy"};
- _ ->
- {skip, "No ssh_proxy_host configured in ts.config"}
- end.
+ case {os:find_executable("ssh"),ct:get_config(ssh_proxy_host)} of
+ {SSH,Name} when is_list(Name), is_list(SSH) ->
+ do_no_nonlocal_kill(Config,Name);
+ {false,_} ->
+ {skip, "No ssh command found to create proxy"};
+ _ ->
+ {skip, "No ssh_proxy_host configured in ts.config"}
+ end.
do_no_nonlocal_kill(Config,SSHHost) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line ProxyPort = proxy_port(),
- ?line ok = ssh_proxy(SSHHost,ProxyPort),
+ ok = epmdrun(),
+ ProxyPort = proxy_port(),
+ ok = ssh_proxy(SSHHost,ProxyPort),
Res = try
- {ok, E} = connect("localhost",ProxyPort,passive),
- M = [?EPMD_KILL_REQ],
- send(E, [size16(M), M]),
- closed = recv(E,2),
- gen_tcp:close(E),
- sleep(?MEDIUM_PAUSE),
- {ok, E2} = connect("localhost",ProxyPort,passive),
- gen_tcp:close(E2),
- true
- catch
- _:_ ->
- false
- end,
+ {ok, E} = connect("localhost",ProxyPort,passive),
+ M = [?EPMD_KILL_REQ],
+ send(E, [size16(M), M]),
+ closed = recv(E,2),
+ gen_tcp:close(E),
+ sleep(?MEDIUM_PAUSE),
+ {ok, E2} = connect("localhost",ProxyPort,passive),
+ gen_tcp:close(E2),
+ true
+ catch
+ _:_ ->
+ false
+ end,
%erlang:display(Res),
true = Res,
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-no_live_killing(doc) ->
- ["Dont allow killing with live nodes or any unregistering w/o -relaxed_command_check"];
-no_live_killing(suite) ->
- [];
+
+%% Dont allow killing with live nodes or any unregistering w/o -relaxed_command_check
no_live_killing(Config) when is_list(Config) ->
- ?line ok = epmdrun(),
- ?line {ok,RSock} = register_node("foo"),
- ?line {ok,Sock} = connect(),
- ?line M = [?EPMD_KILL_REQ],
- ?line ok = send(Sock,[size16(M),M]),
- ?line {ok,"NO"} = recv(Sock,2),
- ?line close(Sock),
- ?line {ok,Sock2} = connect(),
- ?line M2 = [?EPMD_STOP_REQ,"foo"],
- ?line ok = send(Sock2,[size16(M2),M2]),
- ?line closed = recv(Sock2,1),
- ?line close(Sock2),
- ?line close(RSock),
- ?line sleep(?MEDIUM_PAUSE),
- ?line {ok,Sock3} = connect(),
- ?line M3 = [?EPMD_KILL_REQ],
- ?line ok = send(Sock3,[size16(M3),M3]),
- ?line {ok,"OK"} = recv(Sock3,2),
- ?line close(Sock3),
+ ok = epmdrun(),
+ {ok,RSock} = register_node("foo"),
+ {ok,Sock} = connect(),
+ M = [?EPMD_KILL_REQ],
+ ok = send(Sock,[size16(M),M]),
+ {ok,"NO"} = recv(Sock,2),
+ close(Sock),
+ {ok,Sock2} = connect(),
+ M2 = [?EPMD_STOP_REQ,"foo"],
+ ok = send(Sock2,[size16(M2),M2]),
+ closed = recv(Sock2,1),
+ close(Sock2),
+ close(RSock),
+ sleep(?MEDIUM_PAUSE),
+ {ok,Sock3} = connect(),
+ M3 = [?EPMD_KILL_REQ],
+ ok = send(Sock3,[size16(M3),M3]),
+ {ok,"OK"} = recv(Sock3,2),
+ close(Sock3),
ok.
-socket_reset_before_alive2_reply_is_written(doc) ->
- ["Check for regression - don't make zombie from node which "
- "sends TCP RST at wrong time"];
-socket_reset_before_alive2_reply_is_written(suite) ->
- [];
+%% Check for regression - don't make zombie from node which
+%% sends TCP RST at wrong time
socket_reset_before_alive2_reply_is_written(Config) when is_list(Config) ->
%% - delay_write for easier triggering of race condition
%% - relaxed_command_check for gracefull shutdown of epmd even if there
%% is stuck node.
- ?line ok = epmdrun("-delay_write 1 -relaxed_command_check"),
+ ok = epmdrun("-delay_write 1 -relaxed_command_check"),
%% We can't use send_req/1 directly as we want to do inet:setopts/2
%% on our socket.
- ?line {ok, Sock} = connect(),
+ {ok, Sock} = connect(),
%% Issuing close/1 on such socket will result in immediate RST packet.
- ?line ok = inet:setopts(Sock, [{linger, {true, 0}}]),
+ ok = inet:setopts(Sock, [{linger, {true, 0}}]),
Req = alive2_req(4711, 77, 0, 5, 5, "test", []),
- ?line ok = send(Sock, [size16(Req), Req]),
+ ok = send(Sock, [size16(Req), Req]),
timer:sleep(500), %% Wait for the first 1/2 of delay_write before closing
- ?line ok = close(Sock),
+ ok = close(Sock),
timer:sleep(500 + ?SHORT_PAUSE), %% Wait for the other 1/2 of delay_write
@@ -992,11 +861,11 @@ socket_reset_before_alive2_reply_is_written(Config) when is_list(Config) ->
%% Should be removed when this is issue is fixed there.
timer:sleep(1000),
- ?line {ok, SockForNames} = connect_active(),
+ {ok, SockForNames} = connect_active(),
%% And there should be no stuck nodes
- ?line {ok, []} = do_get_names(SockForNames),
- ?line ok = close(SockForNames),
+ {ok, []} = do_get_names(SockForNames),
+ ok = close(SockForNames),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1005,14 +874,14 @@ socket_reset_before_alive2_reply_is_written(Config) when is_list(Config) ->
cleanup() ->
sleep(?MEDIUM_PAUSE),
case connect() of
- {ok,Sock} ->
- M = [?EPMD_KILL_REQ],
- send(Sock, [size16(M), M]),
- recv(Sock,length("OK")),
- close(Sock),
- sleep(?MEDIUM_PAUSE);
- _ ->
- true
+ {ok,Sock} ->
+ M = [?EPMD_KILL_REQ],
+ send(Sock, [size16(M), M]),
+ recv(Sock,length("OK")),
+ close(Sock),
+ sleep(?MEDIUM_PAUSE);
+ _ ->
+ true
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1022,11 +891,11 @@ proxy_port() ->
?PORT+1.
ssh_proxy(SSHHost,ProxyPort) ->
- ?line Host = lists:nth(2,string:tokens(atom_to_list(node()),"@")),
+ Host = lists:nth(2,string:tokens(atom_to_list(node()),"@")),
% Requires proxy to be a unix host with the command 'read' accessible
- ?line osrun("ssh -L "++integer_to_list(ProxyPort)++":"++Host++":"
- ++integer_to_list(?PORT)++" "++SSHHost++" read").
-
+ osrun("ssh -L "++integer_to_list(ProxyPort)++":"++Host++":"
+ ++integer_to_list(?PORT)++" "++SSHHost++" read").
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1036,21 +905,21 @@ epmdrun() ->
epmdrun([]).
epmdrun(Args) ->
case os:find_executable(epmd) of
- false ->
- {error, {could_not_find_epmd_in_path}};
- Path ->
- epmdrun(Path,Args)
+ false ->
+ {error, {could_not_find_epmd_in_path}};
+ Path ->
+ epmdrun(Path,Args)
end.
epmdrun(Epmd,Args0) ->
- %% test_server:format("epmdrun() => Epmd = ~p",[Epmd]),
+ %% test_server:format("epmdrun() => Epmd = ~p",[Epmd]),
Args = case Args0 of
- [] ->
- [];
- O ->
- " "++O
- end,
- osrun("\"" ++ Epmd ++ "\"" ++ " " ?EPMDARGS " -port " ++ integer_to_list(?PORT) ++ Args).
+ [] ->
+ [];
+ O ->
+ " "++O
+ end,
+ osrun("\"" ++ Epmd ++ "\"" ++ " " ?EPMDARGS " -port " ++ integer_to_list(?PORT) ++ Args).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1059,7 +928,7 @@ epmdrun(Epmd,Args0) ->
osrun(Cmd) ->
_ = open_port({spawn, Cmd}, []),
ok.
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Wrappers of TCP functions
@@ -1084,16 +953,16 @@ connect(Addr, Port, Mode) ->
connect(Addr, Port, Mode, ?CONN_SLEEP, ?CONN_RETRY).
connect(Addr, Port, Mode, Sleep, Retry) ->
case connect_repeat(Addr, Retry, Port, Mode, Sleep) of
- {ok,Sock} ->
- {ok,Sock};
- {error,timeout} ->
- timeout;
- {error,Reason} ->
- test_server:format("connect: error: ~w~n",[Reason]),
- error;
- Any ->
- test_server:format("connect: unknown message: ~w~n",[Any]),
- exit(1)
+ {ok,Sock} ->
+ {ok,Sock};
+ {error,timeout} ->
+ timeout;
+ {error,Reason} ->
+ test_server:format("connect: error: ~w~n",[Reason]),
+ error;
+ Any ->
+ test_server:format("connect: unknown message: ~w~n",[Any]),
+ exit(1)
end.
@@ -1104,33 +973,33 @@ connect_repeat(Addr, 1, Port, Mode, _Sleep) ->
connect_mode(Addr,Port, Mode);
connect_repeat(Addr,Retry, Port, Mode, Sleep) ->
case connect_mode(Addr,Port, Mode) of
- {ok,Sock} ->
- {ok,Sock};
- {error,Reason} ->
- test_server:format("connect: error: ~w~n",[Reason]),
- timer:sleep(Sleep),
- connect_repeat(Addr, Retry - 1, Port, Mode, Sleep);
- Any ->
- test_server:format("connect: unknown message: ~w~n",[Any]),
- exit(1)
+ {ok,Sock} ->
+ {ok,Sock};
+ {error,Reason} ->
+ test_server:format("connect: error: ~w~n",[Reason]),
+ timer:sleep(Sleep),
+ connect_repeat(Addr, Retry - 1, Port, Mode, Sleep);
+ Any ->
+ test_server:format("connect: unknown message: ~w~n",[Any]),
+ exit(1)
end.
connect_mode(Addr,Port, active) ->
gen_tcp:connect(Addr, Port, [{packet, 0}], ?CONN_TIMEOUT);
connect_mode(Addr, Port, passive) ->
gen_tcp:connect(Addr, Port, [{packet, 0}, {active, false}],
- ?CONN_TIMEOUT).
+ ?CONN_TIMEOUT).
close(Sock) ->
case gen_tcp:close(Sock) of
- {error,_} ->
- error;
- ok ->
- ok;
- Any ->
- test_server:format("unknown message: ~w~n",[Any]),
- exit(1)
+ {error,_} ->
+ error;
+ ok ->
+ ok;
+ Any ->
+ test_server:format("unknown message: ~w~n",[Any]),
+ exit(1)
end.
recv(Sock, Len) ->
@@ -1138,19 +1007,19 @@ recv(Sock, Len) ->
recv(Sock, Len, Timeout) ->
case gen_tcp:recv(Sock, Len, Timeout) of
- {ok,[]} -> % Should not be the case
- recv(Sock, 1, 1); % any longer
- {ok,Data} ->
- {ok,Data};
- {error,timeout} ->
- timeout;
- {error,closed} ->
- closed;
- {error,_}=Error ->
- Error;
- Any ->
- test_server:format("unknown message: ~w~n",[Any]),
- exit(1)
+ {ok,[]} -> % Should not be the case
+ recv(Sock, 1, 1); % any longer
+ {ok,Data} ->
+ {ok,Data};
+ {error,timeout} ->
+ timeout;
+ {error,closed} ->
+ closed;
+ {error,_}=Error ->
+ Error;
+ Any ->
+ test_server:format("unknown message: ~w~n",[Any]),
+ exit(1)
end.
%% Send data to socket. The list can be non flat and contain
@@ -1159,12 +1028,12 @@ recv(Sock, Len, Timeout) ->
send(Sock, SendSpec) ->
case send(SendSpec, [], Sock) of
- {ok,[]} ->
- ok;
- {ok,RevBytes} ->
- send_direct(Sock, lists:reverse(RevBytes));
- Any ->
- Any
+ {ok,[]} ->
+ ok;
+ {ok,RevBytes} ->
+ send_direct(Sock, lists:reverse(RevBytes));
+ Any ->
+ Any
end.
@@ -1179,54 +1048,54 @@ send([Byte | Spec], RevBytes, Sock) when is_integer(Byte) ->
send(Spec, [Byte | RevBytes], Sock);
send([List | Spec], RevBytes, Sock) when is_list(List) ->
case send(List, RevBytes, Sock) of
- {ok,Left} ->
- send(Spec, Left, Sock);
- Other ->
- Other
+ {ok,Left} ->
+ send(Spec, Left, Sock);
+ Other ->
+ Other
end;
send([d | Spec], RevBytes, Sock) ->
send([{d,1000} | Spec], RevBytes, Sock);
send([{d,S} | Spec], RevBytes, Sock) ->
case send_direct(Sock, lists:reverse(RevBytes)) of
- ok ->
- timer:sleep(S),
- send(Spec, [], Sock);
- Any ->
- Any
+ ok ->
+ timer:sleep(S),
+ send(Spec, [], Sock);
+ Any ->
+ Any
end.
%%%%
send_direct(Sock, Bytes) ->
case gen_tcp:send(Sock, Bytes) of
- ok ->
- ok;
- {error, closed} ->
- closed;
- {error, _Reason} ->
- error;
- Any ->
- test_server:format("unknown message: ~w~n",[Any]),
- Any
+ ok ->
+ ok;
+ {error, closed} ->
+ closed;
+ {error, _Reason} ->
+ error;
+ Any ->
+ test_server:format("unknown message: ~w~n",[Any]),
+ Any
end.
send_req(Req) ->
send_req(Req, "localhost").
send_req(Req, Addr) ->
case connect(Addr) of
- {ok,Sock} ->
- case send(Sock, [size16(Req), Req]) of
- ok ->
- {ok,Sock};
- Other ->
- test_server:format("Failed to send ~w on sock ~w: ~w~n",
- [Req,Sock,Other]),
- error
- end;
- Other ->
- test_server:format("Connect failed when sending ~w: ~p~n",
- [Req, Other]),
- error
+ {ok,Sock} ->
+ case send(Sock, [size16(Req), Req]) of
+ ok ->
+ {ok,Sock};
+ Other ->
+ test_server:format("Failed to send ~w on sock ~w: ~w~n",
+ [Req,Sock,Other]),
+ error
+ end;
+ Other ->
+ test_server:format("Connect failed when sending ~w: ~p~n",
+ [Req, Other]),
+ error
end.
recv_until_sock_closes(Sock) ->
@@ -1234,12 +1103,12 @@ recv_until_sock_closes(Sock) ->
recv_until_sock_closes_2(Sock,AccData) ->
case recv(Sock,0) of
- {ok,Data} ->
- recv_until_sock_closes_2(Sock,AccData++Data);
- closed ->
- {ok,AccData};
- Other ->
- Other
+ {ok,Data} ->
+ recv_until_sock_closes_2(Sock,AccData++Data);
+ closed ->
+ {ok,AccData};
+ Other ->
+ Other
end.
sleep(MilliSeconds) ->
@@ -1261,7 +1130,7 @@ flat_count([H|T], N) when is_list(H) ->
flat_count([_|T], N) ->
flat_count(T, N);
flat_count([], N) -> N.
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%