diff options
Diffstat (limited to 'erts/emulator/test')
-rw-r--r-- | erts/emulator/test/alloc_SUITE.erl | 7 | ||||
-rw-r--r-- | erts/emulator/test/binary_SUITE.erl | 7 | ||||
-rw-r--r-- | erts/emulator/test/code_parallel_load_SUITE.erl | 36 | ||||
-rw-r--r-- | erts/emulator/test/fun_SUITE.erl | 10 | ||||
-rw-r--r-- | erts/emulator/test/hash_SUITE.erl | 1 | ||||
-rw-r--r-- | erts/emulator/test/match_spec_SUITE.erl | 16 | ||||
-rw-r--r-- | erts/emulator/test/mtx_SUITE_data/Makefile.src | 4 | ||||
-rw-r--r-- | erts/emulator/test/port_SUITE.erl | 69 | ||||
-rw-r--r-- | erts/emulator/test/process_SUITE.erl | 219 |
9 files changed, 333 insertions, 36 deletions
diff --git a/erts/emulator/test/alloc_SUITE.erl b/erts/emulator/test/alloc_SUITE.erl index cd2d043f7e..35c44c229a 100644 --- a/erts/emulator/test/alloc_SUITE.erl +++ b/erts/emulator/test/alloc_SUITE.erl @@ -127,7 +127,12 @@ erts_mmap(Config) when is_list(Config) -> erts_mmap_do(Config, SCO, SCRPM, SCRFSD) -> - SCS = 100, % Mb + %% 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), diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl index a340a805b5..44dbb2c588 100644 --- a/erts/emulator/test/binary_SUITE.erl +++ b/erts/emulator/test/binary_SUITE.erl @@ -935,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. @@ -944,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>>); 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/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 738c9c8b16..647bb45049 100644 --- a/erts/emulator/test/hash_SUITE.erl +++ b/erts/emulator/test/hash_SUITE.erl @@ -1,4 +1,3 @@ -%% -*- coding: utf-8 -*- %% %% %CopyrightBegin% %% 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) -> |