summaryrefslogtreecommitdiff
path: root/lib/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib')
-rw-r--r--lib/stdlib/src/digraph.erl4
-rw-r--r--lib/stdlib/test/digraph_SUITE.erl51
-rw-r--r--lib/stdlib/test/ets_SUITE.erl116
-rw-r--r--lib/stdlib/test/gen_statem_SUITE.erl107
4 files changed, 163 insertions, 115 deletions
diff --git a/lib/stdlib/src/digraph.erl b/lib/stdlib/src/digraph.erl
index 8a4df95027..58d493cf54 100644
--- a/lib/stdlib/src/digraph.erl
+++ b/lib/stdlib/src/digraph.erl
@@ -230,7 +230,7 @@ in_neighbours(G, V) ->
Edges :: [edge()].
in_edges(G, V) ->
- ets:select(G#digraph.ntab, [{{{in, V}, '$1'}, [], ['$1']}]).
+ [E || {{in, _}, E} <- ets:lookup(G#digraph.ntab, {in, V})].
-spec out_degree(G, V) -> non_neg_integer() when
G :: graph(),
@@ -255,7 +255,7 @@ out_neighbours(G, V) ->
Edges :: [edge()].
out_edges(G, V) ->
- ets:select(G#digraph.ntab, [{{{out, V}, '$1'}, [], ['$1']}]).
+ [E || {{out, _}, E} <- ets:lookup(G#digraph.ntab, {out, V})].
-spec add_edge(G, V1, V2) -> edge() | {'error', add_edge_err_rsn()} when
G :: graph(),
diff --git a/lib/stdlib/test/digraph_SUITE.erl b/lib/stdlib/test/digraph_SUITE.erl
index b5d3452616..ce0bc90f1c 100644
--- a/lib/stdlib/test/digraph_SUITE.erl
+++ b/lib/stdlib/test/digraph_SUITE.erl
@@ -31,7 +31,7 @@
init_per_group/2,end_per_group/2]).
-export([opts/1, degree/1, path/1, cycle/1, vertices/1,
- edges/1, data/1, otp_3522/1, otp_3630/1, otp_8066/1]).
+ edges/1, data/1, otp_3522/1, otp_3630/1, otp_8066/1, vertex_names/1]).
-export([spawn_graph/2]).
@@ -41,10 +41,10 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[opts, degree, path, cycle, {group, misc},
- {group, tickets}].
+ {group, tickets}, vertex_names].
groups() ->
- [{misc, [], [vertices, edges, data]},
+ [{misc, [], [vertices, edges, data, vertex_names]},
{tickets, [], [otp_3522, otp_3630, otp_8066]}].
init_per_suite(Config) ->
@@ -337,6 +337,51 @@ otp_8066(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+vertex_names(Config) when is_list(Config) ->
+ %% Check that a node named '_' does not lead to wildcard matches
+ %% in ets.
+
+ G = digraph:new([acyclic]),
+ A = digraph:add_vertex(G, 'A'),
+ B = digraph:add_vertex(G, '_'),
+ AB = digraph:add_edge(G, A, B),
+
+ %% Link A -> B
+ 1 = digraph:out_degree(G, A),
+ 1 = digraph:in_degree(G, B),
+ 0 = digraph:out_degree(G, B),
+ 0 = digraph:in_degree(G, A),
+ [B] = digraph:out_neighbours(G, A),
+ [A] = digraph:in_neighbours(G, B),
+ [] = digraph:out_neighbours(G, B),
+ [] = digraph:in_neighbours(G, A),
+ [AB] = digraph:out_edges(G, A),
+ [AB] = digraph:in_edges(G, B),
+ [] = digraph:out_edges(G, B),
+ [] = digraph:in_edges(G, A),
+
+ %% Reverse the edge
+ digraph:del_edge(G, AB),
+ BA = digraph:add_edge(G, B, A),
+
+ 1 = digraph:out_degree(G, B),
+ 1 = digraph:in_degree(G, A),
+ 0 = digraph:out_degree(G, A),
+ 0 = digraph:in_degree(G, B),
+ [A] = digraph:out_neighbours(G, B),
+ [B] = digraph:in_neighbours(G, A),
+ [] = digraph:out_neighbours(G, A),
+ [] = digraph:in_neighbours(G, B),
+ [BA] = digraph:out_edges(G, B),
+ [BA] = digraph:in_edges(G, A),
+ [] = digraph:out_edges(G, A),
+ [] = digraph:in_edges(G, B),
+
+ digraph:delete(G),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
sane(G) ->
sane1(G),
erase(sane) =:= undefined.
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 3b2dde6b9b..9e5410c10f 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -1278,9 +1278,9 @@ ets_insert_new_with_check(Table, ToInsert) ->
t_insert_list_parallel_do(Opts) ->
[(fun(I) ->
- t_insert_list_parallel_do(Opts, I, 2, 100, 5000),
- t_insert_list_parallel_do(Opts, I, 10, 100, 500),
- t_insert_list_parallel_do(Opts, I, 1000, 100, 50),
+ t_insert_list_parallel_do(Opts, I, 2, 100, 500),
+ t_insert_list_parallel_do(Opts, I, 10, 100, 100),
+ t_insert_list_parallel_do(Opts, I, 1000, 100, 10),
t_insert_list_parallel_do(Opts, I, 50000, 3, 1)
end)(InsertFun) || InsertFun <- [fun ets_insert_with_check/2,
fun ets_insert_new_with_check/2]].
@@ -5118,7 +5118,7 @@ test_delete_table_while_size_snapshot_helper(TableType) ->
Problem -> TopParent ! Problem
end || _ <- Pids]
end,
- 15000),
+ 100*erlang:system_info(schedulers_online)),
receive
Problem -> throw(Problem)
after 0 -> ok
@@ -6853,7 +6853,7 @@ verify_table_load(T) ->
false;
true ->
- io:format("Stats = ~p\n",[Stats]),
+ io:format("Stats = ~p\n~p\n",[Stats, ets:info(T)]),
ok
end
end.
@@ -8134,58 +8134,60 @@ wait_for_memory_deallocations() ->
end.
etsmem() ->
- % The following is done twice to avoid an inconsistent memory
- % "snapshot" (see verify_etsmem/2).
- lists:foldl(
- fun(AttemptNr, PrevEtsMem) ->
- AllTabsExceptions = [logger, code],
- %% The logger table is excluded from the AllTabs list
- %% below because it uses decentralized counters to keep
- %% track of the size and the memory counters. This cause
- %% ets:info(T,size) and ets:info(T,memory) to trigger
- %% allocations and frees that may change the amount of
- %% memory that is allocated for ETS.
- %%
- %% The code table is excluded from the list below
- %% because the amount of memory allocated for it may
- %% change if the tested code loads a new module.
- AllTabs =
- lists:sort(
- [begin
- try ets:info(T, decentralized_counters) of
- true ->
- ct:fail("Background ETS table (~p) that "
- "uses decentralized counters (Add exception?)",
- [ets:info(T,name)]);
- _ -> ok
- catch _:_ ->
- ok
- end,
- {T,
- ets:info(T,name),
- ets:info(T,size),
- ets:info(T,memory),
- ets:info(T,type)}
- end
- || T <- ets:all(),
- not lists:member(ets:info(T, name), AllTabsExceptions)]),
- wait_for_memory_deallocations(),
- EtsAllocSize = erts_debug:alloc_blocks_size(ets_alloc),
- ErlangMemoryEts = try erlang:memory(ets) catch error:notsup -> notsup end,
- FlxCtrMemUsage = try erts_debug:get_internal_state(flxctr_memory_usage) catch error:badarg -> notsup end,
- Mem = {ErlangMemoryEts, EtsAllocSize, FlxCtrMemUsage},
- EtsMem = {Mem, AllTabs},
- case PrevEtsMem of
- first -> ok;
- _ when PrevEtsMem =:= EtsMem -> ok;
- _ ->
- io:format("etsmem(): Change in attempt ~p~n~nbefore:~n~p~n~nafter:~n~p~n~n",
- [AttemptNr, PrevEtsMem, EtsMem])
- end,
- EtsMem
- end,
- first,
- lists:seq(1,2)).
+ etsmem(get_etsmem(), 1).
+
+etsmem(PrevEtsMem, Try) when Try < 10 ->
+ case get_etsmem() of
+ PrevEtsMem ->
+ PrevEtsMem;
+ EtsMem ->
+ io:format("etsmem(): Change in attempt ~p~n~nbefore:~n~p~n~nafter:~n~p~n~n",
+ [Try, PrevEtsMem, EtsMem]),
+ etsmem(EtsMem, Try+1)
+ end;
+etsmem(_, _) ->
+ ct:fail("Failed to get a stable/consistent memory snapshot").
+
+get_etsmem() ->
+ AllTabsExceptions = [logger, code],
+ %% The logger table is excluded from the AllTabs list
+ %% below because it uses decentralized counters to keep
+ %% track of the size and the memory counters. This cause
+ %% ets:info(T,size) and ets:info(T,memory) to trigger
+ %% allocations and frees that may change the amount of
+ %% memory that is allocated for ETS.
+ %%
+ %% The code table is excluded from the list below
+ %% because the amount of memory allocated for it may
+ %% change if the tested code loads a new module.
+ AllTabs =
+ lists:sort(
+ [begin
+ try ets:info(T, decentralized_counters) of
+ true ->
+ ct:fail("Background ETS table (~p) that "
+ "uses decentralized counters (Add exception?)",
+ [ets:info(T,name)]);
+ _ -> ok
+ catch _:_ ->
+ ok
+ end,
+ {T,
+ ets:info(T,name),
+ ets:info(T,size),
+ ets:info(T,memory),
+ ets:info(T,type)}
+ end
+ || T <- ets:all(),
+ not lists:member(ets:info(T, name), AllTabsExceptions)]),
+ wait_for_memory_deallocations(),
+ EtsAllocSize = erts_debug:alloc_blocks_size(ets_alloc),
+ ErlangMemoryEts = try erlang:memory(ets)
+ catch error:notsup -> notsup end,
+ FlxCtrMemUsage = try erts_debug:get_internal_state(flxctr_memory_usage)
+ catch error:badarg -> notsup end,
+ Mem = {ErlangMemoryEts, EtsAllocSize, FlxCtrMemUsage},
+ {Mem, AllTabs}.
verify_etsmem(MI) ->
wait_for_test_procs(),
diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl
index f40dce5d7a..76dee868e9 100644
--- a/lib/stdlib/test/gen_statem_SUITE.erl
+++ b/lib/stdlib/test/gen_statem_SUITE.erl
@@ -534,10 +534,10 @@ abnormal1(Config) ->
gen_statem:start(LocalSTM, ?MODULE, start_arg(Config, []), []),
%% timeout call.
- delayed = gen_statem:call(Name, {delayed_answer,1}, 100),
+ delayed = gen_statem:call(Name, {delayed_answer,100}, 2000),
{timeout,_} =
?EXPECT_FAILURE(
- gen_statem:call(Name, {delayed_answer,1000}, 10),
+ gen_statem:call(Name, {delayed_answer,2000}, 100),
Reason),
ok = gen_statem:stop(Name),
?t:sleep(1100),
@@ -1437,7 +1437,7 @@ hibernate(Config) ->
{ok,Pid0} =
gen_statem:start_link(
?MODULE, start_arg(Config, hiber_now), []),
- is_in_erlang_hibernate(Pid0),
+ wait_erlang_hibernate(Pid0),
stop_it(Pid0),
receive
{'EXIT',Pid0,normal} -> ok
@@ -1450,23 +1450,23 @@ hibernate(Config) ->
true = ({current_function,{erlang,hibernate,3}} =/=
erlang:process_info(Pid,current_function)),
hibernating = gen_statem:call(Pid, hibernate_sync),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
good_morning = gen_statem:call(Pid, wakeup_sync),
is_not_in_erlang_hibernate(Pid),
hibernating = gen_statem:call(Pid, hibernate_sync),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
please_just_five_more = gen_statem:call(Pid, snooze_sync),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
good_morning = gen_statem:call(Pid, wakeup_sync),
is_not_in_erlang_hibernate(Pid),
ok = gen_statem:cast(Pid, hibernate_async),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
ok = gen_statem:cast(Pid, wakeup_async),
is_not_in_erlang_hibernate(Pid),
ok = gen_statem:cast(Pid, hibernate_async),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
ok = gen_statem:cast(Pid, snooze_async),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
ok = gen_statem:cast(Pid, wakeup_async),
is_not_in_erlang_hibernate(Pid),
@@ -1474,14 +1474,14 @@ hibernate(Config) ->
true =
({current_function,{erlang,hibernate,3}} =/=
erlang:process_info(Pid, current_function)),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
'alive!' = gen_statem:call(Pid, 'alive?'),
true =
({current_function,{erlang,hibernate,3}} =/=
erlang:process_info(Pid, current_function)),
Pid ! hibernate_now,
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
'alive!' = gen_statem:call(Pid, 'alive?'),
true =
@@ -1489,34 +1489,34 @@ hibernate(Config) ->
erlang:process_info(Pid, current_function)),
hibernating = gen_statem:call(Pid, hibernate_sync),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
good_morning = gen_statem:call(Pid, wakeup_sync),
is_not_in_erlang_hibernate(Pid),
hibernating = gen_statem:call(Pid, hibernate_sync),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
please_just_five_more = gen_statem:call(Pid, snooze_sync),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
good_morning = gen_statem:call(Pid, wakeup_sync),
is_not_in_erlang_hibernate(Pid),
ok = gen_statem:cast(Pid, hibernate_async),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
ok = gen_statem:cast(Pid, wakeup_async),
is_not_in_erlang_hibernate(Pid),
ok = gen_statem:cast(Pid, hibernate_async),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
ok = gen_statem:cast(Pid, snooze_async),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
ok = gen_statem:cast(Pid, wakeup_async),
is_not_in_erlang_hibernate(Pid),
hibernating = gen_statem:call(Pid, hibernate_sync),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
sys:suspend(Pid),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
sys:resume(Pid),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
receive after 1000 -> ok end,
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
good_morning = gen_statem:call(Pid, wakeup_sync),
is_not_in_erlang_hibernate(Pid),
@@ -1532,15 +1532,16 @@ hibernate(Config) ->
%% Auto-hibernation timeout
auto_hibernate(Config) ->
OldFl = process_flag(trap_exit, true),
- HibernateAfterTimeout = 100,
+ HibernateAfterTimeout = 1000,
{ok,Pid} =
gen_statem:start_link(
- ?MODULE, start_arg(Config, []), [{hibernate_after, HibernateAfterTimeout}]),
+ ?MODULE, start_arg(Config, []),
+ [{hibernate_after, HibernateAfterTimeout}]),
%% After init test
is_not_in_erlang_hibernate(Pid),
timer:sleep(HibernateAfterTimeout),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
%% After info test
Pid ! {hping, self()},
receive
@@ -1551,7 +1552,7 @@ auto_hibernate(Config) ->
end,
is_not_in_erlang_hibernate(Pid),
timer:sleep(HibernateAfterTimeout),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
%% After cast test
ok = gen_statem:cast(Pid, {hping, self()}),
receive
@@ -1562,42 +1563,42 @@ auto_hibernate(Config) ->
end,
is_not_in_erlang_hibernate(Pid),
timer:sleep(HibernateAfterTimeout),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
%% After call test
hpong = gen_statem:call(Pid, hping),
is_not_in_erlang_hibernate(Pid),
timer:sleep(HibernateAfterTimeout),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
%% Timer test 1
- TimerTimeout1 = 50,
- ok = gen_statem:call(Pid, {arm_htimer, self(), TimerTimeout1}),
+ TimerTimeout1 = HibernateAfterTimeout div 2,
+ ok = gen_statem:call(Pid, {start_htimer, self(), TimerTimeout1}),
is_not_in_erlang_hibernate(Pid),
timer:sleep(TimerTimeout1),
is_not_in_erlang_hibernate(Pid),
receive
- {Pid, htimer_armed} ->
+ {Pid, htimer_timeout} ->
ok
after 1000 ->
ct:fail(timer1)
end,
is_not_in_erlang_hibernate(Pid),
timer:sleep(HibernateAfterTimeout),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
%% Timer test 2
- TimerTimeout2 = 150,
- ok = gen_statem:call(Pid, {arm_htimer, self(), TimerTimeout2}),
+ TimerTimeout2 = HibernateAfterTimeout * 2,
+ ok = gen_statem:call(Pid, {start_htimer, self(), TimerTimeout2}),
is_not_in_erlang_hibernate(Pid),
timer:sleep(HibernateAfterTimeout),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
receive
- {Pid, htimer_armed} ->
+ {Pid, htimer_timeout} ->
ok
- after 1000 ->
+ after TimerTimeout2 ->
ct:fail(timer2)
end,
is_not_in_erlang_hibernate(Pid),
timer:sleep(HibernateAfterTimeout),
- is_in_erlang_hibernate(Pid),
+ wait_erlang_hibernate(Pid),
stop_it(Pid),
process_flag(trap_exit, OldFl),
receive
@@ -1607,38 +1608,38 @@ auto_hibernate(Config) ->
end,
ok = verify_empty_msgq().
-is_in_erlang_hibernate(Pid) ->
+
+wait_erlang_hibernate(Pid) ->
receive after 1 -> ok end,
- is_in_erlang_hibernate_1(200, Pid).
+ wait_erlang_hibernate_1(200, Pid).
-is_in_erlang_hibernate_1(0, Pid) ->
+wait_erlang_hibernate_1(0, Pid) ->
ct:log("~p\n", [erlang:process_info(Pid, current_function)]),
- ct:fail(not_in_erlang_hibernate_3);
-is_in_erlang_hibernate_1(N, Pid) ->
+ ct:fail(should_be_in_erlang_hibernate_3);
+wait_erlang_hibernate_1(N, Pid) ->
{current_function,MFA} = erlang:process_info(Pid, current_function),
case MFA of
{erlang,hibernate,3} ->
ok;
_ ->
receive after 10 -> ok end,
- is_in_erlang_hibernate_1(N-1, Pid)
+ wait_erlang_hibernate_1(N-1, Pid)
end.
is_not_in_erlang_hibernate(Pid) ->
receive after 1 -> ok end,
is_not_in_erlang_hibernate_1(200, Pid).
-is_not_in_erlang_hibernate_1(0, Pid) ->
- ct:log("~p\n", [erlang:process_info(Pid, current_function)]),
- ct:fail(not_in_erlang_hibernate_3);
+is_not_in_erlang_hibernate_1(0, _Pid) ->
+ ct:fail(should_not_be_in_erlang_hibernate_3);
is_not_in_erlang_hibernate_1(N, Pid) ->
{current_function,MFA} = erlang:process_info(Pid, current_function),
case MFA of
- {erlang,hibernate,3} ->
+ {erlang,hibernate,3} ->
receive after 10 -> ok end,
is_not_in_erlang_hibernate_1(N-1, Pid);
- _ ->
- ok
+ _ ->
+ ok
end.
@@ -2430,10 +2431,10 @@ idle(cast, {hping,Pid}, Data) ->
{keep_state, Data};
idle({call, From}, hping, _Data) ->
{keep_state_and_data, [{reply, From, hpong}]};
-idle({call, From}, {arm_htimer, Pid, Timeout}, _Data) ->
- {keep_state_and_data, [{reply, From, ok}, {timeout, Timeout, {arm_htimer, Pid}}]};
-idle(timeout, {arm_htimer, Pid}, _Data) ->
- Pid ! {self(), htimer_armed},
+idle({call, From}, {start_htimer, Pid, Timeout}, _Data) ->
+ {keep_state_and_data, [{reply, From, ok}, {timeout, Timeout, {htimer, Pid}}]};
+idle(timeout, {htimer, Pid}, _Data) ->
+ Pid ! {self(), htimer_timeout},
keep_state_and_data;
idle(cast, {connect,Pid}, Data) ->
Pid ! accept,