aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/test')
-rw-r--r--erts/emulator/test/alloc_SUITE.erl19
-rw-r--r--erts/emulator/test/bif_SUITE.erl10
-rw-r--r--erts/emulator/test/binary_SUITE.erl254
-rw-r--r--erts/emulator/test/code_parallel_load_SUITE.erl36
-rw-r--r--erts/emulator/test/driver_SUITE.erl68
-rw-r--r--erts/emulator/test/exception_SUITE.erl11
-rw-r--r--erts/emulator/test/fun_SUITE.erl10
-rw-r--r--erts/emulator/test/hash_SUITE.erl7
-rw-r--r--erts/emulator/test/match_spec_SUITE.erl16
-rw-r--r--erts/emulator/test/mtx_SUITE_data/Makefile.src4
-rw-r--r--erts/emulator/test/port_SUITE.erl69
-rw-r--r--erts/emulator/test/process_SUITE.erl219
-rw-r--r--erts/emulator/test/scheduler_SUITE.erl2
13 files changed, 547 insertions, 178 deletions
diff --git a/erts/emulator/test/alloc_SUITE.erl b/erts/emulator/test/alloc_SUITE.erl
index f6ff6bb813..35c44c229a 100644
--- a/erts/emulator/test/alloc_SUITE.erl
+++ b/erts/emulator/test/alloc_SUITE.erl
@@ -114,8 +114,8 @@ cpool(Cfg) -> ?line drv_case(Cfg).
erts_mmap(Config) when is_list(Config) ->
case {?t:os_type(), is_halfword_vm()} of
{{unix, _}, false} ->
- [erts_mmap_do(Config, SCO, SCRPM, SCMGC)
- || SCO <-[true,false], SCMGC <-[1234,0], SCRPM <- [true,false]];
+ [erts_mmap_do(Config, SCO, SCRPM, SCRFSD)
+ || SCO <-[true,false], SCRFSD <-[1234,0], SCRPM <- [true,false]];
{_,true} ->
{skipped, "No supercarrier support on halfword vm"};
@@ -126,14 +126,19 @@ erts_mmap(Config) when is_list(Config) ->
end.
-erts_mmap_do(Config, SCO, SCRPM, SCMGC) ->
- SCS = 100, % Mb
+erts_mmap_do(Config, SCO, SCRPM, SCRFSD) ->
+ %% We use the number of schedulers + 1 * approx main carriers size
+ %% to calculate how large the super carrier has to be
+ %% and then use a minimum of 100 for systems with a low amount of
+ %% schedulers
+ Schldr = erlang:system_info(schedulers_online)+1,
+ SCS = max(round((262144 * 6 + 3 * 1048576) * Schldr / 1024 / 1024),100),
O1 = "+MMscs" ++ integer_to_list(SCS)
++ " +MMsco" ++ atom_to_list(SCO)
++ " +MMscrpm" ++ atom_to_list(SCRPM),
- Opts = case SCMGC of
+ Opts = case SCRFSD of
0 -> O1;
- _ -> O1 ++ " +MMscmgc"++integer_to_list(SCMGC)
+ _ -> O1 ++ " +MMscrfsd"++integer_to_list(SCRFSD)
end,
{ok, Node} = start_node(Config, Opts),
Self = self(),
@@ -148,7 +153,7 @@ erts_mmap_do(Config, SCO, SCRPM, SCMGC) ->
Total = SCS*1024*1024,
{reserved,Reserved} = lists:keyfind(reserved,1,Segs),
- true = (Reserved >= SCMGC),
+ true = (Reserved >= SCRFSD),
case {SCO,lists:keyfind(os,1,EM)} of
{true, false} -> ok;
diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl
index 02c6de8cb1..fbc229bc53 100644
--- a/erts/emulator/test/bif_SUITE.erl
+++ b/erts/emulator/test/bif_SUITE.erl
@@ -388,8 +388,12 @@ os_env(Config) when is_list(Config) ->
false -> ?line ok;
BadVal -> ?line ?t:fail(BadVal)
end,
- %% os:putenv and os:getenv currently uses a temp buf of size 1024
- %% for storing key+value
+ true = os:putenv(EnvVar1, "mors"),
+ true = os:unsetenv(EnvVar1),
+ false = os:getenv(EnvVar1),
+ true = os:unsetenv(EnvVar1), % unset unset variable
+ %% os:putenv, os:getenv and os:unsetenv currently use a temp
+ %% buffer of size 1024 for storing key+value
?line os_env_long(1010, 1030, "hej hopp").
os_env_long(Min, Max, _Value) when Min > Max ->
@@ -398,7 +402,7 @@ os_env_long(Min, Max, Value) ->
?line EnvVar = lists:duplicate(Min, $X),
?line true = os:putenv(EnvVar, Value),
?line Value = os:getenv(EnvVar),
- ?line true = os:putenv(EnvVar, ""),
+ true = os:unsetenv(EnvVar),
?line os_env_long(Min+1, Max, Value).
otp_7526(doc) ->
diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl
index 08ab094019..a390c536bb 100644
--- a/erts/emulator/test/binary_SUITE.erl
+++ b/erts/emulator/test/binary_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. 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
@@ -58,10 +58,10 @@
ordering/1,unaligned_order/1,gc_test/1,
bit_sized_binary_sizes/1,
otp_6817/1,deep/1,obsolete_funs/1,robustness/1,otp_8117/1,
- otp_8180/1, ttb_trap/1]).
+ otp_8180/1, trapping/1]).
%% Internal exports.
--export([sleeper/0,ttb_loop/2]).
+-export([sleeper/0,trapping_loop/4]).
suite() -> [{ct_hooks,[ts_install_cth]},
{timetrap,{minutes,2}}].
@@ -76,7 +76,7 @@ all() ->
bad_term_to_binary, more_bad_terms, otp_5484, otp_5933,
ordering, unaligned_order, gc_test,
bit_sized_binary_sizes, otp_6817, otp_8117, deep,
- obsolete_funs, robustness, otp_8180, ttb_trap].
+ obsolete_funs, robustness, otp_8180, trapping].
groups() ->
[].
@@ -447,26 +447,26 @@ terms(Config) when is_list(Config) ->
Sz1 when is_integer(Sz1), size(Bin1) =< Sz1 ->
ok
end,
- Term = binary_to_term(Bin),
- Term = binary_to_term(Bin, [safe]),
+ Term = binary_to_term_stress(Bin),
+ Term = binary_to_term_stress(Bin, [safe]),
Unaligned = make_unaligned_sub_binary(Bin),
- Term = binary_to_term(Unaligned),
- Term = binary_to_term(Unaligned, []),
- Term = binary_to_term(Bin, [safe]),
+ Term = binary_to_term_stress(Unaligned),
+ Term = binary_to_term_stress(Unaligned, []),
+ Term = binary_to_term_stress(Bin, [safe]),
BinC = erlang:term_to_binary(Term, [compressed]),
- Term = binary_to_term(BinC),
+ Term = binary_to_term_stress(BinC),
true = size(BinC) =< size(Bin),
Bin = term_to_binary(Term, [{compressed,0}]),
terms_compression_levels(Term, size(Bin), 1),
UnalignedC = make_unaligned_sub_binary(BinC),
- Term = binary_to_term(UnalignedC)
+ Term = binary_to_term_stress(UnalignedC)
end,
?line test_terms(TestFun),
ok.
terms_compression_levels(Term, UncompressedSz, Level) when Level < 10 ->
BinC = erlang:term_to_binary(Term, [{compressed,Level}]),
- Term = binary_to_term(BinC),
+ Term = binary_to_term_stress(BinC),
Sz = byte_size(BinC),
true = Sz =< UncompressedSz,
terms_compression_levels(Term, UncompressedSz, Level+1);
@@ -476,9 +476,9 @@ terms_float(Config) when is_list(Config) ->
?line test_floats(fun(Term) ->
Bin0 = term_to_binary(Term),
Bin0 = term_to_binary(Term, [{minor_version,0}]),
- Term = binary_to_term(Bin0),
+ Term = binary_to_term_stress(Bin0),
Bin1 = term_to_binary(Term, [{minor_version,1}]),
- Term = binary_to_term(Bin1),
+ Term = binary_to_term_stress(Bin1),
true = size(Bin1) < size(Bin0),
Size0 = erlang:external_size(Term),
Size00 = erlang:external_size(Term, [{minor_version, 0}]),
@@ -490,7 +490,7 @@ terms_float(Config) when is_list(Config) ->
float_middle_endian(Config) when is_list(Config) ->
%% Testing for roundtrip is not enough.
?line <<131,70,63,240,0,0,0,0,0,0>> = term_to_binary(1.0, [{minor_version,1}]),
- ?line 1.0 = binary_to_term(<<131,70,63,240,0,0,0,0,0,0>>).
+ ?line 1.0 = binary_to_term_stress(<<131,70,63,240,0,0,0,0,0,0>>).
external_size(Config) when is_list(Config) ->
%% Build a term whose external size only fits in a big num (on 32-bit CPU).
@@ -506,8 +506,8 @@ external_size(Config) when is_list(Config) ->
io:format("Unaligned size: ~p\n", [Sz2]),
?line ?t:fail()
end,
- ?line erlang:external_size(Bin) =:= erlang:external_size(Bin, [{minor_version, 1}]),
- ?line erlang:external_size(Unaligned) =:= erlang:external_size(Unaligned, [{minor_version, 1}]).
+ true = (erlang:external_size(Bin) =:= erlang:external_size(Bin, [{minor_version, 1}])),
+ true = (erlang:external_size(Unaligned) =:= erlang:external_size(Unaligned, [{minor_version, 1}])).
external_size_1(Term, Size0, Limit) when Size0 < Limit ->
case erlang:external_size(Term) of
@@ -608,10 +608,10 @@ bad_binary_to_term(Config) when is_list(Config) ->
ok.
bad_bin_to_term(BadBin) ->
- {'EXIT',{badarg,_}} = (catch binary_to_term(BadBin)).
+ {'EXIT',{badarg,_}} = (catch binary_to_term_stress(BadBin)).
bad_bin_to_term(BadBin,Opts) ->
- {'EXIT',{badarg,_}} = (catch binary_to_term(BadBin,Opts)).
+ {'EXIT',{badarg,_}} = (catch binary_to_term_stress(BadBin,Opts)).
safe_binary_to_term2(doc) -> "Test safety options for binary_to_term/2";
safe_binary_to_term2(Config) when is_list(Config) ->
@@ -622,7 +622,7 @@ safe_binary_to_term2(Config) when is_list(Config) ->
BadRef = <<131,114,0,3,BadHostAtom/binary,0,<<0,0,0,255>>/binary,
Empty/binary,Empty/binary>>,
?line bad_bin_to_term(BadRef, [safe]), % good ref, with a bad atom
- ?line fullsweep_after = binary_to_term(<<131,100,0,15,"fullsweep_after">>, [safe]), % should be a good atom
+ ?line fullsweep_after = binary_to_term_stress(<<131,100,0,15,"fullsweep_after">>, [safe]), % should be a good atom
BadExtFun = <<131,113,100,0,4,98,108,117,101,100,0,4,109,111,111,110,97,3>>,
?line bad_bin_to_term(BadExtFun, [safe]),
ok.
@@ -631,7 +631,13 @@ safe_binary_to_term2(Config) when is_list(Config) ->
bad_terms(suite) -> [];
bad_terms(Config) when is_list(Config) ->
- ?line test_terms(fun corrupter/1).
+ ?line test_terms(fun corrupter/1),
+ {'EXIT',{badarg,_}} = (catch binary_to_term(<<131,$M,3:32,0,11,22,33>>)),
+ {'EXIT',{badarg,_}} = (catch binary_to_term(<<131,$M,3:32,9,11,22,33>>)),
+ {'EXIT',{badarg,_}} = (catch binary_to_term(<<131,$M,0:32,1,11,22,33>>)),
+ {'EXIT',{badarg,_}} = (catch binary_to_term(<<131,$M,-1:32,1,11,22,33>>)),
+ ok.
+
corrupter(Term) when is_function(Term);
is_function(hd(Term));
@@ -673,14 +679,14 @@ corrupter0(Term) ->
corrupter(Bin, Pos) when Pos >= 0 ->
?line {ShorterBin, Rest} = split_binary(Bin, Pos),
- ?line catch binary_to_term(ShorterBin), %% emulator shouldn't crash
+ ?line catch binary_to_term_stress(ShorterBin), %% emulator shouldn't crash
?line MovedBin = list_to_binary([ShorterBin]),
- ?line catch binary_to_term(MovedBin), %% emulator shouldn't crash
+ ?line catch binary_to_term_stress(MovedBin), %% emulator shouldn't crash
%% Bit faults, shouldn't crash
<<Byte,Tail/binary>> = Rest,
Fun = fun(M) -> FaultyByte = Byte bxor M,
- catch binary_to_term(<<ShorterBin/binary,
+ catch binary_to_term_stress(<<ShorterBin/binary,
FaultyByte, Tail/binary>>) end,
?line lists:foreach(Fun,[1,2,4,8,16,32,64,128,255]),
?line corrupter(Bin, Pos-1);
@@ -694,7 +700,7 @@ more_bad_terms(Config) when is_list(Config) ->
?line ok = io:format("File: ~s\n", [BadFile]),
?line case file:read_file(BadFile) of
{ok,Bin} ->
- ?line {'EXIT',{badarg,_}} = (catch binary_to_term(Bin)),
+ ?line {'EXIT',{badarg,_}} = (catch binary_to_term_stress(Bin)),
ok;
Other ->
?line ?t:fail(Other)
@@ -703,7 +709,7 @@ more_bad_terms(Config) when is_list(Config) ->
otp_5484(Config) when is_list(Config) ->
?line {'EXIT',_} =
(catch
- binary_to_term(
+ binary_to_term_stress(
<<131,
104,2, %Tuple, 2 elements
103, %Pid
@@ -716,7 +722,7 @@ otp_5484(Config) when is_list(Config) ->
?line {'EXIT',_} =
(catch
- binary_to_term(
+ binary_to_term_stress(
<<131,
104,2, %Tuple, 2 elements
103, %Pid
@@ -728,13 +734,13 @@ otp_5484(Config) when is_list(Config) ->
?line {'EXIT',_} =
(catch
- binary_to_term(
+ binary_to_term_stress(
%% A old-type fun in a list containing a bad creator pid.
<<131,108,0,0,0,1,117,0,0,0,0,103,100,0,13,110,111,110,111,100,101,64,110,111,104,111,115,116,255,255,0,25,255,0,0,0,0,100,0,1,116,97,0,98,6,142,121,72,106>>)),
?line {'EXIT',_} =
(catch
- binary_to_term(
+ binary_to_term_stress(
%% A new-type fun in a list containing a bad creator pid.
%%
<<131,
@@ -746,7 +752,7 @@ otp_5484(Config) when is_list(Config) ->
?line {'EXIT',_} =
(catch
- binary_to_term(
+ binary_to_term_stress(
%% A new-type fun in a list containing a bad module.
<<131,
108,0,0,0,1, %List, 1 element
@@ -757,7 +763,7 @@ otp_5484(Config) when is_list(Config) ->
?line {'EXIT',_} =
(catch
- binary_to_term(
+ binary_to_term_stress(
%% A new-type fun in a list containing a bad index.
<<131,
108,0,0,0,1, %List, 1 element
@@ -769,7 +775,7 @@ otp_5484(Config) when is_list(Config) ->
?line {'EXIT',_} =
(catch
- binary_to_term(
+ binary_to_term_stress(
%% A new-type fun in a list containing a bad unique value.
<<131,
108,0,0,0,1, %List, 1 element
@@ -782,46 +788,46 @@ otp_5484(Config) when is_list(Config) ->
%% An absurdly large atom.
?line {'EXIT',_} =
- (catch binary_to_term(iolist_to_binary([<<131,100,65000:16>>|
+ (catch binary_to_term_stress(iolist_to_binary([<<131,100,65000:16>>|
lists:duplicate(65000, 42)]))),
%% Longer than 255 characters.
?line {'EXIT',_} =
- (catch binary_to_term(iolist_to_binary([<<131,100,256:16>>|
+ (catch binary_to_term_stress(iolist_to_binary([<<131,100,256:16>>|
lists:duplicate(256, 42)]))),
%% OTP-7218. Thanks to Matthew Dempsky. Also make sure that we
%% cover the other error cases for external funs (EXPORT_EXT).
?line {'EXIT',_} =
- (catch binary_to_term(
+ (catch binary_to_term_stress(
<<131,
113, %EXPORT_EXP
97,13, %Integer: 13
97,13, %Integer: 13
97,13>>)), %Integer: 13
?line {'EXIT',_} =
- (catch binary_to_term(
+ (catch binary_to_term_stress(
<<131,
113, %EXPORT_EXP
100,0,1,64, %Atom: '@'
97,13, %Integer: 13
97,13>>)), %Integer: 13
?line {'EXIT',_} =
- (catch binary_to_term(
+ (catch binary_to_term_stress(
<<131,
113, %EXPORT_EXP
100,0,1,64, %Atom: '@'
100,0,1,64, %Atom: '@'
106>>)), %NIL
?line {'EXIT',_} =
- (catch binary_to_term(
+ (catch binary_to_term_stress(
<<131,
113, %EXPORT_EXP
100,0,1,64, %Atom: '@'
100,0,1,64, %Atom: '@'
98,255,255,255,255>>)), %Integer: -1
?line {'EXIT',_} =
- (catch binary_to_term(
+ (catch binary_to_term_stress(
<<131,
113, %EXPORT_EXP
100,0,1,64, %Atom: '@'
@@ -829,7 +835,7 @@ otp_5484(Config) when is_list(Config) ->
113,97,13,97,13,97,13>>)), %fun 13:13/13
%% Bad funs.
- ?line {'EXIT',_} = (catch binary_to_term(fake_fun(0, lists:seq(0, 256)))),
+ ?line {'EXIT',_} = (catch binary_to_term_stress(fake_fun(0, lists:seq(0, 256)))),
ok.
fake_fun(Arity, Env0) ->
@@ -863,7 +869,7 @@ try_bad_lengths(B) ->
try_bad_lengths(B, L) when L > 16#FFFFFFF0 ->
Bin = <<B/binary,L:32>>,
io:format("~p\n", [Bin]),
- {'EXIT',_} = (catch binary_to_term(Bin)),
+ {'EXIT',_} = (catch binary_to_term_stress(Bin)),
try_bad_lengths(B, L-1);
try_bad_lengths(_, _) -> ok.
@@ -917,7 +923,7 @@ otp_6817_try_bin(Bin) ->
%% If the bug is present, the heap pointer will moved when the invalid term
%% is found and we will have a linked list passing through the limbo area
%% between the heap top and the stack pointer.
- catch binary_to_term(Bin),
+ catch binary_to_term_stress(Bin),
%% If the bug is present, we will overwrite the pointers in the limbo area.
Filler = erlang:make_tuple(1024, 16#3FA),
@@ -929,7 +935,7 @@ otp_6817_try_bin(Bin) ->
otp_8117(doc) -> "Some bugs in binary_to_term when 32-bit integers are negative.";
otp_8117(suite) -> [];
otp_8117(Config) when is_list(Config) ->
- [otp_8117_do(Op,-(1 bsl N)) || Op <- ['fun',list,tuple],
+ [otp_8117_do(Op,-(1 bsl N)) || Op <- ['fun',named_fun,list,tuple],
N <- lists:seq(0,31)],
ok.
@@ -938,6 +944,11 @@ otp_8117_do('fun',Neg) ->
FunBin = term_to_binary(fun() -> ok end),
?line <<B1:27/binary,_NumFree:32,Rest/binary>> = FunBin,
?line bad_bin_to_term(<<B1/binary,Neg:32,Rest/binary>>);
+otp_8117_do(named_fun,Neg) ->
+ % Named fun with negative num_free
+ FunBin = term_to_binary(fun F() -> F end),
+ ?line <<B1:27/binary,_NumFree:32,Rest/binary>> = FunBin,
+ ?line bad_bin_to_term(<<B1/binary,Neg:32,Rest/binary>>);
otp_8117_do(list,Neg) ->
%% List with negative length
?line bad_bin_to_term(<<131,104,2,108,Neg:32,97,11,104,1,97,12,97,13,106,97,14>>);
@@ -1221,35 +1232,41 @@ gc() ->
gc1() -> ok.
bit_sized_binary_sizes(Config) when is_list(Config) ->
- ?line [bsbs_1(A) || A <- lists:seq(0, 7)],
+ ?line [bsbs_1(A) || A <- lists:seq(1, 8)],
ok.
-bsbs_1(0) ->
- BinSize = 32+8,
- io:format("A: ~p BinSize: ~p", [0,BinSize]),
- Bin = binary_to_term(<<131,$M,5:32,0,0,0,0,0,0>>),
- BinSize = bit_size(Bin);
bsbs_1(A) ->
BinSize = 32+A,
io:format("A: ~p BinSize: ~p", [A,BinSize]),
- Bin = binary_to_term(<<131,$M,5:32,A,0,0,0,0,0>>),
+ Bin = binary_to_term_stress(<<131,$M,5:32,A,0,0,0,0,0>>),
BinSize = bit_size(Bin).
+%% lists:foldl(_,_,lists:seq(_,_)) with less heap consumption
+lists_foldl_seq(Fun, Acc0, N, To) when N =< To ->
+ Acc1 = Fun(N, Acc0),
+ lists_foldl_seq(Fun, Acc1, N+1, To);
+
+lists_foldl_seq(_, Acc, _, _) ->
+ Acc.
+
deep(Config) when is_list(Config) ->
- ?line deep_roundtrip(lists:foldl(fun(E, A) ->
- [E,A]
- end, [], lists:seq(1, 1000000))),
- ?line deep_roundtrip(lists:foldl(fun(E, A) ->
- {E,A}
- end, [], lists:seq(1, 1000000))),
- ?line deep_roundtrip(lists:foldl(fun(E, A) ->
- fun() -> {E,A} end
- end, [], lists:seq(1, 1000000))),
+ deep_roundtrip(lists_foldl_seq(fun(E, A) ->
+ [E,A]
+ end, [], 1, 1000000)),
+ erlang:garbage_collect(),
+ deep_roundtrip(lists_foldl_seq(fun(E, A) ->
+ {E,A}
+ end, [], 1, 1000000)),
+ erlang:garbage_collect(),
+ deep_roundtrip(lists_foldl_seq(fun(E, A) ->
+ fun() -> {E,A} end
+ end, [], 1, 1000000)),
+ erlang:garbage_collect(),
ok.
deep_roundtrip(T) ->
B = term_to_binary(T),
- T = binary_to_term(B).
+ T = binary_to_term_stress(B).
obsolete_funs(Config) when is_list(Config) ->
erts_debug:set_internal_state(available_internal_state, true),
@@ -1284,29 +1301,29 @@ obsolete_fun(Fun) ->
Tuple = no_fun_roundtrip(Fun).
no_fun_roundtrip(Term) ->
- binary_to_term(erts_debug:get_internal_state({term_to_binary_no_funs,Term})).
+ binary_to_term_stress(erts_debug:get_internal_state({term_to_binary_no_funs,Term})).
%% Test non-standard encodings never generated by term_to_binary/1
%% but recognized by binary_to_term/1.
robustness(Config) when is_list(Config) ->
- ?line [] = binary_to_term(<<131,107,0,0>>), %Empty string.
- ?line [] = binary_to_term(<<131,108,0,0,0,0,106>>), %Zero-length list.
+ ?line [] = binary_to_term_stress(<<131,107,0,0>>), %Empty string.
+ ?line [] = binary_to_term_stress(<<131,108,0,0,0,0,106>>), %Zero-length list.
%% {[],a} where [] is a zero-length list.
- ?line {[],a} = binary_to_term(<<131,104,2,108,0,0,0,0,106,100,0,1,97>>),
+ ?line {[],a} = binary_to_term_stress(<<131,104,2,108,0,0,0,0,106,100,0,1,97>>),
%% {42,a} where 42 is a zero-length list with 42 in the tail.
- ?line {42,a} = binary_to_term(<<131,104,2,108,0,0,0,0,97,42,100,0,1,97>>),
+ ?line {42,a} = binary_to_term_stress(<<131,104,2,108,0,0,0,0,97,42,100,0,1,97>>),
%% {{x,y},a} where {x,y} is a zero-length list with {x,y} in the tail.
- ?line {{x,y},a} = binary_to_term(<<131,104,2,108,0,0,0,0,
+ ?line {{x,y},a} = binary_to_term_stress(<<131,104,2,108,0,0,0,0,
104,2,100,0,1,120,100,0,1,
121,100,0,1,97>>),
%% Bignums fitting in 32 bits.
- ?line 16#7FFFFFFF = binary_to_term(<<131,98,127,255,255,255>>),
- ?line -1 = binary_to_term(<<131,98,255,255,255,255>>),
+ ?line 16#7FFFFFFF = binary_to_term_stress(<<131,98,127,255,255,255>>),
+ ?line -1 = binary_to_term_stress(<<131,98,255,255,255,255>>),
ok.
@@ -1324,40 +1341,48 @@ run_otp_8180(Name) ->
?line {ok,Bins} = file:consult(Name),
[begin
io:format("~p\n", [Bin]),
- ?line {'EXIT',{badarg,_}} = (catch binary_to_term(Bin))
+ ?line {'EXIT',{badarg,_}} = (catch binary_to_term_stress(Bin))
end || Bin <- Bins],
ok.
-%% Test that exit and GC during term_to_binary trap does not crash.
-ttb_trap(Config) when is_list(Config)->
- case erlang:system_info(wordsize) of
- N when N < 8 ->
- {skipped, "Only on 64bit machines"};
- _ ->
- do_ttb_trap(5)
- end.
+%% Test that exit and GC during trapping term_to_binary and binary_to_term
+%% does not crash.
+trapping(Config) when is_list(Config)->
+ do_trapping(5, term_to_binary,
+ fun() -> [lists:duplicate(2000000,2000000)] end),
+ do_trapping(5, binary_to_term,
+ fun() -> [term_to_binary(lists:duplicate(2000000,2000000))] end).
-do_ttb_trap(0) ->
+do_trapping(0, _, _) ->
ok;
-do_ttb_trap(N) ->
- Pid = spawn(?MODULE,ttb_loop,[1000,self()]),
+do_trapping(N, Bif, ArgFun) ->
+ io:format("N=~p: Do ~p ~s gc.\n", [N, Bif, case N rem 2 of 0 -> "with"; 1 -> "without" end]),
+ Pid = spawn(?MODULE,trapping_loop,[Bif, ArgFun, 1000, self()]),
receive ok -> ok end,
receive after 100 -> ok end,
- erlang:garbage_collect(Pid),
- receive after 100 -> ok end,
+ Ref = make_ref(),
+ case N rem 2 of
+ 0 -> erlang:garbage_collect(Pid, [{async,Ref}]),
+ receive after 100 -> ok end;
+ 1 -> void
+ end,
exit(Pid,kill),
+ case N rem 2 of
+ 0 -> receive {garbage_collect, Ref, _} -> ok end;
+ 1 -> void
+ end,
receive after 1 -> ok end,
- do_ttb_trap(N-1).
+ do_trapping(N-1, Bif, ArgFun).
-ttb_loop(N,Pid) ->
- Term = lists:duplicate(2000000,2000000),
+trapping_loop(Bif, ArgFun, N, Pid) ->
+ Args = ArgFun(),
Pid ! ok,
- ttb_loop2(N,Term).
-ttb_loop2(0,_T) ->
+ trapping_loop2(Bif,Args,N).
+trapping_loop2(_,_,0) ->
ok;
-ttb_loop2(N,T) ->
- apply(erlang,term_to_binary,[T]),
- ttb_loop2(N-1,T).
+trapping_loop2(Bif,Args,N) ->
+ apply(erlang,Bif,Args),
+ trapping_loop2(Bif, Args, N-1).
%% Utilities.
@@ -1393,3 +1418,52 @@ unaligned_sub_bin(Bin0, Offs) ->
Bin.
id(I) -> I.
+
+
+%% Stress binary_to_term with different initial reductions
+binary_to_term_stress(Bin) ->
+ binary_to_term_stress(Bin, no_opts).
+
+binary_to_term_stress(Bin, Opts) ->
+ Reds = get_reds(),
+ T = b2t(erlang:system_info(context_reductions),
+ Bin, Opts, catch_binary_to_term(Bin, Opts)),
+ set_reds(Reds),
+ T = case Opts of
+ no_opts -> binary_to_term(Bin);
+ _ -> binary_to_term(Bin,Opts)
+ end.
+
+catch_binary_to_term(Bin, no_opts) ->
+ try binary_to_term(Bin)
+ catch
+ error:badarg -> binary_to_term_throws_badarg
+ end;
+catch_binary_to_term(Bin, Opts) ->
+ try binary_to_term(Bin, Opts)
+ catch
+ error:badarg -> binary_to_term_throws_badarg
+ end.
+
+b2t(0, _Bin, _Opts, Term) ->
+ Term;
+b2t(Reds, Bin, Opts, Term) ->
+ set_reds(Reds),
+ Term = catch_binary_to_term(Bin,Opts),
+ b2t(Reds div 3, Bin, Opts, Term).
+
+set_reds(Reds) ->
+ try erts_debug:set_internal_state(reds_left, Reds)
+ catch
+ error:undef ->
+ erts_debug:set_internal_state(available_internal_state, true),
+ set_reds(Reds)
+ end.
+
+get_reds() ->
+ try erts_debug:get_internal_state(reds_left)
+ catch
+ error:undef ->
+ erts_debug:set_internal_state(available_internal_state, true),
+ get_reds()
+ end.
diff --git a/erts/emulator/test/code_parallel_load_SUITE.erl b/erts/emulator/test/code_parallel_load_SUITE.erl
index 1cfe015ea6..428f1242ab 100644
--- a/erts/emulator/test/code_parallel_load_SUITE.erl
+++ b/erts/emulator/test/code_parallel_load_SUITE.erl
@@ -159,22 +159,34 @@ setup_checkers(_,0) -> [];
setup_checkers(T,N) -> [spawn_link(fun() -> ?model:check(T) end) | setup_checkers(T, N-1)].
check_and_purge_processes_code(Pids, M) ->
- check_and_purge_processes_code(Pids, M, []).
-check_and_purge_processes_code([], M, []) ->
+ Tag = make_ref(),
+ N = request_cpc(Pids, M, Tag),
+ ok = handle_cpc_responses(N, Tag, M),
erlang:purge_module(M),
+ ok.
+
+request_cpc(Pid, M, Tag) when is_pid(Pid) ->
+ erlang:check_process_code(Pid, M, [{async, {Tag, Pid}}]),
+ 1;
+request_cpc(Pids, M, Tag) when is_list(Pids) ->
+ request_cpc(Pids, M, Tag, 0).
+
+request_cpc([], _M, _Tag, N) ->
+ N;
+request_cpc([Pid|Pids], M, Tag, N) ->
+ request_cpc(Pids, M, Tag, N + request_cpc(Pid, M, Tag)).
+
+handle_cpc_responses(0, _Tag, _Module) ->
ok;
-check_and_purge_processes_code([], M, Pending) ->
- io:format("Processes ~w are still executing old code - retrying.~n", [Pending]),
- check_and_purge_processes_code(Pending, M, []);
-check_and_purge_processes_code([Pid|Pids], M, Pending) ->
- case erlang:check_process_code(Pid, M) of
- false ->
- check_and_purge_processes_code(Pids, M, Pending);
- true ->
- check_and_purge_processes_code(Pids, M, [Pid|Pending])
+handle_cpc_responses(N, Tag, Module) ->
+ receive
+ {check_process_code, {Tag, _Pid}, false} ->
+ handle_cpc_responses(N-1, Tag, Module);
+ {check_process_code, {Tag, Pid}, true} ->
+ 1 = request_cpc(Pid, Module, Tag),
+ handle_cpc_responses(N, Tag, Module)
end.
-
generate(Module, Attributes, FunStrings) ->
FunForms = function_forms(FunStrings),
Forms = [
diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl
index 7087542899..06211406b4 100644
--- a/erts/emulator/test/driver_SUITE.erl
+++ b/erts/emulator/test/driver_SUITE.erl
@@ -2075,6 +2075,21 @@ thr_msg_blast(Config) when is_list(Config) ->
Res
end.
+-define(IN_RANGE(LoW_, VaLuE_, HiGh_),
+ case in_range(LoW_, VaLuE_, HiGh_) of
+ true -> ok;
+ false ->
+ case erlang:system_info(lock_checking) of
+ true ->
+ ?t:format("~p:~p: Ignore bad sched count due to "
+ "lock checking~n",
+ [?MODULE,?LINE]);
+ false ->
+ ?t:fail({unexpected_sched_counts, VaLuE_})
+ end
+ end).
+
+
consume_timeslice(Config) when is_list(Config) ->
%%
%% Verify that erl_drv_consume_timeslice() works.
@@ -2131,15 +2146,8 @@ consume_timeslice(Config) when is_list(Config) ->
Proc1 ! Go,
wait_command_msgs(Port, 10),
[{Port, Sprt1}, {Proc1, Sproc1}] = count_pp_sched_stop([Port, Proc1]),
- case Sprt1 of
- 10 ->
- true = in_range(5, Sproc1-10, 7);
- _ ->
- case erlang:system_info(lock_checking) of
- true -> ?t:format("Ignore bad sched count due to lock checking", []);
- false -> ?t:fail({unexpected_sched_counts, Sprt1, Sproc1})
- end
- end,
+ ?IN_RANGE(10, Sprt1, 10),
+ ?IN_RANGE(5, Sproc1-10, 7),
"disabled" = port_control(Port, $D, ""),
Proc2 = spawn_link(fun () ->
@@ -2160,15 +2168,8 @@ consume_timeslice(Config) when is_list(Config) ->
Proc2 ! Go,
wait_command_msgs(Port, 10),
[{Port, Sprt2}, {Proc2, Sproc2}] = count_pp_sched_stop([Port, Proc2]),
- case Sprt2 of
- 10 ->
- true = in_range(1, Sproc2-10, 2);
- _ ->
- case erlang:system_info(lock_checking) of
- true -> ?t:format("Ignore bad sched count due to lock checking", []);
- false -> ?t:fail({unexpected_sched_counts, Sprt2, Sproc2})
- end
- end,
+ ?IN_RANGE(10, Sprt2, 10),
+ ?IN_RANGE(1, Sproc2-10, 2),
"enabled" = port_control(Port, $E, ""),
Proc3 = spawn_link(fun () ->
@@ -2188,15 +2189,8 @@ consume_timeslice(Config) when is_list(Config) ->
Proc3 ! Go,
wait_command_msgs(Port, 10),
[{Port, Sprt3}, {Proc3, Sproc3}] = count_pp_sched_stop([Port, Proc3]),
- case Sprt3 of
- 10 ->
- true = in_range(5, Sproc3-10, 7);
- _ ->
- case erlang:system_info(lock_checking) of
- true -> ?t:format("Ignore bad sched count due to lock checking", []);
- false -> ?t:fail({unexpected_sched_counts, Sprt3, Sproc3})
- end
- end,
+ ?IN_RANGE(10, Sprt3, 10),
+ ?IN_RANGE(5, Sproc3-10, 7),
"disabled" = port_control(Port, $D, ""),
Proc4 = spawn_link(fun () ->
@@ -2216,15 +2210,8 @@ consume_timeslice(Config) when is_list(Config) ->
Proc4 ! Go,
wait_command_msgs(Port, 10),
[{Port, Sprt4}, {Proc4, Sproc4}] = count_pp_sched_stop([Port, Proc4]),
- case Sprt4 of
- 10 ->
- true = in_range(1, Sproc4-10, 2);
- _ ->
- case erlang:system_info(lock_checking) of
- true -> ?t:format("Ignore bad sched count due to lock checking", []);
- false -> ?t:fail({unexpected_sched_counts, Sprt4, Sproc4})
- end
- end,
+ ?IN_RANGE(10, Sprt4, 10),
+ ?IN_RANGE(1, Sproc4-10, 2),
SOnl = erlang:system_info(schedulers_online),
%% If only one scheduler use port with parallelism set to true,
@@ -2272,8 +2259,8 @@ consume_timeslice(Config) when is_list(Config) ->
wait_procs_exit([W5, Proc5]),
wait_command_msgs(Port2, 10),
[{Port2, Sprt5}, {Proc5, Sproc5}] = count_pp_sched_stop([Port2, Proc5]),
- true = in_range(2, Sproc5, 3),
- true = in_range(7, Sprt5, 20),
+ ?IN_RANGE(2, Sproc5, 3),
+ ?IN_RANGE(6, Sprt5, 20),
count_pp_sched_start(),
"disabled" = port_control(Port2, $D, ""),
@@ -2307,8 +2294,8 @@ consume_timeslice(Config) when is_list(Config) ->
wait_procs_exit([W6, Proc6]),
wait_command_msgs(Port2, 10),
[{Port2, Sprt6}, {Proc6, Sproc6}] = count_pp_sched_stop([Port2, Proc6]),
- true = in_range(2, Sproc6, 3),
- true = in_range(3, Sprt6, 6),
+ ?IN_RANGE(2, Sproc6, 3),
+ ?IN_RANGE(2, Sprt6, 6),
process_flag(scheduler, 0),
@@ -2316,6 +2303,7 @@ consume_timeslice(Config) when is_list(Config) ->
receive {Port2, closed} -> ok end,
ok.
+
wait_command_msgs(_, 0) ->
ok;
wait_command_msgs(Port, N) ->
diff --git a/erts/emulator/test/exception_SUITE.erl b/erts/emulator/test/exception_SUITE.erl
index 109cec25cb..09a7a87a9a 100644
--- a/erts/emulator/test/exception_SUITE.erl
+++ b/erts/emulator/test/exception_SUITE.erl
@@ -589,6 +589,13 @@ line_numbers(Config) when is_list(Config) ->
[{file,ModFile},{line,_}]}|_]}} =
(catch build_binary2(8, bad_binary)),
+ <<"abc",357:16>> = build_binary3(<<"abc">>),
+ {'EXIT',{badarg,[{?MODULE,build_binary3,1,
+ [{file,"bit_syntax.erl"},{line,72511}]},
+ {?MODULE,line_numbers,1,
+ [{file,ModFile},{line,_}]}|_]}} =
+ (catch build_binary3(no_binary)),
+
{'EXIT',{function_clause,
[{?MODULE,do_call_abs,[y,y],
[{file,"gc_bif.erl"},{line,18}]},
@@ -691,6 +698,10 @@ build_binary2(Size, Bin) -> %Line 72505
id(0), %Line 72506
<<7:Size,Bin/binary>>. %Line 72507
+build_binary3(Bin) -> %Line 72509
+ id(0), %Line 72510
+ <<Bin/binary,357:16>>. %Line 72511
+
-file("gc_bif.erl", 17).
do_call_abs(x, Arg) -> %Line 18
abs(Arg). %Line 19
diff --git a/erts/emulator/test/fun_SUITE.erl b/erts/emulator/test/fun_SUITE.erl
index 36ba4e0f48..8ad5f290ed 100644
--- a/erts/emulator/test/fun_SUITE.erl
+++ b/erts/emulator/test/fun_SUITE.erl
@@ -262,6 +262,16 @@ equality(Config) when is_list(Config) ->
?line false = eq(FF2, FF4),
?line false = eq(FF3, FF4),
+ %% EEP37
+ H1 = fun Fact(N) when N > 0 -> N * Fact(N - 1); Fact(0) -> 1 end,
+ H2 = fun Pow(N, M) when M > 0 -> N * Pow(N, M - 1); Pow(_, 0) -> 1 end,
+ H1_copy = copy_term(H1),
+
+ true = eq(H1, H1),
+ true = eq(H1, H1_copy),
+ true = eq(H2, H2),
+ false = eq(H1, H2),
+
ok.
eq(X, X) -> true;
diff --git a/erts/emulator/test/hash_SUITE.erl b/erts/emulator/test/hash_SUITE.erl
index 43c9d64af7..647bb45049 100644
--- a/erts/emulator/test/hash_SUITE.erl
+++ b/erts/emulator/test/hash_SUITE.erl
@@ -1,4 +1,3 @@
-%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -32,7 +31,7 @@
%%
-module(hash_SUITE).
-export([basic_test/0,cmp_test/1,range_test/0,spread_test/1,
- phash2_test/0, otp_5292_test/0, bit_level_binaries/0,
+ phash2_test/0, otp_5292_test/0,
otp_7127_test/0]).
-compile({nowarn_deprecated_function, {erlang,hash,2}}).
@@ -152,7 +151,7 @@ otp_5292(Config) when is_list(Config) ->
%% Test hashing bit-level binaries.
bit_level_binaries(Config) when is_list(Config) ->
- bit_level_binaries().
+ bit_level_binaries_do().
otp_7127(suite) ->
[];
@@ -537,7 +536,7 @@ hash_int(Start, End, F) ->
md5(T) ->
erlang:md5(term_to_binary(T)).
-bit_level_binaries() ->
+bit_level_binaries_do() ->
[3511317,7022633,14044578,28087749,56173436,112344123,90467083|_] =
bit_level_all_different(fun erlang:hash/2),
[3511317,7022633,14044578,28087749,56173436,112344123,90467083|_] =
diff --git a/erts/emulator/test/match_spec_SUITE.erl b/erts/emulator/test/match_spec_SUITE.erl
index b56b7ce525..bcc46d78ba 100644
--- a/erts/emulator/test/match_spec_SUITE.erl
+++ b/erts/emulator/test/match_spec_SUITE.erl
@@ -213,7 +213,7 @@ test_3(Config) when is_list(Config) ->
otp_9422(doc) -> [];
otp_9422(Config) when is_list(Config) ->
- Laps = 1000,
+ Laps = 10000,
?line Fun1 = fun() -> otp_9422_tracee() end,
?line P1 = spawn_link(?MODULE, loop_runner, [self(), Fun1, Laps]),
io:format("spawned ~p as tracee\n", [P1]),
@@ -230,7 +230,7 @@ otp_9422(Config) when is_list(Config) ->
%%receive after 10*1000 -> ok end,
stop_collect(P1),
- stop_collect(P2),
+ stop_collect(P2, abort),
ok.
otp_9422_tracee() ->
@@ -975,7 +975,9 @@ start_collect(P) ->
P ! {go, self()}.
stop_collect(P) ->
- P ! {done, self()},
+ stop_collect(P, done).
+stop_collect(P, Order) ->
+ P ! {Order, self()},
receive
{gone, P} ->
ok
@@ -1008,7 +1010,13 @@ loop_runner_cont(_Collector, _Fun, Laps, Laps) ->
end;
loop_runner_cont(Collector, Fun, N, Laps) ->
Fun(),
- loop_runner_cont(Collector, Fun, N+1, Laps).
+ receive
+ {abort, Collector} ->
+ io:format("loop_runner ~p aborted after ~p of ~p laps\n", [self(), N+1, Laps]),
+ Collector ! {gone, self()}
+ after 0 ->
+ loop_runner_cont(Collector, Fun, N+1, Laps)
+ end.
f1(X) ->
diff --git a/erts/emulator/test/mtx_SUITE_data/Makefile.src b/erts/emulator/test/mtx_SUITE_data/Makefile.src
index e65d99e968..04412280c0 100644
--- a/erts/emulator/test/mtx_SUITE_data/Makefile.src
+++ b/erts/emulator/test/mtx_SUITE_data/Makefile.src
@@ -17,8 +17,8 @@
# %CopyrightEnd%
#
-include @erts_lib_include_internal_generated@@[email protected]
-include @erts_lib_include_internal_generated@@DS@erts_internal.mk
+include @erts_lib_make_ethread@
+include @erts_lib_make_internal@
NIF_LIBS = mtx_SUITE@dll@
diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl
index fcd4457c34..202a8b7537 100644
--- a/erts/emulator/test/port_SUITE.erl
+++ b/erts/emulator/test/port_SUITE.erl
@@ -949,6 +949,20 @@ cd(Config) when is_list(Config) ->
Other2 ->
test_server:fail({env, Other2})
end,
+ _ = open_port({spawn, Cmd},
+ [{cd, unicode:characters_to_binary(TestDir)},
+ {line, 256}]),
+ receive
+ {_, {data, {eol, String2}}} ->
+ case filename_equal(String2, TestDir) of
+ true ->
+ ok;
+ false ->
+ test_server:fail({cd, String2})
+ end;
+ Other3 ->
+ test_server:fail({env, Other3})
+ end,
test_server:timetrap_cancel(Dog),
ok.
@@ -1353,19 +1367,28 @@ spawn_executable(Config) when is_list(Config) ->
EchoArgs1 = filename:join([DataDir,"echo_args"]),
ExactFile1 = filename:nativename(os:find_executable(EchoArgs1)),
[ExactFile1] = run_echo_args(DataDir,[]),
+ [ExactFile1] = run_echo_args(DataDir,[binary]),
["echo_args"] = run_echo_args(DataDir,["echo_args"]),
+ ["echo_args"] = run_echo_args(DataDir,[binary, "echo_args"]),
["echo_arguments"] = run_echo_args(DataDir,["echo_arguments"]),
+ ["echo_arguments"] = run_echo_args(DataDir,[binary, "echo_arguments"]),
[ExactFile1,"hello world","dlrow olleh"] =
run_echo_args(DataDir,[ExactFile1,"hello world","dlrow olleh"]),
[ExactFile1] = run_echo_args(DataDir,[default]),
+ [ExactFile1] = run_echo_args(DataDir,[binary, default]),
[ExactFile1,"hello world","dlrow olleh"] =
run_echo_args(DataDir,[switch_order,ExactFile1,"hello world",
"dlrow olleh"]),
[ExactFile1,"hello world","dlrow olleh"] =
+ run_echo_args(DataDir,[binary,switch_order,ExactFile1,"hello world",
+ "dlrow olleh"]),
+ [ExactFile1,"hello world","dlrow olleh"] =
run_echo_args(DataDir,[default,"hello world","dlrow olleh"]),
[ExactFile1,"hello world","dlrow olleh"] =
run_echo_args_2("\""++ExactFile1++"\" "++"\"hello world\" \"dlrow olleh\""),
+ [ExactFile1,"hello world","dlrow olleh"] =
+ run_echo_args_2(unicode:characters_to_binary("\""++ExactFile1++"\" "++"\"hello world\" \"dlrow olleh\"")),
PrivDir = ?config(priv_dir, Config),
SpaceDir =filename:join([PrivDir,"With Spaces"]),
@@ -1380,6 +1403,8 @@ spawn_executable(Config) when is_list(Config) ->
["echo_arguments"] = run_echo_args(SpaceDir,["echo_arguments"]),
[ExactFile2,"hello world","dlrow olleh"] =
run_echo_args(SpaceDir,[ExactFile2,"hello world","dlrow olleh"]),
+ [ExactFile2,"hello world","dlrow olleh"] =
+ run_echo_args(SpaceDir,[binary, ExactFile2,"hello world","dlrow olleh"]),
[ExactFile2] = run_echo_args(SpaceDir,[default]),
[ExactFile2,"hello world","dlrow olleh"] =
run_echo_args(SpaceDir,[switch_order,ExactFile2,"hello world",
@@ -1388,6 +1413,8 @@ spawn_executable(Config) when is_list(Config) ->
run_echo_args(SpaceDir,[default,"hello world","dlrow olleh"]),
[ExactFile2,"hello world","dlrow olleh"] =
run_echo_args_2("\""++ExactFile2++"\" "++"\"hello world\" \"dlrow olleh\""),
+ [ExactFile2,"hello world","dlrow olleh"] =
+ run_echo_args_2(unicode:characters_to_binary("\""++ExactFile2++"\" "++"\"hello world\" \"dlrow olleh\"")),
ExeExt =
case string:to_lower(lists:last(string:tokens(ExactFile2,"."))) of
@@ -1415,9 +1442,12 @@ spawn_executable(Config) when is_list(Config) ->
[default,"hello world","dlrow olleh"]),
[ExactFile3,"hello world","dlrow olleh"] =
run_echo_args_2("\""++ExactFile3++"\" "++"\"hello world\" \"dlrow olleh\""),
+ [ExactFile3,"hello world","dlrow olleh"] =
+ run_echo_args_2(unicode:characters_to_binary("\""++ExactFile3++"\" "++"\"hello world\" \"dlrow olleh\"")),
{'EXIT',{enoent,_}} = (catch run_echo_args(SpaceDir,"fnurflmonfi",
[default,"hello world",
"dlrow olleh"])),
+
NonExec = "kronxfrt"++ExeExt,
file:write_file(filename:join([SpaceDir,NonExec]),
<<"Not an executable">>),
@@ -1518,25 +1548,40 @@ run_echo_args_2(FullnameAndArgs) ->
run_echo_args(Where,Args) ->
- run_echo_args(Where,"echo_args",Args).
+ run_echo_args(Where,"echo_args",Args).
run_echo_args(Where,Prog,Args) ->
- ArgvArg = case Args of
- [] ->
- [];
- [default|T] ->
- [{args,T}];
- [switch_order,H|T] ->
- [{args,T},{arg0,H}];
- [H|T] ->
- [{arg0,H},{args,T}]
+ {Binary, ArgvArg} = pack_argv(Args),
+ Command0 = filename:join([Where,Prog]),
+ Command = case Binary of
+ true -> unicode:characters_to_binary(Command0);
+ false -> Command0
end,
- Command = filename:join([Where,Prog]),
Port = open_port({spawn_executable,Command},ArgvArg++[eof]),
Data = collect_data(Port),
Port ! {self(), close},
receive {Port, closed} -> ok end,
parse_echo_args_output(Data).
-
+
+pack_argv([binary|Args]) ->
+ {true, pack_argv(Args, true)};
+pack_argv(Args) ->
+ {false, pack_argv(Args, false)}.
+
+pack_argv(Args, Binary) ->
+ case Args of
+ [] ->
+ [];
+ [default|T] ->
+ [{args,[make_bin(Arg,Binary) || Arg <- T]}];
+ [switch_order,H|T] ->
+ [{args,[make_bin(Arg,Binary) || Arg <- T]},{arg0,make_bin(H,Binary)}];
+ [H|T] ->
+ [{arg0,make_bin(H,Binary)},{args,[make_bin(Arg,Binary) || Arg <- T]}]
+ end.
+
+make_bin(Str, false) -> Str;
+make_bin(Str, true) -> unicode:characters_to_binary(Str).
+
collect_data(Port) ->
receive
{Port, {data, Data}} ->
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index e3aae17df4..bf31655066 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -51,7 +51,13 @@
processes_term_proc_list/1,
otp_7738_waiting/1, otp_7738_suspended/1,
otp_7738_resume/1,
- garb_other_running/1]).
+ garb_other_running/1,
+ no_priority_inversion/1,
+ no_priority_inversion2/1,
+ system_task_blast/1,
+ system_task_on_suspended/1,
+ gc_request_when_gc_disabled/1,
+ gc_request_blast_when_gc_disabled/1]).
-export([prio_server/2, prio_client/2]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -73,7 +79,8 @@ all() ->
bad_register, garbage_collect, process_info_messages,
process_flag_badarg, process_flag_heap_size,
spawn_opt_heap_size, otp_6237, {group, processes_bif},
- {group, otp_7738}, garb_other_running].
+ {group, otp_7738}, garb_other_running,
+ {group, system_task}].
groups() ->
[{t_exit_2, [],
@@ -87,7 +94,11 @@ groups() ->
processes_gc_trap, processes_term_proc_list]},
{otp_7738, [],
[otp_7738_waiting, otp_7738_suspended,
- otp_7738_resume]}].
+ otp_7738_resume]},
+ {system_task, [],
+ [no_priority_inversion, no_priority_inversion2,
+ system_task_blast, system_task_on_suspended,
+ gc_request_when_gc_disabled, gc_request_blast_when_gc_disabled]}].
init_per_suite(Config) ->
A0 = case application:start(sasl) of
@@ -2214,6 +2225,208 @@ garb_other_running(Config) when is_list(Config) ->
receive {'DOWN', Mon, process, Pid, normal} -> ok end,
ok.
+no_priority_inversion(Config) when is_list(Config) ->
+ Prio = process_flag(priority, max),
+ HTLs = lists:map(fun (_) ->
+ spawn_opt(fun () ->
+ tok_loop()
+ end,
+ [{priority, high}, monitor, link])
+ end,
+ lists:seq(1, 2*erlang:system_info(schedulers))),
+ receive after 500 -> ok end,
+ LTL = spawn_opt(fun () ->
+ tok_loop()
+ end,
+ [{priority, low}, monitor, link]),
+ false = erlang:check_process_code(element(1, LTL), nonexisting_module),
+ true = erlang:garbage_collect(element(1, LTL)),
+ lists:foreach(fun ({P, _}) ->
+ unlink(P),
+ exit(P, kill)
+ end, [LTL | HTLs]),
+ lists:foreach(fun ({P, M}) ->
+ receive
+ {'DOWN', M, process, P, killed} ->
+ ok
+ end
+ end, [LTL | HTLs]),
+ process_flag(priority, Prio),
+ ok.
+
+no_priority_inversion2(Config) when is_list(Config) ->
+ Prio = process_flag(priority, max),
+ MTLs = lists:map(fun (_) ->
+ spawn_opt(fun () ->
+ tok_loop()
+ end,
+ [{priority, max}, monitor, link])
+ end,
+ lists:seq(1, 2*erlang:system_info(schedulers))),
+ receive after 500 -> ok end,
+ {PL, ML} = spawn_opt(fun () ->
+ tok_loop()
+ end,
+ [{priority, low}, monitor, link]),
+ RL = request_gc(PL, low),
+ RN = request_gc(PL, normal),
+ RH = request_gc(PL, high),
+ receive
+ {garbage_collect, _, _} ->
+ ?t:fail(unexpected_gc)
+ after 1000 ->
+ ok
+ end,
+ RM = request_gc(PL, max),
+ receive
+ {garbage_collect, RM, true} ->
+ ok
+ end,
+ lists:foreach(fun ({P, _}) ->
+ unlink(P),
+ exit(P, kill)
+ end, MTLs),
+ lists:foreach(fun ({P, M}) ->
+ receive
+ {'DOWN', M, process, P, killed} ->
+ ok
+ end
+ end, MTLs),
+ receive
+ {garbage_collect, RH, true} ->
+ ok
+ end,
+ receive
+ {garbage_collect, RN, true} ->
+ ok
+ end,
+ receive
+ {garbage_collect, RL, true} ->
+ ok
+ end,
+ unlink(PL),
+ exit(PL, kill),
+ receive
+ {'DOWN', ML, process, PL, killed} ->
+ ok
+ end,
+ process_flag(priority, Prio),
+ ok.
+
+request_gc(Pid, Prio) ->
+ Ref = make_ref(),
+ erts_internal:request_system_task(Pid, Prio, {garbage_collect, Ref}),
+ Ref.
+
+system_task_blast(Config) when is_list(Config) ->
+ Me = self(),
+ GCReq = fun () ->
+ RL = gc_req(Me, 100),
+ lists:foreach(fun (R) ->
+ receive
+ {garbage_collect, R, true} ->
+ ok
+ end
+ end, RL),
+ exit(it_worked)
+ end,
+ HTLs = lists:map(fun (_) -> spawn_monitor(GCReq) end, lists:seq(1, 1000)),
+ lists:foreach(fun ({P, M}) ->
+ receive
+ {'DOWN', M, process, P, it_worked} ->
+ ok
+ end
+ end, HTLs),
+ ok.
+
+gc_req(_Pid, 0) ->
+ [];
+gc_req(Pid, N) ->
+ R0 = request_gc(Pid, low),
+ R1 = request_gc(Pid, normal),
+ R2 = request_gc(Pid, high),
+ R3 = request_gc(Pid, max),
+ [R0, R1, R2, R3 | gc_req(Pid, N-1)].
+
+system_task_on_suspended(Config) when is_list(Config) ->
+ {P, M} = spawn_monitor(fun () ->
+ tok_loop()
+ end),
+ true = erlang:suspend_process(P),
+ {status, suspended} = process_info(P, status),
+ true = erlang:garbage_collect(P),
+ {status, suspended} = process_info(P, status),
+ true = erlang:resume_process(P),
+ false = ({status, suspended} == process_info(P, status)),
+ exit(P, kill),
+ receive
+ {'DOWN', M, process, P, killed} ->
+ ok
+ end.
+
+gc_request_when_gc_disabled(Config) when is_list(Config) ->
+ Master = self(),
+ AIS = erts_debug:set_internal_state(available_internal_state, true),
+ {P, M} = spawn_opt(fun () ->
+ true = erts_debug:set_internal_state(gc_state,
+ false),
+ Master ! {self(), gc_state, false},
+ receive after 1000 -> ok end,
+ Master ! {self(), gc_state, true},
+ false = erts_debug:set_internal_state(gc_state,
+ true),
+ receive after 100 -> ok end
+ end, [monitor, link]),
+ receive {P, gc_state, false} -> ok end,
+ ReqId = make_ref(),
+ async = garbage_collect(P, [{async, ReqId}]),
+ receive
+ {garbage_collect, ReqId, Result} ->
+ ?t:fail({unexpected_gc, Result});
+ {P, gc_state, true} ->
+ ok
+ end,
+ receive {garbage_collect, ReqId, true} -> ok end,
+ erts_debug:set_internal_state(available_internal_state, AIS),
+ receive {'DOWN', M, process, P, _Reason} -> ok end,
+ ok.
+
+gc_request_blast_when_gc_disabled(Config) when is_list(Config) ->
+ Master = self(),
+ AIS = erts_debug:set_internal_state(available_internal_state, true),
+ {P, M} = spawn_opt(fun () ->
+ true = erts_debug:set_internal_state(gc_state,
+ false),
+ Master ! {self(), gc_state, false},
+ receive after 1000 -> ok end,
+ false = erts_debug:set_internal_state(gc_state,
+ true),
+ receive after 100 -> ok end
+ end, [monitor, link]),
+ receive {P, gc_state, false} -> ok end,
+ PMs = lists:map(fun (N) ->
+ Prio = case N rem 4 of
+ 0 -> max;
+ 1 -> high;
+ 2 -> normal;
+ 3 -> low
+ end,
+ spawn_opt(fun () ->
+ erlang:garbage_collect(P)
+ end, [monitor, link, {priority, Prio}])
+ end, lists:seq(1, 10000)),
+ lists:foreach(fun ({Proc, Mon}) ->
+ receive
+ {'DOWN', Mon, process, Proc, normal} ->
+ ok
+ end
+ end,
+ PMs),
+ erts_debug:set_internal_state(available_internal_state, AIS),
+ receive {'DOWN', M, process, P, _Reason} -> ok end,
+ ok.
+
+
%% Internal functions
wait_until(Fun) ->
diff --git a/erts/emulator/test/scheduler_SUITE.erl b/erts/emulator/test/scheduler_SUITE.erl
index 81539faa09..6a43e2b0e7 100644
--- a/erts/emulator/test/scheduler_SUITE.erl
+++ b/erts/emulator/test/scheduler_SUITE.erl
@@ -1495,7 +1495,7 @@ mcall(Node, Funs) ->
end, Refs).
erl_rel_flag_var() ->
- "ERL_"++erlang:system_info(otp_release)++"_FLAGS".
+ "ERL_OTP"++erlang:system_info(otp_release)++"_FLAGS".
clear_erl_rel_flags() ->
EnvVar = erl_rel_flag_var(),