aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/test')
-rw-r--r--erts/emulator/test/bif_SUITE.erl75
-rw-r--r--erts/emulator/test/dump_SUITE.erl4
-rw-r--r--erts/emulator/test/exception_SUITE.erl56
-rw-r--r--erts/emulator/test/lcnt_SUITE.erl17
-rw-r--r--erts/emulator/test/nif_SUITE.erl2
-rw-r--r--erts/emulator/test/num_bif_SUITE.erl34
-rw-r--r--erts/emulator/test/process_SUITE.erl172
-rw-r--r--erts/emulator/test/tracer_SUITE.erl24
-rw-r--r--erts/emulator/test/z_SUITE.erl8
9 files changed, 353 insertions, 39 deletions
diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl
index 22706ae8b1..32bfcd5520 100644
--- a/erts/emulator/test/bif_SUITE.erl
+++ b/erts/emulator/test/bif_SUITE.erl
@@ -35,7 +35,8 @@
is_builtin/1, error_stacktrace/1,
error_stacktrace_during_call_trace/1,
group_leader_prio/1, group_leader_prio_dirty/1,
- is_process_alive/1]).
+ is_process_alive/1,
+ process_info_blast/1]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -50,7 +51,7 @@ all() ->
erl_crash_dump_bytes, min_max, erlang_halt, is_builtin,
error_stacktrace, error_stacktrace_during_call_trace,
group_leader_prio, group_leader_prio_dirty,
- is_process_alive].
+ is_process_alive, process_info_blast].
%% Uses erlang:display to test that erts_printf does not do deep recursion
display(Config) when is_list(Config) ->
@@ -1099,6 +1100,76 @@ is_process_alive(Config) when is_list(Config) ->
Ps),
ok.
+process_info_blast(Config) when is_list(Config) ->
+ Tester = self(),
+ NoAttackers = 1000,
+ NoAL = lists:seq(1, NoAttackers),
+ Consume = make_ref(),
+ Victim = spawn_link(fun () ->
+ receive
+ Consume ->
+ ok
+ end,
+ consume_msgs()
+ end),
+ AFun = fun () ->
+ Victim ! hej,
+ Res = process_info(Victim, message_queue_len),
+ Tester ! {self(), Res}
+ end,
+ Attackers0 = lists:map(fun (_) ->
+ spawn_link(AFun)
+ end,
+ NoAL),
+ lists:foreach(fun (A) ->
+ receive
+ {A, Res} ->
+ case Res of
+ {message_queue_len, Len} when Len > 0, Len =< NoAttackers ->
+ Len;
+ Error ->
+ exit({unexpected, Error})
+ end
+ end
+ end,
+ Attackers0),
+ Attackers1 = lists:map(fun (_) ->
+ spawn_link(AFun)
+ end,
+ NoAL),
+ Victim ! Consume,
+ lists:foreach(fun (A) ->
+ receive
+ {A, Res} ->
+ case Res of
+ {message_queue_len, Len} when Len >= 0, Len =< 2*NoAttackers+1 ->
+ ok;
+ undefined ->
+ ok;
+ Error ->
+ exit({unexpected, Error})
+ end
+ end
+ end,
+ Attackers1),
+ KillFun = fun (P) ->
+ unlink(P),
+ exit(P, kill),
+ false = erlang:is_process_alive(P)
+ end,
+ lists:foreach(fun (A) -> KillFun(A) end, Attackers0),
+ lists:foreach(fun (A) -> KillFun(A) end, Attackers1),
+ KillFun(Victim),
+ ok.
+
+consume_msgs() ->
+ receive
+ _ ->
+ consume_msgs()
+ after 0 ->
+ ok
+ end.
+
%% helpers
id(I) -> I.
diff --git a/erts/emulator/test/dump_SUITE.erl b/erts/emulator/test/dump_SUITE.erl
index 38fa198ea6..8d18d46d92 100644
--- a/erts/emulator/test/dump_SUITE.erl
+++ b/erts/emulator/test/dump_SUITE.erl
@@ -96,12 +96,12 @@ get_dump_when_done(Dump) ->
{ok, #file_info{ size = Sz }} ->
get_dump_when_done(Dump, Sz);
{error, enoent} ->
- timer:sleep(100),
+ timer:sleep(1000),
get_dump_when_done(Dump)
end.
get_dump_when_done(Dump, Sz) ->
- timer:sleep(100),
+ timer:sleep(1000),
case file:read_file_info(Dump) of
{ok, #file_info{ size = Sz }} ->
file:read_file(Dump);
diff --git a/erts/emulator/test/exception_SUITE.erl b/erts/emulator/test/exception_SUITE.erl
index da0292f385..60d14ce841 100644
--- a/erts/emulator/test/exception_SUITE.erl
+++ b/erts/emulator/test/exception_SUITE.erl
@@ -23,7 +23,8 @@
-export([all/0, suite/0,
badmatch/1, pending_errors/1, nil_arith/1, top_of_stacktrace/1,
stacktrace/1, nested_stacktrace/1, raise/1, gunilla/1, per/1,
- exception_with_heap_frag/1, line_numbers/1]).
+ exception_with_heap_frag/1, backtrace_depth/1,
+ line_numbers/1]).
-export([bad_guy/2]).
-export([crash/1]).
@@ -42,7 +43,7 @@ suite() ->
all() ->
[badmatch, pending_errors, nil_arith, top_of_stacktrace,
stacktrace, nested_stacktrace, raise, gunilla, per,
- exception_with_heap_frag, line_numbers].
+ exception_with_heap_frag, backtrace_depth, line_numbers].
-define(try_match(E),
catch ?MODULE:bar(),
@@ -572,6 +573,57 @@ do_exception_with_heap_frag(Bin, [Sz|Sizes]) ->
do_exception_with_heap_frag(Bin, Sizes);
do_exception_with_heap_frag(_, []) -> ok.
+backtrace_depth(Config) when is_list(Config) ->
+ _ = [do_backtrace_depth(D) || D <- lists:seq(0, 8)],
+ ok.
+
+do_backtrace_depth(D) ->
+ Old = erlang:system_flag(backtrace_depth, D),
+ try
+ Expected = max(1, D),
+ do_backtrace_depth_1(Expected)
+ after
+ _ = erlang:system_flag(backtrace_depth, Old)
+ end.
+
+do_backtrace_depth_1(D) ->
+ Exit = fun() ->
+ error(reason)
+ end,
+ HandCrafted = fun() ->
+ {'EXIT',{_,Stk0}} = (catch error(get_stacktrace)),
+ %% Fool the compiler to force a hand-crafted
+ %% stacktrace.
+ Stk = [hd(Stk0)|tl(Stk0)],
+ erlang:raise(error, reason, Stk)
+ end,
+ PassedOn = fun() ->
+ try error(get_stacktrace)
+ catch error:_:Stk ->
+ %% Just pass on the given stacktrace.
+ erlang:raise(error, reason, Stk)
+ end
+ end,
+ do_backtrace_depth_2(D, Exit),
+ do_backtrace_depth_2(D, HandCrafted),
+ do_backtrace_depth_2(D, PassedOn),
+ ok.
+
+do_backtrace_depth_2(D, Exc) ->
+ try
+ Exc()
+ catch
+ error:reason:Stk ->
+ if
+ length(Stk) =/= D ->
+ io:format("Expected depth: ~p\n", [D]),
+ io:format("~p\n", [Stk]),
+ error(bad_depth);
+ true ->
+ ok
+ end
+ end.
+
line_numbers(Config) when is_list(Config) ->
{'EXIT',{{case_clause,bad_tag},
[{?MODULE,line1,2,
diff --git a/erts/emulator/test/lcnt_SUITE.erl b/erts/emulator/test/lcnt_SUITE.erl
index 4e52c2813c..dfffd662e2 100644
--- a/erts/emulator/test/lcnt_SUITE.erl
+++ b/erts/emulator/test/lcnt_SUITE.erl
@@ -87,8 +87,9 @@ wait_for_empty_lock_list() ->
wait_for_empty_lock_list(10).
wait_for_empty_lock_list(Tries) when Tries > 0 ->
try_flush_cleanup_ops(),
- case erts_debug:lcnt_collect() of
- [{duration, _}, {locks, []}] ->
+ [{duration, _}, {locks, Locks}] = erts_debug:lcnt_collect(),
+ case remove_untoggleable_locks(Locks) of
+ [] ->
ok;
_ ->
timer:sleep(50),
@@ -124,7 +125,7 @@ toggle_lock_counting(Config) when is_list(Config) ->
get_lock_info_for(Categories) when is_list(Categories) ->
ok = erts_debug:lcnt_control(mask, Categories),
[{duration, _}, {locks, Locks}] = erts_debug:lcnt_collect(),
- Locks;
+ remove_untoggleable_locks(Locks);
get_lock_info_for(Category) when is_atom(Category) ->
get_lock_info_for([Category]).
@@ -178,3 +179,13 @@ registered_db_tables(Config) when is_list(Config) ->
(_Lock) -> false
end, DbLocks),
ok.
+
+%% Not all locks can be toggled on or off due to technical limitations, so we
+%% need to filter them out when checking whether we successfully disabled lock
+%% counting.
+remove_untoggleable_locks([]) ->
+ [];
+remove_untoggleable_locks([{resource_monitors, _, _, _} | T]) ->
+ remove_untoggleable_locks(T);
+remove_untoggleable_locks([H | T]) ->
+ [H | remove_untoggleable_locks(T)].
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index a9eb4b2768..df521311e3 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -653,7 +653,7 @@ select_steal(Config) when is_list(Config) ->
check_stop_ret(select_nif(RFd, ?ERL_NIF_SELECT_STOP, RFd, null, Ref)),
?assertMatch([{fd_resource_stop, RPtr, _}], flush()),
- {1, {RPtr, 1}} = last_fd_stop_call(),
+ {1, {RPtr, _DirectCall}} = last_fd_stop_call(),
?assert(is_closed_nif(WFd)),
diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl
index 592542405f..290bb61fc8 100644
--- a/erts/emulator/test/num_bif_SUITE.erl
+++ b/erts/emulator/test/num_bif_SUITE.erl
@@ -213,6 +213,20 @@ fts_rand_float_decimals(N) ->
[begin
F0 = rand_float_reasonable(),
L0 = float_to_list(F0, [{decimals, D}]),
+ case conform_with_io_lib_format_os(F0,D) of
+ false -> ok;
+ true ->
+ IOL = lists:flatten(io_lib:format("~.*f", [D, F0])),
+ true = case L0 =:= IOL of
+ true -> true;
+ false ->
+ io:format("F0 = ~w ~w\n", [F0, <<F0/float>>]),
+ io:format("decimals = ~w\n", [D]),
+ io:format("float_to_list = ~s\n", [L0]),
+ io:format("io_lib:format = ~s\n", [IOL]),
+ false
+ end
+ end,
L1 = case D of
0 -> L0 ++ ".0";
_ -> L0
@@ -234,6 +248,26 @@ fts_rand_float_decimals(N) ->
fts_rand_float_decimals(N-1).
+conform_with_io_lib_format_os(F, D) ->
+ case os:type() of
+ {win32,_} ->
+ %% io_lib:format("~.*f") buggy on windows? OTP-15010
+ false;
+ _ ->
+ conform_with_io_lib_format(F, D)
+ end.
+
+conform_with_io_lib_format(_, 0) ->
+ %% io_lib:format("~.*f") does not support zero decimals
+ false;
+conform_with_io_lib_format(_, D) when D > 10 ->
+ %% Seems float_to_list gets it slightly wrong sometimes for many decimals
+ false;
+conform_with_io_lib_format(F, D) ->
+ %% io_lib:format prints '0' for input bits beyond mantissa precision
+ %% float_to_list treats those unknown input bits as if they were zeros.
+ math:log2(abs(F) * math:pow(10,D)) < 54.
+
max_diff_decimals(F, D) ->
IntBits = floor(math:log2(abs(F))) + 1,
FracBits = (52 - IntBits),
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index 7eff786e8b..585c5a1871 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -42,6 +42,8 @@
process_info_lock_reschedule2/1,
process_info_lock_reschedule3/1,
process_info_garbage_collection/1,
+ process_info_smoke_all/1,
+ process_info_status_handled_signal/1,
bump_reductions/1, low_prio/1, binary_owner/1, yield/1, yield2/1,
otp_4725/1, bad_register/1, garbage_collect/1, otp_6237/1,
process_info_messages/1, process_flag_badarg/1, process_flag_heap_size/1,
@@ -79,6 +81,8 @@ all() ->
process_info_lock_reschedule2,
process_info_lock_reschedule3,
process_info_garbage_collection,
+ process_info_smoke_all,
+ process_info_status_handled_signal,
bump_reductions, low_prio, yield, yield2, otp_4725,
bad_register, garbage_collect, process_info_messages,
process_flag_badarg, process_flag_heap_size,
@@ -510,14 +514,20 @@ pio_current_location(N, Pid, Pi, Looper) ->
case Where of
{erlang,process_info,2,[]} ->
pio_current_location(N-1, Pid, Pi+1, Looper);
+ {erts_internal,await_result,1, Loc} when is_list(Loc) ->
+ pio_current_location(N-1, Pid, Pi+1, Looper);
{?MODULE,process_info_looper,1,Loc} when is_list(Loc) ->
- pio_current_location(N-1, Pid, Pi, Looper+1)
+ pio_current_location(N-1, Pid, Pi, Looper+1);
+ _ ->
+ exit({unexpected_location, Where})
end.
pio_current_stacktrace() ->
L = [begin
- {current_stacktrace,Stk} = process_info(P, current_stacktrace),
- {P,Stk}
+ case process_info(P, current_stacktrace) of
+ {current_stacktrace, Stk} -> {P,Stk};
+ undefined -> {P, []}
+ end
end || P <- processes()],
[erlang:garbage_collect(P) || {P,_} <- L],
erlang:garbage_collect(),
@@ -973,6 +983,106 @@ process_info_garbage_collection(_Config) ->
gv(Key,List) ->
proplists:get_value(Key,List).
+process_info_smoke_all_tester() ->
+ register(process_info_smoke_all_tester, self()),
+ put(ets_ref, ets:new(blupp, [])),
+ put(binary, [list_to_binary(lists:duplicate(1000, 1)),
+ list_to_binary(lists:duplicate(1000, 2))]),
+ process_info_smoke_all_tester_loop().
+
+process_info_smoke_all_tester_loop() ->
+ receive
+ {other_process, Pid} ->
+ case get(procs) of
+ undefined -> put(procs, [Pid]);
+ Procs -> put(procs, [Pid|Procs])
+ end,
+ erlang:monitor(process, Pid),
+ link(Pid),
+ process_info_smoke_all_tester_loop()
+ end.
+
+process_info_smoke_all(Config) when is_list(Config) ->
+ AllPIOptions = [registered_name,
+ current_function,
+ initial_call,
+ messages,
+ message_queue_len,
+ links,
+ monitors,
+ monitored_by,
+ dictionary,
+ trap_exit,
+ error_handler,
+ heap_size,
+ stack_size,
+ memory,
+ garbage_collection,
+ group_leader,
+ reductions,
+ priority,
+ trace,
+ binary,
+ sequential_trace_token,
+ catchlevel,
+ backtrace,
+ last_calls,
+ total_heap_size,
+ suspending,
+ min_heap_size,
+ min_bin_vheap_size,
+ max_heap_size,
+ current_location,
+ current_stacktrace,
+ message_queue_data,
+ garbage_collection_info,
+ magic_ref,
+ fullsweep_after],
+
+ {ok, Node} = start_node(Config, ""),
+ RP = spawn_link(Node, fun process_info_smoke_all_tester/0),
+ LP = spawn_link(fun process_info_smoke_all_tester/0),
+ RP ! {other_process, LP},
+ LP ! {other_process, RP},
+ LP ! {other_process, self()},
+ LP ! ets:new(blapp, []),
+ LP ! ets:new(blipp, []),
+ LP ! list_to_binary(lists:duplicate(1000, 3)),
+ receive after 1000 -> ok end,
+ _MLP = erlang:monitor(process, LP),
+ true = is_process_alive(LP),
+ PI = process_info(LP, AllPIOptions),
+ io:format("~p~n", [PI]),
+ garbage_collect(),
+ unlink(RP),
+ unlink(LP),
+ exit(RP, kill),
+ exit(LP, kill),
+ false = is_process_alive(LP),
+ stop_node(Node),
+ ok.
+
+process_info_status_handled_signal(Config) when is_list(Config) ->
+ P = spawn_link(fun () ->
+ receive after infinity -> ok end
+ end),
+ wait_until(fun () ->
+ process_info(P, status) == {status, waiting}
+ end),
+ %%
+ %% The 'messages' option will force a process-info-request
+ %% signal to be scheduled on the process. Ensure that status
+ %% 'waiting' is reported even though it is actually running
+ %% when handling the request. We want it to report the status
+ %% it would have had if it had not been handling the
+ %% process-info-request...
+ %%
+ [{status, waiting}, {messages, []}] = process_info(P, [status, messages]),
+ unlink(P),
+ exit(P, kill),
+ false = erlang:is_process_alive(P),
+ ok.
+
%% Tests erlang:bump_reductions/1.
bump_reductions(Config) when is_list(Config) ->
erlang:garbage_collect(),
@@ -2107,36 +2217,44 @@ handle_event(Event, Pid) ->
processes_term_proc_list(Config) when is_list(Config) ->
Tester = self(),
- as_expected = processes_term_proc_list_test(false),
- {ok, Node} = start_node(Config, "+Mis true"),
- RT = spawn_link(Node, fun () ->
- receive after 1000 -> ok end,
- processes_term_proc_list_test(false),
- Tester ! {it_worked, self()}
- end),
- receive {it_worked, RT} -> ok end,
- stop_node(Node),
+
+ Run = fun(Args) ->
+ {ok, Node} = start_node(Config, Args),
+ RT = spawn_link(Node, fun () ->
+ receive after 1000 -> ok end,
+ as_expected = processes_term_proc_list_test(false),
+ Tester ! {it_worked, self()}
+ end),
+ receive {it_worked, RT} -> ok end,
+ stop_node(Node)
+ end,
+
+ %% We have to run this test case with +S1 since instrument:allocations()
+ %% will report a free()'d block as present until it's actually deallocated
+ %% by its employer.
+ Run("+MSe true +MSatags false +S1"),
+ Run("+MSe true +MSatags true +S1"),
+
ok.
-
+
-define(CHK_TERM_PROC_LIST(MC, XB),
chk_term_proc_list(?LINE, MC, XB)).
chk_term_proc_list(Line, MustChk, ExpectBlks) ->
- case {MustChk, instrument:memory_status(types)} of
- {false, false} ->
+ Allocs = instrument:allocations(#{ allocator_types => [sl_alloc] }),
+ case {MustChk, Allocs} of
+ {false, {error, not_enabled}} ->
not_enabled;
- {_, MS} ->
- {value,
- {ptab_list_deleted_el,
- DL}} = lists:keysearch(ptab_list_deleted_el, 1, MS),
- case lists:keysearch(blocks, 1, DL) of
- {value, {blocks, ExpectBlks, _, _}} ->
- ok;
- {value, {blocks, Blks, _, _}} ->
- exit({line, Line,
- mismatch, expected, ExpectBlks, actual, Blks});
- Unexpected ->
- exit(Unexpected)
+ {_, {ok, {_Shift, _Unscanned, ByOrigin}}} ->
+ ByType = maps:get(system, ByOrigin, #{}),
+ Hist = maps:get(ptab_list_deleted_el, ByType, {}),
+ case lists:sum(tuple_to_list(Hist)) of
+ ExpectBlks ->
+ ok;
+ Blks ->
+ exit({line, Line, mismatch,
+ expected, ExpectBlks,
+ actual, Blks})
end
end,
ok.
diff --git a/erts/emulator/test/tracer_SUITE.erl b/erts/emulator/test/tracer_SUITE.erl
index ab7d047bc3..e1362ef07a 100644
--- a/erts/emulator/test/tracer_SUITE.erl
+++ b/erts/emulator/test/tracer_SUITE.erl
@@ -30,7 +30,8 @@
-export([load/1, unload/1, reload/1, invalid_tracers/1]).
-export([send/1, recv/1, call/1, call_return/1, spawn/1, exit/1,
link/1, unlink/1, getting_linked/1, getting_unlinked/1,
- register/1, unregister/1, in/1, out/1, gc_start/1, gc_end/1]).
+ register/1, unregister/1, in/1, out/1, gc_start/1, gc_end/1,
+ seq_trace/1]).
suite() -> [{ct_hooks,[ts_install_cth]},
{timetrap, {minutes, 1}}].
@@ -41,7 +42,8 @@ all() ->
groups() ->
[{ basic, [], [send, recv, call, call_return, spawn, exit,
link, unlink, getting_linked, getting_unlinked,
- register, unregister, in, out, gc_start, gc_end]}].
+ register, unregister, in, out, gc_start, gc_end,
+ seq_trace]}].
init_per_suite(Config) ->
erlang:trace_pattern({'_','_','_'}, false, [local]),
@@ -583,6 +585,24 @@ gc_end(_Config) ->
test(gc_major_end, garbage_collection, Tc, Expect, false).
+seq_trace(_Config) ->
+
+ seq_trace:set_system_tracer({tracer_test,
+ {#{ seq_trace => trace }, self(), []}}),
+ erlang:spawn(fun() ->
+ seq_trace:set_token(label,17),
+ seq_trace:set_token(print,true),
+ seq_trace:print(17,"**** Trace Started ****")
+ end),
+ receive
+ {seq_trace, _, 17, {print, _, _, _, _}, _} ->
+ ok;
+ M ->
+ ct:fail("~p~n",[M])
+ after 100 ->
+ ct:fail(timeout)
+ end.
+
test(Event, Tc, Expect) ->
test(Event, Tc, Expect, false).
test(Event, Tc, Expect, Removes) ->
diff --git a/erts/emulator/test/z_SUITE.erl b/erts/emulator/test/z_SUITE.erl
index ac3df8bfbf..103f9f1550 100644
--- a/erts/emulator/test/z_SUITE.erl
+++ b/erts/emulator/test/z_SUITE.erl
@@ -37,6 +37,7 @@
-export([schedulers_alive/1, node_container_refc_check/1,
long_timers/1, pollset_size/1,
check_io_debug/1, get_check_io_info/0,
+ lc_graph/1,
leaked_processes/1]).
suite() ->
@@ -46,6 +47,7 @@ suite() ->
all() ->
[schedulers_alive, node_container_refc_check,
long_timers, pollset_size, check_io_debug,
+ lc_graph,
%% Make sure that the leaked_processes/1 is always
%% run last.
leaked_processes].
@@ -289,6 +291,12 @@ has_gethost([P|T]) ->
has_gethost([]) ->
false.
+lc_graph(Config) when is_list(Config) ->
+ %% Create "lc_graph" file in current working dir
+ %% if lock checker is enabled
+ erts_debug:lc_graph(),
+ ok.
+
leaked_processes(Config) when is_list(Config) ->
%% Replace the defualt timetrap with a timetrap with
%% known pid.