aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test/driver_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/test/driver_SUITE.erl')
-rw-r--r--erts/emulator/test/driver_SUITE.erl467
1 files changed, 343 insertions, 124 deletions
diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl
index c31ceb4d4b..1d2ae4fb51 100644
--- a/erts/emulator/test/driver_SUITE.erl
+++ b/erts/emulator/test/driver_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -43,9 +43,9 @@
outputv_errors/1,
driver_unloaded/1,
io_ready_exit/1,
+ use_fallback_pollset/0,
use_fallback_pollset/1,
bad_fd_in_pollset/1,
- driver_event/1,
fd_change/1,
steal_control/1,
otp_6602/1,
@@ -58,11 +58,9 @@
ioq_exit_ready_output/1,
ioq_exit_timeout/1,
ioq_exit_ready_async/1,
- ioq_exit_event/1,
ioq_exit_ready_input_async/1,
ioq_exit_ready_output_async/1,
ioq_exit_timeout_async/1,
- ioq_exit_event_async/1,
zero_extended_marker_garb_drv/1,
invalid_extended_marker_drv/1,
larger_major_vsn_drv/1,
@@ -82,10 +80,14 @@
async_blast/1,
thr_msg_blast/1,
consume_timeslice/1,
+ env/1,
+ poll_pipe/1,
z_test/1]).
-export([bin_prefix/2]).
+-export([get_check_io_total/1]). % for z_SUITE.erl
+
-include_lib("common_test/include/ct.hrl").
@@ -119,17 +121,26 @@
-define(heap_binary_size, 64).
init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- case catch erts_debug:get_internal_state(available_internal_state) of
- true -> ok;
- _ -> erts_debug:set_internal_state(available_internal_state, true)
- end,
+ CIOD = rpc(Config,
+ fun() ->
+ case catch erts_debug:get_internal_state(available_internal_state) of
+ true -> ok;
+ _ -> erts_debug:set_internal_state(available_internal_state, true)
+ end,
+ erts_debug:get_internal_state(check_io_debug)
+ end),
erlang:display({init_per_testcase, Case}),
- 0 = element(1, erts_debug:get_internal_state(check_io_debug)),
+ 0 = element(1, CIOD),
[{testcase, Case}|Config].
-end_per_testcase(Case, _Config) ->
+end_per_testcase(Case, Config) ->
erlang:display({end_per_testcase, Case}),
- 0 = element(1, erts_debug:get_internal_state(check_io_debug)),
+ CIOD = rpc(Config,
+ fun() ->
+ get_stable_check_io_info(),
+ erts_debug:get_internal_state(check_io_debug)
+ end),
+ 0 = element(1, CIOD),
ok.
suite() ->
@@ -137,10 +148,13 @@ suite() ->
{timetrap, {minutes, 1}}].
all() -> %% Keep a_test first and z_test last...
- [a_test, outputv_errors, outputv_echo, queue_echo, {group, timer},
- driver_unloaded, io_ready_exit, use_fallback_pollset,
- bad_fd_in_pollset, driver_event, fd_change,
- steal_control, otp_6602, driver_system_info_base_ver,
+ [a_test, outputv_errors, outputv_echo, queue_echo,
+ {group, timer},
+ driver_unloaded, io_ready_exit, otp_6602,
+ {group, polling},
+ {group, poll_thread},
+ {group, poll_set},
+ driver_system_info_base_ver,
driver_system_info_prev_ver,
driver_system_info_current_ver, driver_monitor,
{group, ioq_exit}, zero_extended_marker_garb_drv,
@@ -148,24 +162,32 @@ all() -> %% Keep a_test first and z_test last...
larger_minor_vsn_drv, smaller_major_vsn_drv,
smaller_minor_vsn_drv, peek_non_existing_queue,
otp_6879, caller, many_events, missing_callbacks,
- smp_select, driver_select_use,
thread_mseg_alloc_cache_clean,
otp_9302,
thr_free_drv,
async_blast,
thr_msg_blast,
consume_timeslice,
+ env,
+ poll_pipe,
z_test].
groups() ->
[{timer, [],
[timer_measure, timer_cancel, timer_delay,
timer_change]},
+ {poll_thread, [], [{group, polling}]},
+ {poll_set, [], [{group, polling}]},
+ {polling, [],
+ [a_test, use_fallback_pollset,
+ bad_fd_in_pollset, fd_change,
+ steal_control, smp_select,
+ driver_select_use, z_test]},
{ioq_exit, [],
[ioq_exit_ready_input, ioq_exit_ready_output,
- ioq_exit_timeout, ioq_exit_ready_async, ioq_exit_event,
+ ioq_exit_timeout, ioq_exit_ready_async,
ioq_exit_ready_input_async, ioq_exit_ready_output_async,
- ioq_exit_timeout_async, ioq_exit_event_async]}].
+ ioq_exit_timeout_async]}].
init_per_suite(Config) ->
Config.
@@ -173,10 +195,28 @@ init_per_suite(Config) ->
end_per_suite(_Config) ->
catch erts_debug:set_internal_state(available_internal_state, false).
+init_per_group(poll_thread, Config) ->
+ [{node_args, "+IOt 2"} | Config];
+init_per_group(poll_set, Config) ->
+ [{node_args, "+IOt 2 +IOp 2"} | Config];
+init_per_group(polling, Config) ->
+ case proplists:get_value(node_args, Config) of
+ undefined ->
+ Config;
+ Args ->
+ {ok, Node} = start_node(polling, Args),
+ [{node, Node} | Config]
+ end;
init_per_group(_GroupName, Config) ->
Config.
end_per_group(_GroupName, Config) ->
+ case proplists:get_value(node, Config) of
+ undefined ->
+ ok;
+ Node ->
+ stop_node(Node)
+ end,
Config.
%% Test sending bad types to port with an outputv-capable driver.
@@ -778,21 +818,23 @@ io_ready_exit(Config) when is_list(Config) ->
-define(CHKIO_STOP, 0).
-define(CHKIO_USE_FALLBACK_POLLSET, 1).
-define(CHKIO_BAD_FD_IN_POLLSET, 2).
--define(CHKIO_DRIVER_EVENT, 3).
-define(CHKIO_FD_CHANGE, 4).
-define(CHKIO_STEAL, 5).
-define(CHKIO_STEAL_AUX, 6).
-define(CHKIO_SMP_SELECT, 7).
-define(CHKIO_DRV_USE, 8).
+use_fallback_pollset() ->
+ [{timetrap, {minutes, 2}}].
+
use_fallback_pollset(Config) when is_list(Config) ->
+ rpc(Config, fun() -> use_fallback_pollset_t(Config) end).
+
+use_fallback_pollset_t(Config) when is_list(Config) ->
FlbkFun = fun () ->
- ChkIoDuring = erlang:system_info(check_io),
- case lists:keysearch(fallback_poll_set_size,
- 1,
- ChkIoDuring) of
- {value,
- {fallback_poll_set_size, N}} when N > 0 ->
+ {Flbk, _} = get_fallback(erlang:system_info(check_io)),
+ case lists:keysearch(total_poll_set_size, 1, Flbk) of
+ {value, {total_poll_set_size, N}} when N > 0 ->
ok;
Error ->
ct:fail({failed_to_use_fallback, Error})
@@ -814,6 +856,7 @@ use_fallback_pollset(Config) when is_list(Config) ->
Skip ->
{fun () -> ok end, Skip, ok}
end,
+ io:format("Node = ~p~n",[node()]),
case chkio_test_fini(chkio_test(Handel,
?CHKIO_USE_FALLBACK_POLLSET,
fun () ->
@@ -825,27 +868,31 @@ use_fallback_pollset(Config) when is_list(Config) ->
end.
bad_fd_in_pollset(Config) when is_list(Config) ->
- chkio_test_fini(chkio_test(chkio_test_init(Config),
- ?CHKIO_BAD_FD_IN_POLLSET,
- fun () -> sleep(1000) end)).
-
-driver_event(Config) when is_list(Config) ->
- chkio_test_fini(chkio_test(chkio_test_init(Config),
- ?CHKIO_DRIVER_EVENT,
- fun () -> sleep(1000) end)).
+ rpc(Config,
+ fun() ->
+ chkio_test_fini(chkio_test(chkio_test_init(Config),
+ ?CHKIO_BAD_FD_IN_POLLSET,
+ fun () -> sleep(1000) end))
+ end).
fd_change(Config) when is_list(Config) ->
- chkio_test_fini(chkio_test(chkio_test_init(Config),
- ?CHKIO_FD_CHANGE,
- fun () -> sleep(1000) end)).
+ rpc(Config,
+ fun() ->
+ chkio_test_fini(chkio_test(chkio_test_init(Config),
+ ?CHKIO_FD_CHANGE,
+ fun () -> sleep(1000) end))
+ end).
steal_control(Config) when is_list(Config) ->
- chkio_test_fini(case chkio_test_init(Config) of
- {erts_poll_info, _} = Hndl ->
- steal_control_test(Hndl);
- Skip ->
- Skip
- end).
+ rpc(Config,
+ fun() ->
+ chkio_test_fini(case chkio_test_init(Config) of
+ {erts_poll_info, _} = Hndl ->
+ steal_control_test(Hndl);
+ Skip ->
+ Skip
+ end)
+ end).
steal_control_test(Hndl = {erts_poll_info, Before}) ->
Port = open_chkio_port(),
@@ -887,7 +934,7 @@ chkio_test_init(Config) when is_list(Config) ->
ChkIo = get_stable_check_io_info(),
case catch lists:keysearch(name, 1, ChkIo) of
{value, {name, erts_poll}} ->
- io:format("Before test: ~p~n", [ChkIo]),
+ ct:log("Before test: ~p~n", [ChkIo]),
Path = proplists:get_value(data_dir, Config),
erl_ddll:start(),
ok = load_driver(Path, 'chkio_drv'),
@@ -948,8 +995,9 @@ chkio_test({erts_poll_info, Before},
"ok" ->
chk_chkio_port(Port),
Fun(),
- During = erlang:system_info(check_io),
+ During = get_check_io_total(erlang:system_info(check_io)),
erlang:display(During),
+
0 = element(1, erts_debug:get_internal_state(check_io_debug)),
io:format("During test: ~p~n", [During]),
chk_chkio_port(Port),
@@ -1001,22 +1049,88 @@ verify_chkio_state(Before, After) ->
ok.
get_stable_check_io_info() ->
- ChkIo = erlang:system_info(check_io),
- PendUpdNo = case lists:keysearch(pending_updates, 1, ChkIo) of
- {value, {pending_updates, PendNo}} ->
- PendNo;
- false ->
- 0
- end,
- {value, {active_fds, ActFds}} = lists:keysearch(active_fds, 1, ChkIo),
+ get_stable_check_io_info(10).
+get_stable_check_io_info(0) ->
+ get_check_io_total(erlang:system_info(check_io));
+get_stable_check_io_info(N) ->
+ ChkIo = get_check_io_total(erlang:system_info(check_io)),
+ PendUpdNo = proplists:get_value(pending_updates, ChkIo, 0),
+ ActFds = proplists:get_value(active_fds, ChkIo),
case {PendUpdNo, ActFds} of
{0, 0} ->
ChkIo;
_ ->
- receive after 10 -> ok end,
- get_stable_check_io_info()
+ receive after 100 -> ok end,
+ get_stable_check_io_info(N-1)
+ end.
+
+%% Merge return from erlang:system_info(check_io)
+%% as if it was one big pollset.
+get_check_io_total(ChkIo) ->
+ ct:log("ChkIo = ~p~n",[ChkIo]),
+ {Fallback, Rest} = get_fallback(ChkIo),
+ OnlyPollThreads = [PS || PS <- Rest, not is_scheduler_pollset(PS)],
+ add_fallback_infos(Fallback,
+ lists:foldl(
+ fun(Pollset, Acc) ->
+ lists:zipwith(fun(A, B) ->
+ add_pollset_infos(A,B)
+ end,
+ Pollset, Acc)
+ end,
+ hd(OnlyPollThreads), tl(OnlyPollThreads))).
+
+is_scheduler_pollset(Pollset) ->
+ proplists:get_value(poll_threads, Pollset) == 0.
+
+add_pollset_infos({Tag, A}=TA , {Tag, B}=TB) ->
+ case tag_type(Tag) of
+ sum ->
+ {Tag, A + B};
+ const ->
+ case A of
+ B -> TA;
+ _ ->
+ ct:fail("Unexpected diff in pollsets ~p != ~p",
+ [TA,TB])
+ end
end.
+get_fallback([MaybeFallback | ChkIo] = AllChkIo) ->
+ case proplists:get_value(fallback, MaybeFallback) of
+ true ->
+ {MaybeFallback, ChkIo};
+ false ->
+ {undefined, AllChkIo}
+ end.
+
+add_fallback_infos(undefined, Acc) ->
+ Acc;
+add_fallback_infos(Flbk, Acc) ->
+ lists:zipwith(fun({Tag, A}=TA, {Tag, B}=TB) ->
+ case tag_type(Tag) of
+ sum -> {Tag, A + B};
+ const when Tag =:= fallback -> TA;
+ const -> TB
+ end
+ end,
+ Flbk, Acc).
+
+tag_type(name) -> const;
+tag_type(primary) -> const;
+tag_type(fallback) -> const;
+tag_type(kernel_poll) -> const;
+tag_type(memory_size) -> sum;
+tag_type(total_poll_set_size) -> sum;
+tag_type(lazy_updates) -> const;
+tag_type(pending_updates) -> sum;
+tag_type(batch_updates) -> const;
+tag_type(concurrent_updates) -> const;
+tag_type(max_fds) -> const;
+tag_type(active_fds) -> sum;
+tag_type(poll_threads) -> sum.
+
+
%% Missed port lock when stealing control of fd from a
%% driver that didn't use the same lock. The lock checker
%% used to trigger on this and dump core.
@@ -1087,9 +1201,9 @@ check_driver_system_info_result(Result) ->
io:format("All names: ~p~n", [?EXPECTED_SYSTEM_INFO_NAMES]),
io:format("Result: ~p~n", [Result]),
{[], Ns, DDVSN} = chk_sis(lists:map(fun (Str) ->
- string:tokens(Str, "=")
+ string:lexemes(Str, "=")
end,
- string:tokens(Result, " ")),
+ string:lexemes(Result, " ")),
?EXPECTED_SYSTEM_INFO_NAMES),
case {DDVSN,
drv_vsn_str2tup(erlang:system_info(driver_version))} of
@@ -1144,8 +1258,6 @@ check_si_res(["thread", "false"]) ->
false = erlang:system_info(threads);
check_si_res(["smp", "true"]) ->
true = erlang:system_info(smp_support);
-check_si_res(["smp", "false"]) ->
- false = erlang:system_info(smp_support);
%% Data added in second version of driver_system_info() (driver version 1.1)
check_si_res(["async_thrs", Value]) ->
@@ -1338,11 +1450,9 @@ driver_monitor(Config) when is_list(Config) ->
-define(IOQ_EXIT_READY_OUTPUT, 2).
-define(IOQ_EXIT_TIMEOUT, 3).
-define(IOQ_EXIT_READY_ASYNC, 4).
--define(IOQ_EXIT_EVENT, 5).
-define(IOQ_EXIT_READY_INPUT_ASYNC, 6).
-define(IOQ_EXIT_READY_OUTPUT_ASYNC, 7).
-define(IOQ_EXIT_TIMEOUT_ASYNC, 8).
--define(IOQ_EXIT_EVENT_ASYNC, 9).
ioq_exit_test(Config, TestNo) ->
Drv = ioq_exit_drv,
@@ -1395,9 +1505,6 @@ ioq_exit_timeout(Config) when is_list(Config) ->
ioq_exit_ready_async(Config) when is_list(Config) ->
ioq_exit_test(Config, ?IOQ_EXIT_READY_ASYNC).
-ioq_exit_event(Config) when is_list(Config) ->
- ioq_exit_test(Config, ?IOQ_EXIT_EVENT).
-
ioq_exit_ready_input_async(Config) when is_list(Config) ->
ioq_exit_test(Config, ?IOQ_EXIT_READY_INPUT_ASYNC).
@@ -1407,9 +1514,6 @@ ioq_exit_ready_output_async(Config) when is_list(Config) ->
ioq_exit_timeout_async(Config) when is_list(Config) ->
ioq_exit_test(Config, ?IOQ_EXIT_TIMEOUT_ASYNC).
-ioq_exit_event_async(Config) when is_list(Config) ->
- ioq_exit_test(Config, ?IOQ_EXIT_EVENT_ASYNC).
-
vsn_mismatch_test(Config, LoadResult) ->
Path = proplists:get_value(data_dir, Config),
@@ -1643,7 +1747,7 @@ missing_callbacks(Config) when is_list(Config) ->
smp_select(Config) when is_list(Config) ->
case os:type() of
{win32,_} -> {skipped, "Test not implemented for this OS"};
- _ -> smp_select0(Config)
+ _ -> rpc(Config, fun() -> smp_select0(Config) end)
end.
smp_select0(Config) ->
@@ -1655,7 +1759,7 @@ smp_select0(Config) ->
ProcFun = fun()-> io:format("Worker ~p starting\n",[self()]),
Port = open_port({spawn, DrvName}, []),
smp_select_loop(Port, 100000),
- sleep(1000), % wait for driver to handle pending events
+ smp_select_done(Port),
true = erlang:port_close(Port),
Master ! {ok,self()},
io:format("Worker ~p finished\n",[self()])
@@ -1685,6 +1789,21 @@ smp_select_loop(Port, N) ->
smp_select_loop(Port, N-1)
end.
+smp_select_done(Port) ->
+ case erlang:port_control(Port, ?CHKIO_SMP_SELECT, "done") of
+ "wait" ->
+ receive
+ {Port, done} ->
+ ok
+ after 10*1000 ->
+ %% Seems we have a lost ready_input event.
+ %% Go ahead anyway, port will crash VM when closed.
+ ok
+ end;
+
+ "ok" -> ok
+ end.
+
smp_select_wait([], _) ->
ok;
smp_select_wait(Pids, TimeoutMsg) ->
@@ -1702,7 +1821,7 @@ smp_select_wait(Pids, TimeoutMsg) ->
driver_select_use(Config) when is_list(Config) ->
case os:type() of
{win32,_} -> {skipped, "Test not implemented for this OS"};
- _ -> driver_select_use0(Config)
+ _ -> rpc(Config, fun() -> driver_select_use0(Config) end)
end.
driver_select_use0(Config) ->
@@ -1947,44 +2066,39 @@ thr_msg_blast_receiver_proc(Port, Max, Parent, Done) ->
end.
thr_msg_blast(Config) when is_list(Config) ->
- case erlang:system_info(smp_support) of
- false ->
- {skipped, "Non-SMP emulator; nothing to test..."};
- true ->
- Path = proplists:get_value(data_dir, Config),
- erl_ddll:start(),
- ok = load_driver(Path, thr_msg_blast_drv),
- MemBefore = driver_alloc_size(),
- Start = os:timestamp(),
- Port = open_port({spawn, thr_msg_blast_drv}, []),
- true = is_port(Port),
- Done = make_ref(),
- Me = self(),
- spawn(fun () ->
- thr_msg_blast_receiver_proc(Port, 1, Me, Done)
- end),
- receive
- Done -> ok
- end,
- ok = thr_msg_blast_receiver(Port, 0, 32*10000),
- port_close(Port),
- End = os:timestamp(),
- receive
- Garbage ->
- ct:fail({received_garbage, Port, Garbage})
- after 2000 ->
- ok
- end,
- MemAfter = driver_alloc_size(),
- io:format("MemBefore=~p, MemAfter=~p~n",
- [MemBefore, MemAfter]),
- ThrMsgBlastTime = timer:now_diff(End,Start)/1000000,
- io:format("ThrMsgBlastTime=~p~n", [ThrMsgBlastTime]),
- MemBefore = MemAfter,
- Res = {thr_msg_blast_time, ThrMsgBlastTime},
- erlang:display(Res),
- Res
- end.
+ Path = proplists:get_value(data_dir, Config),
+ erl_ddll:start(),
+ ok = load_driver(Path, thr_msg_blast_drv),
+ MemBefore = driver_alloc_size(),
+ Start = os:timestamp(),
+ Port = open_port({spawn, thr_msg_blast_drv}, []),
+ true = is_port(Port),
+ Done = make_ref(),
+ Me = self(),
+ spawn(fun () ->
+ thr_msg_blast_receiver_proc(Port, 1, Me, Done)
+ end),
+ receive
+ Done -> ok
+ end,
+ ok = thr_msg_blast_receiver(Port, 0, 32*10000),
+ port_close(Port),
+ End = os:timestamp(),
+ receive
+ Garbage ->
+ ct:fail({received_garbage, Port, Garbage})
+ after 2000 ->
+ ok
+ end,
+ MemAfter = driver_alloc_size(),
+ io:format("MemBefore=~p, MemAfter=~p~n",
+ [MemBefore, MemAfter]),
+ ThrMsgBlastTime = timer:now_diff(End,Start)/1000000,
+ io:format("ThrMsgBlastTime=~p~n", [ThrMsgBlastTime]),
+ MemBefore = MemAfter,
+ Res = {thr_msg_blast_time, ThrMsgBlastTime},
+ erlang:display(Res),
+ Res.
-define(IN_RANGE(LoW_, VaLuE_, HiGh_),
case in_range(LoW_, VaLuE_, HiGh_) of
@@ -2273,11 +2387,56 @@ count_proc_sched(Ps, PNs) ->
PNs
end.
+%%
+%% Tests whether erl_drv_putenv reflects in os:getenv and vice versa.
+%%
+env(Config) when is_list(Config) ->
+ ok = load_driver(proplists:get_value(data_dir, Config), env_drv),
+ Port = open_port({spawn_driver, env_drv}, []),
+ true = is_port(Port),
+
+ Keys = ["env_drv_a_key", "env_drv_b_key", "env_drv_c_key"],
+ Values = ["a_value", "b_value", "c_value"],
+
+ [env_put_test(Port, Key, Value) || Key <- Keys, Value <- Values],
+ [env_get_test(Port, Key, Value) || Key <- Keys, Value <- Values],
+ [env_oversize_test(Port, Key) || Key <- Keys],
+ [env_notfound_test(Port, Key) || Key <- Keys],
+
+ true = port_close(Port),
+ erl_ddll:unload_driver(env_drv),
+ ok.
+
+env_control(Port, Command, Key, Value) ->
+ KeyBin = list_to_binary(Key),
+ ValueBin = list_to_binary(Value),
+ Header = <<(byte_size(KeyBin)), (byte_size(ValueBin))>>,
+ Payload = <<KeyBin/binary, ValueBin/binary>>,
+ port_control(Port, Command, <<Header/binary, Payload/binary>>).
+
+env_put_test(Port, Key, Value) ->
+ os:unsetenv(Key),
+ [0] = env_control(Port, 0, Key, Value),
+ Value = os:getenv(Key).
+
+env_get_test(Port, Key, ExpectedValue) ->
+ true = os:putenv(Key, ExpectedValue),
+ [0] = env_control(Port, 1, Key, ExpectedValue).
+
+env_oversize_test(Port, Key) ->
+ os:putenv(Key, [$A || _ <- lists:seq(1, 1024)]),
+ [127] = env_control(Port, 1, Key, "").
+
+env_notfound_test(Port, Key) ->
+ true = os:unsetenv(Key),
+ [255] = env_control(Port, 1, Key, "").
+
+
a_test(Config) when is_list(Config) ->
- check_io_debug().
+ rpc(Config, fun check_io_debug/0).
z_test(Config) when is_list(Config) ->
- check_io_debug().
+ rpc(Config, fun check_io_debug/0).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Utilities
@@ -2285,8 +2444,8 @@ z_test(Config) when is_list(Config) ->
check_io_debug() ->
get_stable_check_io_info(),
- {NoErrorFds, NoUsedFds, NoDrvSelStructs, NoDrvEvStructs} = CheckIoDebug
- = erts_debug:get_internal_state(check_io_debug),
+ {NoErrorFds, NoUsedFds, NoDrvSelStructs, NoEnifSelStructs}
+ = CheckIoDebug = erts_debug:get_internal_state(check_io_debug),
HasGetHost = has_gethost(),
ct:log("check_io_debug: ~p~n"
"HasGetHost: ~p",[CheckIoDebug, HasGetHost]),
@@ -2299,7 +2458,7 @@ check_io_debug() ->
%% one extra used fd that is not selected on
ok
end,
- 0 = NoDrvEvStructs,
+ 0 = NoEnifSelStructs,
ok.
has_gethost() ->
@@ -2351,7 +2510,7 @@ wait_until(Fun) ->
end.
drv_vsn_str2tup(Str) ->
- [Major, Minor] = string:tokens(Str, "."),
+ [Major, Minor] = string:lexemes(Str, "."),
{list_to_integer(Major), list_to_integer(Minor)}.
%% Build port data from a template.
@@ -2452,8 +2611,18 @@ stop_driver(Port, Name) ->
ok = erl_ddll:stop().
load_driver(Dir, Driver) ->
+ Before = erlang:system_info(taints),
case erl_ddll:load_driver(Dir, Driver) of
- ok -> ok;
+ ok ->
+ After = erlang:system_info(taints),
+ case lists:member(Driver, Before) of
+ true ->
+ After = Before;
+ false ->
+ true = lists:member(Driver, After),
+ Before = lists:delete(Driver, After)
+ end,
+ ok;
{error, Error} = Res ->
io:format("~s\n", [erl_ddll:format_error(Error)]),
Res
@@ -2469,15 +2638,19 @@ sleep(Ms) when is_integer(Ms), Ms >= 0 ->
start_node(Config) when is_list(Config) ->
+ start_node(proplists:get_value(testcase, Config));
+start_node(Name) ->
+ start_node(Name, "").
+start_node(NodeName, Args) ->
Pa = filename:dirname(code:which(?MODULE)),
Name = list_to_atom(atom_to_list(?MODULE)
++ "-"
- ++ atom_to_list(proplists:get_value(testcase, Config))
+ ++ atom_to_list(NodeName)
++ "-"
++ integer_to_list(erlang:system_time(second))
++ "-"
++ integer_to_list(erlang:unique_integer([positive]))),
- test_server:start_node(Name, slave, [{args, "-pa "++Pa}]).
+ test_server:start_node(Name, slave, [{args, Args ++ " -pa "++Pa}]).
stop_node(Node) ->
test_server:stop_node(Node).
@@ -2491,14 +2664,6 @@ wait_deallocations() ->
end.
driver_alloc_size() ->
- case erlang:system_info(smp_support) of
- true ->
- ok;
- false ->
- %% driver_alloc also used by elements in lock-free queues,
- %% give these some time to be deallocated...
- receive after 100 -> ok end
- end,
wait_deallocations(),
case erlang:system_info({allocator_sizes, driver_alloc}) of
false ->
@@ -2518,3 +2683,57 @@ driver_alloc_size() ->
Sz0+Sz
end, 0, CS)
end.
+
+rpc(Config, Fun) ->
+ case proplists:get_value(node, Config) of
+ undefined ->
+ Fun();
+ Node ->
+ Self = self(),
+ Ref = make_ref(),
+ Pid = spawn(Node,
+ fun() ->
+ Result
+ = try Fun() of
+ Res -> Res
+ catch E:R:Stk ->
+ {'EXIT',E,R,Stk}
+ end,
+ Self ! {Ref, Result}
+ end),
+ MRef = monitor(process, Pid),
+ receive
+ {'DOWN', MRef, _Type, _Object, Info} ->
+ erlang:error({died, Pid, Info});
+ {Ref, {'EXIT',E,R,ST}} ->
+ erlang:demonitor(MRef, [flush]),
+ erlang:raise(E,R,ST);
+ {Ref, Ret} ->
+ erlang:demonitor(MRef, [flush]),
+ Ret;
+ Other ->
+ ct:fail(Other)
+ end
+ end.
+
+poll_pipe(Config) when is_list(Config) ->
+ %% ERL-647; we wouldn't see any events on EOF when polling a pipe using
+ %% kqueue(2).
+ case os:type() of
+ {unix, _} ->
+ Command = "erl -noshell -eval "
+ "'\"DATA\n\" = io:get_line(\"\"),"
+ "eof = io:get_line(\"\"),"
+ "halt()' <<< 'DATA'",
+ Ref = make_ref(),
+ Self = self(),
+ Pid = spawn(fun() -> os:cmd(Command), Self ! Ref end),
+ receive
+ Ref -> ok
+ after 5000 ->
+ exit(Pid, kill),
+ ct:fail("Stuck reading from stdin.")
+ end;
+ _ ->
+ {skipped, "Unix-only test"}
+ end.