aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib/test
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib/test')
-rw-r--r--lib/stdlib/test/Makefile1
-rw-r--r--lib/stdlib/test/beam_lib_SUITE.erl56
-rw-r--r--lib/stdlib/test/dets_SUITE.erl321
-rw-r--r--lib/stdlib/test/epp_SUITE.erl37
-rw-r--r--lib/stdlib/test/epp_SUITE_data/bar.hrl4
-rw-r--r--lib/stdlib/test/epp_SUITE_data/include/bar.hrl3
-rw-r--r--lib/stdlib/test/epp_SUITE_data/include/foo.hrl4
-rw-r--r--lib/stdlib/test/epp_SUITE_data/include_local.erl6
-rw-r--r--lib/stdlib/test/erl_eval_SUITE.erl10
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl2
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl7
-rw-r--r--lib/stdlib/test/erl_scan_SUITE.erl4
-rw-r--r--lib/stdlib/test/ets_SUITE.erl360
-rw-r--r--lib/stdlib/test/file_sorter_SUITE.erl16
-rw-r--r--lib/stdlib/test/filelib_SUITE.erl11
-rw-r--r--lib/stdlib/test/gen_server_SUITE.erl2
-rw-r--r--lib/stdlib/test/io_SUITE.erl30
-rw-r--r--lib/stdlib/test/ms_transform_SUITE.erl45
-rw-r--r--lib/stdlib/test/proc_lib_SUITE.erl2
-rw-r--r--lib/stdlib/test/qlc_SUITE.erl2
-rw-r--r--lib/stdlib/test/re_SUITE.erl92
-rw-r--r--lib/stdlib/test/shell_SUITE.erl6
-rw-r--r--lib/stdlib/test/sofs_SUITE.erl33
-rw-r--r--lib/stdlib/test/string_SUITE.erl4
-rw-r--r--lib/stdlib/test/supervisor_1.erl6
-rw-r--r--lib/stdlib/test/supervisor_2.erl42
-rw-r--r--lib/stdlib/test/supervisor_SUITE.erl401
-rw-r--r--lib/stdlib/test/supervisor_bridge_SUITE.erl44
-rw-r--r--lib/stdlib/test/sys_SUITE.erl2
-rw-r--r--lib/stdlib/test/tar_SUITE.erl78
-rw-r--r--lib/stdlib/test/timer_simple_SUITE.erl31
-rw-r--r--lib/stdlib/test/unicode_SUITE.erl4
-rw-r--r--lib/stdlib/test/zip_SUITE.erl3
33 files changed, 1224 insertions, 445 deletions
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
index 5502c69fa5..aa6a660c34 100644
--- a/lib/stdlib/test/Makefile
+++ b/lib/stdlib/test/Makefile
@@ -65,6 +65,7 @@ MODULES= \
stdlib_SUITE \
string_SUITE \
supervisor_1 \
+ supervisor_2 \
naughty_child \
shell_SUITE \
supervisor_SUITE \
diff --git a/lib/stdlib/test/beam_lib_SUITE.erl b/lib/stdlib/test/beam_lib_SUITE.erl
index 4ccc863795..5df19ca7f1 100644
--- a/lib/stdlib/test/beam_lib_SUITE.erl
+++ b/lib/stdlib/test/beam_lib_SUITE.erl
@@ -181,7 +181,8 @@ error(Conf) when is_list(Conf) ->
?line verify(not_a_beam_file, beam_lib:info(<<"short">>)),
?line {Binary1, _} = split_binary(Binary, byte_size(Binary)-10),
- ?line verify(chunk_too_big, beam_lib:chunks(Binary1, ["Abst"])),
+ LastChunk = last_chunk(Binary),
+ ?line verify(chunk_too_big, beam_lib:chunks(Binary1, [LastChunk])),
?line Chunks = chunk_info(Binary),
?line {value, {_, AbstractStart, _}} = lists:keysearch("Abst", 1, Chunks),
?line {Binary2, _} = split_binary(Binary, AbstractStart),
@@ -205,6 +206,12 @@ error(Conf) when is_list(Conf) ->
?line file:delete(ACopy),
ok.
+last_chunk(Bin) ->
+ L = beam_lib:info(Bin),
+ {chunks,Chunks} = lists:keyfind(chunks, 1, L),
+ {Last,_,_} = lists:last(Chunks),
+ Last.
+
do_error(BeamFile, ACopy) ->
% evil tests
?line Chunks = chunk_info(BeamFile),
@@ -242,8 +249,8 @@ cmp(doc) -> ["Compare contents of BEAM files and directories"];
cmp(Conf) when is_list(Conf) ->
?line PrivDir = ?privdir,
- ?line Dir1 = filename:join(PrivDir, dir1),
- ?line Dir2 = filename:join(PrivDir, dir2),
+ ?line Dir1 = filename:join(PrivDir, "dir1"),
+ ?line Dir2 = filename:join(PrivDir, "dir2"),
ok = file:make_dir(Dir1),
ok = file:make_dir(Dir2),
@@ -292,8 +299,8 @@ cmp_literals(doc) -> ["Compare contents of BEAM files having literals"];
cmp_literals(Conf) when is_list(Conf) ->
?line PrivDir = ?privdir,
- ?line Dir1 = filename:join(PrivDir, dir1),
- ?line Dir2 = filename:join(PrivDir, dir2),
+ ?line Dir1 = filename:join(PrivDir, "dir1"),
+ ?line Dir2 = filename:join(PrivDir, "dir2"),
ok = file:make_dir(Dir1),
ok = file:make_dir(Dir2),
@@ -330,6 +337,7 @@ strip(Conf) when is_list(Conf) ->
?line {Source2D1, BeamFile2D1} = make_beam(PrivDir, simple2, concat),
?line {Source3D1, BeamFile3D1} = make_beam(PrivDir, make_fun, make_fun),
?line {Source4D1, BeamFile4D1} = make_beam(PrivDir, constant, constant),
+ ?line {Source5D1, BeamFile5D1} = make_beam(PrivDir, lines, lines),
?line NoOfTables = length(ets:all()),
?line P0 = pps(),
@@ -360,13 +368,25 @@ strip(Conf) when is_list(Conf) ->
?line {module, make_fun} = code:load_abs(filename:rootname(BeamFile3D1)),
?line {module, constant} = code:load_abs(filename:rootname(BeamFile4D1)),
+ %% check that line number information is still present after stripping
+ ?line {module, lines} = code:load_abs(filename:rootname(BeamFile5D1)),
+ ?line {'EXIT',{badarith,[{lines,t,1,Info}|_]}} =
+ (catch lines:t(atom)),
+ ?line true = code:delete(lines),
+ ?line false = code:purge(lines),
+ ?line {ok, {lines,BeamFile5D1}} = beam_lib:strip(BeamFile5D1),
+ ?line {module, lines} = code:load_abs(filename:rootname(BeamFile5D1)),
+ ?line {'EXIT',{badarith,[{lines,t,1,Info}|_]}} =
+ (catch lines:t(atom)),
+
?line true = (P0 == pps()),
?line NoOfTables = length(ets:all()),
?line delete_files([SourceD1, BeamFileD1,
Source2D1, BeamFile2D1,
Source3D1, BeamFile3D1,
- Source4D1, BeamFile4D1]),
+ Source4D1, BeamFile4D1,
+ Source5D1, BeamFile5D1]),
ok.
@@ -381,7 +401,7 @@ otp_6711(Conf) when is_list(Conf) ->
(catch {a, beam_lib:strip_files([3])}),
?line PrivDir = ?privdir,
- ?line Dir = filename:join(PrivDir, dir),
+ ?line Dir = filename:join(PrivDir, "dir"),
?line Lib = filename:join(Dir, "lib"),
?line App = filename:join(Lib, "app"),
?line EBin = filename:join(App, "ebin"),
@@ -417,8 +437,8 @@ building(doc) -> "Testing building of BEAM files.";
building(Conf) when is_list(Conf) ->
?line PrivDir = ?privdir,
- ?line Dir1 = filename:join(PrivDir, b_dir1),
- ?line Dir2 = filename:join(PrivDir, b_dir2),
+ ?line Dir1 = filename:join(PrivDir, "b_dir1"),
+ ?line Dir2 = filename:join(PrivDir, "b_dir2"),
ok = file:make_dir(Dir1),
ok = file:make_dir(Dir2),
@@ -571,8 +591,18 @@ do_encrypted_abstr(Beam, Key) ->
?line {ok,{simple,[{"Abst",Abst}]}} = beam_lib:chunks(Beam, ["Abst"]),
?line {ok,cleared} = beam_lib:clear_crypto_key_fun(),
+
+ %% Try to force a stop/start race.
+ ?line start_stop_race(10000),
+
ok.
+start_stop_race(0) ->
+ ok;
+start_stop_race(N) ->
+ {error,_} = beam_lib:crypto_key_fun(bad_fun),
+ undefined = beam_lib:clear_crypto_key_fun(),
+ start_stop_race(N-1).
bad_fun(F) ->
{error,E} = beam_lib:crypto_key_fun(F),
@@ -688,7 +718,7 @@ chunk_info(File) ->
Chunks.
make_beam(Dir, Module, F) ->
- ?line FileBase = filename:join(Dir, Module),
+ ?line FileBase = filename:join(Dir, atom_to_list(Module)),
?line Source = FileBase ++ ".erl",
?line BeamFile = FileBase ++ ".beam",
?line simple_file(Source, Module, F),
@@ -773,6 +803,12 @@ simple_file(File, Module, constant2) ->
"t(A) -> "
" {a,b,[2,3],x,y}. "]),
ok = file:write_file(File, B);
+simple_file(File, Module, lines) ->
+ B = list_to_binary(["-module(", atom_to_list(Module), ").\n"
+ "-export([t/1]).\n"
+ "t(A) ->\n"
+ " A+1.\n"]),
+ ok = file:write_file(File, B);
simple_file(File, Module, F) ->
B = list_to_binary(["-module(", atom_to_list(Module), "). "
"-export([t/0]). "
diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl
index 9fcc9e6aaf..6f77cff2b9 100644
--- a/lib/stdlib/test/dets_SUITE.erl
+++ b/lib/stdlib/test/dets_SUITE.erl
@@ -34,6 +34,8 @@
-define(datadir(Conf), ?config(data_dir, Conf)).
-endif.
+-compile(r13). % OTP-9607
+
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
not_run/1, newly_started/1, basic_v8/1, basic_v9/1,
@@ -53,7 +55,7 @@
simultaneous_open/1, insert_new/1, repair_continuation/1,
otp_5487/1, otp_6206/1, otp_6359/1, otp_4738/1, otp_7146/1,
otp_8070/1, otp_8856/1, otp_8898/1, otp_8899/1, otp_8903/1,
- otp_8923/1]).
+ otp_8923/1, otp_9282/1, otp_9607/1]).
-export([dets_dirty_loop/0]).
@@ -112,7 +114,7 @@ all() ->
many_clients, otp_4906, otp_5402, simultaneous_open,
insert_new, repair_continuation, otp_5487, otp_6206,
otp_6359, otp_4738, otp_7146, otp_8070, otp_8856, otp_8898,
- otp_8899, otp_8903, otp_8923]
+ otp_8899, otp_8903, otp_8923, otp_9282, otp_9607]
end.
groups() ->
@@ -554,7 +556,11 @@ dets_dirty_loop() ->
{From, [write, Name, Value]} ->
Ret = dets:insert(Name, Value),
From ! {self(), Ret},
- dets_dirty_loop()
+ dets_dirty_loop();
+ {From, [close, Name]} ->
+ Ret = dets:close(Name),
+ From ! {self(), Ret},
+ dets_dirty_loop()
end.
@@ -1516,7 +1522,7 @@ repair(Config, V) ->
if
V =:= 8 ->
%% first estimated number of objects is wrong, repair once more
- ?line {ok, Fd} = file:open(Fname, read_write),
+ ?line {ok, Fd} = file:open(Fname, [read,write]),
NoPos = HeadSize - 8, % no_objects
?line file:pwrite(Fd, NoPos, <<0:32>>), % NoItems
ok = file:close(Fd),
@@ -1568,8 +1574,10 @@ repair(Config, V) ->
?line FileSize = dets:info(TabRef, memory),
?line ok = dets:close(TabRef),
crash(Fname, FileSize+20),
- ?line {error, {bad_freelists, Fname}} =
+ %% Used to return bad_freelists, but that changed in OTP-9622
+ ?line {ok, TabRef} =
dets:open_file(TabRef, [{file,Fname},{version,V}]),
+ ?line ok = dets:close(TabRef),
?line file:delete(Fname),
%% File not closed, opening with read and read_write access tried.
@@ -1857,10 +1865,10 @@ fixtable(Config, Version) when is_list(Config) ->
?line {ok, _} = dets:open_file(T, Args),
%% badarg
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:safe_fixtable(no_table,true)),
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[T,undefined]}|_]}} =
- (catch dets:safe_fixtable(T,undefined)),
+ ?line check_badarg(catch dets:safe_fixtable(no_table,true),
+ dets, safe_fixtable, [no_table,true]),
+ ?line check_badarg(catch dets:safe_fixtable(T,undefined),
+ dets, safe_fixtable, [T,undefined]),
%% The table is not allowed to grow while the elements are inserted:
@@ -1940,22 +1948,22 @@ match(Config, Version) ->
%% match, badarg
MSpec = [{'_',[],['$_']}],
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:match(no_table, '_')),
- ?line {'EXIT', {badarg, [{dets,match,[T,'_',not_a_number]}|_]}} =
- (catch dets:match(T, '_', not_a_number)),
+ ?line check_badarg(catch dets:match(no_table, '_'),
+ dets, safe_fixtable, [no_table,true]),
+ ?line check_badarg(catch dets:match(T, '_', not_a_number),
+ dets, match, [T,'_',not_a_number]),
?line {EC1, _} = dets:select(T, MSpec, 1),
- ?line {'EXIT', {badarg, [{dets,match,[EC1]}|_]}} =
- (catch dets:match(EC1)),
+ ?line check_badarg(catch dets:match(EC1),
+ dets, match, [EC1]),
%% match_object, badarg
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:match_object(no_table, '_')),
- ?line {'EXIT', {badarg, [{dets,match_object,[T,'_',not_a_number]}|_]}} =
- (catch dets:match_object(T, '_', not_a_number)),
+ ?line check_badarg(catch dets:match_object(no_table, '_'),
+ dets, safe_fixtable, [no_table,true]),
+ ?line check_badarg(catch dets:match_object(T, '_', not_a_number),
+ dets, match_object, [T,'_',not_a_number]),
?line {EC2, _} = dets:select(T, MSpec, 1),
- ?line {'EXIT', {badarg, [{dets,match_object,[EC2]}|_]}} =
- (catch dets:match_object(EC2)),
+ ?line check_badarg(catch dets:match_object(EC2),
+ dets, match_object, [EC2]),
dets:safe_fixtable(T, true),
?line {[_, _], C1} = dets:match_object(T, '_', 2),
@@ -2118,17 +2126,17 @@ select(Config, Version) ->
%% badarg
MSpec = [{'_',[],['$_']}],
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:select(no_table, MSpec)),
- ?line {'EXIT', {badarg, [{dets,select,[T,<<17>>]}|_]}} =
- (catch dets:select(T, <<17>>)),
- ?line {'EXIT', {badarg, [{dets,select,[T,[]]}|_]}} =
- (catch dets:select(T, [])),
- ?line {'EXIT', {badarg, [{dets,select,[T,MSpec,not_a_number]}|_]}} =
- (catch dets:select(T, MSpec, not_a_number)),
+ ?line check_badarg(catch dets:select(no_table, MSpec),
+ dets, safe_fixtable, [no_table,true]),
+ ?line check_badarg(catch dets:select(T, <<17>>),
+ dets, select, [T,<<17>>]),
+ ?line check_badarg(catch dets:select(T, []),
+ dets, select, [T,[]]),
+ ?line check_badarg(catch dets:select(T, MSpec, not_a_number),
+ dets, select, [T,MSpec,not_a_number]),
?line {EC, _} = dets:match(T, '_', 1),
- ?line {'EXIT', {badarg, [{dets,select,[EC]}|_]}} =
- (catch dets:select(EC)),
+ ?line check_badarg(catch dets:select(EC),
+ dets, select, [EC]),
AllSpec = [{'_',[],['$_']}],
@@ -2210,8 +2218,8 @@ update_counter(Config) when is_list(Config) ->
?line file:delete(Fname),
P0 = pps(),
- ?line {'EXIT', {badarg, [{dets,update_counter,[no_table,1,1]}|_]}} =
- (catch dets:update_counter(no_table, 1, 1)),
+ ?line check_badarg(catch dets:update_counter(no_table, 1, 1),
+ dets, update_counter, [no_table,1,1]),
Args = [{file,Fname},{keypos,2}],
?line {ok, _} = dets:open_file(T, [{type,set} | Args]),
@@ -2254,66 +2262,66 @@ badarg(Config) when is_list(Config) ->
%% badargs are tested in match, select and fixtable too.
%% open
- ?line {'EXIT', {badarg, [{dets,open_file,[{a,tuple},[]]}|_]}} =
- (catch dets:open_file({a,tuple},[])),
- ?line {'EXIT', {badarg, [{dets,open_file,[{a,tuple}]}|_]}} =
- (catch dets:open_file({a,tuple})),
- ?line {'EXIT', {badarg, [{dets,open_file,[file,[foo]]}|_]}} =
- (catch dets:open_file(file,[foo])),
- ?line {'EXIT', {badarg,[{dets,open_file,[{hej,san},[{type,set}|3]]}|_]}} =
- (catch dets:open_file({hej,san},[{type,set}|3])),
+ ?line check_badarg(catch dets:open_file({a,tuple},[]),
+ dets, open_file, [{a,tuple},[]]),
+ ?line check_badarg(catch dets:open_file({a,tuple}),
+ dets, open_file,[{a,tuple}]),
+ ?line check_badarg(catch dets:open_file(file,[foo]),
+ dets, open_file, [file,[foo]]),
+ ?line check_badarg(catch dets:open_file({hej,san},[{type,set}|3]),
+ dets, open_file, [{hej,san},[{type,set}|3]]),
%% insert
- ?line {'EXIT', {badarg, [{dets,insert,[no_table,{1,2}]}|_]}} =
- (catch dets:insert(no_table, {1,2})),
- ?line {'EXIT', {badarg, [{dets,insert,[no_table,[{1,2}]]}|_]}} =
- (catch dets:insert(no_table, [{1,2}])),
- ?line {'EXIT', {badarg, [{dets,insert,[T,{1,2}]}|_]}} =
- (catch dets:insert(T, {1,2})),
- ?line {'EXIT', {badarg, [{dets,insert,[T,[{1,2}]]}|_]}} =
- (catch dets:insert(T, [{1,2}])),
- ?line {'EXIT', {badarg, [{dets,insert,[T,[{1,2,3}|3]]}|_]}} =
- (catch dets:insert(T, [{1,2,3} | 3])),
+ ?line check_badarg(catch dets:insert(no_table, {1,2}),
+ dets, insert, [no_table,{1,2}]),
+ ?line check_badarg(catch dets:insert(no_table, [{1,2}]),
+ dets, insert, [no_table,[{1,2}]]),
+ ?line check_badarg(catch dets:insert(T, {1,2}),
+ dets, insert, [T,{1,2}]),
+ ?line check_badarg(catch dets:insert(T, [{1,2}]),
+ dets, insert, [T,[{1,2}]]),
+ ?line check_badarg(catch dets:insert(T, [{1,2,3} | 3]),
+ dets, insert, [T,[{1,2,3}|3]]),
%% lookup{_keys}
- ?line {'EXIT', {badarg, [{dets,lookup_keys,[badarg,[]]}|_]}} =
- (catch dets:lookup_keys(T, [])),
- ?line {'EXIT', {badarg, [{dets,lookup,[no_table,1]}|_]}} =
- (catch dets:lookup(no_table, 1)),
- ?line {'EXIT', {badarg, [{dets,lookup_keys,[T,[1|2]]}|_]}} =
- (catch dets:lookup_keys(T, [1 | 2])),
+ ?line check_badarg(catch dets:lookup_keys(T, []),
+ dets, lookup_keys, [badarg,[]]),
+ ?line check_badarg(catch dets:lookup(no_table, 1),
+ dets, lookup, [no_table,1]),
+ ?line check_badarg(catch dets:lookup_keys(T, [1 | 2]),
+ dets, lookup_keys, [T,[1|2]]),
%% member
- ?line {'EXIT', {badarg, [{dets,member,[no_table,1]}|_]}} =
- (catch dets:member(no_table, 1)),
+ ?line check_badarg(catch dets:member(no_table, 1),
+ dets, member, [no_table,1]),
%% sync
- ?line {'EXIT', {badarg, [{dets,sync,[no_table]}|_]}} =
- (catch dets:sync(no_table)),
+ ?line check_badarg(catch dets:sync(no_table),
+ dets, sync, [no_table]),
%% delete{_keys}
- ?line {'EXIT', {badarg, [{dets,delete,[no_table,1]}|_]}} =
- (catch dets:delete(no_table, 1)),
+ ?line check_badarg(catch dets:delete(no_table, 1),
+ dets, delete, [no_table,1]),
%% delete_object
- ?line {'EXIT', {badarg, [{dets,delete_object,[no_table,{1,2,3}]}|_]}} =
- (catch dets:delete_object(no_table, {1,2,3})),
- ?line {'EXIT', {badarg, [{dets,delete_object,[T,{1,2}]}|_]}} =
- (catch dets:delete_object(T, {1,2})),
- ?line {'EXIT', {badarg, [{dets,delete_object,[no_table,[{1,2,3}]]}|_]}} =
- (catch dets:delete_object(no_table, [{1,2,3}])),
- ?line {'EXIT', {badarg, [{dets,delete_object,[T,[{1,2}]]}|_]}} =
- (catch dets:delete_object(T, [{1,2}])),
- ?line {'EXIT', {badarg, [{dets,delete_object,[T,[{1,2,3}|3]]}|_]}} =
- (catch dets:delete_object(T, [{1,2,3} | 3])),
+ ?line check_badarg(catch dets:delete_object(no_table, {1,2,3}),
+ dets, delete_object, [no_table,{1,2,3}]),
+ ?line check_badarg(catch dets:delete_object(T, {1,2}),
+ dets, delete_object, [T,{1,2}]),
+ ?line check_badarg(catch dets:delete_object(no_table, [{1,2,3}]),
+ dets, delete_object, [no_table,[{1,2,3}]]),
+ ?line check_badarg(catch dets:delete_object(T, [{1,2}]),
+ dets, delete_object, [T,[{1,2}]]),
+ ?line check_badarg(catch dets:delete_object(T, [{1,2,3} | 3]),
+ dets, delete_object, [T,[{1,2,3}|3]]),
%% first,next,slot
- ?line {'EXIT', {badarg, [{dets,first,[no_table]}|_]}} =
- (catch dets:first(no_table)),
- ?line {'EXIT', {badarg, [{dets,next,[no_table,1]}|_]}} =
- (catch dets:next(no_table, 1)),
- ?line {'EXIT', {badarg, [{dets,slot,[no_table,0]}|_]}} =
- (catch dets:slot(no_table, 0)),
+ ?line check_badarg(catch dets:first(no_table),
+ dets, first, [no_table]),
+ ?line check_badarg(catch dets:next(no_table, 1),
+ dets, next, [no_table,1]),
+ ?line check_badarg(catch dets:slot(no_table, 0),
+ dets, slot, [no_table,0]),
%% info
?line undefined = dets:info(no_table),
@@ -2321,27 +2329,27 @@ badarg(Config) when is_list(Config) ->
?line undefined = dets:info(T, foo),
%% match_delete
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:match_delete(no_table, '_')),
+ ?line check_badarg(catch dets:match_delete(no_table, '_'),
+ dets, safe_fixtable, [no_table,true]),
%% delete_all_objects
- ?line {'EXIT', {badarg, [{dets,delete_all_objects,[no_table]}|_]}} =
- (catch dets:delete_all_objects(no_table)),
+ ?line check_badarg(catch dets:delete_all_objects(no_table),
+ dets, delete_all_objects, [no_table]),
%% select_delete
MSpec = [{'_',[],['$_']}],
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:select_delete(no_table, MSpec)),
- ?line {'EXIT', {badarg, [{dets,select_delete,[T, <<17>>]}|_]}} =
- (catch dets:select_delete(T, <<17>>)),
+ ?line check_badarg(catch dets:select_delete(no_table, MSpec),
+ dets, safe_fixtable, [no_table,true]),
+ ?line check_badarg(catch dets:select_delete(T, <<17>>),
+ dets, select_delete, [T, <<17>>]),
%% traverse, fold
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:traverse(no_table, fun(_) -> continue end)),
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:foldl(fun(_, A) -> A end, [], no_table)),
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:foldr(fun(_, A) -> A end, [], no_table)),
+ ?line check_badarg(catch dets:traverse(no_table, fun(_) -> continue end),
+ dets, safe_fixtable, [no_table,true]),
+ ?line check_badarg(catch dets:foldl(fun(_, A) -> A end, [], no_table),
+ dets, safe_fixtable, [no_table,true]),
+ ?line check_badarg(catch dets:foldr(fun(_, A) -> A end, [], no_table),
+ dets, safe_fixtable, [no_table,true]),
%% close
?line ok = dets:close(T),
@@ -2349,15 +2357,16 @@ badarg(Config) when is_list(Config) ->
?line {error, not_owner} = dets:close(T),
%% init_table
- ?line {'EXIT', {badarg,[{dets,init_table,[no_table,_,[]]}|_]}} =
- (catch dets:init_table(no_table, fun(X) -> X end)),
- ?line {'EXIT', {badarg,[{dets,init_table,[no_table,_,[]]}|_]}} =
- (catch dets:init_table(no_table, fun(X) -> X end, [])),
+ IF = fun(X) -> X end,
+ ?line check_badarg(catch dets:init_table(no_table, IF),
+ dets, init_table, [no_table,IF,[]]),
+ ?line check_badarg(catch dets:init_table(no_table, IF, []),
+ dets, init_table, [no_table,IF,[]]),
%% from_ets
Ets = ets:new(ets,[]),
- ?line {'EXIT', {badarg,[{dets,from_ets,[no_table,_]}|_]}} =
- (catch dets:from_ets(no_table, Ets)),
+ ?line check_badarg(catch dets:from_ets(no_table, Ets),
+ dets, from_ets, [no_table,Ets]),
ets:delete(Ets),
?line {ok, T} = dets:open_file(T, Args),
@@ -3247,7 +3256,7 @@ otp_5402(suite) ->
[];
otp_5402(Config) when is_list(Config) ->
Tab = otp_5402,
- ?line File = filename:join([cannot, write, this, file]),
+ ?line File = filename:join(["cannot", "write", "this", "file"]),
%% close
?line{ok, T} = dets:open_file(Tab, [{ram_file,true},
@@ -3857,15 +3866,118 @@ otp_8923(Config) when is_list(Config) ->
file:delete(File),
ok.
+otp_9282(doc) ->
+ ["OTP-9282. The name of a table can be an arbitrary term"];
+otp_9282(suite) ->
+ [];
+otp_9282(Config) when is_list(Config) ->
+ some_calls(make_ref(), Config),
+ some_calls({a,typical,name}, Config),
+ some_calls(fun() -> a_funny_name end, Config),
+ ok.
+
+some_calls(Tab, Config) ->
+ File = filename(ref, Config),
+ ?line {ok,T} = dets:open_file(Tab, [{file,File}]),
+ ?line T = Tab,
+ ?line false = dets:info(T, safe_fixed),
+ ?line File = dets:info(T, filename),
+ ?line ok = dets:insert(Tab, [{3,0}]),
+ ?line [{3,0}] = dets:lookup(Tab, 3),
+ ?line [{3,0}] = dets:traverse(Tab, fun(X) -> {continue, X} end),
+ ?line ok = dets:close(T),
+ file:delete(File).
+
+otp_9607(doc) ->
+ ["OTP-9607. Test downgrading the slightly changed format."];
+otp_9607(suite) ->
+ [];
+otp_9607(Config) when is_list(Config) ->
+ %% Note: the bug is about almost full tables. The fix of that
+ %% problem is *not* tested here.
+ Version = r13b,
+ case ?t:is_release_available(atom_to_list(Version)) of
+ true ->
+ T = otp_9607,
+ File = filename(T, Config),
+ Key = a,
+ Value = 1,
+ Args = [{file,File}],
+ ?line {ok, T} = dets:open_file(T, Args),
+ ?line ok = dets:insert(T, {Key, Value}),
+ ?line ok = dets:close(T),
+
+ ?line Call = fun(P, A) ->
+ P ! {self(), A},
+ receive
+ {P, Ans} ->
+ Ans
+ after 5000 ->
+ exit(other_process_dead)
+ end
+ end,
+ %% Create a file on the modified format, read the file
+ %% with an emulator that doesn't know about the modified
+ %% format.
+ ?line {ok, Node} = start_node_rel(Version, Version, slave),
+ ?line Pid = rpc:call(Node, erlang, spawn,
+ [?MODULE, dets_dirty_loop, []]),
+ ?line {error,{needs_repair, File}} =
+ Call(Pid, [open, T, Args++[{repair,false}]]),
+ io:format("Expect repair:~n"),
+ ?line {ok, T} = Call(Pid, [open, T, Args]),
+ ?line [{Key,Value}] = Call(Pid, [read, T, Key]),
+ ?line ok = Call(Pid, [close, T]),
+ file:delete(File),
+
+ %% Create a file on the unmodified format. Modify the file
+ %% using an emulator that must not turn the file into the
+ %% modified format. Read the file and make sure it is not
+ %% repaired.
+ ?line {ok, T} = Call(Pid, [open, T, Args]),
+ ?line ok = Call(Pid, [write, T, {Key,Value}]),
+ ?line [{Key,Value}] = Call(Pid, [read, T, Key]),
+ ?line ok = Call(Pid, [close, T]),
+
+ Key2 = b,
+ Value2 = 2,
+
+ ?line {ok, T} = dets:open_file(T, Args),
+ ?line [{Key,Value}] = dets:lookup(T, Key),
+ ?line ok = dets:insert(T, {Key2,Value2}),
+ ?line ok = dets:close(T),
+
+ ?line {ok, T} = Call(Pid, [open, T, Args++[{repair,false}]]),
+ ?line [{Key2,Value2}] = Call(Pid, [read, T, Key2]),
+ ?line ok = Call(Pid, [close, T]),
+
+ ?t:stop_node(Node),
+ file:delete(File),
+ ok;
+ false ->
+ {skipped, "No support for old node"}
+ end.
+
+
+
%%
%% Parts common to several test cases
%%
+start_node_rel(Name, Rel, How) ->
+ Release = [{release, atom_to_list(Rel)}],
+ ?line Pa = filename:dirname(code:which(?MODULE)),
+ ?line test_server:start_node(Name, How,
+ [{args,
+ " -kernel net_setuptime 100 "
+ " -pa " ++ Pa},
+ {erl, Release}]).
+
crash(File, Where) ->
crash(File, Where, 10).
crash(File, Where, What) when is_integer(What) ->
- ?line {ok, Fd} = file:open(File, read_write),
+ ?line {ok, Fd} = file:open(File, [read,write]),
?line file:position(Fd, Where),
?line ok = file:write(Fd, [What]),
?line ok = file:close(Fd).
@@ -4009,7 +4121,7 @@ writable(Fname) ->
?line file:write_file_info(Fname, Info#file_info{mode = Mode}).
truncate(File, Where) ->
- ?line {ok, Fd} = file:open(File, read_write),
+ ?line {ok, Fd} = file:open(File, [read,write]),
?line file:position(Fd, Where),
?line ok = file:truncate(Fd),
?line ok = file:close(Fd).
@@ -4246,6 +4358,11 @@ bad_object({error,{{bad_object,_}, FileName}}, FileName) ->
bad_object({error,{{{bad_object,_,_},_,_,_}, FileName}}, FileName) ->
ok. % Debug.
+check_badarg({'EXIT', {badarg, [{M,F,Args,_} | _]}}, M, F, Args) ->
+ true;
+check_badarg({'EXIT', {badarg, [{M,F,A,_} | _]}}, M, F, Args) ->
+ true = test_server:is_native(M) andalso length(Args) =:= A.
+
check_pps(P0) ->
case pps() of
P0 ->
diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl
index 9b024a5b49..f79414db49 100644
--- a/lib/stdlib/test/epp_SUITE.erl
+++ b/lib/stdlib/test/epp_SUITE.erl
@@ -20,7 +20,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
--export([rec_1/1, predef_mac/1,
+-export([rec_1/1, include_local/1, predef_mac/1,
upcase_mac_1/1, upcase_mac_2/1,
variable_1/1, otp_4870/1, otp_4871/1, otp_5362/1,
pmod/1, not_circular/1, skip_header/1, otp_6277/1, otp_7702/1,
@@ -63,7 +63,7 @@ end_per_testcase(_, Config) ->
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [rec_1, {group, upcase_mac}, predef_mac,
+ [rec_1, {group, upcase_mac}, include_local, predef_mac,
{group, variable}, otp_4870, otp_4871, otp_5362, pmod,
not_circular, skip_header, otp_6277, otp_7702, otp_8130,
overload_mac, otp_8388, otp_8470, otp_8503, otp_8562,
@@ -97,6 +97,22 @@ rec_1(Config) when is_list(Config) ->
?line check_errors(List),
ok.
+include_local(doc) ->
+ [];
+include_local(suite) ->
+ [];
+include_local(Config) when is_list(Config) ->
+ ?line DataDir = ?config(data_dir, Config),
+ ?line File = filename:join(DataDir, "include_local.erl"),
+ %% include_local.erl includes include/foo.hrl which
+ %% includes bar.hrl (also in include/) without requiring
+ %% any additional include path, and overriding any file
+ %% of the same name that the path points to
+ ?line {ok, List} = epp:parse_file(File, [DataDir], []),
+ ?line {value, {attribute,_,a,{true,true}}} =
+ lists:keysearch(a,3,List),
+ ok.
+
%%% Here is a little reimplementation of epp:parse_file, which times out
%%% after 4 seconds if the epp server doesn't respond. If we use the
%%% regular epp:parse_file, the test case will time out, and then epp
@@ -234,16 +250,23 @@ otp_4871(Config) when is_list(Config) ->
%% so there are some sanity checks before killing.
?line {ok,Epp} = epp:open(File, []),
timer:sleep(1),
- ?line {current_function,{epp,_,_}} = process_info(Epp, current_function),
+ ?line true = current_module(Epp, epp),
?line {monitored_by,[Io]} = process_info(Epp, monitored_by),
- ?line {current_function,{file_io_server,_,_}} =
- process_info(Io, current_function),
+ ?line true = current_module(Io, file_io_server),
?line exit(Io, emulate_crash),
timer:sleep(1),
?line {error,{_Line,epp,cannot_parse}} = otp_4871_parse_file(Epp),
?line epp:close(Epp),
ok.
+current_module(Pid, Mod) ->
+ case process_info(Pid, current_function) of
+ {current_function, undefined} ->
+ true = test_server:is_native(Mod);
+ {current_function, {Mod, _, _}} ->
+ true
+ end.
+
otp_4871_parse_file(Epp) ->
case epp:parse_erl_form(Epp) of
{ok,_} -> otp_4871_parse_file(Epp);
@@ -1280,7 +1303,7 @@ eval_tests(Config, Fun, Tests) ->
check_test(Config, Test) ->
- Filename = 'epp_test.erl',
+ Filename = "epp_test.erl",
?line PrivDir = ?config(priv_dir, Config),
?line File = filename:join(PrivDir, Filename),
?line ok = file:write_file(File, Test),
@@ -1293,7 +1316,7 @@ check_test(Config, Test) ->
compile_test(Config, Test0) ->
Test = [<<"-module(epp_test). -compile(export_all). ">>, Test0],
- Filename = 'epp_test.erl',
+ Filename = "epp_test.erl",
?line PrivDir = ?config(priv_dir, Config),
?line File = filename:join(PrivDir, Filename),
?line ok = file:write_file(File, Test),
diff --git a/lib/stdlib/test/epp_SUITE_data/bar.hrl b/lib/stdlib/test/epp_SUITE_data/bar.hrl
new file mode 100644
index 0000000000..01c527d549
--- /dev/null
+++ b/lib/stdlib/test/epp_SUITE_data/bar.hrl
@@ -0,0 +1,4 @@
+%% should not be included from include/foo.hrl even though the
+%% include path points here - include/bar.hrl overrides it
+
+-define(BAR_HRL, false).
diff --git a/lib/stdlib/test/epp_SUITE_data/include/bar.hrl b/lib/stdlib/test/epp_SUITE_data/include/bar.hrl
new file mode 100644
index 0000000000..038d3c900e
--- /dev/null
+++ b/lib/stdlib/test/epp_SUITE_data/include/bar.hrl
@@ -0,0 +1,3 @@
+%% included from foo.hrl in same directory
+
+-define(BAR_HRL, true).
diff --git a/lib/stdlib/test/epp_SUITE_data/include/foo.hrl b/lib/stdlib/test/epp_SUITE_data/include/foo.hrl
new file mode 100644
index 0000000000..a6dfa3d18a
--- /dev/null
+++ b/lib/stdlib/test/epp_SUITE_data/include/foo.hrl
@@ -0,0 +1,4 @@
+%% includes bar.hrl in same directory
+
+-define(FOO_HRL, true).
+-include("bar.hrl").
diff --git a/lib/stdlib/test/epp_SUITE_data/include_local.erl b/lib/stdlib/test/epp_SUITE_data/include_local.erl
new file mode 100644
index 0000000000..c8e155a064
--- /dev/null
+++ b/lib/stdlib/test/epp_SUITE_data/include_local.erl
@@ -0,0 +1,6 @@
+
+-module(include_local).
+
+-include("include/foo.hrl").
+
+-a({?FOO_HRL, ?BAR_HRL}).
diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl
index 4b59cee99e..369d8b224e 100644
--- a/lib/stdlib/test/erl_eval_SUITE.erl
+++ b/lib/stdlib/test/erl_eval_SUITE.erl
@@ -1036,6 +1036,12 @@ funs(Config) when is_list(Config) ->
lists:usort([run_many_args(SAs) || SAs <- many_args(MaxArgs)]),
?line {'EXIT',{{argument_limit,_},_}} =
(catch run_many_args(many_args1(MaxArgs+1))),
+
+ ?line check(fun() -> M = lists, F = fun M:reverse/1,
+ [1,2] = F([2,1]), ok end,
+ "begin M = lists, F = fun M:reverse/1,"
+ " [1,2] = F([2,1]), ok end.",
+ ok),
ok.
run_many_args({S, As}) ->
@@ -1189,7 +1195,7 @@ lfh() ->
{eval, fun(F, As, Bs) -> local_func(F, As, Bs) end}.
local_func(F, As0, Bs0) when is_atom(F) ->
- {As,Bs} = erl_eval:expr_list(As0, Bs0, {eval,lfh()}),
+ {As,Bs} = erl_eval:expr_list(As0, Bs0, lfh()),
case erlang:function_exported(?MODULE, F, length(As)) of
true ->
{value,apply(?MODULE, F, As),Bs};
@@ -1199,7 +1205,7 @@ local_func(F, As0, Bs0) when is_atom(F) ->
lfh_value_extra() ->
%% Not documented.
- {value, fun(F, As) -> local_func_value(F, As) end, []}.
+ {value, fun(F, As, a1, a2) -> local_func_value(F, As) end, [a1, a2]}.
lfh_value() ->
{value, fun(F, As) -> local_func_value(F, As) end}.
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index f980d52e4e..9041adbe5c 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -2981,7 +2981,7 @@ run_test(Conf, Test0, Warnings0) ->
run_test2(Conf, Test, Warnings0).
run_test2(Conf, Test, Warnings0) ->
- Filename = 'lint_test.erl',
+ Filename = "lint_test.erl",
DataDir = ?privdir,
File = filename:join(DataDir, Filename),
Opts = case Warnings0 of
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index bc811355ab..64853ca078 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -116,7 +116,6 @@ func(Config) when is_list(Config) ->
{func_3,
<<"t() -> fun t/0.">>},
{func_4,
- %% Has already been expanded away in sys_pre_expand.
<<"t() -> fun modul:foo/3.">>},
{func_5, % 'when' is moved down one line
<<"tkjlksjflksdjflsdjlk()
@@ -127,7 +126,9 @@ func(Config) when is_list(Config) ->
<<"t() ->
(fun() ->
true
- end)().">>}
+ end)().">>},
+ {func_7,
+ <<"t(M, F, A) -> fun M:F/A.">>}
],
?line compile(Config, Ts),
ok.
@@ -1161,7 +1162,7 @@ parse_forms2(String, Cont0, Line, Forms) ->
{done, {ok, Tokens, EndLine}, Chars} ->
{ok, Form} = erl_parse:parse_form(Tokens),
parse_forms2(Chars, [], EndLine, [Form | Forms]);
- {more, Cont} when element(3, Cont) =:= [] ->
+ {more, Cont} when element(4, Cont) =:= [] ->
%% extra spaces after forms...
parse_forms2([], Cont, Line, Forms);
{more, Cont} ->
diff --git a/lib/stdlib/test/erl_scan_SUITE.erl b/lib/stdlib/test/erl_scan_SUITE.erl
index 31a4f94294..4298b2c701 100644
--- a/lib/stdlib/test/erl_scan_SUITE.erl
+++ b/lib/stdlib/test/erl_scan_SUITE.erl
@@ -737,6 +737,10 @@ set_attribute() ->
(catch {foo, erl_scan:set_attribute(line, [], F2)}), % type error
?line {'EXIT',{badarg,_}} =
(catch {foo, erl_scan:set_attribute(column, [], F2)}), % type error
+
+ %% OTP-9412
+ ?line 8 = erl_scan:set_attribute(line, [{line,{nos,'X',8}}],
+ fun({nos,_V,VL}) -> VL end),
ok.
column_errors() ->
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 9d348b5f1a..0e8849b5b3 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -72,8 +72,9 @@
exit_many_many_tables_owner/1]).
-export([write_concurrency/1, heir/1, give_away/1, setopts/1]).
-export([bad_table/1, types/1]).
+-export([otp_9423/1]).
--export([init_per_testcase/2, end_per_testcase/2]).
+-export([init_per_testcase/2]).
%% Convenience for manual testing
-export([random_test/0]).
@@ -143,7 +144,8 @@ all() ->
otp_8166, exit_large_table_owner,
exit_many_large_table_owner, exit_many_tables_owner,
exit_many_many_tables_owner, write_concurrency, heir,
- give_away, setopts, bad_table, types].
+ give_away, setopts, bad_table, types,
+ otp_9423].
groups() ->
[{new, [],
@@ -174,6 +176,7 @@ groups() ->
meta_newdel_unnamed, meta_newdel_named]}].
init_per_suite(Config) ->
+ erts_debug:set_internal_state(available_internal_state, true),
Config.
end_per_suite(_Config) ->
@@ -302,7 +305,6 @@ t_match_spec_run(Config) when is_list(Config) ->
end,
repeat_for_permutations(F, N_MS)
end,
-
test_terms(Fun, skip_refc_check),
?line verify_etsmem(EtsMem).
@@ -322,7 +324,7 @@ t_match_spec_run_test(List, MS, Result) ->
%% Check that tracing agree
Self = self(),
- {Tracee, MonRef} = spawn_monitor(fun() -> ms_tracee(Self, List) end),
+ {Tracee, MonRef} = my_spawn_monitor(fun() -> ms_tracee(Self, List) end),
receive {Tracee, ready} -> ok end,
MST = lists:map(fun(Clause) -> ms_clause_ets_to_trace(Clause) end, MS),
@@ -583,7 +585,6 @@ select_fail_do(Opts) ->
memory(doc) -> ["Whitebox test of ets:info(X,memory)"];
memory(suite) -> [];
memory(Config) when is_list(Config) ->
- ?line erts_debug:set_internal_state(available_internal_state, true),
?line ok = chk_normal_tab_struct_size(),
repeat_for_opts(memory_do,[compressed]),
?line catch erts_debug:set_internal_state(available_internal_state, false).
@@ -793,21 +794,26 @@ t_ets_dets(Config, Opts) ->
?line true = ets:from_dets(ETab,DTab),
?line 3000 = ets:info(ETab,size),
?line ets:delete(ETab),
- ?line {'EXIT',{badarg,[{ets,to_dets,[ETab,DTab]}|_]}} =
- (catch ets:to_dets(ETab,DTab)),
- ?line {'EXIT',{badarg,[{ets,from_dets,[ETab,DTab]}|_]}} =
- (catch ets:from_dets(ETab,DTab)),
+ ?line check_badarg(catch ets:to_dets(ETab,DTab),
+ ets, to_dets, [ETab,DTab]),
+ ?line check_badarg(catch ets:from_dets(ETab,DTab),
+ ets, from_dets, [ETab,DTab]),
?line ETab2 = ets_new(x,Opts),
?line filltabint(ETab2,3000),
?line dets:close(DTab),
- ?line {'EXIT',{badarg,[{ets,to_dets,[ETab2,DTab]}|_]}} =
- (catch ets:to_dets(ETab2,DTab)),
- ?line {'EXIT',{badarg,[{ets,from_dets,[ETab2,DTab]}|_]}} =
- (catch ets:from_dets(ETab2,DTab)),
+ ?line check_badarg(catch ets:to_dets(ETab2,DTab),
+ ets, to_dets, [ETab2,DTab]),
+ ?line check_badarg(catch ets:from_dets(ETab2,DTab),
+ ets, from_dets, [ETab2,DTab]),
?line ets:delete(ETab2),
?line (catch file:delete(Fname)),
ok.
+check_badarg({'EXIT', {badarg, [{M,F,Args,_} | _]}}, M, F, Args) ->
+ true;
+check_badarg({'EXIT', {badarg, [{M,F,A,_} | _]}}, M, F, Args) ->
+ true = test_server:is_native(M) andalso length(Args) =:= A.
+
t_delete_all_objects(doc) ->
["Test ets:delete_all_objects/1"];
t_delete_all_objects(suite) ->
@@ -817,6 +823,14 @@ t_delete_all_objects(Config) when is_list(Config) ->
repeat_for_opts(t_delete_all_objects_do),
?line verify_etsmem(EtsMem).
+get_kept_objects(T) ->
+ case ets:info(T,stats) of
+ false ->
+ 0;
+ {_,_,_,_,_,_,KO} ->
+ KO
+ end.
+
t_delete_all_objects_do(Opts) ->
?line T=ets_new(x,Opts),
?line filltabint(T,4000),
@@ -826,10 +840,10 @@ t_delete_all_objects_do(Opts) ->
?line true = ets:delete_all_objects(T),
?line '$end_of_table' = ets:next(T,O),
?line 0 = ets:info(T,size),
- ?line 4000 = ets:info(T,kept_objects),
+ ?line 4000 = get_kept_objects(T),
?line ets:safe_fixtable(T,false),
?line 0 = ets:info(T,size),
- ?line 0 = ets:info(T,kept_objects),
+ ?line 0 = get_kept_objects(T),
?line filltabint(T,4000),
?line 4000 = ets:info(T,size),
?line true = ets:delete_all_objects(T),
@@ -859,10 +873,10 @@ t_delete_object_do(Opts) ->
?line ets:delete_object(T,{First, integer_to_list(First)}),
?line Next = ets:next(T,First),
?line 3999 = ets:info(T,size),
- ?line 1 = ets:info(T,kept_objects),
+ ?line 1 = get_kept_objects(T),
?line ets:safe_fixtable(T,false),
?line 3999 = ets:info(T,size),
- ?line 0 = ets:info(T,kept_objects),
+ ?line 0 = get_kept_objects(T),
?line ets:delete(T),
?line T1 = ets_new(x,[ordered_set | Opts]),
?line filltabint(T1,4000),
@@ -1932,7 +1946,7 @@ evil_update_counter(Config) when is_list(Config) ->
evil_update_counter_do(Opts) ->
?line EtsMem = etsmem(),
?line process_flag(trap_exit, true),
- ?line Pids = [spawn_link(fun() -> evil_counter(I,Opts) end) || I <- lists:seq(1, 40)],
+ ?line Pids = [my_spawn_link(fun() -> evil_counter(I,Opts) end) || I <- lists:seq(1, 40)],
?line wait_for_all(gb_sets:from_list(Pids)),
?line verify_etsmem(EtsMem),
ok.
@@ -2138,24 +2152,24 @@ heir_do(Opts) ->
Combos),
%% No heir
- {Founder1,MrefF1} = spawn_monitor(fun()->heir_founder(Master,foo_data,Opts)end),
+ {Founder1,MrefF1} = my_spawn_monitor(fun()->heir_founder(Master,foo_data,Opts)end),
Founder1 ! {go, none},
?line {"No heir",Founder1} = receive_any(),
?line {'DOWN', MrefF1, process, Founder1, normal} = receive_any(),
?line undefined = ets:info(foo),
%% An already dead heir
- {Heir2,MrefH2} = spawn_monitor(fun()->die end),
+ {Heir2,MrefH2} = my_spawn_monitor(fun()->die end),
?line {'DOWN', MrefH2, process, Heir2, normal} = receive_any(),
- {Founder2,MrefF2} = spawn_monitor(fun()->heir_founder(Master,foo_data,Opts)end),
+ {Founder2,MrefF2} = my_spawn_monitor(fun()->heir_founder(Master,foo_data,Opts)end),
Founder2 ! {go, Heir2},
?line {"No heir",Founder2} = receive_any(),
?line {'DOWN', MrefF2, process, Founder2, normal} = receive_any(),
?line undefined = ets:info(foo),
%% When heir dies before founder
- {Founder3,MrefF3} = spawn_monitor(fun()->heir_founder(Master,"The dying heir",Opts)end),
- {Heir3,MrefH3} = spawn_monitor(fun()->heir_heir(Founder3)end),
+ {Founder3,MrefF3} = my_spawn_monitor(fun()->heir_founder(Master,"The dying heir",Opts)end),
+ {Heir3,MrefH3} = my_spawn_monitor(fun()->heir_heir(Founder3)end),
Founder3 ! {go, Heir3},
?line {'DOWN', MrefH3, process, Heir3, normal} = receive_any(),
Founder3 ! die_please,
@@ -2163,14 +2177,12 @@ heir_do(Opts) ->
?line undefined = ets:info(foo),
%% When heir dies and pid reused before founder dies
- erts_debug:set_internal_state(available_internal_state,true),
NextPidIx = erts_debug:get_internal_state(next_pid),
- {Founder4,MrefF4} = spawn_monitor(fun()->heir_founder(Master,"The dying heir",Opts)end),
- {Heir4,MrefH4} = spawn_monitor(fun()->heir_heir(Founder4)end),
+ {Founder4,MrefF4} = my_spawn_monitor(fun()->heir_founder(Master,"The dying heir",Opts)end),
+ {Heir4,MrefH4} = my_spawn_monitor(fun()->heir_heir(Founder4)end),
Founder4 ! {go, Heir4},
?line {'DOWN', MrefH4, process, Heir4, normal} = receive_any(),
erts_debug:set_internal_state(next_pid, NextPidIx),
- erts_debug:set_internal_state(available_internal_state,false),
{Heir4,MrefH4_B} = spawn_monitor_with_pid(Heir4,
fun()-> ?line die_please = receive_any() end),
Founder4 ! die_please,
@@ -2246,9 +2258,9 @@ heir_heir(Founder, Mode) ->
heir_1(HeirData,Mode,Opts) ->
io:format("test with heir_data = ~p\n", [HeirData]),
Master = self(),
- ?line Founder = spawn_link(fun() -> heir_founder(Master,HeirData,Opts) end),
+ ?line Founder = my_spawn_link(fun() -> heir_founder(Master,HeirData,Opts) end),
io:format("founder spawned = ~p\n", [Founder]),
- ?line {Heir,Mref} = spawn_monitor(fun() -> heir_heir(Founder,Mode) end),
+ ?line {Heir,Mref} = my_spawn_monitor(fun() -> heir_heir(Founder,Mode) end),
io:format("heir spawned = ~p\n", [{Heir,Mref}]),
?line Founder ! {go, Heir},
?line {'DOWN', Mref, process, Heir, normal} = receive_any().
@@ -2265,7 +2277,7 @@ give_away_do(Opts) ->
Parent = self(),
%% Give and then give back
- ?line {Receiver,Mref} = spawn_monitor(fun()-> give_away_receiver(T,Parent) end),
+ ?line {Receiver,Mref} = my_spawn_monitor(fun()-> give_away_receiver(T,Parent) end),
?line give_me = receive_any(),
?line true = ets:give_away(T,Receiver,here_you_are),
?line {'EXIT',{badarg,_}} = (catch ets:lookup(T,key)),
@@ -2276,7 +2288,7 @@ give_away_do(Opts) ->
%% Give and then let receiver keep it
?line true = ets:insert(T,{key,1}),
- ?line {Receiver3,Mref3} = spawn_monitor(fun()-> give_away_receiver(T,Parent) end),
+ ?line {Receiver3,Mref3} = my_spawn_monitor(fun()-> give_away_receiver(T,Parent) end),
?line give_me = receive_any(),
?line true = ets:give_away(T,Receiver3,here_you_are),
?line {'EXIT',{badarg,_}} = (catch ets:lookup(T,key)),
@@ -2288,7 +2300,7 @@ give_away_do(Opts) ->
?line T2 = ets_new(foo,[private | Opts]),
?line true = ets:insert(T2,{key,1}),
?line ets:setopts(T2,{heir,self(),"Som en gummiboll..."}),
- ?line {Receiver2,Mref2} = spawn_monitor(fun()-> give_away_receiver(T2,Parent) end),
+ ?line {Receiver2,Mref2} = my_spawn_monitor(fun()-> give_away_receiver(T2,Parent) end),
?line give_me = receive_any(),
?line true = ets:give_away(T2,Receiver2,here_you_are),
?line {'EXIT',{badarg,_}} = (catch ets:lookup(T2,key)),
@@ -2303,12 +2315,12 @@ give_away_do(Opts) ->
?line {'EXIT',{badarg,_}} = (catch ets:give_away(T2,"not a pid","To wrong type")),
?line true = ets:delete(T2),
- ?line {ReceiverNeg,MrefNeg} = spawn_monitor(fun()-> give_away_receiver(T2,Parent) end),
+ ?line {ReceiverNeg,MrefNeg} = my_spawn_monitor(fun()-> give_away_receiver(T2,Parent) end),
?line give_me = receive_any(),
?line {'EXIT',{badarg,_}} = (catch ets:give_away(T2,ReceiverNeg,"A deleted table")),
?line T3 = ets_new(foo,[public | Opts]),
- spawn_link(fun()-> {'EXIT',{badarg,_}} = (catch ets:give_away(T3,ReceiverNeg,"From non owner")),
+ my_spawn_link(fun()-> {'EXIT',{badarg,_}} = (catch ets:give_away(T3,ReceiverNeg,"From non owner")),
Parent ! done
end),
?line done = receive_any(),
@@ -2344,7 +2356,7 @@ setopts_do(Opts) ->
Self = self(),
?line T = ets_new(foo,[named_table, private | Opts]),
?line none = ets:info(T,heir),
- Heir = spawn_link(fun()->heir_heir(Self) end),
+ Heir = my_spawn_link(fun()->heir_heir(Self) end),
?line ets:setopts(T,{heir,Heir,"Data"}),
?line Heir = ets:info(T,heir),
?line ets:setopts(T,{heir,self(),"Data"}),
@@ -2395,14 +2407,14 @@ bad_table(Config) when is_list(Config) ->
bad_table_do(Opts, DummyFile) ->
Parent = self(),
- {Pid,Mref} = spawn_opt(fun()-> ets_new(priv,[private,named_table | Opts]),
- Priv = ets_new(priv,[private | Opts]),
- ets_new(prot,[protected,named_table | Opts]),
- Prot = ets_new(prot,[protected | Opts]),
- Parent ! {self(),Priv,Prot},
- die_please = receive_any()
- end,
- [link, monitor]),
+ {Pid,Mref} = my_spawn_opt(fun()-> ets_new(priv,[private,named_table | Opts]),
+ Priv = ets_new(priv,[private | Opts]),
+ ets_new(prot,[protected,named_table | Opts]),
+ Prot = ets_new(prot,[protected | Opts]),
+ Parent ! {self(),Priv,Prot},
+ die_please = receive_any()
+ end,
+ [link, monitor]),
{Pid,Priv,Prot} = receive_any(),
MatchSpec = {{key,'_'}, [], ['$$']},
Fun = fun(X,_) -> X end,
@@ -2642,7 +2654,7 @@ maybe_sort(L) when is_list(L) ->
%maybe_sort({'EXIT',{Reason, [{Module, Function, _}|_]}}) ->
% {'EXIT',{Reason, [{Module, Function, '_'}]}};
maybe_sort({'EXIT',{Reason, List}}) when is_list(List) ->
- {'EXIT',{Reason, lists:map(fun({Module, Function, _}) ->
+ {'EXIT',{Reason, lists:map(fun({Module, Function, _, _}) ->
{Module, Function, '_'}
end,
List)}};
@@ -2715,7 +2727,8 @@ ordered_do(Opts) ->
9,10,11,12,
1,2,3,4,
17,18,19,20,
- 13,14,15,16
+ 13,14,15,16,
+ 1 bsl 33
],
?line lists:foreach(fun(X) ->
ets:insert(T,{X,integer_to_list(X)})
@@ -2730,13 +2743,14 @@ ordered_do(Opts) ->
?line S2 = L2,
?line [{1,"1"}] = ets:slot(T,0),
?line [{28,"28"}] = ets:slot(T,27),
+ ?line [{1 bsl 33,_}] = ets:slot(T,28),
?line 27 = ets:prev(T,28),
?line [{7,"7"}] = ets:slot(T,6),
- ?line '$end_of_table' = ets:next(T,28),
+ ?line '$end_of_table' = ets:next(T,1 bsl 33),
?line [{12,"12"}] = ets:slot(T,11),
- ?line '$end_of_table' = ets:slot(T,28),
+ ?line '$end_of_table' = ets:slot(T,29),
?line [{1,"1"}] = ets:slot(T,0),
- ?line 28 = ets:prev(T,29),
+ ?line 28 = ets:prev(T,1 bsl 33),
?line 1 = ets:next(T,0),
?line pick_all_forward(T),
?line [{7,"7"}] = ets:slot(T,6),
@@ -3246,7 +3260,7 @@ delete_large_named_table_1(Name, Flags, Data, Fix) ->
?line lists:foreach(fun({K,_}) -> ets:delete(Tab, K) end, Data)
end,
Parent = self(),
- Pid = spawn_link(fun() ->
+ Pid = my_spawn_link(fun() ->
receive
{trace,Parent,call,_} ->
ets_new(Name, [named_table])
@@ -3608,7 +3622,7 @@ cycle(Tab, L) ->
ets:insert(Tab,list_to_tuple(L)),
cycle(Tab, tl(L)++[hd(L)]).
-dynamic_go() -> spawn_link(fun dynamic_init/0).
+dynamic_go() -> my_spawn_link(fun dynamic_init/0).
dynamic_init() -> [dyn_lookup(?MODULE) || _ <- lists:seq(1, 10)].
@@ -3835,7 +3849,7 @@ safe_fixtable_do(Opts) ->
Self = self(),
?line {{_,_,_},[{Self,1}]} = ets:info(Tab,safe_fixed),
%% Test that an unjustified 'unfix' is a no-op.
- {Pid,MRef} = spawn_monitor(fun() -> true = ets:safe_fixtable(Tab,false) end),
+ {Pid,MRef} = my_spawn_monitor(fun() -> true = ets:safe_fixtable(Tab,false) end),
{'DOWN', MRef, process, Pid, normal} = receive M -> M end,
?line true = ets:info(Tab,fixed),
?line {{_,_,_},[{Self,1}]} = ets:info(Tab,safe_fixed),
@@ -4239,7 +4253,7 @@ do_heavy_concurrent(Opts) ->
?line ok = fill_tab2(Tab, 0, Size),
?line Procs = lists:map(
fun (N) ->
- spawn_link(
+ my_spawn_link(
fun () ->
do_heavy_concurrent_proc(Tab, Size, N)
end)
@@ -4843,12 +4857,7 @@ otp_7665_act(Tab,Min,Max,DelNr) ->
%% Whitebox testing of meta name table hashing.
meta_wb(Config) when is_list(Config) ->
?line EtsMem = etsmem(),
- ?line erts_debug:set_internal_state(available_internal_state, true),
- try
- repeat_for_opts(meta_wb_do)
- after
- erts_debug:set_internal_state(available_internal_state, false)
- end,
+ repeat_for_opts(meta_wb_do),
?line verify_etsmem(EtsMem).
@@ -4917,12 +4926,15 @@ colliding_names(Name) ->
grow_shrink(Config) when is_list(Config) ->
?line EtsMem = etsmem(),
- grow_shrink_0(lists:seq(3071, 5000), EtsMem).
+ ?line grow_shrink_0(lists:seq(3071, 5000), EtsMem),
+ ?line verify_etsmem(EtsMem).
grow_shrink_0([N|Ns], EtsMem) ->
?line grow_shrink_1(N, [set]),
?line grow_shrink_1(N, [ordered_set]),
- ?line verify_etsmem(EtsMem),
+ %% Verifying ets-memory here takes too long time, since
+ %% lock-free allocators were introduced...
+ %% ?line verify_etsmem(EtsMem),
grow_shrink_0(Ns, EtsMem);
grow_shrink_0([], _) -> ok.
@@ -4967,21 +4979,21 @@ grow_pseudo_deleted_do(Type) ->
[true]}]),
Left = Mult*(Mod-1),
?line Left = ets:info(T,size),
- ?line Mult = ets:info(T,kept_objects),
+ ?line Mult = get_kept_objects(T),
filltabstr(T,Mult),
- spawn_opt(fun()-> ?line true = ets:info(T,fixed),
- Self ! start,
- io:format("Starting to filltabstr... ~p\n",[now()]),
- filltabstr(T,Mult,Mult+10000),
- io:format("Done with filltabstr. ~p\n",[now()]),
- Self ! done
- end, [link, {scheduler,2}]),
+ my_spawn_opt(fun()-> ?line true = ets:info(T,fixed),
+ Self ! start,
+ io:format("Starting to filltabstr... ~p\n",[now()]),
+ filltabstr(T,Mult,Mult+10000),
+ io:format("Done with filltabstr. ~p\n",[now()]),
+ Self ! done
+ end, [link, {scheduler,2}]),
?line start = receive_any(),
io:format("Unfixing table...~p nitems=~p\n",[now(),ets:info(T,size)]),
?line true = ets:safe_fixtable(T,false),
io:format("Unfix table done. ~p nitems=~p\n",[now(),ets:info(T,size)]),
?line false = ets:info(T,fixed),
- ?line 0 = ets:info(T,kept_objects),
+ ?line 0 = get_kept_objects(T),
?line done = receive_any(),
%%verify_table_load(T), % may fail if concurrency is poor (genny)
ets:delete(T),
@@ -5008,20 +5020,20 @@ shrink_pseudo_deleted_do(Type) ->
[{'>', '$1', Half}],
[true]}]),
?line Half = ets:info(T,size),
- ?line Half = ets:info(T,kept_objects),
- spawn_opt(fun()-> ?line true = ets:info(T,fixed),
- Self ! start,
- io:format("Starting to delete... ~p\n",[now()]),
- del_one_by_one_set(T,1,Half+1),
- io:format("Done with delete. ~p\n",[now()]),
- Self ! done
- end, [link, {scheduler,2}]),
+ ?line Half = get_kept_objects(T),
+ my_spawn_opt(fun()-> ?line true = ets:info(T,fixed),
+ Self ! start,
+ io:format("Starting to delete... ~p\n",[now()]),
+ del_one_by_one_set(T,1,Half+1),
+ io:format("Done with delete. ~p\n",[now()]),
+ Self ! done
+ end, [link, {scheduler,2}]),
?line start = receive_any(),
io:format("Unfixing table...~p nitems=~p\n",[now(),ets:info(T,size)]),
?line true = ets:safe_fixtable(T,false),
io:format("Unfix table done. ~p nitems=~p\n",[now(),ets:info(T,size)]),
?line false = ets:info(T,fixed),
- ?line 0 = ets:info(T,kept_objects),
+ ?line 0 = get_kept_objects(T),
?line done = receive_any(),
%%verify_table_load(T), % may fail if concurrency is poor (genny)
ets:delete(T),
@@ -5137,7 +5149,7 @@ smp_fixed_delete_do() ->
?line 0 = ets:info(T,size),
?line true = ets:info(T,fixed),
?line Buckets = num_of_buckets(T),
- ?line NumOfObjs = ets:info(T,kept_objects),
+ ?line NumOfObjs = get_kept_objects(T),
ets:safe_fixtable(T,false),
%% Will fail as unfix does not shrink the table:
%%?line Mem = ets:info(T,memory),
@@ -5169,27 +5181,27 @@ smp_unfix_fix_do() ->
Left = NumOfObjs - Deleted,
?line Left = ets:info(T,size),
?line true = ets:info(T,fixed),
- ?line Deleted = ets:info(T,kept_objects),
+ ?line Deleted = get_kept_objects(T),
{Child, Mref} =
- spawn_opt(fun()-> ?line true = ets:info(T,fixed),
- Parent ! start,
- io:format("Child waiting for table to be unfixed... now=~p mem=~p\n",
- [now(),ets:info(T,memory)]),
- repeat_while(fun()-> ets:info(T,fixed) end),
- io:format("Table unfixed. Child Fixating! now=~p mem=~p\n",
- [now(),ets:info(T,memory)]),
- ?line true = ets:safe_fixtable(T,true),
- repeat_while(fun(Key) when Key =< NumOfObjs ->
- ets:delete(T,Key), {true,Key+1};
- (Key) -> {false,Key}
- end,
- Deleted),
- ?line 0 = ets:info(T,size),
- ?line true = ets:info(T,kept_objects) >= Left,
- ?line done = receive_any()
- end,
- [link, monitor, {scheduler,2}]),
+ my_spawn_opt(fun()-> ?line true = ets:info(T,fixed),
+ Parent ! start,
+ io:format("Child waiting for table to be unfixed... now=~p mem=~p\n",
+ [now(),ets:info(T,memory)]),
+ repeat_while(fun()-> ets:info(T,fixed) end),
+ io:format("Table unfixed. Child Fixating! now=~p mem=~p\n",
+ [now(),ets:info(T,memory)]),
+ ?line true = ets:safe_fixtable(T,true),
+ repeat_while(fun(Key) when Key =< NumOfObjs ->
+ ets:delete(T,Key), {true,Key+1};
+ (Key) -> {false,Key}
+ end,
+ Deleted),
+ ?line 0 = ets:info(T,size),
+ ?line true = get_kept_objects(T) >= Left,
+ ?line done = receive_any()
+ end,
+ [link, monitor, {scheduler,2}]),
?line start = receive_any(),
?line true = ets:info(T,fixed),
@@ -5199,7 +5211,7 @@ smp_unfix_fix_do() ->
Child ! done,
{'DOWN', Mref, process, Child, normal} = receive_any(),
?line false = ets:info(T,fixed),
- ?line 0 = ets:info(T,kept_objects),
+ ?line 0 = get_kept_objects(T),
%%verify_table_load(T),
ets:delete(T),
process_flag(scheduler,0).
@@ -5220,11 +5232,11 @@ otp_8166_do(WC) ->
Deleted = NumOfObjs div 2,
filltabint(T,NumOfObjs),
{ReaderPid, ReaderMref} =
- spawn_opt(fun()-> otp_8166_reader(T,NumOfObjs) end,
- [link, monitor, {scheduler,2}]),
+ my_spawn_opt(fun()-> otp_8166_reader(T,NumOfObjs) end,
+ [link, monitor, {scheduler,2}]),
{ZombieCrPid, ZombieCrMref} =
- spawn_opt(fun()-> otp_8166_zombie_creator(T,Deleted) end,
- [link, monitor, {scheduler,3}]),
+ my_spawn_opt(fun()-> otp_8166_zombie_creator(T,Deleted) end,
+ [link, monitor, {scheduler,3}]),
repeat(fun() -> ZombieCrPid ! {loop, self()},
zombies_created = receive_any(),
@@ -5237,7 +5249,7 @@ otp_8166_do(WC) ->
ZombieCrPid ! quit,
{'DOWN', ZombieCrMref, process, ZombieCrPid, normal} = receive_any(),
?line false = ets:info(T,fixed),
- ?line 0 = ets:info(T,kept_objects),
+ ?line 0 = get_kept_objects(T),
%%verify_table_load(T),
ets:delete(T),
process_flag(scheduler,0).
@@ -5304,7 +5316,7 @@ otp_8166_zombie_creator(T,Deleted) ->
verify_table_load(T) ->
?line Stats = ets:info(T,stats),
- ?line {Buckets,AvgLen,StdDev,ExpSD,_MinLen,_MaxLen} = Stats,
+ ?line {Buckets,AvgLen,StdDev,ExpSD,_MinLen,_MaxLen,_} = Stats,
?line ok = if
AvgLen > 7 ->
io:format("Table overloaded: Stats=~p\n~p\n",
@@ -5420,7 +5432,39 @@ types_do(Opts) ->
?line verify_etsmem(EtsMem).
-
+otp_9423(doc) -> ["vm-deadlock caused by race between ets:delete and others on write_concurrency table"];
+otp_9423(Config) when is_list(Config) ->
+ InitF = fun(_) -> {0,0} end,
+ ExecF = fun({S,F}) ->
+ receive
+ stop ->
+ io:format("~p got stop\n", [self()]),
+ [end_of_work | {"Succeded=",S,"Failed=",F}]
+ after 0 ->
+ %%io:format("~p (~p) doing lookup\n", [self(), {S,F}]),
+ try ets:lookup(otp_9423, key) of
+ [] -> {S+1,F}
+ catch
+ error:badarg -> {S,F+1}
+ end
+ end
+ end,
+ FiniF = fun(R) -> R end,
+ case run_workers(InitF, ExecF, FiniF, infinite, 1) of
+ Pids when is_list(Pids) ->
+ %%[P ! start || P <- Pids],
+ repeat(fun() -> ets:new(otp_9423, [named_table, public, {write_concurrency,true}]),
+ ets:delete(otp_9423)
+ end, 10000),
+ [P ! stop || P <- Pids],
+ wait_pids(Pids),
+ ok;
+
+ Skipped -> Skipped
+ end.
+
+
+
%
% Utility functions:
@@ -5434,21 +5478,30 @@ add_lists([E1|T1], [E2|T2], Acc) ->
add_lists(T1, T2, [E1+E2 | Acc]).
run_workers(InitF,ExecF,FiniF,Laps) ->
+ run_workers(InitF,ExecF,FiniF,Laps, 0).
+run_workers(InitF,ExecF,FiniF,Laps, Exclude) ->
case erlang:system_info(smp_support) of
true ->
- run_workers_do(InitF,ExecF,FiniF,Laps);
+ run_workers_do(InitF,ExecF,FiniF,Laps, Exclude);
false ->
{skipped,"No smp support"}
end.
-
+
run_workers_do(InitF,ExecF,FiniF,Laps) ->
- NumOfProcs = erlang:system_info(schedulers),
+ run_workers_do(InitF,ExecF,FiniF,Laps, 0).
+run_workers_do(InitF,ExecF,FiniF,Laps, Exclude) ->
+ ?line NumOfProcs = case erlang:system_info(schedulers) of
+ N when (N > Exclude) -> N - Exclude
+ end,
io:format("smp starting ~p workers\n",[NumOfProcs]),
Seeds = [{ProcN,random:uniform(9999)} || ProcN <- lists:seq(1,NumOfProcs)],
Parent = self(),
- Pids = [spawn_link(fun()-> worker(Seed,InitF,ExecF,FiniF,Laps,Parent,NumOfProcs) end)
+ Pids = [my_spawn_link(fun()-> worker(Seed,InitF,ExecF,FiniF,Laps,Parent,NumOfProcs) end)
|| Seed <- Seeds],
- wait_pids(Pids).
+ case Laps of
+ infinite -> Pids;
+ _ -> wait_pids(Pids)
+ end.
worker({ProcN,Seed}, InitF, ExecF, FiniF, Laps, Parent, NumOfProcs) ->
io:format("smp worker ~p, seed=~p~n",[self(),Seed]),
@@ -5463,6 +5516,8 @@ worker_loop(0, _, State) ->
State;
worker_loop(_, _, [end_of_work|State]) ->
State;
+worker_loop(infinite, ExecF, State) ->
+ worker_loop(infinite,ExecF,ExecF(State));
worker_loop(N, ExecF, State) ->
worker_loop(N-1,ExecF,ExecF(State)).
@@ -5490,47 +5545,47 @@ my_tab_to_list(_Ts,'$end_of_table', Acc) -> lists:reverse(Acc);
my_tab_to_list(Ts,Key, Acc) ->
my_tab_to_list(Ts,ets:next(Ts,Key),[ets:lookup(Ts, Key)| Acc]).
-wait_for_all_schedulers_online_to_execute() ->
- PMs = lists:map(fun (Sched) ->
- spawn_opt(fun () -> ok end,
- [monitor, {scheduler, Sched}])
- end,
- lists:seq(1,erlang:system_info(schedulers_online))),
- lists:foreach(fun ({P, M}) ->
- receive
- {'DOWN', M, process, P, _} -> ok
- end
- end,
- PMs),
- ok.
+
+wait_for_memory_deallocations() ->
+ try
+ erts_debug:set_internal_state(wait, deallocations)
+ catch
+ error:undef ->
+ erts_debug:set_internal_state(available_internal_state, true),
+ wait_for_memory_deallocations()
+ end.
+
etsmem() ->
- %% Wait until it is guaranteed that all already scheduled
- %% deallocations of DbTable structures have completed.
- wait_for_all_schedulers_online_to_execute(),
+ wait_for_memory_deallocations(),
AllTabs = lists:map(fun(T) -> {T,ets:info(T,name),ets:info(T,size),
ets:info(T,memory),ets:info(T,type)}
end, ets:all()),
+
+ EtsAllocInfo = erlang:system_info({allocator,ets_alloc}),
+ ErlangMemoryEts = try erlang:memory(ets) catch error:notsup -> notsup end,
+
Mem =
- {try erlang:memory(ets) catch error:notsup -> notsup end,
- case erlang:system_info({allocator,ets_alloc}) of
+ {ErlangMemoryEts,
+ case EtsAllocInfo of
false -> undefined;
MemInfo ->
- MSBCS = lists:foldl(
- fun ({instance, _, L}, Acc) ->
- {value,{_,MBCS}} = lists:keysearch(mbcs, 1, L),
- {value,{_,SBCS}} = lists:keysearch(sbcs, 1, L),
- [MBCS,SBCS | Acc]
- end,
- [],
- MemInfo),
+ CS = lists:foldl(
+ fun ({instance, _, L}, Acc) ->
+ {value,{_,SBMBCS}} = lists:keysearch(sbmbcs, 1, L),
+ {value,{_,MBCS}} = lists:keysearch(mbcs, 1, L),
+ {value,{_,SBCS}} = lists:keysearch(sbcs, 1, L),
+ [SBMBCS,MBCS,SBCS | Acc]
+ end,
+ [],
+ MemInfo),
lists:foldl(
fun(L, {Bl0,BlSz0}) ->
{value,{_,Bl,_,_}} = lists:keysearch(blocks, 1, L),
{value,{_,BlSz,_,_}} = lists:keysearch(blocks_size, 1, L),
{Bl0+Bl,BlSz0+BlSz}
- end, {0,0}, MSBCS)
+ end, {0,0}, CS)
end},
{Mem,AllTabs}.
@@ -5590,6 +5645,7 @@ spawn_logger(Procs) ->
true -> exit(Proc, kill);
_ -> ok
end,
+ erlang:display(process_info(Proc)),
receive
{'DOWN', Mon, _, _, _} ->
ok
@@ -5625,7 +5681,7 @@ wait_for_test_procs(Kill) ->
ets_test_spawn_logger ! {sync_test_procs, Kill, self()},
receive test_procs_synced -> ok end.
-log_test_proc(Proc) ->
+log_test_proc(Proc) when is_pid(Proc) ->
ets_test_spawn_logger ! {new_test_proc, Proc},
Proc.
@@ -5637,9 +5693,17 @@ my_spawn_link(Fun) -> log_test_proc(spawn_link(Fun)).
my_spawn_link(M,F,A) -> log_test_proc(spawn_link(M,F,A)).
%%my_spawn_link(N,M,F,A) -> log_test_proc(spawn_link(N,M,F,A)).
-my_spawn_opt(Fun,Opts) -> log_test_proc(spawn_opt(Fun,Opts)).
-%%my_spawn_opt(M,F,A,Opts) -> log_test_proc(spawn_opt(M,F,A,Opts)).
-%%my_spawn_opt(N,M,F,A,Opts) -> log_test_proc(spawn_opt(N,M,F,A,Opts)).
+my_spawn_opt(Fun,Opts) ->
+ case spawn_opt(Fun,Opts) of
+ Pid when is_pid(Pid) -> log_test_proc(Pid);
+ {Pid, _} = Res when is_pid(Pid) -> log_test_proc(Pid), Res
+ end.
+
+my_spawn_monitor(Fun) ->
+ Res = spawn_monitor(Fun),
+ {Pid, _} = Res,
+ log_test_proc(Pid),
+ Res.
repeat(_Fun, 0) ->
ok;
@@ -5702,11 +5766,11 @@ spawn_monitor_with_pid(Pid, Fun, N, M) when N > M*10 ->
spawn_monitor_with_pid(Pid, Fun, N, M*10);
spawn_monitor_with_pid(Pid, Fun, N, M) ->
?line false = is_process_alive(Pid),
- case spawn(fun()-> case self() of
- Pid -> Fun();
- _ -> die
- end
- end) of
+ case my_spawn(fun()-> case self() of
+ Pid -> Fun();
+ _ -> die
+ end
+ end) of
Pid ->
{Pid, erlang:monitor(process, Pid)};
Other ->
@@ -5872,7 +5936,7 @@ very_big_num(0, Result) ->
?line Result.
make_port() ->
- ?line open_port({spawn, efile}, [eof]).
+ ?line open_port({spawn, "efile"}, [eof]).
make_pid() ->
?line spawn_link(?MODULE, sleeper, []).
diff --git a/lib/stdlib/test/file_sorter_SUITE.erl b/lib/stdlib/test/file_sorter_SUITE.erl
index 80d4ea5fdc..74c08912be 100644
--- a/lib/stdlib/test/file_sorter_SUITE.erl
+++ b/lib/stdlib/test/file_sorter_SUITE.erl
@@ -89,7 +89,7 @@ basic(suite) ->
basic(Config) when is_list(Config) ->
Fmt = binary,
Arg = {format,Fmt},
- Foo = outfile(foo, Config),
+ Foo = outfile("foo", Config),
P0 = pps(),
?line F1s = [F1] = to_files([[]], Fmt, Config),
@@ -455,7 +455,7 @@ inout(suite) ->
[];
inout(Config) when is_list(Config) ->
BTF = {format, binary_term},
- Foo = outfile(foo, Config),
+ Foo = outfile("foo", Config),
%% Input is fun.
End = fun(read) -> end_of_input end,
@@ -522,7 +522,7 @@ many(doc) ->
many(suite) ->
[];
many(Config) when is_list(Config) ->
- Foo = outfile(foo, Config),
+ Foo = outfile("foo", Config),
PrivDir = ?privdir(Config),
P0 = pps(),
@@ -587,7 +587,7 @@ misc(suite) ->
[];
misc(Config) when is_list(Config) ->
BTF = {format, binary_term},
- Foo = outfile(foo, Config),
+ Foo = outfile("foo", Config),
FFoo = filename:absname(Foo),
P0 = pps(),
@@ -704,7 +704,7 @@ misc(Config) when is_list(Config) ->
sort(Fmt, XArgs, Config) ->
Args = make_args(Fmt, [{size,5} | XArgs]),
TmpArgs = [{tmpdir,?privdir(Config)} | Args],
- Foo = outfile(foo, Config),
+ Foo = outfile("foo", Config),
%% Input is a fun. Output is a fun.
?line [] = file_sorter:sort(input([], 2, Fmt), output([], Fmt), Args),
@@ -777,7 +777,7 @@ sort(Fmt, XArgs, Config) ->
keysort(Fmt, XArgs, Config) ->
Args = make_args(Fmt, [{size,50}, {no_files, 2} | XArgs]),
TmpArgs = Args ++ [{tmpdir,?privdir(Config)}],
- Foo = outfile(foo, Config),
+ Foo = outfile("foo", Config),
%% Input is files. Output is a file.
?line ok = file_sorter:keysort(2, [], Foo, Args),
@@ -836,7 +836,7 @@ keysort(Fmt, XArgs, Config) ->
merge(Fmt, XArgs, Config) ->
Args = make_args(Fmt, [{size,5} | XArgs]),
- Foo = outfile(foo, Config),
+ Foo = outfile("foo", Config),
%% Input is a file. Output is a fun.
?line [] = file_sorter:merge([], output([], Fmt), Args),
@@ -873,7 +873,7 @@ merge(Fmt, XArgs, Config) ->
keymerge(Fmt, XArgs, Config) ->
Args = make_args(Fmt, [{size,50}, {no_files, 2} | XArgs]),
- Foo = outfile(foo, Config),
+ Foo = outfile("foo", Config),
%% Input is files. Output is a file.
?line ok = file_sorter:keymerge(2, [], Foo, Args),
diff --git a/lib/stdlib/test/filelib_SUITE.erl b/lib/stdlib/test/filelib_SUITE.erl
index a355097fe2..1de639a166 100644
--- a/lib/stdlib/test/filelib_SUITE.erl
+++ b/lib/stdlib/test/filelib_SUITE.erl
@@ -97,11 +97,12 @@ wildcard_errors(Config) when is_list(Config) ->
wcc(Wc, Error) ->
{'EXIT',{{badpattern,Error},
- [{filelib,compile_wildcard,1}|_]}} = (catch filelib:compile_wildcard(Wc)),
+ [{filelib,compile_wildcard,1,_}|_]}} =
+ (catch filelib:compile_wildcard(Wc)),
{'EXIT',{{badpattern,Error},
- [{filelib,wildcard,1}|_]}} = (catch filelib:wildcard(Wc)),
+ [{filelib,wildcard,1,_}|_]}} = (catch filelib:wildcard(Wc)),
{'EXIT',{{badpattern,Error},
- [{filelib,wildcard,2}|_]}} = (catch filelib:wildcard(Wc, ".")).
+ [{filelib,wildcard,2,_}|_]}} = (catch filelib:wildcard(Wc, ".")).
do_wildcard_1(Dir, Wcf0) ->
do_wildcard_2(Dir, Wcf0),
@@ -243,7 +244,7 @@ otp_5960(doc) ->
["Test that filelib:ensure_dir/1 returns ok or {error,Reason}"];
otp_5960(Config) when is_list(Config) ->
?line PrivDir = ?config(priv_dir, Config),
- ?line Dir = filename:join(PrivDir, otp_5960_dir),
+ ?line Dir = filename:join(PrivDir, "otp_5960_dir"),
?line Name1 = filename:join(Dir, name1),
?line Name2 = filename:join(Dir, name2),
?line ok = filelib:ensure_dir(Name1), % parent is created
@@ -268,7 +269,7 @@ otp_5960(Config) when is_list(Config) ->
ensure_dir_eexist(Config) when is_list(Config) ->
?line PrivDir = ?config(priv_dir, Config),
- ?line Dir = filename:join(PrivDir, ensure_dir_eexist),
+ ?line Dir = filename:join(PrivDir, "ensure_dir_eexist"),
?line Name = filename:join(Dir, "same_name_as_file_and_dir"),
?line ok = filelib:ensure_dir(Name),
?line ok = file:write_file(Name, <<"some string\n">>),
diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl
index a614d6595d..7fb8d54f2d 100644
--- a/lib/stdlib/test/gen_server_SUITE.erl
+++ b/lib/stdlib/test/gen_server_SUITE.erl
@@ -694,7 +694,7 @@ multicall_down(Config) when is_list(Config) ->
%% We use 'global' as a gen_server to call.
?line {Good, Bad} = gen_server:multi_call([Name, node()],
global_name_server,
- {whereis, gurkburk},
+ info,
3000),
io:format("good = ~p, bad = ~p~n", [Good, Bad]),
?line [Name] = Bad,
diff --git a/lib/stdlib/test/io_SUITE.erl b/lib/stdlib/test/io_SUITE.erl
index 54a98985cd..bb02a879c2 100644
--- a/lib/stdlib/test/io_SUITE.erl
+++ b/lib/stdlib/test/io_SUITE.erl
@@ -27,7 +27,7 @@
otp_6282/1, otp_6354/1, otp_6495/1, otp_6517/1, otp_6502/1,
manpage/1, otp_6708/1, otp_7084/1, otp_7421/1,
io_lib_collect_line_3_wb/1, cr_whitespace_in_string/1,
- io_fread_newlines/1, otp_8989/1]).
+ io_fread_newlines/1, otp_8989/1, io_lib_fread_literal/1]).
%-define(debug, true).
@@ -62,7 +62,7 @@ all() ->
otp_6282, otp_6354, otp_6495, otp_6517, otp_6502,
manpage, otp_6708, otp_7084, otp_7421,
io_lib_collect_line_3_wb, cr_whitespace_in_string,
- io_fread_newlines, otp_8989].
+ io_fread_newlines, otp_8989, io_lib_fread_literal].
groups() ->
[].
@@ -1995,3 +1995,29 @@ otp_8989(Suite) when is_list(Suite) ->
?line "Hel " = fmt("~-4.*s", [3,Hello]),
?line "Hel " = fmt("~*.*s", [-4,3,Hello]),
ok.
+
+io_lib_fread_literal(doc) ->
+ "OTP-9439 io_lib:fread bug for literate at end";
+io_lib_fread_literal(Suite) when is_list(Suite) ->
+ ?line {more,"~d",0,""} = io_lib:fread("~d", ""),
+ ?line {error,{fread,integer}} = io_lib:fread("~d", " "),
+ ?line {more,"~d",1,""} = io_lib:fread(" ~d", " "),
+ ?line {ok,[17],"X"} = io_lib:fread(" ~d", " 17X"),
+ %%
+ ?line {more,"d",0,""} = io_lib:fread("d", ""),
+ ?line {error,{fread,input}} = io_lib:fread("d", " "),
+ ?line {more,"d",1,""} = io_lib:fread(" d", " "),
+ ?line {ok,[],"X"} = io_lib:fread(" d", " dX"),
+ %%
+ ?line {done,eof,_} = io_lib:fread([], eof, "~d"),
+ ?line {done,eof,_} = io_lib:fread([], eof, " ~d"),
+ ?line {more,C1} = io_lib:fread([], " \n", " ~d"),
+ ?line {done,{error,{fread,input}},_} = io_lib:fread(C1, eof, " ~d"),
+ ?line {done,{ok,[18]},""} = io_lib:fread(C1, "18\n", " ~d"),
+ %%
+ ?line {done,eof,_} = io_lib:fread([], eof, "d"),
+ ?line {done,eof,_} = io_lib:fread([], eof, " d"),
+ ?line {more,C2} = io_lib:fread([], " \n", " d"),
+ ?line {done,{error,{fread,input}},_} = io_lib:fread(C2, eof, " d"),
+ ?line {done,{ok,[]},[]} = io_lib:fread(C2, "d\n", " d"),
+ ok.
diff --git a/lib/stdlib/test/ms_transform_SUITE.erl b/lib/stdlib/test/ms_transform_SUITE.erl
index 4e5df12798..c9688354b1 100644
--- a/lib/stdlib/test/ms_transform_SUITE.erl
+++ b/lib/stdlib/test/ms_transform_SUITE.erl
@@ -39,6 +39,7 @@
-export([float_1_function/1]).
-export([action_function/1]).
-export([warnings/1]).
+-export([no_warnings/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
init_per_testcase(_Func, Config) ->
@@ -55,7 +56,7 @@ all() ->
[from_shell, basic_ets, basic_dbg, records,
record_index, multipass, bitsyntax, record_defaults,
andalso_orelse, float_1_function, action_function,
- warnings, top_match, old_guards, autoimported,
+ warnings, no_warnings, top_match, old_guards, autoimported,
semicolon].
groups() ->
@@ -155,6 +156,34 @@ warnings(Config) when is_list(Config) ->
compile_ww(Prog7),
ok.
+no_warnings(suite) ->
+ [];
+no_warnings(doc) ->
+ ["Check that variables bound in other function clauses don't generate "
+ "warning"];
+no_warnings(Config) when is_list(Config) ->
+ ?line setup(Config),
+ Prog = <<"tmp(X) when X > 100 ->\n",
+ " Y=X,\n"
+ " Y;\n"
+ "tmp(X) ->\n"
+ " ets:fun2ms(fun(Y) ->\n"
+ " {X, 3*Y}\n"
+ " end)">>,
+ ?line [] = compile_no_ww(Prog),
+
+ Prog2 = <<"tmp(X) when X > 100 ->\n",
+ " Y=X,\n"
+ " Y;\n"
+ "tmp(X) when X < 200 ->\n"
+ " ok;\n"
+ "tmp(X) ->\n"
+ " ets:fun2ms(fun(Y) ->\n"
+ " {X, 3*Y}\n"
+ " end)">>,
+ ?line [] = compile_no_ww(Prog2),
+ ok.
+
andalso_orelse(suite) ->
[];
andalso_orelse(doc) ->
@@ -842,6 +871,20 @@ compile_ww(Records,Expr) ->
nowarn_unused_record]),
Wlist.
+compile_no_ww(Expr) ->
+ Prog = <<
+ "-module(tmp).\n",
+ "-include_lib(\"stdlib/include/ms_transform.hrl\").\n",
+ "-export([tmp/1]).\n\n",
+ Expr/binary,".\n">>,
+ FN=temp_name(),
+ file:write_file(FN,Prog),
+ {ok,Forms} = epp:parse_file(FN,"",""),
+ {ok,tmp,_Bin,Wlist} = compile:forms(Forms,[return_warnings,
+ nowarn_unused_vars,
+ nowarn_unused_record]),
+ Wlist.
+
do_eval(String) ->
{done,{ok,T,_},[]} = erl_scan:tokens(
[],
diff --git a/lib/stdlib/test/proc_lib_SUITE.erl b/lib/stdlib/test/proc_lib_SUITE.erl
index 1565aa9bba..c95089117c 100644
--- a/lib/stdlib/test/proc_lib_SUITE.erl
+++ b/lib/stdlib/test/proc_lib_SUITE.erl
@@ -328,7 +328,7 @@ otp_6345(doc) ->
["'monitor' spawn_opt option"];
otp_6345(Config) when is_list(Config) ->
Opts = [link,monitor],
- {'EXIT', {badarg,[{proc_lib,check_for_monitor,_}|_Stack]}} =
+ {'EXIT', {badarg,[{proc_lib,check_for_monitor,_,_}|_Stack]}} =
(catch proc_lib:start(?MODULE, otp_6345_init, [self()],
1000, Opts)),
ok.
diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl
index 98eeaee118..8a9d8f7883 100644
--- a/lib/stdlib/test/qlc_SUITE.erl
+++ b/lib/stdlib/test/qlc_SUITE.erl
@@ -6632,7 +6632,7 @@ otp_7232(Config) when is_list(Config) ->
{call,_,
{remote,_,{atom,_,qlc},{atom,_,sort}},
[{cons,_,
- {'fun',_,{function,math,sqrt,_}},
+ {'fun',_,{function,{atom,_,math},{atom,_,sqrt},_}},
{cons,_,
{string,_,\"<0.4.1>\"}, % could use list_to_pid..
{cons,_,{string,_,\"#Ref<\"++_},{nil,_}}}},
diff --git a/lib/stdlib/test/re_SUITE.erl b/lib/stdlib/test/re_SUITE.erl
index c4817c0d38..3b2e637c84 100644
--- a/lib/stdlib/test/re_SUITE.erl
+++ b/lib/stdlib/test/re_SUITE.erl
@@ -454,115 +454,115 @@ error_handling(Config) when is_list(Config) ->
% The malformed precomiled RE is detected after
% the trap to re:grun from grun, in the grun function clause
% that handles precompiled expressions
- ?line {'EXIT',{badarg,[{re,run,["apa",{1,2,3,4},[global]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,run,["apa",{1,2,3,4},[global]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:run("apa",{1,2,3,4},[global])),
% An invalid capture list will also cause a badarg late,
% but with a non pre compiled RE, the exception should be thrown by the
% grun function clause that handles RE's compiled implicitly by
% the run/3 BIF before trapping.
- ?line {'EXIT',{badarg,[{re,run,["apa","p",[{capture,[1,{a}]},global]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,run,["apa","p",[{capture,[1,{a}]},global]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:run("apa","p",[{capture,[1,{a}]},global])),
% And so the case of a precompiled expression together with
% a compile-option (binary and list subject):
?line {ok,RE} = re:compile("(p)"),
?line {match,[[{1,1},{1,1}]]} = re:run(<<"apa">>,RE,[global]),
?line {match,[[{1,1},{1,1}]]} = re:run("apa",RE,[global]),
- {'EXIT',{badarg,[{re,run,
- [<<"apa">>,
- {re_pattern,1,0,_},
- [global,unicode]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,run,
+ [<<"apa">>,
+ {re_pattern,1,0,_},
+ [global,unicode]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:run(<<"apa">>,RE,[global,unicode])),
- {'EXIT',{badarg,[{re,run,
- ["apa",
- {re_pattern,1,0,_},
- [global,unicode]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,run,
+ ["apa",
+ {re_pattern,1,0,_},
+ [global,unicode]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:run("apa",RE,[global,unicode])),
?line {'EXIT',{badarg,_}} = (catch re:run("apa","(p",[])),
?line {'EXIT',{badarg,_}} = (catch re:run("apa","(p",[global])),
% The replace errors:
- ?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:replace("apa",{1,2,3,4},"X",[])),
- ?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[global]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[global]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:replace("apa",{1,2,3,4},"X",[global])),
?line {'EXIT',{badarg,[{re,replace,
["apa",
{re_pattern,1,0,_},
"X",
- [unicode]]},
- {?MODULE, error_handling,1} | _]}} =
+ [unicode]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:replace("apa",RE,"X",[unicode])),
?line <<"aXa">> = iolist_to_binary(re:replace("apa","p","X",[])),
?line {'EXIT',{badarg,[{re,replace,
- ["apa","p","X",[{capture,all,binary}]]},
- {?MODULE, error_handling,1} | _]}} =
+ ["apa","p","X",[{capture,all,binary}]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch iolist_to_binary(re:replace("apa","p","X",
[{capture,all,binary}]))),
?line {'EXIT',{badarg,[{re,replace,
- ["apa","p","X",[{capture,all}]]},
- {?MODULE, error_handling,1} | _]}} =
+ ["apa","p","X",[{capture,all}]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch iolist_to_binary(re:replace("apa","p","X",
[{capture,all}]))),
?line {'EXIT',{badarg,[{re,replace,
- ["apa","p","X",[{return,banana}]]},
- {?MODULE, error_handling,1} | _]}} =
+ ["apa","p","X",[{return,banana}]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch iolist_to_binary(re:replace("apa","p","X",
[{return,banana}]))),
?line {'EXIT',{badarg,_}} = (catch re:replace("apa","(p","X",[])),
% Badarg, not compile error.
?line {'EXIT',{badarg,[{re,replace,
- ["apa","(p","X",[{return,banana}]]},
- {?MODULE, error_handling,1} | _]}} =
+ ["apa","(p","X",[{return,banana}]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch iolist_to_binary(re:replace("apa","(p","X",
[{return,banana}]))),
% And the split errors:
?line [<<"a">>,<<"a">>] = (catch re:split("apa","p",[])),
?line [<<"a">>,<<"p">>,<<"a">>] = (catch re:split("apa",RE,[])),
- ?line {'EXIT',{badarg,[{re,split,["apa","p",[global]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,split,["apa","p",[global]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:split("apa","p",[global])),
- ?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all}]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all}]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:split("apa","p",[{capture,all}])),
- ?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all,binary}]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all,binary}]],_},
+ {?MODULE, error_handling,1,_} | _]}} =
(catch re:split("apa","p",[{capture,all,binary}])),
- ?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:split("apa",{1,2,3,4})),
- ?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:split("apa",{1,2,3,4},[])),
?line {'EXIT',{badarg,[{re,split,
["apa",
RE,
- [unicode]]},
- {?MODULE, error_handling,1} | _]}} =
+ [unicode]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:split("apa",RE,[unicode])),
?line {'EXIT',{badarg,[{re,split,
["apa",
RE,
- [{return,banana}]]},
- {?MODULE, error_handling,1} | _]}} =
+ [{return,banana}]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:split("apa",RE,[{return,banana}])),
?line {'EXIT',{badarg,[{re,split,
["apa",
RE,
- [banana]]},
- {?MODULE, error_handling,1} | _]}} =
+ [banana]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:split("apa",RE,[banana])),
?line {'EXIT',{badarg,_}} = (catch re:split("apa","(p")),
%Exception on bad argument, not compilation error
?line {'EXIT',{badarg,[{re,split,
["apa",
"(p",
- [banana]]},
- {?MODULE, error_handling,1} | _]}} =
+ [banana]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:split("apa","(p",[banana])),
?t:timetrap_cancel(Dog),
ok.
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
index 8273377ba1..b6019b86f0 100644
--- a/lib/stdlib/test/shell_SUITE.erl
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -2388,12 +2388,12 @@ otp_6554(Config) when is_list(Config) ->
comm_err(<<"V = lists:seq(1, 20), case V of a -> ok end.">>),
?line "exception error: no function clause matching" =
comm_err(<<"fun(P) when is_pid(P) -> true end(a).">>),
- ?line "exception error: {function_clause,[{erl_eval,do_apply,[unproper|list]}"++_ =
+ ?line "exception error: {function_clause," =
comm_err(<<"erlang:error(function_clause, [unproper | list]).">>),
?line "exception error: function_clause" =
comm_err(<<"erlang:error(function_clause, 4).">>),
%% Cheating:
- ?line "exception error: no function clause matching erl_eval:do_apply(4)" =
+ ?line "exception error: no function clause matching erl_eval:do_apply(4)" ++ _ =
comm_err(<<"erlang:error(function_clause, [4]).">>),
?line "exception error: no function clause matching" ++ _ =
comm_err(<<"fun(a, b, c, d) -> foo end"
@@ -2406,7 +2406,7 @@ otp_6554(Config) when is_list(Config) ->
comm_err(<<"fun(P, q) when is_pid(P) -> true end(a, b).">>),
?line "exception error: no function clause matching lists:reverse(" ++ _ =
comm_err(<<"F=fun() -> hello end, lists:reverse(F).">>),
- ?line "exception error: no function clause matching lists:reverse(34)" =
+ ?line "exception error: no function clause matching lists:reverse(34) (lists.erl, line " ++ _ =
comm_err(<<"lists:reverse(34).">>),
?line "exception error: no true branch found when evaluating an if expression" =
comm_err(<<"if length([a,b]) > 17 -> a end.">>),
diff --git a/lib/stdlib/test/sofs_SUITE.erl b/lib/stdlib/test/sofs_SUITE.erl
index 01de1f0600..73b282149a 100644
--- a/lib/stdlib/test/sofs_SUITE.erl
+++ b/lib/stdlib/test/sofs_SUITE.erl
@@ -1602,19 +1602,15 @@ relative_product_2(Conf) when is_list(Conf) ->
from_term([{{a},b}])}, ER)),
?line {'EXIT', {badarg, _}} = (catch relative_product({}, ER)),
- ?line eval(relative_product({relation([{a,b}])},
- from_term([],[{{atom},atom}])),
- ER),
- ?line eval(relative_product({relation([{a,b}]),relation([{a,1}])},
- from_term([{{b,1},{tjo,hej,sa}}])),
- from_term([{a,{tjo,hej,sa}}])),
- ?line eval(relative_product({relation([{a,b}]), ER},
- from_term([{{a,b},b}])),
- ER),
- ?line eval(relative_product({relation([{a,b},{c,a}]),
- relation([{a,1},{a,2}])},
- from_term([{{b,1},b1},{{b,2},b2}])),
- relation([{a,b1},{a,b2}])),
+ ?line relprod2({relation([{a,b}])}, from_term([],[{{atom},atom}]), ER),
+ ?line relprod2({relation([{a,b}]),relation([{a,1}])},
+ from_term([{{b,1},{tjo,hej,sa}}]),
+ from_term([{a,{tjo,hej,sa}}])),
+ ?line relprod2({relation([{a,b}]), ER}, from_term([{{a,b},b}]), ER),
+ ?line relprod2({relation([{a,b},{c,a}]),
+ relation([{a,1},{a,2}])},
+ from_term([{{b,1},b1},{{b,2},b2}]),
+ relation([{a,b1},{a,b2}])),
?line eval(relative_product({relation([{a,b}]), ER}),
from_term([],[{atom,{atom,atom}}])),
?line eval(relative_product({from_term([{{a,[a,b]},[a]}]),
@@ -1622,6 +1618,11 @@ relative_product_2(Conf) when is_list(Conf) ->
from_term([{{a,[a,b]},{[a],[[a,b]]}}])),
ok.
+relprod2(A1T, A2, R) ->
+ %% A tuple as first argument is the old interface:
+ eval(relative_product(A1T, A2), R),
+ eval(relative_product(tuple_to_list(A1T), A2), R).
+
product_1(suite) -> [];
product_1(doc) -> [""];
product_1(Conf) when is_list(Conf) ->
@@ -1878,11 +1879,11 @@ digraph(Conf) when is_list(Conf) ->
?line {'EXIT', {badarg, _}} =
(catch family_to_digraph(set([a]))),
- ?line {'EXIT', {badarg, [{sofs,family_to_digraph,[_,_]}|_]}} =
+ ?line {'EXIT', {badarg, [{sofs,family_to_digraph,[_,_],_}|_]}} =
(catch family_to_digraph(set([a]), [foo])),
- ?line {'EXIT', {badarg, [{sofs,family_to_digraph,[_,_]}|_]}} =
+ ?line {'EXIT', {badarg, [{sofs,family_to_digraph,[_,_],_}|_]}} =
(catch family_to_digraph(F, [foo])),
- ?line {'EXIT', {cyclic, [{sofs,family_to_digraph,[_,_]}|_]}} =
+ ?line {'EXIT', {cyclic, [{sofs,family_to_digraph,[_,_],_}|_]}} =
(catch family_to_digraph(family([{a,[a]}]),[acyclic])),
?line G1 = family_to_digraph(E),
diff --git a/lib/stdlib/test/string_SUITE.erl b/lib/stdlib/test/string_SUITE.erl
index 1dcd4be21e..6969c095a0 100644
--- a/lib/stdlib/test/string_SUITE.erl
+++ b/lib/stdlib/test/string_SUITE.erl
@@ -273,9 +273,9 @@ words(Config) when is_list(Config) ->
?line 2 = string:words("2.35", $.),
?line 100 = string:words(string:copies(". ", 100)),
%% invalid arg type
- ?line {'EXIT',_} = (catch string:chars(hej)),
+ ?line {'EXIT',_} = (catch string:chars(hej, 1)),
%% invalid arg type
- ?line {'EXIT',_} = (catch string:chars("hej", " ")),
+ ?line {'EXIT',_} = (catch string:chars("hej", 1, " ")),
ok.
diff --git a/lib/stdlib/test/supervisor_1.erl b/lib/stdlib/test/supervisor_1.erl
index 3198be0fed..f819594c46 100644
--- a/lib/stdlib/test/supervisor_1.erl
+++ b/lib/stdlib/test/supervisor_1.erl
@@ -62,6 +62,12 @@ handle_info(die, State) ->
handle_info(stop, State) ->
{stop, normal, State};
+handle_info({'EXIT',_,shutdown}, State) ->
+ {stop, shutdown, State};
+
+handle_info({'EXIT',_,{shutdown,Term}}, State) ->
+ {stop, {shutdown,Term}, State};
+
handle_info({sleep, Time}, State) ->
io:format("FOO: ~p~n", [Time]),
timer:sleep(Time),
diff --git a/lib/stdlib/test/supervisor_2.erl b/lib/stdlib/test/supervisor_2.erl
new file mode 100644
index 0000000000..67aacf5a9c
--- /dev/null
+++ b/lib/stdlib/test/supervisor_2.erl
@@ -0,0 +1,42 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Description: Simulates the behaviour that a child process may have.
+%% Is used by the supervisor_SUITE test suite.
+-module(supervisor_2).
+
+-export([start_child/1, init/1]).
+
+-export([handle_call/3, handle_info/2, terminate/2]).
+
+start_child(Time) when is_integer(Time), Time > 0 ->
+ gen_server:start_link(?MODULE, Time, []).
+
+init(Time) ->
+ process_flag(trap_exit, true),
+ {ok, Time}.
+
+handle_call(Req, _From, State) ->
+ {reply, Req, State}.
+
+handle_info(_, State) ->
+ {noreply, State}.
+
+terminate(_Reason, Time) ->
+ timer:sleep(Time),
+ ok.
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index f9ceed8f84..d3d140abbc 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -20,7 +20,7 @@
-module(supervisor_SUITE).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
-define(TIMEOUT, 1000).
%% Testserver specific export
@@ -28,8 +28,9 @@
init_per_group/2,end_per_group/2, init_per_testcase/2,
end_per_testcase/2]).
-%% Indirect spawn export
--export([init/1]).
+%% Internal export
+-export([init/1, terminate_all_children/1,
+ middle9212/0, gen_server9212/0, handle_info/2]).
%% API tests
-export([ sup_start_normal/1, sup_start_ignore_init/1,
@@ -41,8 +42,10 @@
%% Tests concept permanent, transient and temporary
-export([ permanent_normal/1, transient_normal/1,
temporary_normal/1,
+ permanent_shutdown/1, transient_shutdown/1,
+ temporary_shutdown/1,
permanent_abnormal/1, transient_abnormal/1,
- temporary_abnormal/1]).
+ temporary_abnormal/1, temporary_bystander/1]).
%% Restart strategy tests
-export([ one_for_one/1,
@@ -50,12 +53,14 @@
one_for_all_escalation/1,
simple_one_for_one/1, simple_one_for_one_escalation/1,
rest_for_one/1, rest_for_one_escalation/1,
- simple_one_for_one_extra/1]).
+ simple_one_for_one_extra/1, simple_one_for_one_shutdown/1]).
%% Misc tests
-export([child_unlink/1, tree/1, count_children_memory/1,
do_not_save_start_parameters_for_temporary_children/1,
- do_not_save_child_specs_for_temporary_children/1]).
+ do_not_save_child_specs_for_temporary_children/1,
+ simple_one_for_one_scale_many_temporary_children/1,
+ simple_global_supervisor/1]).
%%-------------------------------------------------------------------------
@@ -70,9 +75,12 @@ all() ->
{group, restart_simple_one_for_one},
{group, restart_rest_for_one},
{group, normal_termination},
+ {group, shutdown_termination},
{group, abnormal_termination}, child_unlink, tree,
count_children_memory, do_not_save_start_parameters_for_temporary_children,
- do_not_save_child_specs_for_temporary_children].
+ do_not_save_child_specs_for_temporary_children,
+ simple_one_for_one_scale_many_temporary_children, temporary_bystander,
+ simple_global_supervisor].
groups() ->
[{sup_start, [],
@@ -84,6 +92,8 @@ groups() ->
sup_stop_brutal_kill]},
{normal_termination, [],
[permanent_normal, transient_normal, temporary_normal]},
+ {shutdown_termination, [],
+ [permanent_shutdown, transient_shutdown, temporary_shutdown]},
{abnormal_termination, [],
[permanent_abnormal, transient_abnormal,
temporary_abnormal]},
@@ -92,8 +102,8 @@ groups() ->
{restart_one_for_all, [],
[one_for_all, one_for_all_escalation]},
{restart_simple_one_for_one, [],
- [simple_one_for_one, simple_one_for_one_extra,
- simple_one_for_one_escalation]},
+ [simple_one_for_one, simple_one_for_one_shutdown,
+ simple_one_for_one_extra, simple_one_for_one_escalation]},
{restart_rest_for_one, [],
[rest_for_one, rest_for_one_escalation]}].
@@ -112,16 +122,20 @@ end_per_group(_GroupName, Config) ->
Config.
init_per_testcase(count_children_memory, Config) ->
- MemoryState = erlang:system_info(allocator),
- case count_children_allocator_test(MemoryState) of
- true -> Config;
- false ->
+ try erlang:memory() of
+ _ ->
+ erts_debug:set_internal_state(available_internal_state, true),
+ Config
+ catch error:notsup ->
{skip, "+Meamin used during test; erlang:memory/1 not available"}
end;
init_per_testcase(_Case, Config) ->
erlang:display(_Case),
Config.
+end_per_testcase(count_children_memory, _Config) ->
+ catch erts_debug:set_internal_state(available_internal_state, false),
+ ok;
end_per_testcase(_Case, _Config) ->
ok.
@@ -203,8 +217,8 @@ sup_start_fail(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
sup_stop_infinity(doc) ->
- ["See sup_stop/1 when Shutdown = infinity, this walue is only allowed "
- "for children of type supervisor"];
+ ["See sup_stop/1 when Shutdown = infinity, this walue is allowed "
+ "for children of type supervisor _AND_ worker"];
sup_stop_infinity(suite) -> [];
sup_stop_infinity(Config) when is_list(Config) ->
@@ -215,12 +229,13 @@ sup_stop_infinity(Config) when is_list(Config) ->
Child2 = {child2, {supervisor_1, start_child, []}, permanent,
infinity, worker, []},
{ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ {ok, CPid2} = supervisor:start_child(sup_test, Child2),
link(CPid1),
- {error, {invalid_shutdown,infinity}} =
- supervisor:start_child(sup_test, Child2),
+ link(CPid2),
terminate(Pid, shutdown),
- check_exit_reason(CPid1, shutdown).
+ check_exit_reason(CPid1, shutdown),
+ check_exit_reason(CPid2, shutdown).
%%-------------------------------------------------------------------------
@@ -349,8 +364,7 @@ child_adm(Config) when is_list(Config) ->
ok = supervisor:terminate_child(sup_test, child1),
%% Start of already existing but not running process
- {error,already_present} =
- supervisor:start_child(sup_test, Child),
+ {error,already_present} = supervisor:start_child(sup_test, Child),
%% Restart
{ok, CPid2} = supervisor:restart_child(sup_test, child1),
@@ -377,6 +391,11 @@ child_adm(Config) when is_list(Config) ->
[{child1, CPid3, worker, []}] = supervisor:which_children(sup_test),
[1,1,0,1] = get_child_counts(sup_test),
+ %% Terminate with Pid not allowed when not simple_one_for_one
+ {error,not_found} = supervisor:terminate_child(sup_test, CPid3),
+ [{child1, CPid3, worker, []}] = supervisor:which_children(sup_test),
+ [1,1,0,1] = get_child_counts(sup_test),
+
{'EXIT',{noproc,{gen_server,call,[foo,which_children,infinity]}}}
= (catch supervisor:which_children(foo)),
{'EXIT',{noproc,{gen_server,call,[foo,count_children,infinity]}}}
@@ -412,16 +431,26 @@ child_adm_simple(Config) when is_list(Config) ->
[1,2,0,2] = get_child_counts(sup_test),
%% Termination
- {error, simple_one_for_one} =
- supervisor:terminate_child(sup_test, child1),
+ {error, simple_one_for_one} = supervisor:terminate_child(sup_test, child1),
+ [1,2,0,2] = get_child_counts(sup_test),
+ ok = supervisor:terminate_child(sup_test,CPid1),
+ [_] = supervisor:which_children(sup_test),
+ [1,1,0,1] = get_child_counts(sup_test),
+ false = erlang:is_process_alive(CPid1),
+ %% Terminate non-existing proccess is ok
+ ok = supervisor:terminate_child(sup_test,CPid1),
+ [_] = supervisor:which_children(sup_test),
+ [1,1,0,1] = get_child_counts(sup_test),
+ %% Terminate pid which is not a child of this supervisor is not ok
+ NoChildPid = spawn_link(fun() -> receive after infinity -> ok end end),
+ {error, not_found} = supervisor:terminate_child(sup_test, NoChildPid),
+ true = erlang:is_process_alive(NoChildPid),
%% Restart
- {error, simple_one_for_one} =
- supervisor:restart_child(sup_test, child1),
+ {error, simple_one_for_one} = supervisor:restart_child(sup_test, child1),
%% Deletion
- {error, simple_one_for_one} =
- supervisor:delete_child(sup_test, child1),
+ {error, simple_one_for_one} = supervisor:delete_child(sup_test, child1),
ok.
%%-------------------------------------------------------------------------
@@ -438,9 +467,8 @@ child_specs(Config) when is_list(Config) ->
B2 = {child, {m,f,[a]}, prmanent, 1000, worker, []},
B3 = {child, {m,f,[a]}, permanent, -10, worker, []},
B4 = {child, {m,f,[a]}, permanent, 10, wrker, []},
- B5 = {child, {m,f,[a]}, permanent, infinity, worker, []},
- B6 = {child, {m,f,[a]}, permanent, 1000, worker, dy},
- B7 = {child, {m,f,[a]}, permanent, 1000, worker, [1,2,3]},
+ B5 = {child, {m,f,[a]}, permanent, 1000, worker, dy},
+ B6 = {child, {m,f,[a]}, permanent, 1000, worker, [1,2,3]},
%% Correct child specs!
%% <Modules> (last parameter in a child spec) can be [] as we do
@@ -449,6 +477,7 @@ child_specs(Config) when is_list(Config) ->
C2 = {child, {m,f,[a]}, permanent, 1000, supervisor, []},
C3 = {child, {m,f,[a]}, temporary, 1000, worker, dynamic},
C4 = {child, {m,f,[a]}, transient, 1000, worker, [m]},
+ C5 = {child, {m,f,[a]}, permanent, infinity, worker, [m]},
{error, {invalid_mfa,mfa}} = supervisor:start_child(sup_test, B1),
{error, {invalid_restart_type, prmanent}} =
@@ -457,9 +486,8 @@ child_specs(Config) when is_list(Config) ->
= supervisor:start_child(sup_test, B3),
{error, {invalid_child_type,wrker}}
= supervisor:start_child(sup_test, B4),
- {error, _} = supervisor:start_child(sup_test, B5),
{error, {invalid_modules,dy}}
- = supervisor:start_child(sup_test, B6),
+ = supervisor:start_child(sup_test, B5),
{error, {invalid_mfa,mfa}} = supervisor:check_childspecs([B1]),
{error, {invalid_restart_type,prmanent}} =
@@ -467,15 +495,15 @@ child_specs(Config) when is_list(Config) ->
{error, {invalid_shutdown,-10}} = supervisor:check_childspecs([B3]),
{error, {invalid_child_type,wrker}}
= supervisor:check_childspecs([B4]),
- {error, _} = supervisor:check_childspecs([B5]),
- {error, {invalid_modules,dy}} = supervisor:check_childspecs([B6]),
+ {error, {invalid_modules,dy}} = supervisor:check_childspecs([B5]),
{error, {invalid_module, 1}} =
- supervisor:check_childspecs([B7]),
+ supervisor:check_childspecs([B6]),
ok = supervisor:check_childspecs([C1]),
ok = supervisor:check_childspecs([C2]),
ok = supervisor:check_childspecs([C3]),
ok = supervisor:check_childspecs([C4]),
+ ok = supervisor:check_childspecs([C5]),
ok.
%%-------------------------------------------------------------------------
@@ -534,6 +562,87 @@ temporary_normal(Config) when is_list(Config) ->
[0,0,0,0] = get_child_counts(sup_test).
%%-------------------------------------------------------------------------
+permanent_shutdown(doc) ->
+ ["A permanent child should always be restarted"];
+permanent_shutdown(suite) -> [];
+permanent_shutdown(Config) when is_list(Config) ->
+ {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ terminate(SupPid, CPid1, child1, shutdown),
+
+ [{child1, CPid2 ,worker,[]}] = supervisor:which_children(sup_test),
+ case is_pid(CPid2) of
+ true ->
+ ok;
+ false ->
+ test_server:fail({permanent_child_not_restarted, Child1})
+ end,
+ [1,1,0,1] = get_child_counts(sup_test),
+
+ terminate(SupPid, CPid2, child1, {shutdown, some_info}),
+
+ [{child1, CPid3 ,worker,[]}] = supervisor:which_children(sup_test),
+ case is_pid(CPid3) of
+ true ->
+ ok;
+ false ->
+ test_server:fail({permanent_child_not_restarted, Child1})
+ end,
+
+ [1,1,0,1] = get_child_counts(sup_test).
+
+%%-------------------------------------------------------------------------
+transient_shutdown(doc) ->
+ ["A transient child should not be restarted if it exits with "
+ "reason shutdown or {shutdown,Term}"];
+transient_shutdown(suite) -> [];
+transient_shutdown(Config) when is_list(Config) ->
+ {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []}, transient, 1000,
+ worker, []},
+
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ terminate(SupPid, CPid1, child1, shutdown),
+
+ [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
+ [1,0,0,1] = get_child_counts(sup_test),
+
+ {ok, CPid2} = supervisor:restart_child(sup_test, child1),
+
+ terminate(SupPid, CPid2, child1, {shutdown, some_info}),
+
+ [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
+ [1,0,0,1] = get_child_counts(sup_test).
+
+%%-------------------------------------------------------------------------
+temporary_shutdown(doc) ->
+ ["A temporary process should never be restarted"];
+temporary_shutdown(suite) -> [];
+temporary_shutdown(Config) when is_list(Config) ->
+ {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []}, temporary, 1000,
+ worker, []},
+
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ terminate(SupPid, CPid1, child1, shutdown),
+
+ [] = supervisor:which_children(sup_test),
+ [0,0,0,0] = get_child_counts(sup_test),
+
+ {ok, CPid2} = supervisor:start_child(sup_test, Child1),
+
+ terminate(SupPid, CPid2, child1, {shutdown, some_info}),
+
+ [] = supervisor:which_children(sup_test),
+ [0,0,0,0] = get_child_counts(sup_test).
+
+%%-------------------------------------------------------------------------
permanent_abnormal(doc) ->
["A permanent child should always be restarted"];
permanent_abnormal(suite) -> [];
@@ -592,6 +701,37 @@ temporary_abnormal(Config) when is_list(Config) ->
[0,0,0,0] = get_child_counts(sup_test).
%%-------------------------------------------------------------------------
+temporary_bystander(doc) ->
+ ["A temporary process killed as part of a rest_for_one or one_for_all "
+ "restart strategy should not be restarted given its args are not "
+ " saved. Otherwise the supervisor hits its limit and crashes."];
+temporary_bystander(suite) -> [];
+temporary_bystander(_Config) ->
+ Child1 = {child1, {supervisor_1, start_child, []}, permanent, 100,
+ worker, []},
+ Child2 = {child2, {supervisor_1, start_child, []}, temporary, 100,
+ worker, []},
+ {ok, SupPid1} = supervisor:start_link(?MODULE, {ok, {{one_for_all, 2, 300}, []}}),
+ {ok, SupPid2} = supervisor:start_link(?MODULE, {ok, {{rest_for_one, 2, 300}, []}}),
+ unlink(SupPid1), % otherwise we crash with it
+ unlink(SupPid2), % otherwise we crash with it
+ {ok, CPid1} = supervisor:start_child(SupPid1, Child1),
+ {ok, _CPid2} = supervisor:start_child(SupPid1, Child2),
+ {ok, CPid3} = supervisor:start_child(SupPid2, Child1),
+ {ok, _CPid4} = supervisor:start_child(SupPid2, Child2),
+ terminate(SupPid1, CPid1, child1, normal),
+ terminate(SupPid2, CPid3, child1, normal),
+ timer:sleep(350),
+ catch link(SupPid1),
+ catch link(SupPid2),
+ %% The supervisor would die attempting to restart child2
+ true = erlang:is_process_alive(SupPid1),
+ true = erlang:is_process_alive(SupPid2),
+ %% Child2 has not been restarted
+ [{child1, _, _, _}] = supervisor:which_children(SupPid1),
+ [{child1, _, _, _}] = supervisor:which_children(SupPid2).
+
+%%-------------------------------------------------------------------------
one_for_one(doc) ->
["Test the one_for_one base case."];
one_for_one(suite) -> [];
@@ -736,6 +876,38 @@ simple_one_for_one(Config) when is_list(Config) ->
terminate(SupPid, Pid4, Id4, abnormal),
check_exit([SupPid]).
+
+%%-------------------------------------------------------------------------
+simple_one_for_one_shutdown(doc) ->
+ ["Test simple_one_for_one children shutdown accordingly to the "
+ "supervisor's shutdown strategy."];
+simple_one_for_one_shutdown(suite) -> [];
+simple_one_for_one_shutdown(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ShutdownTime = 1000,
+ Child = {child, {supervisor_2, start_child, []},
+ permanent, 2*ShutdownTime, worker, []},
+ {ok, SupPid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
+
+ %% Will be gracefully shutdown
+ {ok, _CPid1} = supervisor:start_child(sup_test, [ShutdownTime]),
+ {ok, _CPid2} = supervisor:start_child(sup_test, [ShutdownTime]),
+
+ %% Will be killed after 2*ShutdownTime milliseconds
+ {ok, _CPid3} = supervisor:start_child(sup_test, [5*ShutdownTime]),
+
+ {T, ok} = timer:tc(fun terminate/2, [SupPid, shutdown]),
+ if T < 1000*ShutdownTime ->
+ %% Because supervisor's children wait before exiting, it can't
+ %% terminate quickly
+ test_server:fail({shutdown_too_short, T});
+ T >= 1000*5*ShutdownTime ->
+ test_server:fail({shutdown_too_long, T});
+ true ->
+ check_exit([SupPid])
+ end.
+
+
%%-------------------------------------------------------------------------
simple_one_for_one_extra(doc) ->
["Tests automatic restart of children "
@@ -972,25 +1144,25 @@ count_children_memory(Config) when is_list(Config) ->
[supervisor:start_child(sup_test, []) || _Ignore <- lists:seq(1,1000)],
garbage_collect(),
- _Size1 = erlang:memory(processes_used),
+ _Size1 = proc_memory(),
Children = supervisor:which_children(sup_test),
- _Size2 = erlang:memory(processes_used),
+ _Size2 = proc_memory(),
ChildCount = get_child_counts(sup_test),
- _Size3 = erlang:memory(processes_used),
+ _Size3 = proc_memory(),
[supervisor:start_child(sup_test, []) || _Ignore2 <- lists:seq(1,1000)],
garbage_collect(),
Children2 = supervisor:which_children(sup_test),
- Size4 = erlang:memory(processes_used),
+ Size4 = proc_memory(),
ChildCount2 = get_child_counts(sup_test),
- Size5 = erlang:memory(processes_used),
+ Size5 = proc_memory(),
garbage_collect(),
Children3 = supervisor:which_children(sup_test),
- Size6 = erlang:memory(processes_used),
+ Size6 = proc_memory(),
ChildCount3 = get_child_counts(sup_test),
- Size7 = erlang:memory(processes_used),
+ Size7 = proc_memory(),
1000 = length(Children),
[1,1000,0,1000] = ChildCount,
@@ -1016,16 +1188,9 @@ count_children_memory(Config) when is_list(Config) ->
[terminate(SupPid, Pid, child, kill) || {undefined, Pid, worker, _Modules} <- Children3],
[1,0,0,0] = get_child_counts(sup_test).
-count_children_allocator_test(MemoryState) ->
- Allocators = [temp_alloc, eheap_alloc, binary_alloc, ets_alloc,
- driver_alloc, sl_alloc, ll_alloc, fix_alloc, std_alloc,
- sys_alloc],
- MemoryStateList = element(4, MemoryState),
- AllocTypes = [lists:keyfind(Alloc, 1, MemoryStateList)
- || Alloc <- Allocators],
- AllocStates = [lists:keyfind(e, 1, AllocValue)
- || {_Type, AllocValue} <- AllocTypes],
- lists:all(fun(State) -> State == {e, true} end, AllocStates).
+proc_memory() ->
+ erts_debug:set_internal_state(wait, deallocations),
+ erlang:memory(processes_used).
%%-------------------------------------------------------------------------
do_not_save_start_parameters_for_temporary_children(doc) ->
@@ -1187,6 +1352,133 @@ restarted(Sup, {Id,_,_,_,_,_} = ChildSpec, TerminateHow) ->
{error, {already_started, _}} = supervisor:start_child(Sup, ChildSpec).
+%%-------------------------------------------------------------------------
+%% OTP-9242: Pids for dynamic temporary children were saved as a list,
+%% which caused bad scaling when adding/deleting many processes.
+simple_one_for_one_scale_many_temporary_children(_Config) ->
+ process_flag(trap_exit, true),
+ Child = {child, {supervisor_1, start_child, []}, temporary, 1000,
+ worker, []},
+ {ok, _SupPid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
+
+ C1 = [begin
+ {ok,P} = supervisor:start_child(sup_test,[]),
+ P
+ end || _<- lists:seq(1,1000)],
+ {T1,done} = timer:tc(?MODULE,terminate_all_children,[C1]),
+
+ C2 = [begin
+ {ok,P} = supervisor:start_child(sup_test,[]),
+ P
+ end || _<- lists:seq(1,10000)],
+ {T2,done} = timer:tc(?MODULE,terminate_all_children,[C2]),
+
+ Scaling = T2 div T1,
+ if Scaling > 20 ->
+ %% The scaling shoul be linear (i.e.10, really), but we
+ %% give some extra here to avoid failing the test
+ %% unecessarily.
+ ?t:fail({bad_scaling,Scaling});
+ true ->
+ ok
+ end.
+
+
+terminate_all_children([C|Cs]) ->
+ ok = supervisor:terminate_child(sup_test,C),
+ terminate_all_children(Cs);
+terminate_all_children([]) ->
+ done.
+
+
+%%-------------------------------------------------------------------------
+%% OTP-9212. Restart of global supervisor.
+simple_global_supervisor(_Config) ->
+ kill_supervisor(),
+ kill_worker(),
+ exit_worker(),
+ restart_worker(),
+ ok.
+
+kill_supervisor() ->
+ {Top, Sup2_1, Server_1} = start9212(),
+
+ %% Killing a supervisor isn't really supported, but try it anyway...
+ exit(Sup2_1, kill),
+ timer:sleep(200),
+ Sup2_2 = global:whereis_name(sup2),
+ Server_2 = global:whereis_name(server),
+ true = is_pid(Sup2_2),
+ true = is_pid(Server_2),
+ true = Sup2_1 =/= Sup2_2,
+ true = Server_1 =/= Server_2,
+
+ stop9212(Top).
+
+handle_info({fail, With, After}, _State) ->
+ timer:sleep(After),
+ erlang:error(With).
+
+kill_worker() ->
+ {Top, _Sup2, Server_1} = start9212(),
+ exit(Server_1, kill),
+ timer:sleep(200),
+ Server_2 = global:whereis_name(server),
+ true = is_pid(Server_2),
+ true = Server_1 =/= Server_2,
+ stop9212(Top).
+
+exit_worker() ->
+ %% Very much the same as kill_worker().
+ {Top, _Sup2, Server_1} = start9212(),
+ Server_1 ! {fail, normal, 0},
+ timer:sleep(200),
+ Server_2 = global:whereis_name(server),
+ true = is_pid(Server_2),
+ true = Server_1 =/= Server_2,
+ stop9212(Top).
+
+restart_worker() ->
+ {Top, _Sup2, Server_1} = start9212(),
+ ok = supervisor:terminate_child({global, sup2}, child),
+ {ok, _Child} = supervisor:restart_child({global, sup2}, child),
+ Server_2 = global:whereis_name(server),
+ true = is_pid(Server_2),
+ true = Server_1 =/= Server_2,
+ stop9212(Top).
+
+start9212() ->
+ Middle = {middle,{?MODULE,middle9212,[]}, permanent,2000,supervisor,[]},
+ InitResult = {ok, {{one_for_all,3,60}, [Middle]}},
+ {ok, TopPid} = start_link(InitResult),
+
+ Sup2 = global:whereis_name(sup2),
+ Server = global:whereis_name(server),
+ true = is_pid(Sup2),
+ true = is_pid(Server),
+ {TopPid, Sup2, Server}.
+
+stop9212(Top) ->
+ Old = process_flag(trap_exit, true),
+ exit(Top, kill),
+ timer:sleep(200),
+ undefined = global:whereis_name(sup2),
+ undefined = global:whereis_name(server),
+ check_exit([Top]),
+ _ = process_flag(trap_exit, Old),
+ ok.
+
+middle9212() ->
+ Child = {child, {?MODULE,gen_server9212,[]},permanent, 2000, worker, []},
+ InitResult = {ok, {{one_for_all,3,60}, [Child]}},
+ supervisor:start_link({global,sup2}, ?MODULE, InitResult).
+
+gen_server9212() ->
+ InitResult = {ok, []},
+ gen_server:start_link({global,server}, ?MODULE, InitResult, []).
+
+
+%%-------------------------------------------------------------------------
terminate(Pid, Reason) when Reason =/= supervisor ->
terminate(dummy, Pid, dummy, Reason).
@@ -1206,6 +1498,13 @@ terminate(_, ChildPid, _, shutdown) ->
{'DOWN', Ref, process, ChildPid, shutdown} ->
ok
end;
+terminate(_, ChildPid, _, {shutdown, Term}) ->
+ Ref = erlang:monitor(process, ChildPid),
+ exit(ChildPid, {shutdown, Term}),
+ receive
+ {'DOWN', Ref, process, ChildPid, {shutdown, Term}} ->
+ ok
+ end;
terminate(_, ChildPid, _, normal) ->
Ref = erlang:monitor(process, ChildPid),
ChildPid ! stop,
diff --git a/lib/stdlib/test/supervisor_bridge_SUITE.erl b/lib/stdlib/test/supervisor_bridge_SUITE.erl
index f2dbad0b3b..b3056ff41a 100644
--- a/lib/stdlib/test/supervisor_bridge_SUITE.erl
+++ b/lib/stdlib/test/supervisor_bridge_SUITE.erl
@@ -19,8 +19,9 @@
-module(supervisor_bridge_SUITE).
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,starting/1,
- mini_terminate/1,mini_die/1,badstart/1]).
--export([client/1,init/1,internal_loop_init/1,terminate/2]).
+ mini_terminate/1,mini_die/1,badstart/1,
+ simple_global_supervisor/1]).
+-export([client/1,init/1,internal_loop_init/1,terminate/2,server9212/0]).
-include_lib("test_server/include/test_server.hrl").
-define(bridge_name,supervisor_bridge_SUITE_server).
@@ -31,7 +32,7 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [starting, mini_terminate, mini_die, badstart].
+ [starting, mini_terminate, mini_die, badstart, simple_global_supervisor].
groups() ->
[].
@@ -138,7 +139,9 @@ init(3) ->
receive
{InternalPid,init_done} ->
{ok,InternalPid,self()}
- end.
+ end;
+init({4,Result}) ->
+ Result.
internal_loop_init(Parent) ->
register(?work_bridge_name, self()),
@@ -158,9 +161,11 @@ internal_loop(State) ->
terminate(Reason,{Parent,Worker}) ->
%% This func knows about supervisor_bridge
io:format("Terminating bridge...\n"),
- exit(kill,Worker),
+ exit(Worker,kill),
Parent ! {dying,Reason},
- anything.
+ anything;
+terminate(_Reason, _State) ->
+ any.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -197,3 +202,30 @@ badstart(Config) when is_list(Config) ->
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% OTP-9212. Restart of global supervisor.
+
+simple_global_supervisor(suite) -> [];
+simple_global_supervisor(doc) -> "Globally registered supervisor.";
+simple_global_supervisor(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap({seconds,10}),
+
+ Child = {child, {?MODULE,server9212,[]}, permanent, 2000, worker, []},
+ InitResult = {ok, {{one_for_all,3,60}, [Child]}},
+ {ok, Sup} =
+ supervisor:start_link({local,bridge9212}, ?MODULE, {4,InitResult}),
+
+ BN_1 = global:whereis_name(?bridge_name),
+ ?line exit(BN_1, kill),
+ timer:sleep(200),
+ BN_2 = global:whereis_name(?bridge_name),
+ ?line true = is_pid(BN_2),
+ ?line true = BN_1 =/= BN_2,
+
+ ?line process_flag(trap_exit, true),
+ exit(Sup, kill),
+ ?line receive {'EXIT', Sup, killed} -> ok end,
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+server9212() ->
+ supervisor_bridge:start_link({global,?bridge_name}, ?MODULE, 3).
diff --git a/lib/stdlib/test/sys_SUITE.erl b/lib/stdlib/test/sys_SUITE.erl
index 72b089aa3f..fe039e8bcc 100644
--- a/lib/stdlib/test/sys_SUITE.erl
+++ b/lib/stdlib/test/sys_SUITE.erl
@@ -71,7 +71,7 @@ log_to_file(Config) when is_list(Config) ->
?line ok = sys:log_to_file(?server,TempName),
?line {ok,-44} = public_call(44),
?line ok = sys:log_to_file(?server,false),
- ?line {ok,Fd} = file:open(TempName,read),
+ ?line {ok,Fd} = file:open(TempName,[read]),
?line Msg1 = io:get_line(Fd,''),
?line Msg2 = io:get_line(Fd,''),
?line file:close(Fd),
diff --git a/lib/stdlib/test/tar_SUITE.erl b/lib/stdlib/test/tar_SUITE.erl
index e32704ca65..9ad3936928 100644
--- a/lib/stdlib/test/tar_SUITE.erl
+++ b/lib/stdlib/test/tar_SUITE.erl
@@ -65,7 +65,7 @@ borderline(Config) when is_list(Config) ->
?line {ok, Cwd} = file:get_cwd(),
?line RootDir = ?config(priv_dir, Config),
- ?line TempDir = remove_prefix(Cwd++"/", filename:join(RootDir, borderline)),
+ ?line TempDir = remove_prefix(Cwd++"/", filename:join(RootDir, "borderline")),
?line ok = file:make_dir(TempDir),
?line Record = 512,
@@ -283,17 +283,16 @@ long_names(doc) ->
long_names(Config) when is_list(Config) ->
?line DataDir = ?config(data_dir, Config),
?line Long = filename:join(DataDir, "long_names.tar"),
+ run_in_short_tempdir(Config,
+ fun() -> do_long_names(Long) end).
+do_long_names(Long) ->
%% Try table/2 and extract/2.
?line case erl_tar:table(Long, [verbose]) of
{ok,List} when is_list(List) ->
?line io:format("~p\n", [List])
end,
-
- %% To avoid getting too long paths for Windows to handle, extract into
- %% the current directory (which is the test_server directory). Its path
- %% is quite a bit shorter than the path to priv_dir.
?line {ok,Cwd} = file:get_cwd(),
?line ok = erl_tar:extract(Long),
?line Base = filename:join([Cwd, "original_software", "written_by",
@@ -312,29 +311,28 @@ long_names(Config) when is_list(Config) ->
?line "Here"++_ = binary_to_list(First),
?line "And"++_ = binary_to_list(Second),
- %% Clean up.
- ?line delete_files([filename:join(Cwd, "original_software"),EmptyDir]),
-
ok.
create_long_names(doc) ->
["Creates a tar file from a deep directory structure (filenames are ",
"longer than 100 characters)."];
create_long_names(Config) when is_list(Config) ->
- ?line PrivDir = ?config(priv_dir, Config),
- ?line ok = file:set_cwd(PrivDir),
- Dirs = [aslfjkshjkhliuf,
- asdhjfehnbfsky,
- sahajfskdfhsz,
- asldfkdlfy4y8rchg,
- f7nafhjgffagkhsfkhsjk,
- dfjasldkfjsdkfjashbv],
+ run_in_short_tempdir(Config, fun create_long_names/0).
+
+create_long_names() ->
+ ?line {ok,Dir} = file:get_cwd(),
+ Dirs = ["aslfjkshjkhliuf",
+ "asdhjfehnbfsky",
+ "sahajfskdfhsz",
+ "asldfkdlfy4y8rchg",
+ "f7nafhjgffagkhsfkhsjk",
+ "dfjasldkfjsdkfjashbv"],
?line DeepDir = make_dirs(Dirs, []),
?line AFile = filename:join(DeepDir, "a_file"),
?line Hello = "hello, world\n",
?line ok = file:write_file(AFile, Hello),
- ?line TarName = filename:join(PrivDir, "my_tar_with_long_names.tar"),
+ ?line TarName = filename:join(Dir, "my_tar_with_long_names.tar"),
?line ok = erl_tar:create(TarName, [AFile]),
%% Print contents.
@@ -347,9 +345,6 @@ create_long_names(Config) when is_list(Config) ->
?line {ok, Bin} = file:read_file(filename:join(ExtractDir, AFile)),
?line Hello = binary_to_list(Bin),
- %% Clean up.
- ?line delete_files([ExtractDir,TarName,hd(Dirs)]),
-
ok.
make_dirs([Dir|Rest], []) ->
@@ -487,7 +482,7 @@ extract_from_binary_compressed(Config) when is_list(Config) ->
%% Trying extracting from a binary.
?line ok = erl_tar:extract({binary,Bin}, [compressed,{cwd,ExtractDir}]),
- ?line {ok,List} = file:list_dir(filename:join(ExtractDir, ddll_SUITE_data)),
+ ?line {ok,List} = file:list_dir(filename:join(ExtractDir, "ddll_SUITE_data")),
?line io:format("~p\n", [List]),
?line 19 = length(List),
@@ -676,7 +671,7 @@ cooked_compressed(Config) when is_list(Config) ->
end, List),
%% Clean up.
- ?line delete_files([filename:join(PrivDir, ddll_SUITE_data)]),
+ ?line delete_files([filename:join(PrivDir, "ddll_SUITE_data")]),
ok.
memory(doc) ->
@@ -734,3 +729,42 @@ delete_files([Item|Rest]) ->
end,
delete_files(Rest).
+%% Move to a temporary directory with as short name as possible and
+%% execute Fun. Remove the directory and any files in it afterwards.
+%% This is necessary because pathnames on Windows may be limited to
+%% 260 characters.
+run_in_short_tempdir(Config, Fun) ->
+ {ok,Cwd} = file:get_cwd(),
+ PrivDir0 = ?config(priv_dir, Config),
+
+ %% Normalize name to make sure that there is no slash at the end.
+ PrivDir = filename:absname(PrivDir0),
+
+ %% We need a base directory with a much shorter pathname than
+ %% priv_dir. We KNOW that priv_dir is located four levels below
+ %% the directory that common_test puts the ct_run.* directories
+ %% in. That fact is not documented, but an usually reliable source
+ %% assured me that the directory structure is unlikely to change
+ %% in future versions of common_test because of backward
+ %% compatibility (tools developed by users of common_test depend
+ %% on the current directory layout).
+ Base = lists:foldl(fun(_, D) ->
+ filename:dirname(D)
+ end, PrivDir, [1,2,3,4]),
+
+ Dir = make_temp_dir(Base, 0),
+ ok = file:set_cwd(Dir),
+ io:format("Running test in ~s\n", [Dir]),
+ try
+ Fun()
+ after
+ file:set_cwd(Cwd),
+ delete_files([Dir])
+ end.
+
+make_temp_dir(Base, I) ->
+ Name = filename:join(Base, integer_to_list(I, 36)),
+ case file:make_dir(Name) of
+ ok -> Name;
+ {error,eexist} -> make_temp_dir(Base, I+1)
+ end.
diff --git a/lib/stdlib/test/timer_simple_SUITE.erl b/lib/stdlib/test/timer_simple_SUITE.erl
index 852afa1a4d..dc751aad16 100644
--- a/lib/stdlib/test/timer_simple_SUITE.erl
+++ b/lib/stdlib/test/timer_simple_SUITE.erl
@@ -229,7 +229,7 @@ cancel2(Config) when is_list(Config) ->
tc(doc) -> "Test sleep/1 and tc/3.";
tc(suite) -> [];
tc(Config) when is_list(Config) ->
- % This should both sleep and tc/3
+ %% This should test both sleep and tc/3
?line {Res1, ok} = timer:tc(timer, sleep, [500]),
?line ok = if
Res1 < 500*1000 -> {too_early, Res1}; % Too early
@@ -237,13 +237,40 @@ tc(Config) when is_list(Config) ->
true -> ok
end,
- % This should both sleep and tc/2
+ %% tc/2
?line {Res2, ok} = timer:tc(fun(T) -> timer:sleep(T) end, [500]),
?line ok = if
Res2 < 500*1000 -> {too_early, Res2}; % Too early
Res2 > 800*1000 -> {too_late, Res2}; % Too much time
true -> ok
end,
+
+ %% tc/1
+ ?line {Res3, ok} = timer:tc(fun() -> timer:sleep(500) end),
+ ?line ok = if
+ Res3 < 500*1000 -> {too_early, Res3}; % Too early
+ Res3 > 800*1000 -> {too_late, Res3}; % Too much time
+ true -> ok
+ end,
+
+ %% Check that timer:tc don't catch errors
+ ?line ok = try timer:tc(erlang, exit, [foo])
+ catch exit:foo -> ok
+ end,
+
+ ?line ok = try timer:tc(fun(Reason) -> 1 = Reason end, [foo])
+ catch error:{badmatch,_} -> ok
+ end,
+
+ ?line ok = try timer:tc(fun() -> throw(foo) end)
+ catch foo -> ok
+ end,
+
+ %% Check that return values are propageted
+ Self = self(),
+ ?line {_, Self} = timer:tc(erlang, self, []),
+ ?line {_, Self} = timer:tc(fun(P) -> P end, [self()]),
+ ?line {_, Self} = timer:tc(fun() -> self() end),
?line Sec = timer:seconds(4),
?line Min = timer:minutes(4),
diff --git a/lib/stdlib/test/unicode_SUITE.erl b/lib/stdlib/test/unicode_SUITE.erl
index 9aa800209d..4055af2741 100644
--- a/lib/stdlib/test/unicode_SUITE.erl
+++ b/lib/stdlib/test/unicode_SUITE.erl
@@ -322,7 +322,7 @@ roundtrips(Config) when is_list(Config) ->
ex_roundtrips(Config) when is_list(Config) ->
?line L1 = ranges(0, 16#D800 - 1,
erlang:system_info(context_reductions) * 11),
- ?line L2 = ranges(16#DFFF + 1, 16#FFFE - 1,
+ ?line L2 = ranges(16#DFFF + 1, 16#10000 - 1,
erlang:system_info(context_reductions) * 11),
%?line L3 = ranges(16#FFFF + 1, 16#10FFFF,
% erlang:system_info(context_reductions) * 11),
@@ -569,7 +569,6 @@ utf16_illegal_sequences_bif(Config) when is_list(Config) ->
ex_utf16_illegal_sequences_bif(Config) when is_list(Config) ->
?line utf16_fail_range_bif_simple(16#10FFFF+1, 16#10FFFF+512), %Too large.
?line utf16_fail_range_bif(16#D800, 16#DFFF), %Reserved for UTF-16.
- ?line utf16_fail_range_bif(16#FFFE, 16#FFFF), %Non-characters.
?line lonely_hi_surrogate_bif(16#D800, 16#DBFF,incomplete),
?line lonely_hi_surrogate_bif(16#DC00, 16#DFFF,error),
@@ -644,7 +643,6 @@ utf8_illegal_sequences_bif(Config) when is_list(Config) ->
ex_utf8_illegal_sequences_bif(Config) when is_list(Config) ->
?line fail_range_bif(16#10FFFF+1, 16#10FFFF+512), %Too large.
?line fail_range_bif(16#D800, 16#DFFF), %Reserved for UTF-16.
- ?line fail_range_bif(16#FFFE, 16#FFFF), %Reserved (BOM).
%% Illegal first character.
?line [fail_bif(<<I,16#8F,16#8F,16#8F>>,unicode) || I <- lists:seq(16#80, 16#BF)],
diff --git a/lib/stdlib/test/zip_SUITE.erl b/lib/stdlib/test/zip_SUITE.erl
index d5f2cd52d4..7233c061ef 100644
--- a/lib/stdlib/test/zip_SUITE.erl
+++ b/lib/stdlib/test/zip_SUITE.erl
@@ -375,7 +375,8 @@ zip_options(Config) when is_list(Config) ->
ok = file:set_cwd(?config(data_dir, Config)),
%% Create a zip archive
- {ok, Zip} = zip:zip("filename_not_used.zip", Names, [memory, {cwd, PrivDir}]),
+ {ok, {_,Zip}} =
+ zip:zip("filename_not_used.zip", Names, [memory, {cwd, PrivDir}]),
%% Open archive
{ok, ZipSrv} = zip:zip_open(Zip, [memory]),