aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/test')
-rw-r--r--erts/emulator/test/bif_SUITE.erl15
-rw-r--r--erts/emulator/test/bs_construct_SUITE.erl48
-rw-r--r--erts/emulator/test/dirty_nif_SUITE.erl129
-rw-r--r--erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c20
4 files changed, 165 insertions, 47 deletions
diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl
index 26bb416bf0..d31399e4af 100644
--- a/erts/emulator/test/bif_SUITE.erl
+++ b/erts/emulator/test/bif_SUITE.erl
@@ -141,9 +141,11 @@ guard_bifs_in_erl_bif_types(_Config) ->
shadow_comments(_Config) ->
ensure_erl_bif_types_compiled(),
+ ErlangList = [{erlang,F,A} || {F,A} <- erlang:module_info(exports),
+ not is_operator(F,A)],
List0 = erlang:system_info(snifs),
- List1 = [MFA || {M,_,_}=MFA <- List0, M =/= hipe_bifs],
- List = [MFA || MFA <- List1, not is_operator(MFA)],
+ List1 = [MFA || {M,_,_}=MFA <- List0, M =/= hipe_bifs, M =/= erlang],
+ List = List1 ++ ErlangList,
HasTypes = [MFA || {M,F,A}=MFA <- List,
erl_bif_types:is_known(M, F, A)],
Path = get_code_path(),
@@ -253,12 +255,15 @@ specs(_) ->
end.
is_operator({erlang,F,A}) ->
+ is_operator(F,A);
+is_operator(_) -> false.
+
+is_operator(F,A) ->
erl_internal:arith_op(F, A) orelse
erl_internal:bool_op(F, A) orelse
erl_internal:comp_op(F, A) orelse
erl_internal:list_op(F, A) orelse
- erl_internal:send_op(F, A);
-is_operator(_) -> false.
+ erl_internal:send_op(F, A).
extract_specs(M, Abstr) ->
[{make_mfa(M, Name),Spec} || {attribute,_,spec,{Name,Spec}} <- Abstr].
@@ -646,6 +651,8 @@ erlang_halt(Config) when is_list(Config) ->
{badrpc,nodedown} = rpc:call(N2, erlang, halt, [0]),
{ok,N3} = slave:start(H, halt_node3),
{badrpc,nodedown} = rpc:call(N3, erlang, halt, [0,[]]),
+ {ok,N4} = slave:start(H, halt_node4),
+ {badrpc,nodedown} = rpc:call(N4, erlang, halt, [lists:duplicate(300,$x)]),
% This test triggers a segfault when dumping a crash dump
% to make sure that we can handle it properly.
diff --git a/erts/emulator/test/bs_construct_SUITE.erl b/erts/emulator/test/bs_construct_SUITE.erl
index 941cb435f7..22a1c0b765 100644
--- a/erts/emulator/test/bs_construct_SUITE.erl
+++ b/erts/emulator/test/bs_construct_SUITE.erl
@@ -527,7 +527,7 @@ huge_float_check({'EXIT',{system_limit,_}}) -> ok;
huge_float_check({'EXIT',{badarg,_}}) -> ok.
huge_binary(Config) when is_list(Config) ->
- ct:timetrap({seconds, 30}),
+ ct:timetrap({seconds, 60}),
16777216 = size(<<0:(id(1 bsl 26)),(-1):(id(1 bsl 26))>>),
garbage_collect(),
{Shift,Return} = case free_mem() of
@@ -561,30 +561,13 @@ huge_binary(Config) when is_list(Config) ->
end.
free_mem() ->
- Cmd = "uname; free",
- Output = string:tokens(os:cmd(Cmd), "\n"),
- io:format("Output from command ~p\n~p\n",[Cmd,Output]),
- case Output of
- [OS, ColumnNames, Values | _] ->
- case string:str(OS,"Linux") of
- 0 ->
- io:format("Unknown OS\n",[]),
- undefined;
- _ ->
- case {string:tokens(ColumnNames, " \t"),
- string:tokens(Values, " \t")} of
- {[_,_,"free"|_],["Mem:",_,_,FreeKb|_]} ->
- list_to_integer(FreeKb) div 1024;
- _ ->
- io:format("Failed to parse output from 'free':\n",[]),
- undefined
- end
- end;
- _ ->
- io:format("Too few lines in output\n",[]),
- undefined
+ {ok,Apps} = application:ensure_all_started(os_mon),
+ Mem = memsup:get_system_memory_data(),
+ [ok = application:stop(App)||App <- Apps],
+ case proplists:get_value(free_memory,Mem) of
+ undefined -> undefined;
+ Val -> Val div 1024
end.
-
system_limit(Config) when is_list(Config) ->
WordSize = erlang:system_info(wordsize),
@@ -614,8 +597,7 @@ system_limit_32() ->
{'EXIT',{system_limit,_}} = (catch <<42:536870912/unit:8>>),
{'EXIT',{system_limit,_}} = (catch <<42:(id(536870912))/unit:8>>),
{'EXIT',{system_limit,_}} = (catch <<0:(id(8)),42:536870912/unit:8>>),
- {'EXIT',{system_limit,_}} =
- (catch <<0:(id(8)),42:(id(536870912))/unit:8>>),
+ {'EXIT',{system_limit,_}} = (catch <<0:(id(8)),42:(id(536870912))/unit:8>>),
%% The size would be silently truncated, resulting in a crash.
{'EXIT',{system_limit,_}} = (catch <<0:(1 bsl 35)>>),
@@ -627,16 +609,10 @@ system_limit_32() ->
ok.
badarg(Config) when is_list(Config) ->
- {'EXIT',{badarg,_}} =
- (catch <<0:(id(1 bsl 100)),0:(id(-1))>>),
- {'EXIT',{badarg,_}} =
- (catch <<0:(id(1 bsl 100)),0:(id(-(1 bsl 70)))>>),
- {'EXIT',{badarg,_}} =
- (catch <<0:(id(-(1 bsl 70))),0:(id(1 bsl 100))>>),
-
- {'EXIT',{badarg,_}} =
- (catch <<(id(<<>>))/binary,0:(id(-(1 bsl 100)))>>),
-
+ {'EXIT',{badarg,_}} = (catch <<0:(id(1 bsl 100)),0:(id(-1))>>),
+ {'EXIT',{badarg,_}} = (catch <<0:(id(1 bsl 100)),0:(id(-(1 bsl 70)))>>),
+ {'EXIT',{badarg,_}} = (catch <<0:(id(-(1 bsl 70))),0:(id(1 bsl 100))>>),
+ {'EXIT',{badarg,_}} = (catch <<(id(<<>>))/binary,0:(id(-(1 bsl 100)))>>),
ok.
copy_writable_binary(Config) when is_list(Config) ->
diff --git a/erts/emulator/test/dirty_nif_SUITE.erl b/erts/emulator/test/dirty_nif_SUITE.erl
index c3afbc0803..83b098a704 100644
--- a/erts/emulator/test/dirty_nif_SUITE.erl
+++ b/erts/emulator/test/dirty_nif_SUITE.erl
@@ -32,19 +32,23 @@
dirty_nif/1, dirty_nif_send/1,
dirty_nif_exception/1, call_dirty_nif_exception/1,
dirty_scheduler_exit/1, dirty_call_while_terminated/1,
- dirty_heap_access/1]).
+ dirty_heap_access/1, dirty_process_info/1,
+ dirty_process_register/1, dirty_process_trace/1]).
-define(nif_stub,nif_stub_error(?LINE)).
suite() -> [{ct_hooks,[ts_install_cth]}].
-all() ->
+all() ->
[dirty_nif,
dirty_nif_send,
dirty_nif_exception,
dirty_scheduler_exit,
dirty_call_while_terminated,
- dirty_heap_access].
+ dirty_heap_access,
+ dirty_process_info,
+ dirty_process_register,
+ dirty_process_trace].
init_per_suite(Config) ->
try erlang:system_info(dirty_cpu_schedulers) of
@@ -187,7 +191,7 @@ dirty_call_while_terminated(Config) when is_list(Config) ->
blipp:blupp(Bin)
end,
[monitor,link]),
- receive {dirty_alive, Pid} -> ok end,
+ receive {dirty_alive, _Pid} -> ok end,
{value, {BinAddr, 4711, 2}} = lists:keysearch(4711, 2,
element(2,
process_info(self(),
@@ -241,7 +245,7 @@ dirty_heap_access(Config) when is_list(Config) ->
end),
{N, R} = access_dirty_heap(Dirty, RGL, 0, 0),
receive
- {Pid, Res} ->
+ {_Pid, Res} ->
1000 = length(Res),
lists:foreach(fun (X) -> Ref = X end, Res)
end,
@@ -269,12 +273,123 @@ access_dirty_heap(Dirty, RGL, N, R) ->
end)
end.
+%% These tests verify that processes that access a process executing a
+%% dirty NIF where the main lock is needed for that access do not get
+%% blocked. Each test passes its pid to dirty_sleeper, which sends a
+%% 'ready' message when it's running on a dirty scheduler and just before
+%% it starts a 6 second sleep. When it receives the message, it verifies
+%% that access to the dirty process is as it expects. After the dirty
+%% process finishes its 6 second sleep but before it returns from the dirty
+%% scheduler, it sends a 'done' message. If the tester already received
+%% that message, the test fails because it means attempting to access the
+%% dirty process waited for that process to return to a regular scheduler,
+%% so verify that we haven't received that message, and also verify that
+%% the dirty process is still alive immediately after accessing it.
+dirty_process_info(Config) when is_list(Config) ->
+ access_dirty_process(
+ Config,
+ fun() -> ok end,
+ fun(NifPid) ->
+ PI = process_info(NifPid),
+ {current_function,{?MODULE,dirty_sleeper,1}} =
+ lists:keyfind(current_function, 1, PI),
+ ok
+ end,
+ fun(_) -> ok end).
+
+dirty_process_register(Config) when is_list(Config) ->
+ access_dirty_process(
+ Config,
+ fun() -> ok end,
+ fun(NifPid) ->
+ register(test_dirty_process_register, NifPid),
+ NifPid = whereis(test_dirty_process_register),
+ unregister(test_dirty_process_register),
+ false = lists:member(test_dirty_process_register,
+ registered()),
+ ok
+ end,
+ fun(_) -> ok end).
+
+dirty_process_trace(Config) when is_list(Config) ->
+ access_dirty_process(
+ Config,
+ fun() ->
+ erlang:trace_pattern({?MODULE,dirty_sleeper,1},
+ [{'_',[],[{return_trace}]}],
+ [local,meta]),
+ ok
+ end,
+ fun(NifPid) ->
+ erlang:trace(NifPid, true, [call,timestamp]),
+ ok
+ end,
+ fun(NifPid) ->
+ receive
+ done ->
+ receive
+ {trace_ts,NifPid,call,{?MODULE,dirty_sleeper,_},_} ->
+ ok
+ after
+ 0 ->
+ error(missing_trace_call_message)
+ end,
+ receive
+ {trace_ts,NifPid,return_from,{?MODULE,dirty_sleeper,1},
+ ok,_} ->
+ ok
+ after
+ 100 ->
+ error(missing_trace_return_message)
+ end
+ after
+ 6500 ->
+ error(missing_done_message)
+ end,
+ ok
+ end).
+
%%
%% Internal...
%%
+access_dirty_process(Config, Start, Test, Finish) ->
+ {ok, Node} = start_node(Config, ""),
+ [ok] = mcall(Node,
+ [fun() ->
+ Path = ?config(data_dir, Config),
+ Lib = atom_to_list(?MODULE),
+ ok = erlang:load_nif(filename:join(Path,Lib), []),
+ ok = test_dirty_process_access(Start, Test, Finish)
+ end]),
+ stop_node(Node),
+ ok.
+
+test_dirty_process_access(Start, Test, Finish) ->
+ ok = Start(),
+ Self = self(),
+ NifPid = spawn_link(fun() ->
+ ok = dirty_sleeper(Self)
+ end),
+ ok = receive
+ ready ->
+ ok = Test(NifPid),
+ receive
+ done ->
+ error(dirty_process_info_blocked)
+ after
+ 0 ->
+ true = erlang:is_process_alive(NifPid),
+ ok
+ end
+ after
+ 3000 ->
+ error(timeout)
+ end,
+ ok = Finish(NifPid).
+
receive_any() ->
- receive M -> M end.
+ receive M -> M end.
start_node(Config) ->
start_node(Config, "").
@@ -314,13 +429,13 @@ mcall(Node, Funs) ->
%% The NIFs:
lib_loaded() -> false.
-call_nif_schedule(_,_) -> ?nif_stub.
call_dirty_nif(_,_,_) -> ?nif_stub.
send_from_dirty_nif(_) -> ?nif_stub.
call_dirty_nif_exception(_) -> ?nif_stub.
call_dirty_nif_zero_args() -> ?nif_stub.
dirty_call_while_terminated_nif(_) -> ?nif_stub.
dirty_sleeper() -> ?nif_stub.
+dirty_sleeper(_) -> ?nif_stub.
dirty_heap_access_nif(_) -> ?nif_stub.
nif_stub_error(Line) ->
diff --git a/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c b/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c
index 155788dceb..e38bececde 100644
--- a/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c
+++ b/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c
@@ -148,12 +148,31 @@ static ERL_NIF_TERM call_dirty_nif_zero_args(ErlNifEnv* env, int argc, const ERL
static ERL_NIF_TERM
dirty_sleeper(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
+ ErlNifPid pid;
+ ErlNifEnv* msg_env = NULL;
+
assert(enif_is_on_dirty_scheduler(env));
+
+ /* If we get a pid argument, it indicates a process involved in the
+ test wants a message from us. Prior to the sleep we send a 'ready'
+ message, and then after the sleep, send a 'done' message. */
+ if (argc == 1 && enif_get_local_pid(env, argv[0], &pid)) {
+ msg_env = enif_alloc_env();
+ enif_send(env, &pid, msg_env, enif_make_atom(msg_env, "ready"));
+ }
+
#ifdef __WIN32__
Sleep(6000);
#else
sleep(6);
#endif
+
+ if (argc == 1) {
+ assert(msg_env != NULL);
+ enif_send(env, &pid, msg_env, enif_make_atom(msg_env, "done"));
+ enif_free_env(msg_env);
+ }
+
return enif_make_atom(env, "ok");
}
@@ -218,6 +237,7 @@ static ErlNifFunc nif_funcs[] =
{"call_dirty_nif_exception", 1, call_dirty_nif_exception, ERL_NIF_DIRTY_JOB_IO_BOUND},
{"call_dirty_nif_zero_args", 0, call_dirty_nif_zero_args, ERL_NIF_DIRTY_JOB_CPU_BOUND},
{"dirty_sleeper", 0, dirty_sleeper, ERL_NIF_DIRTY_JOB_IO_BOUND},
+ {"dirty_sleeper", 1, dirty_sleeper, ERL_NIF_DIRTY_JOB_CPU_BOUND},
{"dirty_call_while_terminated_nif", 1, dirty_call_while_terminated_nif, ERL_NIF_DIRTY_JOB_CPU_BOUND},
{"dirty_heap_access_nif", 1, dirty_heap_access_nif, ERL_NIF_DIRTY_JOB_CPU_BOUND}
};