diff options
Diffstat (limited to 'erts/emulator/test/process_SUITE.erl')
-rw-r--r-- | erts/emulator/test/process_SUITE.erl | 100 |
1 files changed, 87 insertions, 13 deletions
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl index 6ded7ff1c9..95b0a7194f 100644 --- a/erts/emulator/test/process_SUITE.erl +++ b/erts/emulator/test/process_SUITE.erl @@ -58,6 +58,7 @@ no_priority_inversion2/1, system_task_blast/1, system_task_on_suspended/1, + system_task_failed_enqueue/1, gc_request_when_gc_disabled/1, gc_request_blast_when_gc_disabled/1]). -export([prio_server/2, prio_client/2, init/1, handle_event/2]). @@ -104,7 +105,7 @@ groups() -> otp_7738_resume]}, {system_task, [], [no_priority_inversion, no_priority_inversion2, - system_task_blast, system_task_on_suspended, + system_task_blast, system_task_on_suspended, system_task_failed_enqueue, gc_request_when_gc_disabled, gc_request_blast_when_gc_disabled]}]. init_per_suite(Config) -> @@ -152,7 +153,11 @@ spawn_with_binaries(Config) when is_list(Config) -> TwoMeg = lists:duplicate(1024, L), Fun = fun() -> spawn(?MODULE, binary_owner, [list_to_binary(TwoMeg)]), receive after 1 -> ok end end, - test_server:do_times(150, Fun), + Iter = case test_server:is_valgrind() of + true -> 10; + false -> 150 + end, + test_server:do_times(Iter, Fun), ok. binary_owner(Bin) when is_binary(Bin) -> @@ -2390,14 +2395,20 @@ garb_other_running(Config) when is_list(Config) -> no_priority_inversion(Config) when is_list(Config) -> Prio = process_flag(priority, max), - HTLs = lists:map(fun (_) -> + Master = self(), + Executing = make_ref(), + HTLs = lists:map(fun (Sched) -> spawn_opt(fun () -> + Master ! {self(), Executing}, tok_loop() end, - [{priority, high}, monitor, link]) + [{priority, high}, + {scheduler, Sched}, + monitor, + link]) end, - lists:seq(1, 2*erlang:system_info(schedulers))), - receive after 500 -> ok end, + lists:seq(1, erlang:system_info(schedulers_online))), + lists:foreach(fun ({P, _}) -> receive {P,Executing} -> ok end end, HTLs), LTL = spawn_opt(fun () -> tok_loop() end, @@ -2419,14 +2430,19 @@ no_priority_inversion(Config) when is_list(Config) -> no_priority_inversion2(Config) when is_list(Config) -> Prio = process_flag(priority, max), - MTLs = lists:map(fun (_) -> + Master = self(), + Executing = make_ref(), + MTLs = lists:map(fun (Sched) -> spawn_opt(fun () -> + Master ! {self(), Executing}, tok_loop() end, - [{priority, max}, monitor, link]) + [{priority, max}, + {scheduler, Sched}, + monitor, link]) end, - lists:seq(1, 2*erlang:system_info(schedulers))), - receive after 2000 -> ok end, + lists:seq(1, erlang:system_info(schedulers_online))), + lists:foreach(fun ({P, _}) -> receive {P,Executing} -> ok end end, MTLs), {PL, ML} = spawn_opt(fun () -> tok_loop() end, @@ -2527,9 +2543,65 @@ system_task_on_suspended(Config) when is_list(Config) -> ok end. +%% When a system task couldn't be enqueued due to the process being in an +%% incompatible state, it would linger in the system task list and get executed +%% anyway the next time the process was scheduled. This would result in a +%% double-free at best. +%% +%% This test continuously purges modules while other processes run dirty code, +%% which will provoke this error as ERTS_PSTT_CPC can't be enqueued while a +%% process is running dirty code. +system_task_failed_enqueue(Config) when is_list(Config) -> + case erlang:system_info(dirty_cpu_schedulers) of + N when N > 0 -> + system_task_failed_enqueue_1(Config); + _ -> + {skipped, "No dirty scheduler support"} + end. + +system_task_failed_enqueue_1(Config) -> + Priv = proplists:get_value(priv_dir, Config), + + Purgers = [spawn_link(fun() -> purge_loop(Priv, Id) end) + || Id <- lists:seq(1, erlang:system_info(schedulers))], + Hogs = [spawn_link(fun() -> dirty_loop() end) + || _ <- lists:seq(1, erlang:system_info(dirty_cpu_schedulers))], + + ct:sleep(5000), + + [begin + unlink(Pid), + exit(Pid, kill) + end || Pid <- (Purgers ++ Hogs)], + + ok. + +purge_loop(PrivDir, Id) -> + Mod = "failed_enq_" ++ integer_to_list(Id), + Path = PrivDir ++ "/" ++ Mod, + file:write_file(Path ++ ".erl", + "-module('" ++ Mod ++ "').\n" ++ + "-export([t/0]).\n" ++ + "t() -> ok."), + purge_loop_1(Path). +purge_loop_1(Path) -> + {ok, Mod} = compile:file(Path, []), + erlang:delete_module(Mod), + erts_code_purger:purge(Mod), + purge_loop_1(Path). + +dirty_loop() -> + ok = erts_debug:dirty_cpu(reschedule, 10000), + dirty_loop(). + gc_request_when_gc_disabled(Config) when is_list(Config) -> - Master = self(), AIS = erts_debug:set_internal_state(available_internal_state, true), + gc_request_when_gc_disabled_do(ref), + gc_request_when_gc_disabled_do(immed), + erts_debug:set_internal_state(available_internal_state, AIS). + +gc_request_when_gc_disabled_do(ReqIdType) -> + Master = self(), {P, M} = spawn_opt(fun () -> true = erts_debug:set_internal_state(gc_state, false), @@ -2541,7 +2613,10 @@ gc_request_when_gc_disabled(Config) when is_list(Config) -> receive after 100 -> ok end end, [monitor, link]), receive {P, gc_state, false} -> ok end, - ReqId = make_ref(), + ReqId = case ReqIdType of + ref -> make_ref(); + immed -> immed + end, async = garbage_collect(P, [{async, ReqId}]), receive {garbage_collect, ReqId, Result} -> @@ -2550,7 +2625,6 @@ gc_request_when_gc_disabled(Config) when is_list(Config) -> 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. |