aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/test')
-rw-r--r--erts/emulator/test/Makefile9
-rw-r--r--erts/emulator/test/binary_SUITE.erl56
-rw-r--r--erts/emulator/test/bs_construct_SUITE.erl86
-rw-r--r--erts/emulator/test/bs_match_int_SUITE.erl71
-rw-r--r--erts/emulator/test/distribution_SUITE.erl230
-rw-r--r--erts/emulator/test/driver_SUITE.erl82
-rw-r--r--erts/emulator/test/dump_SUITE.erl51
-rw-r--r--erts/emulator/test/efile_SUITE.erl45
-rw-r--r--erts/emulator/test/emulator_bench.spec1
-rw-r--r--erts/emulator/test/erts_debug_SUITE.erl15
-rw-r--r--erts/emulator/test/erts_test_utils.erl2
-rw-r--r--erts/emulator/test/fun_SUITE.erl2
-rw-r--r--erts/emulator/test/lcnt_SUITE.erl3
-rw-r--r--erts/emulator/test/net_SUITE.erl17
-rw-r--r--erts/emulator/test/persistent_term_SUITE.erl73
-rw-r--r--erts/emulator/test/small_SUITE.erl115
-rw-r--r--erts/emulator/test/socket_SUITE.erl233
-rw-r--r--erts/emulator/test/socket_test_evaluator.erl165
-rw-r--r--erts/emulator/test/statistics_SUITE.erl43
19 files changed, 968 insertions, 331 deletions
diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile
index 8c2054cb51..019af2162f 100644
--- a/erts/emulator/test/Makefile
+++ b/erts/emulator/test/Makefile
@@ -124,6 +124,7 @@ MODULES= \
send_term_SUITE \
sensitive_SUITE \
signal_SUITE \
+ small_SUITE \
smoke_test_SUITE \
$(SOCKET_MODULES) \
statistics_SUITE \
@@ -206,14 +207,10 @@ ERL_COMPILE_FLAGS +=
# ----------------------------------------------------
make_emakefile: $(NO_OPT_ERL_FILES) $(NATIVE_ERL_FILES)
- # This special rule can be removed when communication with R7B nodes
- # is no longer supported.
- $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) +compressed -o$(EBIN) \
- '*_SUITE_make' > $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) +compressed -o$(EBIN) \
$(MODULES) >> $(EMAKEFILE)
- $(ERL_TOP)/make/make_emakefile +no_copt +no_postopt $(ERL_COMPILE_FLAGS) \
- -o$(EBIN) $(NO_OPT_MODULES) >> $(EMAKEFILE)
+ $(ERL_TOP)/make/make_emakefile +no_copt +no_postopt +no_ssa_opt +no_bsm_opt \
+ $(ERL_COMPILE_FLAGS) -o$(EBIN) $(NO_OPT_MODULES) >> $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile +native $(ERL_COMPILE_FLAGS) \
-o$(EBIN) $(NATIVE_MODULES) >> $(EMAKEFILE)
diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl
index 563d60cc3f..4fb339926e 100644
--- a/erts/emulator/test/binary_SUITE.erl
+++ b/erts/emulator/test/binary_SUITE.erl
@@ -71,7 +71,8 @@
term2bin_tuple_fallbacks/1,
robustness/1,otp_8117/1,
otp_8180/1, trapping/1, large/1,
- error_after_yield/1, cmp_old_impl/1]).
+ error_after_yield/1, cmp_old_impl/1,
+ t2b_system_limit/1]).
%% Internal exports.
-export([sleeper/0,trapping_loop/4]).
@@ -79,7 +80,7 @@
suite() -> [{ct_hooks,[ts_install_cth]},
{timetrap,{minutes,4}}].
-all() ->
+all() ->
[copy_terms, conversions, deep_lists, deep_bitstr_lists,
t_split_binary, bad_split,
bad_list_to_binary, bad_binary_to_list, terms,
@@ -90,7 +91,8 @@ all() ->
b2t_used_big,
bad_binary_to_term_2, safe_binary_to_term2,
bad_binary_to_term, bad_terms, t_hash, bad_size,
- bad_term_to_binary, more_bad_terms, otp_5484, otp_5933,
+ bad_term_to_binary, t2b_system_limit, more_bad_terms,
+ otp_5484, otp_5933,
ordering, unaligned_order, gc_test,
bit_sized_binary_sizes, otp_6817, otp_8117, deep,
term2bin_tuple_fallbacks,
@@ -462,6 +464,54 @@ bad_term_to_binary(Config) when is_list(Config) ->
ok.
+t2b_system_limit(Config) when is_list(Config) ->
+ case erlang:system_info(wordsize) of
+ 8 ->
+ case proplists:get_value(system_total_memory,
+ memsup:get_system_memory_data()) of
+ Memory when is_integer(Memory),
+ Memory > 6*1024*1024*1024 ->
+ test_t2b_system_limit(),
+ garbage_collect(),
+ ok;
+ _ ->
+ {skipped, "Not enough memory on this machine"}
+ end;
+ 4 ->
+ {skipped, "Only interesting on 64-bit builds"}
+ end.
+
+test_t2b_system_limit() ->
+ io:format("Creating HugeBin~n", []),
+ Bits = ((1 bsl 32)+1)*8,
+ HugeBin = <<0:Bits>>,
+
+ io:format("Testing term_to_binary(HugeBin)~n", []),
+ {'EXIT',{system_limit,[{erlang,term_to_binary,
+ [HugeBin],
+ _} |_]}} = (catch term_to_binary(HugeBin)),
+
+ io:format("Testing term_to_binary(HugeBin, [compressed])~n", []),
+ {'EXIT',{system_limit,[{erlang,term_to_binary,
+ [HugeBin, [compressed]],
+ _} |_]}} = (catch term_to_binary(HugeBin, [compressed])),
+
+ %% Check that it works also after we have trapped...
+ io:format("Creating HugeListBin~n", []),
+ HugeListBin = [lists:duplicate(2000000,2000000), HugeBin],
+
+ io:format("Testing term_to_binary(HugeListBin)~n", []),
+ {'EXIT',{system_limit,[{erlang,term_to_binary,
+ [HugeListBin],
+ _} |_]}} = (catch term_to_binary(HugeListBin)),
+
+ io:format("Testing term_to_binary(HugeListBin, [compressed])~n", []),
+ {'EXIT',{system_limit,[{erlang,term_to_binary,
+ [HugeListBin, [compressed]],
+ _} |_]}} = (catch term_to_binary(HugeListBin, [compressed])),
+
+ ok.
+
%% Tests binary_to_term/1 and term_to_binary/1.
terms(Config) when is_list(Config) ->
diff --git a/erts/emulator/test/bs_construct_SUITE.erl b/erts/emulator/test/bs_construct_SUITE.erl
index ad05cb3689..8fab4f5bc4 100644
--- a/erts/emulator/test/bs_construct_SUITE.erl
+++ b/erts/emulator/test/bs_construct_SUITE.erl
@@ -16,8 +16,6 @@
%% limitations under the License.
%%
%% %CopyrightEnd%
-%%
-%% Purpose : Common utilities used by several optimization passes.
%%
-module(bs_construct_SUITE).
@@ -27,9 +25,9 @@
test1/1, test2/1, test3/1, test4/1, test5/1, testf/1,
not_used/1, in_guard/1,
mem_leak/1, coerce_to_float/1, bjorn/1, append_empty_is_same/1,
- huge_float_field/1, huge_binary/1, system_limit/1, badarg/1,
+ huge_float_field/1, system_limit/1, badarg/1,
copy_writable_binary/1, kostis/1, dynamic/1, bs_add/1,
- otp_7422/1, zero_width/1, bad_append/1, bs_add_overflow/1]).
+ otp_7422/1, zero_width/1, bad_append/1, bs_append_overflow/1]).
-include_lib("common_test/include/ct.hrl").
@@ -40,9 +38,9 @@ suite() ->
all() ->
[test1, test2, test3, test4, test5, testf, not_used,
in_guard, mem_leak, coerce_to_float, bjorn, append_empty_is_same,
- huge_float_field, huge_binary, system_limit, badarg,
+ huge_float_field, system_limit, badarg,
copy_writable_binary, kostis, dynamic, bs_add, otp_7422, zero_width,
- bad_append, bs_add_overflow].
+ bad_append, bs_append_overflow].
init_per_suite(Config) ->
Config.
@@ -543,56 +541,6 @@ huge_float_field(Config) when is_list(Config) ->
huge_float_check({'EXIT',{system_limit,_}}) -> ok;
huge_float_check({'EXIT',{badarg,_}}) -> ok.
-huge_binary(Config) when is_list(Config) ->
- ct:timetrap({seconds, 60}),
- 16777216 = size(<<0:(id(1 bsl 26)),(-1):(id(1 bsl 26))>>),
- garbage_collect(),
- FreeMem = free_mem(),
- io:format("Free memory (Mb): ~p\n", [FreeMem]),
- {Shift,Return} = case free_mem() of
- undefined ->
- %% This test has to be inlined inside the case to
- %% use a literal Shift
- garbage_collect(),
- id(<<0:((1 bsl 32)-1)>>),
- {32,ok};
- Mb when Mb > 600 ->
- garbage_collect(),
- id(<<0:((1 bsl 32)-1)>>),
- {32,ok};
- Mb when Mb > 300 ->
- garbage_collect(),
- id(<<0:((1 bsl 31)-1)>>),
- {31,"Limit huge binaries to 256 Mb"};
- Mb when Mb > 200 ->
- garbage_collect(),
- id(<<0:((1 bsl 30)-1)>>),
- {30,"Limit huge binary to 128 Mb"};
- _ ->
- garbage_collect(),
- id(<<0:((1 bsl 29)-1)>>),
- {29,"Limit huge binary to 64 Mb"}
- end,
- garbage_collect(),
- id(<<0:((1 bsl Shift)-1)>>),
- garbage_collect(),
- id(<<0:(id((1 bsl Shift)-1))>>),
- garbage_collect(),
- case Return of
- ok -> ok;
- Comment -> {comment, Comment}
- end.
-
-%% Return the amount of free memory in Mb.
-free_mem() ->
- {ok,Apps} = application:ensure_all_started(os_mon),
- Mem = memsup:get_system_memory_data(),
- [ok = application:stop(App)||App <- Apps],
- case proplists:get_value(free_memory,Mem) of
- undefined -> undefined;
- Val -> Val div (1024*1024)
- end.
-
system_limit(Config) when is_list(Config) ->
WordSize = erlang:system_info(wordsize),
BitsPerWord = WordSize * 8,
@@ -904,33 +852,37 @@ append_unit_8(Bin) ->
append_unit_16(Bin) ->
<<Bin/binary-unit:16,0:1>>.
-%% Produce a large result of bs_add that, if cast to signed int, would overflow
-%% into a negative number that fits a smallnum.
-bs_add_overflow(_Config) ->
+%% Test that the bs_append instruction will correctly check for
+%% overflow by producing a binary whose total size would exceed the
+%% maximum allowed size for a binary on a 32-bit computer.
+
+bs_append_overflow(_Config) ->
Memsize = memsize(),
io:format("Memsize = ~w Bytes~n", [Memsize]),
case erlang:system_info(wordsize) of
8 ->
+ %% Not possible to test on a 64-bit computer.
{skip, "64-bit architecture"};
_ when Memsize < (2 bsl 30) ->
- {skip, "Less then 2 GB of memory"};
+ {skip, "Less than 2 GB of memory"};
4 ->
- {'EXIT', {system_limit, _}} = (catch bs_add_overflow_signed()),
- {'EXIT', {system_limit, _}} = (catch bs_add_overflow_unsigned()),
+ {'EXIT', {system_limit, _}} = (catch bs_append_overflow_signed()),
+ erlang:garbage_collect(),
+ {'EXIT', {system_limit, _}} = (catch bs_append_overflow_unsigned()),
+ erlang:garbage_collect(),
ok
end.
-bs_add_overflow_signed() ->
- %% Produce a large result of bs_add that, if cast to signed int, would
+bs_append_overflow_signed() ->
+ %% Produce a large binary that, if cast to signed int, would
%% overflow into a negative number that fits a smallnum.
Large = <<0:((1 bsl 30)-1)>>,
<<Large/bits, Large/bits, Large/bits, Large/bits,
Large/bits, Large/bits, Large/bits, Large/bits,
Large/bits>>.
-bs_add_overflow_unsigned() ->
- %% Produce a large result of bs_add that goes beyond the limit of an
- %% unsigned word. This used to succeed but produced an incorrect result
+bs_append_overflow_unsigned() ->
+ %% The following would succeed but would produce an incorrect result
%% where B =:= C!
A = <<0:((1 bsl 32)-8)>>,
B = <<2, 3>>,
diff --git a/erts/emulator/test/bs_match_int_SUITE.erl b/erts/emulator/test/bs_match_int_SUITE.erl
index e913dc98b0..454e55d017 100644
--- a/erts/emulator/test/bs_match_int_SUITE.erl
+++ b/erts/emulator/test/bs_match_int_SUITE.erl
@@ -234,34 +234,49 @@ mml_choose(<<_A:8>>) -> single_byte_binary;
mml_choose(<<_A:8,_T/binary>>) -> multi_byte_binary.
match_huge_int(Config) when is_list(Config) ->
- Sz = 1 bsl 27,
- Bin = <<0:Sz,13:8>>,
- skip_huge_int_1(Sz, Bin),
- 0 = match_huge_int_1(Sz, Bin),
-
- %% Test overflowing the size of an integer field.
- nomatch = overflow_huge_int_skip_32(Bin),
- case erlang:system_info(wordsize) of
- 4 ->
- nomatch = overflow_huge_int_32(Bin);
- 8 ->
- %% An attempt will be made to allocate heap space for
- %% the bignum (which will probably fail); only if the
- %% allocation succeeds will the matching fail because
- %% the binary is too small.
- ok
- end,
- nomatch = overflow_huge_int_skip_64(Bin),
- nomatch = overflow_huge_int_64(Bin),
-
- %% Test overflowing the size of an integer field using variables as sizes.
- Sizes = case erlang:system_info(wordsize) of
- 4 -> lists:seq(25, 32);
- 8 -> []
- end ++ lists:seq(50, 64),
- ok = overflow_huge_int_unit128(Bin, Sizes),
-
- ok.
+ case ?MODULE of
+ bs_match_int_no_opt_SUITE ->
+ %% This test case is written with the assumption that
+ %% bs_skip2 instructions are used when the value of the
+ %% extracted segment will not be used. In OTP 21 and earlier, that
+ %% assumption was always true, because the bs_skip optimization
+ %% was included in v3_codegen and could not be disabled.
+ %% In OTP 22, the bs_skip optimization is done by beam_ssa_opt
+ %% and is disabled.
+ %%
+ %% On memory-constrained computers, using bs_get_integer2
+ %% instructions may cause the runtime system to terminate
+ %% because of insufficient memory.
+ {skip, "unoptimized code would use too much memory"};
+ bs_match_int_SUITE ->
+ Sz = 1 bsl 27,
+ Bin = <<0:Sz,13:8>>,
+ skip_huge_int_1(Sz, Bin),
+ 0 = match_huge_int_1(Sz, Bin),
+
+ %% Test overflowing the size of an integer field.
+ nomatch = overflow_huge_int_skip_32(Bin),
+ case erlang:system_info(wordsize) of
+ 4 ->
+ nomatch = overflow_huge_int_32(Bin);
+ 8 ->
+ %% An attempt will be made to allocate heap space for
+ %% the bignum (which will probably fail); only if the
+ %% allocation succeeds will the matching fail because
+ %% the binary is too small.
+ ok
+ end,
+ nomatch = overflow_huge_int_skip_64(Bin),
+ nomatch = overflow_huge_int_64(Bin),
+
+ %% Test overflowing the size of an integer field using
+ %% variables as sizes.
+ Sizes = case erlang:system_info(wordsize) of
+ 4 -> lists:seq(25, 32);
+ 8 -> []
+ end ++ lists:seq(50, 64),
+ ok = overflow_huge_int_unit128(Bin, Sizes)
+ end.
overflow_huge_int_unit128(Bin, [Sz0|Sizes]) ->
Sz = id(1 bsl Sz0),
diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl
index 449821e5ad..7885d35d9d 100644
--- a/erts/emulator/test/distribution_SUITE.erl
+++ b/erts/emulator/test/distribution_SUITE.erl
@@ -19,7 +19,6 @@
%%
-module(distribution_SUITE).
--compile(r16).
-define(VERSION_MAGIC, 131).
@@ -39,6 +38,8 @@
-define(Line,).
-export([all/0, suite/0, groups/0,
+ init_per_suite/1, end_per_suite/1,
+ init_per_group/2, end_per_group/2,
ping/1, bulk_send_small/1,
group_leader/1,
optimistic_dflags/1,
@@ -53,7 +54,6 @@
dist_parallel_send/1,
atom_roundtrip/1,
unicode_atom_roundtrip/1,
- atom_roundtrip_r16b/1,
contended_atom_cache_entry/1,
contended_unicode_atom_cache_entry/1,
bad_dist_structure/1,
@@ -67,7 +67,8 @@
message_latency_large_message/1,
message_latency_large_link_exit/1,
message_latency_large_monitor_exit/1,
- message_latency_large_exit2/1]).
+ message_latency_large_exit2/1,
+ system_limit/1]).
%% Internal exports.
-export([sender/3, receiver2/2, dummy_waiter/0, dead_process/0,
@@ -75,7 +76,7 @@
optimistic_dflags_echo/0, optimistic_dflags_sender/1,
roundtrip/1, bounce/1, do_dist_auto_connect/1, inet_rpc_server/1,
dist_parallel_sender/3, dist_parallel_receiver/0,
- dist_evil_parallel_receiver/0]).
+ dist_evil_parallel_receiver/0, make_busy/2]).
%% epmd_module exports
-export([start_link/0, register_node/2, register_node/3, port_please/2, address_please/3]).
@@ -93,11 +94,10 @@ all() ->
ref_port_roundtrip, nil_roundtrip, stop_dist,
{group, trap_bif}, {group, dist_auto_connect},
dist_parallel_send, atom_roundtrip, unicode_atom_roundtrip,
- atom_roundtrip_r16b,
contended_atom_cache_entry, contended_unicode_atom_cache_entry,
{group, message_latency},
{group, bad_dist}, {group, bad_dist_ext},
- start_epmd_false, epmd_module].
+ start_epmd_false, epmd_module, system_limit].
groups() ->
[{bulk_send, [], [bulk_send_small, bulk_send_big, bulk_send_bigbig]},
@@ -119,6 +119,28 @@ groups() ->
message_latency_large_exit2]}
].
+init_per_suite(Config) ->
+ {ok, Apps} = application:ensure_all_started(os_mon),
+ [{started_apps, Apps} | Config].
+
+end_per_suite(Config) ->
+ Apps = proplists:get_value(started_apps, Config),
+ [application:stop(App) || App <- lists:reverse(Apps)],
+ Config.
+
+init_per_group(message_latency, Config) ->
+ Free = free_memory(),
+ if Free < 2048 ->
+ {skip, "Not enough memory"};
+ true ->
+ Config
+ end;
+init_per_group(_, Config) ->
+ Config.
+
+end_per_group(_, Config) ->
+ Config.
+
%% Tests pinging a node in different ways.
ping(Config) when is_list(Config) ->
Times = 1024,
@@ -1134,23 +1156,6 @@ atom_roundtrip(Config) when is_list(Config) ->
stop_node(Node),
ok.
-atom_roundtrip_r16b(Config) when is_list(Config) ->
- case test_server:is_release_available("r16b") of
- true ->
- ct:timetrap({minutes, 6}),
- AtomData = unicode_atom_data(),
- verify_atom_data(AtomData),
- case start_node(Config, [], "r16b") of
- {ok, Node} ->
- do_atom_roundtrip(Node, AtomData),
- stop_node(Node);
- {error, timeout} ->
- {skip,"Unable to start OTP R16B release"}
- end;
- false ->
- {skip,"No OTP R16B available"}
- end.
-
unicode_atom_roundtrip(Config) when is_list(Config) ->
AtomData = unicode_atom_data(),
verify_atom_data(AtomData),
@@ -1456,11 +1461,14 @@ measure_latency_large_message(Nodename, DataFun) ->
Echo = spawn(N, fun F() -> receive {From, Msg} -> From ! Msg, F() end end),
- case erlang:system_info(build_type) of
- debug ->
+ BuildType = erlang:system_info(build_type),
+ WordSize = erlang:system_info(wordsize),
+
+ if
+ BuildType =/= opt; WordSize =:= 4 ->
%% Test 3.2 MB and 32 MB and test the latency difference of sent messages
Payloads = [{I, <<0:(I * 32 * 1024 * 8)>>} || I <- [1,10]];
- _ ->
+ true ->
%% Test 32 MB and 320 MB and test the latency difference of sent messages
Payloads = [{I, <<0:(I * 32 * 1024 * 1024 * 8)>>} || I <- [1,10]]
end,
@@ -1475,7 +1483,7 @@ measure_latency_large_message(Nodename, DataFun) ->
stop_node(N),
case {lists:max(Times), lists:min(Times)} of
- {Max, Min} when Max * 0.25 > Min ->
+ {Max, Min} when Max * 0.25 > Min, BuildType =:= opt ->
ct:fail({incorrect_latency, IndexTimes});
_ ->
ok
@@ -1500,13 +1508,19 @@ measure_latency(DataFun, Dropper, Echo, Payload) ->
ok
end || _ <- lists:seq(1,10)],
- {TS, _} =
+ {TS, Times} =
timer:tc(fun() ->
[begin
+ T0 = erlang:monotonic_time(),
Echo ! {self(), hello},
- receive hello -> ok end
+ receive hello -> ok end,
+ (erlang:monotonic_time() - T0) / 1000000
end || _ <- lists:seq(1,100)]
end),
+ Avg = lists:sum(Times) / length(Times),
+ StdDev = math:sqrt(lists:sum([math:pow(V - Avg,2) || V <- Times]) / length(Times)),
+ ct:pal("Times: Avg: ~p Max: ~p Min: ~p Var: ~p",
+ [Avg, lists:max(Times), lists:min(Times), StdDev]),
[begin
Sender ! die,
receive
@@ -1524,6 +1538,144 @@ flush() ->
ok
end.
+system_limit(Config) when is_list(Config) ->
+ case erlang:system_info(wordsize) of
+ 8 ->
+ case proplists:get_value(system_total_memory,
+ memsup:get_system_memory_data()) of
+ Memory when is_integer(Memory),
+ Memory > 6*1024*1024*1024 ->
+ test_system_limit(Config),
+ garbage_collect(),
+ ok;
+ _ ->
+ {skipped, "Not enough memory on this machine"}
+ end;
+ 4 ->
+ {skipped, "Only interesting on 64-bit builds"}
+ end.
+
+test_system_limit(Config) when is_list(Config) ->
+ Bits = ((1 bsl 32)+1)*8,
+ HugeBin = <<0:Bits>>,
+ HugeListBin = [lists:duplicate(2000000,2000000), HugeBin],
+ {ok, N1} = start_node(Config),
+ monitor_node(N1, true),
+ receive
+ {nodedown, N1} ->
+ ct:fail({unexpected_nodedown, N1})
+ after 0 ->
+ ok
+ end,
+ P1 = spawn(N1,
+ fun () ->
+ receive after infinity -> ok end
+ end),
+
+ io:format("~n** distributed send **~n~n", []),
+ try
+ P1 ! HugeBin,
+ exit(oops1)
+ catch
+ error:system_limit -> ok
+ end,
+ try
+ P1 ! HugeListBin,
+ exit(oops2)
+ catch
+ error:system_limit -> ok
+ end,
+
+ io:format("~n** distributed exit **~n~n", []),
+ try
+ exit(P1, HugeBin),
+ exit(oops3)
+ catch
+ error:system_limit -> ok
+ end,
+ try
+ exit(P1, HugeListBin),
+ exit(oops4)
+ catch
+ error:system_limit -> ok
+ end,
+
+ io:format("~n** distributed registered send **~n~n", []),
+ try
+ {missing_proc, N1} ! HugeBin,
+ exit(oops5)
+ catch
+ error:system_limit -> ok
+ end,
+ try
+ {missing_proc, N1} ! HugeListBin,
+ exit(oops6)
+ catch
+ error:system_limit -> ok
+ end,
+ receive
+ {nodedown, N1} ->
+ ct:fail({unexpected_nodedown, N1})
+ after 0 ->
+ ok
+ end,
+
+ %%
+ %% system_limit in exit reasons brings the
+ %% connection down...
+ %%
+
+ io:format("~n** distributed link exit **~n~n", []),
+ spawn(fun () ->
+ link(P1),
+ exit(HugeBin)
+ end),
+ receive {nodedown, N1} -> ok end,
+
+ {ok, N2} = start_node(Config),
+ monitor_node(N2, true),
+ P2 = spawn(N2,
+ fun () ->
+ receive after infinity -> ok end
+ end),
+ spawn(fun () ->
+ link(P2),
+ exit(HugeListBin)
+ end),
+ receive {nodedown, N2} -> ok end,
+
+ io:format("~n** distributed monitor down **~n~n", []),
+ {ok, N3} = start_node(Config),
+ monitor_node(N3, true),
+ Go1 = make_ref(),
+ LP1 = spawn(fun () ->
+ receive Go1 -> ok end,
+ exit(HugeBin)
+ end),
+ _ = spawn(N3,
+ fun () ->
+ _ = erlang:monitor(process, LP1),
+ LP1 ! Go1,
+ receive after infinity -> ok end
+ end),
+ receive {nodedown, N3} -> ok end,
+
+ {ok, N4} = start_node(Config),
+ monitor_node(N4, true),
+ Go2 = make_ref(),
+ LP2 = spawn(fun () ->
+ receive Go2 -> ok end,
+ exit(HugeListBin)
+ end),
+ _ = spawn(N4,
+ fun () ->
+ _ = erlang:monitor(process, LP2),
+ LP2 ! Go2,
+ receive after infinity -> ok end
+ end),
+ receive {nodedown, N4} -> ok end,
+ ok.
+
-define(COOKIE, '').
-define(DOP_LINK, 1).
-define(DOP_SEND, 2).
@@ -2845,3 +2997,23 @@ uint8(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 8 ->
Uint band 16#ff;
uint8(Uint) ->
exit({badarg, uint8, [Uint]}).
+
+free_memory() ->
+ %% Free memory in MB.
+ try
+ SMD = memsup:get_system_memory_data(),
+ {value, {free_memory, Free}} = lists:keysearch(free_memory, 1, SMD),
+ TotFree = (Free +
+ case lists:keysearch(cached_memory, 1, SMD) of
+ {value, {cached_memory, Cached}} -> Cached;
+ false -> 0
+ end +
+ case lists:keysearch(buffered_memory, 1, SMD) of
+ {value, {buffered_memory, Buffed}} -> Buffed;
+ false -> 0
+ end),
+ TotFree div (1024*1024)
+ catch
+ error : undef ->
+ ct:fail({"os_mon not built"})
+ end.
diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl
index bb0f3498ab..f6d7c55017 100644
--- a/erts/emulator/test/driver_SUITE.erl
+++ b/erts/emulator/test/driver_SUITE.erl
@@ -120,29 +120,6 @@
-define(heap_binary_size, 64).
-init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- CIOD = rpc(Config,
- fun() ->
- case catch erts_debug:get_internal_state(available_internal_state) of
- true -> ok;
- _ -> erts_debug:set_internal_state(available_internal_state, true)
- end,
- erts_debug:get_internal_state(check_io_debug)
- end),
- erlang:display({init_per_testcase, Case}),
- 0 = element(1, CIOD),
- [{testcase, Case}|Config].
-
-end_per_testcase(Case, Config) ->
- erlang:display({end_per_testcase, Case}),
- CIOD = rpc(Config,
- fun() ->
- get_stable_check_io_info(),
- erts_debug:get_internal_state(check_io_debug)
- end),
- 0 = element(1, CIOD),
- ok.
-
suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap, {minutes, 1}}].
@@ -219,6 +196,48 @@ end_per_group(_GroupName, Config) ->
end,
Config.
+init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
+ CIOD = rpc(Config,
+ fun() ->
+ case catch erts_debug:get_internal_state(available_internal_state) of
+ true -> ok;
+ _ -> erts_debug:set_internal_state(available_internal_state, true)
+ end,
+ erts_debug:get_internal_state(check_io_debug)
+ end),
+ erlang:display({init_per_testcase, Case}),
+ 0 = element(1, CIOD),
+ [{testcase, Case}|Config].
+
+end_per_testcase(Case, Config) ->
+ erlang:display({end_per_testcase, Case}),
+ try rpc(Config, fun() ->
+ get_stable_check_io_info(),
+ erts_debug:get_internal_state(check_io_debug)
+ end) of
+ CIOD ->
+ 0 = element(1, CIOD)
+ catch _E:_R:_ST ->
+ %% Logs some info about the system
+ ct_os_cmd("epmd -names"),
+ ct_os_cmd("ps aux"),
+ %% Restart the node
+ case proplists:get_value(node, Config) of
+ undefined ->
+ ok;
+ Node ->
+ timer:sleep(1000), %% Give the node time to die
+ [NodeName, _] = string:lexemes(atom_to_list(Node),"@"),
+ {ok, Node} = start_node_final(
+ list_to_atom(NodeName),
+ proplists:get_value(node_args, Config))
+ end
+ end,
+ ok.
+
+ct_os_cmd(Cmd) ->
+ ct:log("~s: ~s",[Cmd,os:cmd(Cmd)]).
+
%% Test sending bad types to port with an outputv-capable driver.
outputv_errors(Config) when is_list(Config) ->
Path = proplists:get_value(data_dir, Config),
@@ -998,7 +1017,9 @@ chkio_test({erts_poll_info, Before},
During = get_check_io_total(erlang:system_info(check_io)),
erlang:display(During),
- 0 = element(1, erts_debug:get_internal_state(check_io_debug)),
+ [0 = element(1, erts_debug:get_internal_state(check_io_debug)) ||
+ %% The pollset is not stable when running the fallback testcase
+ Test /= ?CHKIO_USE_FALLBACK_POLLSET],
io:format("During test: ~p~n", [During]),
chk_chkio_port(Port),
case erlang:port_control(Port, ?CHKIO_STOP, "") of
@@ -2642,7 +2663,6 @@ start_node(Config) when is_list(Config) ->
start_node(Name) ->
start_node(Name, "").
start_node(NodeName, Args) ->
- Pa = filename:dirname(code:which(?MODULE)),
Name = list_to_atom(atom_to_list(?MODULE)
++ "-"
++ atom_to_list(NodeName)
@@ -2650,7 +2670,17 @@ start_node(NodeName, Args) ->
++ integer_to_list(erlang:system_time(second))
++ "-"
++ integer_to_list(erlang:unique_integer([positive]))),
- test_server:start_node(Name, slave, [{args, Args ++ " -pa "++Pa}]).
+ start_node_final(Name, Args).
+start_node_final(Name, Args) ->
+ {ok, Pwd} = file:get_cwd(),
+ FinalArgs = [Args, " -pa ", filename:dirname(code:which(?MODULE))],
+ {ok, Node} = test_server:start_node(Name, slave, [{args, FinalArgs}]),
+ LogPath = Pwd ++ "/error_log." ++ atom_to_list(Name),
+ ct:pal("Logging to: ~s", [LogPath]),
+ rpc:call(Node, logger, add_handler, [file_handler, logger_std_h,
+ #{formatter => {logger_formatter,#{ single_line => false }},
+ config => #{file => LogPath }}]),
+ {ok, Node}.
stop_node(Node) ->
test_server:stop_node(Node).
diff --git a/erts/emulator/test/dump_SUITE.erl b/erts/emulator/test/dump_SUITE.erl
index 3b860ebdf6..9f8ac42fa9 100644
--- a/erts/emulator/test/dump_SUITE.erl
+++ b/erts/emulator/test/dump_SUITE.erl
@@ -137,26 +137,43 @@ exiting_dump(Config) when is_list(Config) ->
free_dump(Config) when is_list(Config) ->
Dump = filename:join(proplists:get_value(priv_dir, Config),"signal_abort.dump"),
- {ok, Node} = start_node(Config),
-
- Self = self(),
-
- Pid = spawn_link(Node,
- fun() ->
- Self ! ready,
- receive
- ok ->
- unlink(Self),
- exit(lists:duplicate(1000,1000))
- end
- end),
+ {ok, NodeA} = start_node(Config),
+ {ok, NodeB} = start_node(Config),
- true = rpc:call(Node, os, putenv, ["ERL_CRASH_DUMP",Dump]),
- [erlang:monitor(process, Pid) || _ <- lists:seq(1,10000)],
- receive ready -> unlink(Pid), Pid ! ok end,
+ Self = self(),
- rpc:call(Node, erlang, halt, ["dump"]),
+ PidA = spawn_link(
+ NodeA,
+ fun() ->
+ Self ! ready,
+ receive
+ ok ->
+ spawn(fun() ->
+ erlang:system_monitor(self(), [busy_dist_port]),
+ timer:sleep(5),
+ receive
+ M ->
+ io:format("~p",[M]),
+ erlang:halt("dump")
+ end
+ end),
+ exit(lists:duplicate(1000000,100))
+ end
+ end),
+
+ spawn_link(NodeB,
+ fun() ->
+ [erlang:monitor(process, PidA) || _ <- lists:seq(1,10000)],
+ Self ! done,
+ receive _ -> ok end
+ end),
+
+ receive done -> ok end,
+ true = rpc:call(NodeA, os, putenv, ["ERL_CRASH_DUMP",Dump]),
+ ct:pal("~p",[rpc:call(NodeA, distribution_SUITE, make_busy, [NodeB, 1000])]),
+
+ receive ready -> unlink(PidA), PidA ! ok end,
{ok, Bin} = get_dump_when_done(Dump),
diff --git a/erts/emulator/test/efile_SUITE.erl b/erts/emulator/test/efile_SUITE.erl
index 55c5343739..045b351e02 100644
--- a/erts/emulator/test/efile_SUITE.erl
+++ b/erts/emulator/test/efile_SUITE.erl
@@ -105,34 +105,27 @@ open_files(Name) ->
%% a /proc directory), let's read some zero sized files 500 times each, while
%% ensuring that response isn't empty << >>
proc_zero_sized_files(Config) when is_list(Config) ->
- {Type, Flavor} = os:type(),
- %% Some files which exist on Linux but might be missing on other systems
- Inputs = ["/proc/cpuinfo",
- "/proc/meminfo",
- "/proc/partitions",
- "/proc/swaps",
- "/proc/version",
- "/proc/uptime",
- %% curproc is present on freebsd
- "/proc/curproc/cmdline"],
- case filelib:is_dir("/proc") of
- false -> {skip, "/proc not found"}; % skip the test if no /proc
- _ when Type =:= unix andalso Flavor =:= sunos ->
- %% SunOS has a /proc, but no zero sized special files
- {skip, "sunos does not have any zero sized special files"};
- true ->
- %% Take away files which do not exist in proc
- Inputs1 = lists:filter(fun filelib:is_file/1, Inputs),
-
- %% Fail if none of mentioned files exist in /proc, did we just get
- %% a normal /proc directory without any special files?
- ?assertNotEqual([], Inputs1),
-
+ TestFiles0 = [%% Some files which exist on Linux but might be missing on
+ %% other systems
+ "/proc/cpuinfo",
+ "/proc/meminfo",
+ "/proc/partitions",
+ "/proc/swaps",
+ "/proc/version",
+ "/proc/uptime",
+ %% curproc is present on FreeBSD
+ "/proc/curproc/cmdline"],
+
+ TestFiles = [F || F <- TestFiles0, filelib:is_file(F)],
+
+ case TestFiles of
+ [_|_] ->
%% For 6 inputs and 500 attempts each this do run anywhere
%% between 500 and 3000 function calls.
- lists:foreach(
- fun(Filename) -> do_proc_zero_sized(Filename, 500) end,
- Inputs1)
+ [do_proc_zero_sized(F, 500) || F <- TestFiles],
+ ok;
+ [] ->
+ {skip, "Failed to find any known zero-sized files"}
end.
%% @doc Test one file N times to also trigger possible leaking fds and memory
diff --git a/erts/emulator/test/emulator_bench.spec b/erts/emulator/test/emulator_bench.spec
index 2a180b440c..03638bfa23 100644
--- a/erts/emulator/test/emulator_bench.spec
+++ b/erts/emulator/test/emulator_bench.spec
@@ -1,2 +1,3 @@
{groups,"../emulator_test",estone_SUITE,[estone_bench]}.
{groups,"../emulator_test",binary_SUITE,[iolist_size_benchmarks]}.
+{groups,"../emulator_test",erts_debug_SUITE,[interpreter_size_bench]}.
diff --git a/erts/emulator/test/erts_debug_SUITE.erl b/erts/emulator/test/erts_debug_SUITE.erl
index f39dbedd8f..6798e3bf25 100644
--- a/erts/emulator/test/erts_debug_SUITE.erl
+++ b/erts/emulator/test/erts_debug_SUITE.erl
@@ -20,10 +20,12 @@
-module(erts_debug_SUITE).
-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
--export([all/0, suite/0,
+-export([all/0, suite/0, groups/0,
test_size/1,flat_size_big/1,df/1,term_type/1,
- instructions/1, stack_check/1, alloc_blocks_size/1]).
+ instructions/1, stack_check/1, alloc_blocks_size/1,
+ interpreter_size_bench/1]).
-export([do_alloc_blocks_size/0]).
@@ -35,6 +37,15 @@ all() ->
[test_size, flat_size_big, df, instructions, term_type,
stack_check, alloc_blocks_size].
+groups() ->
+ [{interpreter_size_bench, [], [interpreter_size_bench]}].
+
+interpreter_size_bench(_Config) ->
+ Size = erts_debug:interpreter_size(),
+ ct_event:notify(#event{name=benchmark_data,
+ data=[{value,Size}]}),
+ {comment,integer_to_list(Size)++" bytes"}.
+
test_size(Config) when is_list(Config) ->
ConsCell1 = id([a|b]),
ConsCell2 = id(ConsCell1),
diff --git a/erts/emulator/test/erts_test_utils.erl b/erts/emulator/test/erts_test_utils.erl
index e4e00a0a16..9c9eaa70ed 100644
--- a/erts/emulator/test/erts_test_utils.erl
+++ b/erts/emulator/test/erts_test_utils.erl
@@ -19,7 +19,7 @@
%%
-module(erts_test_utils).
--compile(r16).
+-compile(r20).
%%
%% THIS MODULE IS ALSO USED BY *OTHER* APPLICATIONS TEST CODE
diff --git a/erts/emulator/test/fun_SUITE.erl b/erts/emulator/test/fun_SUITE.erl
index 7f6caa08f1..2cbde621ce 100644
--- a/erts/emulator/test/fun_SUITE.erl
+++ b/erts/emulator/test/fun_SUITE.erl
@@ -513,6 +513,8 @@ refc(Config) when is_list(Config) ->
Other -> ct:fail({unexpected,Other})
end,
process_flag(trap_exit, false),
+ %% Wait to make sure that the process has terminated completely.
+ receive after 1 -> ok end,
{refc,3} = erlang:fun_info(F1, refc),
%% Garbage collect. Only the F2 fun will be left.
diff --git a/erts/emulator/test/lcnt_SUITE.erl b/erts/emulator/test/lcnt_SUITE.erl
index 87b97037d6..2dbaec9942 100644
--- a/erts/emulator/test/lcnt_SUITE.erl
+++ b/erts/emulator/test/lcnt_SUITE.erl
@@ -187,5 +187,8 @@ remove_untoggleable_locks([]) ->
[];
remove_untoggleable_locks([{resource_monitors, _, _, _} | T]) ->
remove_untoggleable_locks(T);
+remove_untoggleable_locks([{'socket[gcnt]', _, _, _} | T]) ->
+ %% Global lock used by socket NIF
+ remove_untoggleable_locks(T);
remove_untoggleable_locks([H | T]) ->
[H | remove_untoggleable_locks(T)].
diff --git a/erts/emulator/test/net_SUITE.erl b/erts/emulator/test/net_SUITE.erl
index 1a973cacb2..6111fc76a5 100644
--- a/erts/emulator/test/net_SUITE.erl
+++ b/erts/emulator/test/net_SUITE.erl
@@ -127,12 +127,17 @@ api_basic_cases() ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
init_per_suite(Config) ->
- case os:type() of
- {win32, _} ->
- not_yet_implemented();
- _ ->
- %% ?LOGGER:start(),
- Config
+ case lists:member(socket, erlang:loaded()) of
+ true ->
+ case os:type() of
+ {win32, _} ->
+ not_yet_implemented();
+ _ ->
+ %% ?LOGGER:start(),
+ Config
+ end;
+ false ->
+ {skip, "esock disabled"}
end.
end_per_suite(_) ->
diff --git a/erts/emulator/test/persistent_term_SUITE.erl b/erts/emulator/test/persistent_term_SUITE.erl
index 93eb026ced..c9874e5679 100644
--- a/erts/emulator/test/persistent_term_SUITE.erl
+++ b/erts/emulator/test/persistent_term_SUITE.erl
@@ -25,7 +25,9 @@
basic/1,purging/1,sharing/1,get_trapping/1,
info/1,info_trapping/1,killed_while_trapping/1,
off_heap_values/1,keys/1,collisions/1,
- init_restart/1]).
+ init_restart/1, put_erase_trapping/1,
+ killed_while_trapping_put/1,
+ killed_while_trapping_erase/1]).
%%
-export([test_init_restart_cmd/1]).
@@ -37,7 +39,8 @@ suite() ->
all() ->
[basic,purging,sharing,get_trapping,info,info_trapping,
killed_while_trapping,off_heap_values,keys,collisions,
- init_restart].
+ init_restart, put_erase_trapping, killed_while_trapping_put,
+ killed_while_trapping_erase].
init_per_suite(Config) ->
%% Put a term in the dict so that we know that the testcases handle
@@ -627,3 +630,69 @@ chk_not_stuck(Term) ->
pget({_, Initial}) ->
persistent_term:get() -- Initial.
+
+
+killed_while_trapping_put(_Config) ->
+ erts_debug:set_internal_state(available_internal_state, true),
+ repeat(
+ fun() ->
+ NrOfPutsInChild = 10000,
+ do_puts(2500, my_value),
+ Pid =
+ spawn(fun() ->
+ do_puts(NrOfPutsInChild, my_value2)
+ end),
+ timer:sleep(1),
+ erlang:exit(Pid, kill),
+ do_erases(NrOfPutsInChild)
+ end,
+ 10),
+ erts_debug:set_internal_state(available_internal_state, false).
+
+killed_while_trapping_erase(_Config) ->
+ erts_debug:set_internal_state(available_internal_state, true),
+ repeat(
+ fun() ->
+ NrOfErases = 2500,
+ do_puts(NrOfErases, my_value),
+ Pid =
+ spawn(fun() ->
+ do_erases(NrOfErases)
+ end),
+ timer:sleep(1),
+ erlang:exit(Pid, kill),
+ do_erases(NrOfErases)
+ end,
+ 10),
+ erts_debug:set_internal_state(available_internal_state, false).
+
+put_erase_trapping(_Config) ->
+ NrOfItems = 5000,
+ erts_debug:set_internal_state(available_internal_state, true),
+ do_puts(NrOfItems, first),
+ do_puts(NrOfItems, second),
+ do_erases(NrOfItems),
+ erts_debug:set_internal_state(available_internal_state, false).
+
+do_puts(0, _) -> ok;
+do_puts(NrOfPuts, ValuePrefix) ->
+ Key = {?MODULE, NrOfPuts},
+ Value = {ValuePrefix, NrOfPuts},
+ erts_debug:set_internal_state(reds_left, rand:uniform(250)),
+ persistent_term:put(Key, Value),
+ Value = persistent_term:get(Key),
+ do_puts(NrOfPuts - 1, ValuePrefix).
+
+do_erases(0) -> ok;
+do_erases(NrOfErases) ->
+ Key = {?MODULE,NrOfErases},
+ erts_debug:set_internal_state(reds_left, rand:uniform(500)),
+ persistent_term:erase(Key),
+ not_found = persistent_term:get(Key, not_found),
+ do_erases(NrOfErases - 1).
+
+repeat(_Fun, 0) ->
+ ok;
+repeat(Fun, N) ->
+ Fun(),
+ repeat(Fun, N-1).
diff --git a/erts/emulator/test/small_SUITE.erl b/erts/emulator/test/small_SUITE.erl
new file mode 100644
index 0000000000..00a02e5560
--- /dev/null
+++ b/erts/emulator/test/small_SUITE.erl
@@ -0,0 +1,115 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(small_SUITE).
+
+-export([all/0, suite/0]).
+-export([edge_cases/1]).
+
+-include_lib("common_test/include/ct.hrl").
+
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap, {minutes, 1}}].
+
+all() ->
+ [edge_cases].
+
+edge_cases(Config) when is_list(Config) ->
+ {MinSmall, MaxSmall} = Limits = determine_small_limits(0),
+ ct:pal("Limits = ~p", [Limits]),
+
+ true = (MaxSmall + 1) =:= MaxSmall + id(1),
+ true = (MinSmall - 1) =:= MinSmall - id(1),
+ true = (MaxSmall + 1) > id(MaxSmall),
+ true = (MinSmall - 1) < id(MinSmall),
+ -1 = MinSmall + id(MaxSmall),
+ -1 = MaxSmall + id(MinSmall),
+
+ false = is_small(MinSmall * -1),
+ false = is_small(MinSmall - id(1)),
+ false = is_small(MinSmall - 1),
+ false = is_small(MaxSmall + id(1)),
+
+ Lower = lists:seq(MinSmall, MinSmall + 128),
+ Upper = lists:seq(MaxSmall, MaxSmall - 128, -1),
+ Pow2 = seq_pow2(MinSmall, MaxSmall),
+ NearZero = lists:seq(-128, 128),
+
+ ok = test_combinations([Lower, Upper, Pow2, NearZero], MinSmall, MaxSmall),
+
+ ok.
+
+test_combinations([As | Rest]=TestVectors, MinS, MaxS) ->
+ [begin
+ _ = [arith_test(A, B, MinS, MaxS) || B <- Bs]
+ end || A <- As, Bs <- TestVectors],
+ test_combinations(Rest, MinS, MaxS);
+test_combinations([], _MinS, _MaxS) ->
+ ok.
+
+%% Builds a sequence of all powers of 2 between MinSmall and MaxSmall
+seq_pow2(MinSmall, MaxSmall) ->
+ sp2_1(MinSmall, MinSmall, MaxSmall).
+
+sp2_1(N, _MinS, MaxS) when N >= MaxS ->
+ [];
+sp2_1(-1, MinS, MaxS) ->
+ [-1 | sp2_1(1, MinS, MaxS)];
+sp2_1(N, MinS, MaxS) when N < 0 ->
+ [N | sp2_1(N bsr 1, MinS, MaxS)];
+sp2_1(N, MinS, MaxS) when N > 0 ->
+ [N | sp2_1(N bsl 1, MinS, MaxS)].
+
+arith_test(A, B, MinS, MaxS) ->
+ verify_kind(A + B, MinS, MaxS),
+ verify_kind(B + A, MinS, MaxS),
+ verify_kind(A - B, MinS, MaxS),
+ verify_kind(B - A, MinS, MaxS),
+ verify_kind(A * B, MinS, MaxS),
+ verify_kind(B * A, MinS, MaxS),
+
+ true = A + B =:= apply(erlang, id('+'), [A, B]),
+ true = A - B =:= apply(erlang, id('-'), [A, B]),
+ true = A * B =:= apply(erlang, id('*'), [A, B]),
+
+ true = A + B =:= B + id(A),
+ true = A - B =:= A + id(-B),
+ true = B - A =:= B + id(-A),
+ true = A * B =:= B * id(A),
+
+ true = B =:= 0 orelse ((A * B) div id(B) =:= A),
+ true = A =:= 0 orelse ((B * A) div id(A) =:= B),
+
+ ok.
+
+%% Verifies that N is a small when it should be
+verify_kind(N, MinS, MaxS) ->
+ true = is_small(N) =:= (N >= MinS andalso N =< MaxS).
+
+is_small(N) when is_integer(N) ->
+ 0 =:= erts_debug:flat_size(N).
+
+determine_small_limits(N) ->
+ case is_small(-1 bsl N) of
+ true -> determine_small_limits(N + 1);
+ false -> {-1 bsl (N - 1), (1 bsl (N - 1)) - 1}
+ end.
+
+id(I) -> I.
diff --git a/erts/emulator/test/socket_SUITE.erl b/erts/emulator/test/socket_SUITE.erl
index 2e3f40a350..e3545ccbf9 100644
--- a/erts/emulator/test/socket_SUITE.erl
+++ b/erts/emulator/test/socket_SUITE.erl
@@ -28,10 +28,14 @@
%% ESOCK_TEST_TRAFFIC: include
%% ESOCK_TEST_TTEST: exclude
%%
+%% Variable that controls "verbosity" of the test case(s):
+%%
+%% ESOCK_TEST_QUIET: true (default) | false
+%%
%% Defines the runtime of the ttest cases
%% (This is the time during which "measurement" is performed.
%% the actual time it takes for the test case to complete
-%% will be longer)
+%% will be longer; setup, completion, ...)
%%
%% ESOCK_TEST_TTEST_RUNTIME: 10 seconds
%% Format of values: <integer>[<unit>]
@@ -1381,22 +1385,27 @@ ttest_ssockt_csockt_cases() ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
init_per_suite(Config) ->
- case os:type() of
- {win32, _} ->
- not_yet_implemented();
- _ ->
- case quiet_mode(Config) of
- default ->
- ?LOGGER:start(),
- Config;
- Quiet ->
- ?LOGGER:start(Quiet),
- [{esock_test_quiet, Quiet}|Config]
- end
+ case lists:member(socket, erlang:loaded()) of
+ true ->
+ case os:type() of
+ {win32, _} ->
+ (catch not_yet_implemented());
+ _ ->
+ case quiet_mode(Config) of
+ default ->
+ ?LOGGER:start(),
+ Config;
+ Quiet ->
+ ?LOGGER:start(Quiet),
+ [{esock_test_quiet, Quiet}|Config]
+ end
+ end;
+ false ->
+ {skip, "esock disabled"}
end.
end_per_suite(_) ->
- ?LOGGER:stop(),
+ (catch ?LOGGER:stop()),
ok.
@@ -1643,6 +1652,8 @@ api_b_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config) ->
tc_try(api_b_sendmsg_and_recvmsg_udp4,
fun() ->
Send = fun(Sock, Data, Dest) ->
+ %% We need tests for this,
+ %% but this is not the place it.
%% CMsgHdr = #{level => ip,
%% type => tos,
%% data => reliability},
@@ -1653,9 +1664,12 @@ api_b_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config) ->
socket:sendmsg(Sock, MsgHdr)
end,
Recv = fun(Sock) ->
+ %% We have some issues on old darwing...
+ socket:setopt(Sock, otp, debug, true),
case socket:recvmsg(Sock) of
{ok, #{addr := Source,
iov := [Data]}} ->
+ socket:setopt(Sock, otp, debug, false),
{ok, {Source, Data}};
{error, _} = ERROR ->
ERROR
@@ -1714,21 +1728,37 @@ api_b_send_and_recv_udp(InitState) ->
end},
#{desc => "send req (to dst)",
cmd => fun(#{sock_src := Sock, sa_dst := Dst, send := Send}) ->
- ok = Send(Sock, ?BASIC_REQ, Dst)
+ Send(Sock, ?BASIC_REQ, Dst)
end},
#{desc => "recv req (from src)",
cmd => fun(#{sock_dst := Sock, sa_src := Src, recv := Recv}) ->
- {ok, {Src, ?BASIC_REQ}} = Recv(Sock),
- ok
+ case Recv(Sock) of
+ {ok, {Src, ?BASIC_REQ}} ->
+ ok;
+ {ok, UnexpData} ->
+ {error, {unexpected_data, UnexpData}};
+ {error, _} = ERROR ->
+ %% At the moment there is no way to get
+ %% status or state for the socket...
+ ERROR
+ end
end},
#{desc => "send rep (to src)",
cmd => fun(#{sock_dst := Sock, sa_src := Src, send := Send}) ->
- ok = Send(Sock, ?BASIC_REP, Src)
+ Send(Sock, ?BASIC_REP, Src)
end},
#{desc => "recv rep (from dst)",
cmd => fun(#{sock_src := Sock, sa_dst := Dst, recv := Recv}) ->
- {ok, {Dst, ?BASIC_REP}} = Recv(Sock),
- ok
+ case Recv(Sock) of
+ {ok, {Dst, ?BASIC_REP}} ->
+ ok;
+ {ok, UnexpData} ->
+ {error, {unexpected_data, UnexpData}};
+ {error, _} = ERROR ->
+ %% At the moment there is no way to get
+ %% status or state for the socket...
+ ERROR
+ end
end},
#{desc => "close src socket",
cmd => fun(#{sock_src := Sock}) ->
@@ -3585,8 +3615,8 @@ api_to_connect_tcp(InitState) ->
?SEV_IPRINT("client node ~p started",
[Node]),
{ok, State#{node => Node}};
- {error, Reason, _} ->
- {error, Reason}
+ {error, Reason} ->
+ {skip, Reason}
end
end},
#{desc => "monitor client node",
@@ -3921,7 +3951,7 @@ api_to_connect_tcp_await_timeout2(_ID, To, ServerSA, NewSock) ->
case socket:connect(Sock, ServerSA, To) of
{error, timeout} ->
Stop = t(),
- TDiff = tdiff(Start, Stop),
+ TDiff = Stop - Start,
if
(TDiff >= To) ->
(catch socket:close(Sock)),
@@ -4033,7 +4063,7 @@ api_to_accept_tcp(InitState) ->
end},
#{desc => "validate timeout time",
cmd => fun(#{start := Start, stop := Stop, timeout := To} = _State) ->
- TDiff = tdiff(Start, Stop),
+ TDiff = Stop - Start,
if
(TDiff >= To) ->
ok;
@@ -4169,7 +4199,7 @@ api_to_maccept_tcp(InitState) ->
end},
#{desc => "validate timeout time",
cmd => fun(#{start := Start, stop := Stop, timeout := To} = _State) ->
- TDiff = tdiff(Start, Stop),
+ TDiff = Stop - Start,
if
(TDiff >= To) ->
ok;
@@ -4242,7 +4272,7 @@ api_to_maccept_tcp(InitState) ->
end},
#{desc => "validate timeout time",
cmd => fun(#{start := Start, stop := Stop, timeout := To} = State) ->
- TDiff = tdiff(Start, Stop),
+ TDiff = Stop - Start,
if
(TDiff >= To) ->
State1 = maps:remove(start, State),
@@ -4693,7 +4723,7 @@ api_to_receive_tcp(InitState) ->
end},
#{desc => "validate timeout time",
cmd => fun(#{start := Start, stop := Stop, timeout := To} = State) ->
- TDiff = tdiff(Start, Stop),
+ TDiff = Stop - Start,
if
(TDiff >= To) ->
State1 = maps:remove(start, State),
@@ -5000,7 +5030,8 @@ api_to_receive_udp(InitState) ->
Start = t(),
case Recv(Sock, To) of
{error, timeout} ->
- {ok, State#{start => Start, stop => t()}};
+ {ok, State#{start => Start,
+ stop => t()}};
{ok, _} ->
{error, unexpected_sucsess};
{error, _} = ERROR ->
@@ -5009,7 +5040,7 @@ api_to_receive_udp(InitState) ->
end},
#{desc => "validate timeout time",
cmd => fun(#{start := Start, stop := Stop, timeout := To} = _State) ->
- TDiff = tdiff(Start, Stop),
+ TDiff = Stop - Start,
if
(TDiff >= To) ->
ok;
@@ -5021,7 +5052,7 @@ api_to_receive_udp(InitState) ->
%% *** Termination ***
#{desc => "close socket",
cmd => fun(#{sock := Sock} = _State) ->
- socket:setopt(Sock, otp, debug, true),
+ %% socket:setopt(Sock, otp, debug, true),
sock_close(Sock),
ok
end},
@@ -5591,7 +5622,7 @@ sc_lc_receive_response_tcp(InitState) ->
State1 = maps:remove(sock, State),
{ok, State1};
{error, Reason} = ERROR ->
- ?SEV_EPRINT("Unexpected read faulure: "
+ ?SEV_EPRINT("Unexpected read failure: "
"~n ~p", [Reason]),
ERROR
end
@@ -7218,8 +7249,8 @@ sc_rc_receive_response_tcp(InitState) ->
{ok, Node} ->
?SEV_IPRINT("client node ~p started", [Node]),
{ok, State#{node => Node}};
- {error, Reason, _} ->
- {error, Reason}
+ {error, Reason} ->
+ {skip, Reason}
end
end},
#{desc => "monitor client node 1",
@@ -8095,8 +8126,8 @@ sc_rs_send_shutdown_receive_tcp(InitState) ->
?SEV_IPRINT("client node ~p started",
[Node]),
{ok, State#{node => Node}};
- {error, Reason, _} ->
- {error, Reason}
+ {error, Reason} ->
+ {skip, Reason}
end
end},
#{desc => "monitor client node",
@@ -8987,6 +9018,7 @@ traffic_send_and_recv_chunks_tcp(InitState) ->
end},
#{desc => "recv (one big)",
cmd => fun(#{tester := Tester, csock := Sock, size := Size} = _State) ->
+ %% socket:setopt(Sock, otp, debug, true),
case socket:recv(Sock, Size) of
{ok, Data} ->
?SEV_ANNOUNCE_READY(Tester,
@@ -9045,8 +9077,8 @@ traffic_send_and_recv_chunks_tcp(InitState) ->
?SEV_IPRINT("(remote) client node ~p started",
[Node]),
{ok, State#{node => Node}};
- {error, Reason, _} ->
- {error, Reason}
+ {error, Reason} ->
+ {skip, Reason}
end
end},
#{desc => "monitor client node",
@@ -10169,7 +10201,7 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config)
Num = ?TPP_SMALL_NUM,
tc_try(traffic_ping_pong_small_sendmsg_and_recvmsg_udp4,
fun() ->
- ?TT(?SECS(20)),
+ ?TT(?SECS(60)),
InitState = #{domain => inet,
msg => Msg,
num => Num},
@@ -10196,7 +10228,7 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_udp6(_Config) when is_list(_Config)
tc_try(traffic_ping_pong_small_sendmsg_and_recvmsg_udp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(20)),
+ ?TT(?SECS(30)),
InitState = #{domain => inet,
msg => Msg,
num => Num},
@@ -10523,8 +10555,8 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) ->
?SEV_IPRINT("(remote) client node ~p started",
[Node]),
{ok, State#{node => Node}};
- {error, Reason, _} ->
- {error, Reason}
+ {error, Reason} ->
+ {skip, Reason}
end
end},
#{desc => "monitor client node",
@@ -11044,7 +11076,7 @@ tpp_tcp_client_msg_exchange_loop(Sock, _Send, _Recv, _Msg,
end;
tpp_tcp_client_msg_exchange_loop(Sock, Send, Recv, Data,
Num, N, Sent, Received, Start) ->
- %% d("tpp_tcp_client_msg_exchange_loop(~w,~w) try send", [Num,N]),
+ %% d("tpp_tcp_client_msg_exchange_loop(~w,~w) try send ~w", [Num,N,size(Data)]),
case tpp_tcp_send_req(Sock, Send, Data) of
{ok, SendSz} ->
%% d("tpp_tcp_client_msg_exchange_loop(~w,~w) sent - "
@@ -11057,11 +11089,13 @@ tpp_tcp_client_msg_exchange_loop(Sock, Send, Recv, Data,
Received+RecvSz,
Start);
{error, RReason} ->
- ?SEV_EPRINT("recv (~w of ~w): ~p", [N, Num, RReason]),
+ ?SEV_EPRINT("recv (~w of ~w): ~p: "
+ "~n ~p", [N, Num, RReason, mq()]),
exit({recv, RReason, N})
end;
{error, SReason} ->
- ?SEV_EPRINT("send (~w of ~w): ~p", [N, Num, SReason]),
+ ?SEV_EPRINT("send (~w of ~w): ~p"
+ "~n ~p", [N, Num, SReason, mq()]),
exit({send, SReason, N})
end.
@@ -11121,7 +11155,7 @@ tpp_tcp_recv(Sock, Recv, Tag) ->
tpp_tcp_recv(Sock, Recv, Tag, Remains, size(Msg), [Data]);
{ok, <<Tag:32/integer, _/binary>>} ->
{error, {invalid_msg_tag, Tag}};
- {error, _} = ERROR ->
+ {error, _R} = ERROR ->
ERROR
end.
@@ -11135,7 +11169,7 @@ tpp_tcp_recv(Sock, Recv, Tag, Remaining, AccSz, Acc) ->
tpp_tcp_recv(Sock, Recv, Tag,
Remaining - size(Data), AccSz + size(Data),
[Data | Acc]);
- {error, _} = ERROR ->
+ {error, _R} = ERROR ->
ERROR
end.
@@ -11173,6 +11207,14 @@ tpp_tcp_send_msg(Sock, Send, Msg, AccSz) when is_binary(Msg) ->
%% size_of_iovec([B|IOVec], Sz) ->
%% size_of_iovec(IOVec, Sz+size(B)).
+mq() ->
+ mq(self()).
+
+mq(Pid) when is_pid(Pid) ->
+ Tag = messages,
+ {Tag, Msgs} = process_info(Pid, Tag),
+ Msgs.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -11198,7 +11240,7 @@ traffic_ping_pong_sendmsg_and_recvmsg_udp(InitState) ->
MsgHdr = #{addr => Dest, iov => Data},
socket:sendmsg(Sock, MsgHdr)
end,
- Recv = fun(Sock, Sz) ->
+ Recv = fun(Sock, Sz) ->
case socket:recvmsg(Sock, Sz, 0) of
{ok, #{addr := Source,
iov := [Data]}} ->
@@ -11329,7 +11371,9 @@ traffic_ping_pong_send_and_receive_udp2(InitState) ->
[{handler, Handler}])
end},
#{desc => "order handler to recv",
- cmd => fun(#{handler := Handler} = _State) ->
+ cmd => fun(#{handler := Handler,
+ sock := _Sock} = _State) ->
+ %% socket:setopt(Sock, otp, debug, true),
?SEV_ANNOUNCE_CONTINUE(Handler, recv),
ok
end},
@@ -11425,8 +11469,8 @@ traffic_ping_pong_send_and_receive_udp2(InitState) ->
?SEV_IPRINT("(remote) client node ~p started",
[Node]),
{ok, State#{node => Node}};
- {error, Reason, _} ->
- {error, Reason}
+ {error, Reason} ->
+ {skip, Reason}
end
end},
#{desc => "monitor client node",
@@ -17272,8 +17316,8 @@ ttest_tcp(InitState) ->
case start_node(Host, server) of
{ok, Node} ->
{ok, State#{node => Node}};
- {error, Reason, _} ->
- {error, Reason}
+ {error, Reason} ->
+ {skip, Reason}
end
end},
#{desc => "monitor server node",
@@ -17369,8 +17413,8 @@ ttest_tcp(InitState) ->
case start_node(Host, client) of
{ok, Node} ->
{ok, State#{node => Node}};
- {error, Reason, _} ->
- {error, Reason}
+ {error, Reason} ->
+ {skip, Reason}
end
end},
#{desc => "monitor client node",
@@ -17686,7 +17730,28 @@ ttest_tcp_client_start(Node,
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This mechanism has only one purpose: So that we are able to kill
+%% the node-starter process if it takes to long. The node-starter
+%% runs on the local node.
+%% This crapola is hopefully temporary, but we have seen that on
+%% some platforms the ct_slave:start simply hangs.
+-define(NODE_START_TIMEOUT, 10000).
start_node(Host, NodeName) ->
+ start_node(Host, NodeName, ?NODE_START_TIMEOUT).
+
+start_node(Host, NodeName, Timeout) ->
+ {NodeStarter, _} =
+ spawn_monitor(fun() -> exit(start_unique_node(Host, NodeName)) end),
+ receive
+ {'DOWN', _, process, NodeStarter, Result} ->
+ %% i("Node Starter (~p) reported: ~p", [NodeStarter, Result]),
+ Result
+ after Timeout ->
+ exit(NodeStarter, kill),
+ {error, {failed_starting_node, NodeName, timeout}}
+ end.
+
+start_unique_node(Host, NodeName) ->
UniqueNodeName = f("~w_~w", [NodeName, erlang:system_time(millisecond)]),
case do_start_node(Host, UniqueNodeName) of
{ok, _} = OK ->
@@ -17720,7 +17785,7 @@ stop_node(Node) ->
ERROR
end.
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -17877,9 +17942,15 @@ which_addr2(Domain, [_|IFO]) ->
%% Here are all the *general* test vase condition functions.
%% The idea is that this function shall test if the test host has
-%% support for IPv6. If not there is no point in running IPv6 tests.
+%% support for IPv6. If not, there is no point in running IPv6 tests.
%% Currently we just skip.
has_support_ipv6() ->
+ %% case socket:supports(ipv6) of
+ %% true ->
+ %% ok;
+ %% false ->
+ %% {error, not_supported}
+ %% end.
not_yet_implemented().
@@ -17896,8 +17967,10 @@ skip(Reason) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
t() ->
- os:timestamp().
+ ts(ms).
+ts(ms) ->
+ erlang:monotonic_time(milli_seconds).
tdiff({A1, B1, C1} = _T1x, {A2, B2, C2} = _T2x) ->
T1 = A1*1000000000+B1*1000+(C1 div 1000),
@@ -17930,11 +18003,15 @@ set_tc_name(N) when is_list(N) ->
%% get(tc_name).
tc_begin(TC) ->
+ OldVal = process_flag(trap_exit, true),
+ put(old_trap_exit, OldVal),
set_tc_name(TC),
tc_print("begin ***",
"~n----------------------------------------------------~n", "").
tc_end(Result) when is_list(Result) ->
+ OldVal = erase(old_trap_exit),
+ process_flag(trap_exit, OldVal),
tc_print("done: ~s", [Result],
"", "----------------------------------------------------~n~n"),
ok.
@@ -17965,26 +18042,44 @@ tc_try(Case, TCCondFun, TCFun)
tc_end("ok")
end
catch
- throw:{skip, _} = SKIP ->
- tc_end("skipping"),
+ C:{skip, _} = SKIP when ((C =:= throw) orelse (C =:= exit)) ->
+ %% i("catched[tc] (skip): "
+ %% "~n C: ~p"
+ %% "~n SKIP: ~p"
+ %% "~n", [C, SKIP]),
+ tc_end( f("skipping(catched,~w,tc)", [C]) ),
SKIP;
- Class:Error:Stack ->
- tc_end("failed"),
- erlang:raise(Class, Error, Stack)
+ C:E:S ->
+ %% i("catched[tc]: "
+ %% "~n C: ~p"
+ %% "~n E: ~p"
+ %% "~n S: ~p"
+ %% "~n", [C, E, S]),
+ tc_end( f("failed(catched,~w,tc)", [C]) ),
+ erlang:raise(C, E, S)
end;
{skip, _} = SKIP ->
- tc_end("skipping"),
+ tc_end("skipping(tc)"),
SKIP;
{error, Reason} ->
- tc_end("failed"),
+ tc_end("failed(tc)"),
exit({tc_cond_failed, Reason})
catch
- throw:{skip, _} = SKIP ->
- tc_end("skipping"),
+ C:{skip, _} = SKIP when ((C =:= throw) orelse (C =:= exit)) ->
+ %% i("catched[cond] (skip): "
+ %% "~n C: ~p"
+ %% "~n SKIP: ~p"
+ %% "~n", [C, SKIP]),
+ tc_end( f("skipping(catched,~w,cond)", [C]) ),
SKIP;
- Class:Error:Stack ->
- tc_end("failed"),
- erlang:raise(Class, Error, Stack)
+ C:E:S ->
+ %% i("catched[cond]: "
+ %% "~n C: ~p"
+ %% "~n E: ~p"
+ %% "~n S: ~p"
+ %% "~n", [C, E, S]),
+ tc_end( f("failed(catched,~w,cond)", [C]) ),
+ erlang:raise(C, E, S)
end.
diff --git a/erts/emulator/test/socket_test_evaluator.erl b/erts/emulator/test/socket_test_evaluator.erl
index c5748ac21b..694f0d5f1e 100644
--- a/erts/emulator/test/socket_test_evaluator.erl
+++ b/erts/emulator/test/socket_test_evaluator.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2018-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -106,12 +106,13 @@ start(Name, Seq, InitState)
InitState2 = InitState#{parent => self()},
Pid = erlang:spawn_link(
fun() -> init(Name, Seq, InitState2) end),
- MRef = erlang:monitor(process, Pid),
- #ev{name = Name, pid = Pid, mref = MRef}
+ %% MRef = erlang:monitor(process, Pid),
+ #ev{name = Name, pid = Pid}%, mref = MRef}
end.
init(Name, Seq, Init) ->
put(sname, Name),
+ process_flag(trap_exit, true),
loop(1, Seq, Init).
loop(_ID, [], FinalState) ->
@@ -125,21 +126,26 @@ loop(ID, [#{desc := Desc,
{ok, NewState} ->
loop(ID + 1, Cmds, NewState);
{skip, Reason} ->
+ ?SEV_IPRINT("command ~w skip: "
+ "~n ~p", [ID, Reason]),
exit({skip, Reason});
{error, Reason} ->
- eprint("command ~w failed: "
- "~n Reason: ~p", [ID, Reason]),
+ ?SEV_EPRINT("command ~w failed: "
+ "~n ~p", [ID, Reason]),
exit({command_failed, ID, Reason, State})
catch
- throw:{skip, R} = E:_ ->
- eprint("command ~w skip: "
- "~n Skip Reason: ~p", [ID, R]),
+ C:{skip, command} = E:_ when ((C =:= throw) orelse (C =:= exit)) ->
+ %% Secondary skip
+ exit(E);
+ C:{skip, R} = E:_ when ((C =:= throw) orelse (C =:= exit)) ->
+ ?SEV_IPRINT("command ~w skip catched(~w): "
+ "~n Reason: ~p", [ID, C, R]),
exit(E);
C:E:S ->
- eprint("command ~w crashed: "
- "~n Class: ~p"
- "~n Error: ~p"
- "~n Call Stack: ~p", [ID, C, E, S]),
+ ?SEV_EPRINT("command ~w crashed: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Call Stack: ~p", [ID, C, E, S]),
exit({command_crashed, ID, {C,E,S}, State})
end.
@@ -168,18 +174,32 @@ await_finish(Evs, OK, Fails) ->
{Evs2, OK2, Fails2} = await_finish_normal(Pid, Evs, OK, Fails),
await_finish(Evs2, OK2, Fails2);
- %% The evaluator can skip the teat case:
+ %% The evaluator can skip the test case:
{'DOWN', _MRef, process, Pid, {skip, Reason}} ->
+ %% ?SEV_IPRINT("await_finish -> skip (down) received: "
+ %% "~n Pid: ~p"
+ %% "~n Reason: ~p", [Pid, Reason]),
await_finish_skip(Pid, Reason, Evs, OK);
{'EXIT', Pid, {skip, Reason}} ->
+ %% ?SEV_IPRINT("await_finish -> skip (exit) received: "
+ %% "~n Pid: ~p"
+ %% "~n Reason: ~p", [Pid, Reason]),
await_finish_skip(Pid, Reason, Evs, OK);
%% Evaluator failed
{'DOWN', _MRef, process, Pid, Reason} ->
- {Evs2, OK2, Fails2} = await_finish_fail(Pid, Reason, Evs, OK, Fails),
+ %% ?SEV_IPRINT("await_finish -> fail (down) received: "
+ %% "~n Pid: ~p"
+ %% "~n Reason: ~p", [Pid, Reason]),
+ {Evs2, OK2, Fails2} =
+ await_finish_fail(Pid, Reason, Evs, OK, Fails),
await_finish(Evs2, OK2, Fails2);
{'EXIT', Pid, Reason} ->
- {Evs2, OK2, Fails2} = await_finish_fail(Pid, Reason, Evs, OK, Fails),
+ %% ?SEV_IPRINT("await_finish -> fail (exit) received: "
+ %% "~n Pid: ~p"
+ %% "~n Reason: ~p", [Pid, Reason]),
+ {Evs2, OK2, Fails2} =
+ await_finish_fail(Pid, Reason, Evs, OK, Fails),
await_finish(Evs2, OK2, Fails2)
end.
@@ -202,22 +222,83 @@ await_finish_normal(Pid, Evs, OK, Fails) ->
end.
await_finish_skip(Pid, Reason, Evs, OK) ->
- case lists:keysearch(Pid, #ev.pid, Evs) of
- {value, #ev{name = Name}} ->
- iprint("evaluator '~s' (~p) issued SKIP: "
- "~n ~p", [Name, Pid, Reason]);
- false ->
- case lists:member(Pid, OK) of
- true ->
- ok;
- false ->
- iprint("unknown process ~p issued SKIP: "
- "~n ~p", [Pid, Reason])
- end
- end,
+ Evs2 =
+ case lists:keysearch(Pid, #ev.pid, Evs) of
+ {value, #ev{name = Name}} ->
+ ?SEV_IPRINT("evaluator '~s' (~p) issued SKIP: "
+ "~n ~p", [Name, Pid, Reason]),
+ lists:keydelete(Pid, #ev.pid, Evs);
+ false ->
+ case lists:member(Pid, OK) of
+ true ->
+ ?SEV_IPRINT("already terminated (ok) process ~p skip"
+ "~n ~p", [Pid]),
+ ok;
+ false ->
+ ?SEV_IPRINT("unknown process ~p issued SKIP: "
+ "~n ~p", [Pid, Reason]),
+ iprint("unknown process ~p issued SKIP: "
+ "~n ~p", [Pid, Reason])
+ end,
+ Evs
+ end,
+ await_evs_terminated(Evs2),
?LIB:skip(Reason).
+await_evs_terminated(Evs) ->
+ Instructions =
+ [
+ %% Just wait for the evaluators to die on their own
+ {fun() -> ?SEV_IPRINT("await (no action) evs termination") end,
+ fun(_) -> ok end},
+
+ %% Send them a skip message, causing the evaluators to
+ %% die with a skip reason.
+ {fun() -> ?SEV_IPRINT("await (send skip message) evs termination") end,
+ fun(#ev{pid = Pid}) -> Pid ! skip end},
+ %% And if nothing else works, try to kill the remaining evaluators
+ {fun() -> ?SEV_IPRINT("await (issue exit kill) evs termination") end,
+ fun(#ev{pid = Pid}) -> exit(Pid, kill) end}],
+
+ await_evs_terminated(Evs, Instructions).
+
+await_evs_terminated([], _) ->
+ ok;
+await_evs_terminated(Evs, []) ->
+ {error, {failed_terminated, [P||#ev{pid=P} <- Evs]}};
+await_evs_terminated(Evs, [{Inform, Command}|Instructions]) ->
+ Inform(),
+ lists:foreach(Command, Evs),
+ RemEvs = await_evs_termination(Evs),
+ await_evs_terminated(RemEvs, Instructions).
+
+await_evs_termination(Evs) ->
+ await_evs_termination(Evs, 2000).
+
+await_evs_termination([], _Timeout) ->
+ [];
+await_evs_termination(Evs, Timeout) ->
+ T = t(),
+ receive
+ {'DOWN', _MRef, process, Pid, _Reason} ->
+ %% ?SEV_IPRINT("await_evs_termination -> DOWN: "
+ %% "~n Pid: ~p"
+ %% "~n Reason: ~p", [Pid, Reason]),
+ Evs2 = lists:keydelete(Pid, #ev.pid, Evs),
+ await_evs_termination(Evs2, tdiff(T, t()));
+ {'EXIT', Pid, _Reason} ->
+ %% ?SEV_IPRINT("await_evs_termination -> EXIT: "
+ %% "~n Pid: ~p"
+ %% "~n Reason: ~p", [Pid, Reason]),
+ Evs2 = lists:keydelete(Pid, #ev.pid, Evs),
+ await_evs_termination(Evs2, tdiff(T, t()))
+
+ after Timeout ->
+ Evs
+ end.
+
+
await_finish_fail(Pid, Reason, Evs, OK, Fails) ->
case lists:keysearch(Pid, #ev.pid, Evs) of
{value, #ev{name = Name}} ->
@@ -454,7 +535,7 @@ await_termination(Pid, ExpReason) ->
{'DOWN', _, process, Pid, Reason} when (ExpReason =:= Reason) ->
ok;
{'DOWN', _, process, Pid, Reason} ->
- {error, {unexpected_exit, ExpReason, Reason}}
+ {error, {unexpected_reason, ExpReason, Reason}}
end.
@@ -480,6 +561,10 @@ await(ExpPid, Name, Announcement, Slogan, OtherPids)
is_atom(Slogan) andalso
is_list(OtherPids) ->
receive
+ skip ->
+ %% This means that another evaluator has issued a skip,
+ %% and we have been instructed to terminate as a result.
+ ?LIB:skip(command);
{Announcement, Pid, Slogan, ?EXTRA_NOTHING} when (ExpPid =:= any) ->
{ok, Pid};
{Announcement, Pid, Slogan, Extra} when (ExpPid =:= any) ->
@@ -495,12 +580,15 @@ await(ExpPid, Name, Announcement, Slogan, OtherPids)
{'DOWN', _, process, Pid, Reason} when (Pid =:= ExpPid) ->
eprint("Unexpected DOWN from ~w (~p): "
"~n ~p", [Name, Pid, Reason]),
- {error, {unexpected_exit, Name}};
+ {error, {unexpected_exit, Name, Reason}};
{'DOWN', _, process, OtherPid, Reason} ->
case check_down(OtherPid, Reason, OtherPids) of
ok ->
iprint("DOWN from unknown process ~p: "
- "~n ~p", [OtherPid, Reason]),
+ "~n ~p"
+ "~n when"
+ "~n OtherPids: "
+ "~n ~p", [OtherPid, Reason, OtherPids]),
await(ExpPid, Name, Announcement, Slogan, OtherPids);
{error, _} = ERROR ->
ERROR
@@ -527,7 +615,7 @@ check_down(Pid, DownReason, Pids) ->
{value, {_, Name}} ->
eprint("Unexpected DOWN from ~w (~p): "
"~n ~p", [Name, Pid, DownReason]),
- {error, {unexpected_exit, Name}};
+ {error, {unexpected_exit, Name, DownReason}};
false ->
ok
end.
@@ -561,3 +649,16 @@ print(Prefix, F, A) ->
end,
?LOGGER:format("[~s]~s ~s" ++ F,
[?LIB:formated_timestamp(), IDStr, Prefix | A]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+t() ->
+ os:timestamp().
+
+
+tdiff({A1, B1, C1} = _T1x, {A2, B2, C2} = _T2x) ->
+ T1 = A1*1000000000+B1*1000+(C1 div 1000),
+ T2 = A2*1000000000+B2*1000+(C2 div 1000),
+ T2 - T1.
+
diff --git a/erts/emulator/test/statistics_SUITE.erl b/erts/emulator/test/statistics_SUITE.erl
index ae3099633a..d278ac86c7 100644
--- a/erts/emulator/test/statistics_SUITE.erl
+++ b/erts/emulator/test/statistics_SUITE.erl
@@ -93,25 +93,34 @@ wall_clock_zero_diff1(0) ->
%% statistics(wall_clock) are compatible, and are within a small number
%% of ms of the amount of real time we waited for.
wall_clock_update(Config) when is_list(Config) ->
- wall_clock_update1(6).
+ N = 10,
+ Inc = 200,
+ TotalTime = wall_clock_update1(N, Inc, 0),
+ Overhead = TotalTime - N * Inc,
+ IsDebug = test_server:is_debug(),
-wall_clock_update1(N) when N > 0 ->
- {T1_wc_time, _} = statistics(wall_clock),
- receive after 1000 -> ok end,
- {T2_wc_time, Wc_Diff} = statistics(wall_clock),
-
- Wc_Diff = T2_wc_time - T1_wc_time,
- io:format("Wall clock diff = ~p; should be = 1000..1040~n", [Wc_Diff]),
- case test_server:is_debug() of
- false ->
- true = Wc_Diff =< 1040;
+ %% Check that the average overhead is reasonable.
+ if
+ Overhead < N * 100 ->
+ ok;
+ IsDebug, Overhead < N * 1000 ->
+ ok;
true ->
- true = Wc_Diff =< 2000 %Be more tolerant in debug-compiled emulator.
- end,
- true = Wc_Diff >= 1000,
- wall_clock_update1(N-1);
-wall_clock_update1(0) ->
- ok.
+ io:format("There was an overhead of ~p ms during ~p rounds.",
+ [Overhead,N]),
+ ct:fail(too_much_overhead)
+ end.
+
+wall_clock_update1(N, Inc, Total) when N > 0 ->
+ {Time1, _} = statistics(wall_clock),
+ receive after Inc -> ok end,
+ {Time2, WcDiff} = statistics(wall_clock),
+ WcDiff = Time2 - Time1,
+ io:format("Wall clock diff = ~p (expected at least ~p)\n", [WcDiff,Inc]),
+ true = WcDiff >= Inc,
+ wall_clock_update1(N-1, Inc, Total + WcDiff);
+wall_clock_update1(0, _, Total) ->
+ Total.
%%% Test statistics(runtime).