diff options
Diffstat (limited to 'erts/emulator/test/nif_SUITE.erl')
-rw-r--r-- | erts/emulator/test/nif_SUITE.erl | 1444 |
1 files changed, 846 insertions, 598 deletions
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index af2b955184..a185b72341 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -22,14 +22,13 @@ %%-define(line_trace,true). -define(CHECK(Exp,Got), check(Exp,Got,?LINE)). -%%-define(CHECK(Exp,Got), ?line Exp = Got). +%%-define(CHECK(Exp,Got), Exp = Got). --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, - init_per_testcase/2, - end_per_testcase/2, basic/1, reload/1, upgrade/1, heap_frag/1, +-export([all/0, suite/0, + init_per_testcase/2, end_per_testcase/2, + basic/1, reload/1, upgrade/1, heap_frag/1, types/1, many_args/1, binaries/1, get_string/1, get_atom/1, maps/1, api_macros/1, @@ -42,7 +41,12 @@ otp_9668/1, consume_timeslice/1, dirty_nif/1, dirty_nif_send/1, dirty_nif_exception/1, call_dirty_nif_exception/1, nif_schedule/1, nif_exception/1, call_nif_exception/1, - nif_nan_and_inf/1, nif_atom_too_long/1 + nif_nan_and_inf/1, nif_atom_too_long/1, + nif_monotonic_time/1, nif_time_offset/1, nif_convert_time_unit/1, + nif_now_time/1, nif_cpu_time/1, nif_unique_integer/1, + nif_is_process_alive/1, nif_is_port_alive/1, + nif_term_to_binary/1, nif_binary_to_term/1, + nif_port_command/1 ]). -export([many_args_100/100]). @@ -72,182 +76,164 @@ all() -> otp_9828, otp_9668, consume_timeslice, nif_schedule, dirty_nif, dirty_nif_send, dirty_nif_exception, - nif_exception, nif_nan_and_inf, nif_atom_too_long + nif_exception, nif_nan_and_inf, nif_atom_too_long, + nif_monotonic_time, nif_time_offset, nif_convert_time_unit, + nif_now_time, nif_cpu_time, nif_unique_integer, + nif_is_process_alive, nif_is_port_alive, + nif_term_to_binary, nif_binary_to_term, + nif_port_command ]. -groups() -> - []. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - init_per_testcase(_Case, Config) -> -% ?line Dog = ?t:timetrap(?t:seconds(60*60*24)), Config. end_per_testcase(_Func, _Config) -> - %%Dog = ?config(watchdog, Config), - %%?t:timetrap_cancel(Dog), P1 = code:purge(nif_mod), Del = code:delete(nif_mod), P2 = code:purge(nif_mod), io:format("fin purged=~p, deleted=~p and then purged=~p\n",[P1,Del,P2]). -basic(doc) -> ["Basic smoke test of load_nif and a simple NIF call"]; -basic(suite) -> []; +%% Basic smoke test of load_nif and a simple NIF call basic(Config) when is_list(Config) -> ensure_lib_loaded(Config), - ?line true = (lib_version() =/= undefined), - ?line [{load,1,1,101},{lib_version,1,2,102}] = call_history(), - ?line [] = call_history(), - ?line true = lists:member(?MODULE, erlang:system_info(taints)), + true = (lib_version() =/= undefined), + [{load,1,1,101},{lib_version,1,2,102}] = call_history(), + [] = call_history(), + true = lists:member(?MODULE, erlang:system_info(taints)), ok. -reload(doc) -> ["Test reload callback in nif lib"]; -reload(suite) -> []; +%% Test reload callback in nif lib reload(Config) when is_list(Config) -> TmpMem = tmpmem(), ensure_lib_loaded(Config), - ?line Data = ?config(data_dir, Config), - ?line File = filename:join(Data, "nif_mod"), - ?line {ok,nif_mod,Bin} = compile:file(File, [binary,return_errors]), - ?line {module,nif_mod} = erlang:load_module(nif_mod,Bin), + Data = proplists:get_value(data_dir, Config), + File = filename:join(Data, "nif_mod"), + {ok,nif_mod,Bin} = compile:file(File, [binary,return_errors]), + {module,nif_mod} = erlang:load_module(nif_mod,Bin), - ?line ok = nif_mod:load_nif_lib(Config, 1), + ok = nif_mod:load_nif_lib(Config, 1), - ?line hold_nif_mod_priv_data(nif_mod:get_priv_data_ptr()), - ?line [{load,1,1,101},{get_priv_data_ptr,1,2,102}] = nif_mod_call_history(), + hold_nif_mod_priv_data(nif_mod:get_priv_data_ptr()), + [{load,1,1,101},{get_priv_data_ptr,1,2,102}] = nif_mod_call_history(), - ?line ok = nif_mod:load_nif_lib(Config, 2), - ?line 2 = nif_mod:lib_version(), - ?line [{reload,2,1,201},{lib_version,2,2,202}] = nif_mod_call_history(), + ok = nif_mod:load_nif_lib(Config, 2), + 2 = nif_mod:lib_version(), + [{reload,2,1,201},{lib_version,2,2,202}] = nif_mod_call_history(), - ?line ok = nif_mod:load_nif_lib(Config, 1), - ?line 1 = nif_mod:lib_version(), - ?line [{reload,1,1,101},{lib_version,1,2,102}] = nif_mod_call_history(), + ok = nif_mod:load_nif_lib(Config, 1), + 1 = nif_mod:lib_version(), + [{reload,1,1,101},{lib_version,1,2,102}] = nif_mod_call_history(), - ?line true = erlang:delete_module(nif_mod), - ?line [] = nif_mod_call_history(), + true = erlang:delete_module(nif_mod), + [] = nif_mod_call_history(), - %%?line false= check_process_code(Pid, nif_mod), - ?line true = erlang:purge_module(nif_mod), - ?line [{unload,1,3,103}] = nif_mod_call_history(), + %%false= check_process_code(Pid, nif_mod), + true = erlang:purge_module(nif_mod), + [{unload,1,3,103}] = nif_mod_call_history(), - ?line true = lists:member(?MODULE, erlang:system_info(taints)), - ?line true = lists:member(nif_mod, erlang:system_info(taints)), - ?line verify_tmpmem(TmpMem), + true = lists:member(?MODULE, erlang:system_info(taints)), + true = lists:member(nif_mod, erlang:system_info(taints)), + verify_tmpmem(TmpMem), ok. -upgrade(doc) -> ["Test upgrade callback in nif lib"]; -upgrade(suite) -> []; +%% Test upgrade callback in nif lib upgrade(Config) when is_list(Config) -> TmpMem = tmpmem(), ensure_lib_loaded(Config), - ?line Data = ?config(data_dir, Config), - ?line File = filename:join(Data, "nif_mod"), - ?line {ok,nif_mod,Bin} = compile:file(File, [binary,return_errors]), - ?line {module,nif_mod} = erlang:load_module(nif_mod,Bin), + Data = proplists:get_value(data_dir, Config), + File = filename:join(Data, "nif_mod"), + {ok,nif_mod,Bin} = compile:file(File, [binary,return_errors]), + {module,nif_mod} = erlang:load_module(nif_mod,Bin), - ?line ok = nif_mod:load_nif_lib(Config, 1), - ?line {Pid,MRef} = nif_mod:start(), - ?line 1 = call(Pid,lib_version), + ok = nif_mod:load_nif_lib(Config, 1), + {Pid,MRef} = nif_mod:start(), + 1 = call(Pid,lib_version), - ?line hold_nif_mod_priv_data(nif_mod:get_priv_data_ptr()), - ?line [{load,1,1,101},{lib_version,1,2,102},{get_priv_data_ptr,1,3,103}] = nif_mod_call_history(), + hold_nif_mod_priv_data(nif_mod:get_priv_data_ptr()), + [{load,1,1,101},{lib_version,1,2,102},{get_priv_data_ptr,1,3,103}] = nif_mod_call_history(), %% Module upgrade with same lib-version - ?line {module,nif_mod} = erlang:load_module(nif_mod,Bin), - ?line undefined = nif_mod:lib_version(), - ?line 1 = call(Pid,lib_version), - ?line [{lib_version,1,4,104}] = nif_mod_call_history(), + {module,nif_mod} = erlang:load_module(nif_mod,Bin), + undefined = nif_mod:lib_version(), + 1 = call(Pid,lib_version), + [{lib_version,1,4,104}] = nif_mod_call_history(), - ?line ok = nif_mod:load_nif_lib(Config, 1), - ?line 1 = nif_mod:lib_version(), - ?line [{upgrade,1,5,105},{lib_version,1,6,106}] = nif_mod_call_history(), + ok = nif_mod:load_nif_lib(Config, 1), + 1 = nif_mod:lib_version(), + [{upgrade,1,5,105},{lib_version,1,6,106}] = nif_mod_call_history(), - ?line upgraded = call(Pid,upgrade), - ?line false = check_process_code(Pid, nif_mod), - ?line true = erlang:purge_module(nif_mod), - ?line [{unload,1,7,107}] = nif_mod_call_history(), + upgraded = call(Pid,upgrade), + false = check_process_code(Pid, nif_mod), + true = erlang:purge_module(nif_mod), + [{unload,1,7,107}] = nif_mod_call_history(), - ?line 1 = nif_mod:lib_version(), - ?line [{lib_version,1,8,108}] = nif_mod_call_history(), + 1 = nif_mod:lib_version(), + [{lib_version,1,8,108}] = nif_mod_call_history(), - ?line true = erlang:delete_module(nif_mod), - ?line [] = nif_mod_call_history(), + true = erlang:delete_module(nif_mod), + [] = nif_mod_call_history(), - ?line Pid ! die, - ?line {'DOWN', MRef, process, Pid, normal} = receive_any(), - ?line false = check_process_code(Pid, nif_mod), - ?line true = erlang:purge_module(nif_mod), - ?line [{unload,1,9,109}] = nif_mod_call_history(), + Pid ! die, + {'DOWN', MRef, process, Pid, normal} = receive_any(), + false = check_process_code(Pid, nif_mod), + true = erlang:purge_module(nif_mod), + [{unload,1,9,109}] = nif_mod_call_history(), %% Module upgrade with different lib version - ?line {module,nif_mod} = erlang:load_module(nif_mod,Bin), - ?line undefined = nif_mod:lib_version(), - ?line {Pid2,MRef2} = nif_mod:start(), - ?line undefined = call(Pid2,lib_version), - - ?line ok = nif_mod:load_nif_lib(Config, 1), - ?line hold_nif_mod_priv_data(nif_mod:get_priv_data_ptr()), - ?line 1 = call(Pid2,lib_version), - ?line [{load,1,1,101},{get_priv_data_ptr,1,2,102},{lib_version,1,3,103}] = nif_mod_call_history(), - - ?line {module,nif_mod} = erlang:load_module(nif_mod,Bin), - ?line undefined = nif_mod:lib_version(), - ?line [] = nif_mod_call_history(), - ?line 1 = call(Pid2,lib_version), - ?line [{lib_version,1,4,104}] = nif_mod_call_history(), - - ?line ok = nif_mod:load_nif_lib(Config, 2), - ?line 2 = nif_mod:lib_version(), - ?line [{upgrade,2,1,201},{lib_version,2,2,202}] = nif_mod_call_history(), - - ?line 1 = call(Pid2,lib_version), - ?line [{lib_version,1,5,105}] = nif_mod_call_history(), - - ?line upgraded = call(Pid2,upgrade), - ?line false = check_process_code(Pid2, nif_mod), - ?line true = erlang:purge_module(nif_mod), - ?line [{unload,1,6,106}] = nif_mod_call_history(), - - ?line 2 = nif_mod:lib_version(), - ?line [{lib_version,2,3,203}] = nif_mod_call_history(), - - ?line true = erlang:delete_module(nif_mod), - ?line [] = nif_mod_call_history(), - - ?line Pid2 ! die, - ?line {'DOWN', MRef2, process, Pid2, normal} = receive_any(), - ?line false= check_process_code(Pid2, nif_mod), - ?line true = erlang:purge_module(nif_mod), - ?line [{unload,2,4,204}] = nif_mod_call_history(), - - ?line true = lists:member(?MODULE, erlang:system_info(taints)), - ?line true = lists:member(nif_mod, erlang:system_info(taints)), - ?line verify_tmpmem(TmpMem), + {module,nif_mod} = erlang:load_module(nif_mod,Bin), + undefined = nif_mod:lib_version(), + {Pid2,MRef2} = nif_mod:start(), + undefined = call(Pid2,lib_version), + + ok = nif_mod:load_nif_lib(Config, 1), + hold_nif_mod_priv_data(nif_mod:get_priv_data_ptr()), + 1 = call(Pid2,lib_version), + [{load,1,1,101},{get_priv_data_ptr,1,2,102},{lib_version,1,3,103}] = nif_mod_call_history(), + + {module,nif_mod} = erlang:load_module(nif_mod,Bin), + undefined = nif_mod:lib_version(), + [] = nif_mod_call_history(), + 1 = call(Pid2,lib_version), + [{lib_version,1,4,104}] = nif_mod_call_history(), + + ok = nif_mod:load_nif_lib(Config, 2), + 2 = nif_mod:lib_version(), + [{upgrade,2,1,201},{lib_version,2,2,202}] = nif_mod_call_history(), + + 1 = call(Pid2,lib_version), + [{lib_version,1,5,105}] = nif_mod_call_history(), + + upgraded = call(Pid2,upgrade), + false = check_process_code(Pid2, nif_mod), + true = erlang:purge_module(nif_mod), + [{unload,1,6,106}] = nif_mod_call_history(), + + 2 = nif_mod:lib_version(), + [{lib_version,2,3,203}] = nif_mod_call_history(), + + true = erlang:delete_module(nif_mod), + [] = nif_mod_call_history(), + + Pid2 ! die, + {'DOWN', MRef2, process, Pid2, normal} = receive_any(), + false= check_process_code(Pid2, nif_mod), + true = erlang:purge_module(nif_mod), + [{unload,2,4,204}] = nif_mod_call_history(), + + true = lists:member(?MODULE, erlang:system_info(taints)), + true = lists:member(nif_mod, erlang:system_info(taints)), + verify_tmpmem(TmpMem), ok. -heap_frag(doc) -> ["Test NIF building heap fragments"]; -heap_frag(suite) -> []; +%% Test NIF building heap fragments heap_frag(Config) when is_list(Config) -> TmpMem = tmpmem(), ensure_lib_loaded(Config), heap_frag_do(1,1000000), - ?line verify_tmpmem(TmpMem), + verify_tmpmem(TmpMem), ok. heap_frag_do(N, Max) when N > Max -> @@ -258,12 +244,11 @@ heap_frag_do(N, Max) -> L = list_seq(N), heap_frag_do(((N*5) div 4) + 1, Max). -types(doc) -> ["Type tests"]; -types(suite) -> []; +%% Type tests types(Config) when is_list(Config) -> TmpMem = tmpmem(), ensure_lib_loaded(Config), - ?line ok = type_test(), + ok = type_test(), lists:foreach(fun(Tpl) -> Lst = erlang:tuple_to_list(Tpl), Lst = tuple_2_list(Tpl) @@ -288,18 +273,18 @@ types(Config) when is_list(Config) -> R1 = echo_int(I), %%io:format("echo_int(~p) -> ~p\n", [I, R1]), R2 = my_echo_int(I, Limits), - ?line R1 = R2, - ?line true = (R1 =:= R2), - ?line true = (R1 == R2) + R1 = R2, + true = (R1 =:= R2), + true = (R1 == R2) end, int_list()), - ?line verify_tmpmem(TmpMem), - ?line true = (compare(-1294536544000, -1178704800000) < 0), - ?line true = (compare(-1178704800000, -1294536544000) > 0), - ?line true = (compare(-295147905179352825856, -36893488147419103232) < 0), - ?line true = (compare(-36893488147419103232, -295147905179352825856) > 0), - ?line true = (compare(-29514790517935282585612345678, -36893488147419103232) < 0), - ?line true = (compare(-36893488147419103232, -29514790517935282585612345678) > 0), + verify_tmpmem(TmpMem), + true = (compare(-1294536544000, -1178704800000) < 0), + true = (compare(-1178704800000, -1294536544000) > 0), + true = (compare(-295147905179352825856, -36893488147419103232) < 0), + true = (compare(-36893488147419103232, -295147905179352825856) > 0), + true = (compare(-29514790517935282585612345678, -36893488147419103232) < 0), + true = (compare(-36893488147419103232, -29514790517935282585612345678) > 0), ok. int_list() -> @@ -327,15 +312,15 @@ eq_cmp(A,B) -> eq_cmp_do({A,B},{A,B}). eq_cmp_do(A,B) -> - %%?t:format("compare ~p and ~p\n",[A,B]), + %%io:format("compare ~p and ~p\n",[A,B]), Eq = (A =:= B), - ?line Eq = is_identical(A,B), - ?line Cmp = if + Eq = is_identical(A,B), + Cmp = if A < B -> -1; A == B -> 0; A > B -> 1 end, - ?line Cmp = case compare(A,B) of + Cmp = case compare(A,B) of C when is_integer(C), C < 0 -> -1; 0 -> 0; C when is_integer(C) -> 1 @@ -343,47 +328,45 @@ eq_cmp_do(A,B) -> ok. -many_args(doc) -> ["Test NIF with many arguments"]; -many_args(suite) -> []; +%% Test NIF with many arguments many_args(Config) when is_list(Config) -> TmpMem = tmpmem(), - ?line ensure_lib_loaded(Config ,1), - ?line ok = apply(?MODULE,many_args_100,lists:seq(1,100)), - ?line ok = many_args_100(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100), - ?line verify_tmpmem(TmpMem), + ensure_lib_loaded(Config ,1), + ok = apply(?MODULE,many_args_100,lists:seq(1,100)), + ok = many_args_100(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100), + verify_tmpmem(TmpMem), ok. -binaries(doc) -> ["Test NIF binary handling."]; -binaries(suite) -> []; +%% Test NIF binary handling. binaries(Config) when is_list(Config) -> TmpMem = tmpmem(), - ?line ensure_lib_loaded(Config, 1), - ?line RefcBin = list_to_binary(lists:seq(1,255)), - ?line RefcBin = clone_bin(RefcBin), - ?line HeapBin = list_to_binary(lists:seq(1,20)), - ?line HeapBin = clone_bin(HeapBin), - ?line <<_:8,Sub1:6/binary,_/binary>> = RefcBin, - ?line <<_:8,Sub2:6/binary,_/binary>> = HeapBin, - ?line Sub1 = Sub2, - ?line Sub1 = clone_bin(Sub1), - ?line Sub2 = clone_bin(Sub2), - ?line <<_:9,Sub3:6/binary,_/bitstring>> = RefcBin, - ?line <<_:9,Sub4:6/binary,_/bitstring>> = HeapBin, - ?line Sub3 = Sub4, - ?line Sub3 = clone_bin(Sub3), - ?line Sub4 = clone_bin(Sub4), + ensure_lib_loaded(Config, 1), + RefcBin = list_to_binary(lists:seq(1,255)), + RefcBin = clone_bin(RefcBin), + HeapBin = list_to_binary(lists:seq(1,20)), + HeapBin = clone_bin(HeapBin), + <<_:8,Sub1:6/binary,_/binary>> = RefcBin, + <<_:8,Sub2:6/binary,_/binary>> = HeapBin, + Sub1 = Sub2, + Sub1 = clone_bin(Sub1), + Sub2 = clone_bin(Sub2), + <<_:9,Sub3:6/binary,_/bitstring>> = RefcBin, + <<_:9,Sub4:6/binary,_/bitstring>> = HeapBin, + Sub3 = Sub4, + Sub3 = clone_bin(Sub3), + Sub4 = clone_bin(Sub4), %% When NIFs get bitstring support - %%?line <<_:8,Sub5:27/bitstring,_/bitstring>> = RefcBin, - %%?line <<_:8,Sub6:27/bitstring,_/bitstring>> = HeapBin, - %%?line Sub5 = Sub6, - %%?line Sub5 = clone_bin(Sub5), - %%?line Sub6 = clone_bin(Sub6), - %%?line <<_:9,Sub7:27/bitstring,_/bitstring>> = RefcBin, - %%?line <<_:9,Sub8:27/bitstring,_/bitstring>> = HeapBin, - %%?line Sub7 = Sub8, - %%?line Sub7 = clone_bin(Sub7), - %%?line Sub8 = clone_bin(Sub8), - %%?line <<>> = clone_bin(<<>>), + %%<<_:8,Sub5:27/bitstring,_/bitstring>> = RefcBin, + %%<<_:8,Sub6:27/bitstring,_/bitstring>> = HeapBin, + %%Sub5 = Sub6, + %%Sub5 = clone_bin(Sub5), + %%Sub6 = clone_bin(Sub6), + %%<<_:9,Sub7:27/bitstring,_/bitstring>> = RefcBin, + %%<<_:9,Sub8:27/bitstring,_/bitstring>> = HeapBin, + %%Sub7 = Sub8, + %%Sub7 = clone_bin(Sub7), + %%Sub8 = clone_bin(Sub8), + %%<<>> = clone_bin(<<>>), <<_:8,SubBinA:200/binary,_/binary>> = RefcBin, <<_:9,SubBinB:200/binary,_/bitstring>> = RefcBin, @@ -396,56 +379,53 @@ binaries(Config) when is_list(Config) -> test_make_sub_bin(SubBinC), test_make_sub_bin(SubBinD), - ?line verify_tmpmem(TmpMem), + verify_tmpmem(TmpMem), ok. test_make_sub_bin(Bin) -> Size = byte_size(Bin), Rest10 = Size - 10, Rest1 = Size - 1, - ?line Bin = make_sub_bin(Bin, 0, Size), + Bin = make_sub_bin(Bin, 0, Size), <<_:10/binary,Sub0:Rest10/binary>> = Bin, - ?line Sub0 = make_sub_bin(Bin, 10, Rest10), + Sub0 = make_sub_bin(Bin, 10, Rest10), <<Sub1:10/binary,_/binary>> = Bin, - ?line Sub1 = make_sub_bin(Bin, 0, 10), + Sub1 = make_sub_bin(Bin, 0, 10), <<_:7/binary,Sub2:10/binary,_/binary>> = Bin, - ?line Sub2 = make_sub_bin(Bin, 7, 10), - ?line <<>> = make_sub_bin(Bin, 0, 0), - ?line <<>> = make_sub_bin(Bin, 10, 0), - ?line <<>> = make_sub_bin(Bin, Rest1, 0), - ?line <<>> = make_sub_bin(Bin, Size, 0), + Sub2 = make_sub_bin(Bin, 7, 10), + <<>> = make_sub_bin(Bin, 0, 0), + <<>> = make_sub_bin(Bin, 10, 0), + <<>> = make_sub_bin(Bin, Rest1, 0), + <<>> = make_sub_bin(Bin, Size, 0), ok. -get_string(doc) -> ["Test enif_get_string"]; -get_string(suite) -> []; +%% Test enif_get_string get_string(Config) when is_list(Config) -> - ?line ensure_lib_loaded(Config, 1), - ?line {7, <<"hejsan",0,_:3/binary>>} = string_to_bin("hejsan",10), - ?line {7, <<"hejsan",0,_>>} = string_to_bin("hejsan",8), - ?line {7, <<"hejsan",0>>} = string_to_bin("hejsan",7), - ?line {-6, <<"hejsa",0>>} = string_to_bin("hejsan",6), - ?line {-5, <<"hejs",0>>} = string_to_bin("hejsan",5), - ?line {-1, <<0>>} = string_to_bin("hejsan",1), - ?line {0, <<>>} = string_to_bin("hejsan",0), - ?line {1, <<0>>} = string_to_bin("",1), - ?line {0, <<>>} = string_to_bin("",0), + ensure_lib_loaded(Config, 1), + {7, <<"hejsan",0,_:3/binary>>} = string_to_bin("hejsan",10), + {7, <<"hejsan",0,_>>} = string_to_bin("hejsan",8), + {7, <<"hejsan",0>>} = string_to_bin("hejsan",7), + {-6, <<"hejsa",0>>} = string_to_bin("hejsan",6), + {-5, <<"hejs",0>>} = string_to_bin("hejsan",5), + {-1, <<0>>} = string_to_bin("hejsan",1), + {0, <<>>} = string_to_bin("hejsan",0), + {1, <<0>>} = string_to_bin("",1), + {0, <<>>} = string_to_bin("",0), ok. -get_atom(doc) -> ["Test enif_get_atom"]; -get_atom(suite) -> []; +%% Test enif_get_atom get_atom(Config) when is_list(Config) -> - ?line ensure_lib_loaded(Config, 1), - ?line {7, <<"hejsan",0,_:3/binary>>} = atom_to_bin(hejsan,10), - ?line {7, <<"hejsan",0,_>>} = atom_to_bin(hejsan,8), - ?line {7, <<"hejsan",0>>} = atom_to_bin(hejsan,7), - ?line {0, <<_:6/binary>>} = atom_to_bin(hejsan,6), - ?line {0, <<>>} = atom_to_bin(hejsan,0), - ?line {1, <<0>>} = atom_to_bin('',1), - ?line {0, <<>>} = atom_to_bin('',0), + ensure_lib_loaded(Config, 1), + {7, <<"hejsan",0,_:3/binary>>} = atom_to_bin(hejsan,10), + {7, <<"hejsan",0,_>>} = atom_to_bin(hejsan,8), + {7, <<"hejsan",0>>} = atom_to_bin(hejsan,7), + {0, <<_:6/binary>>} = atom_to_bin(hejsan,6), + {0, <<>>} = atom_to_bin(hejsan,0), + {1, <<0>>} = atom_to_bin('',1), + {0, <<>>} = atom_to_bin('',0), ok. -maps(doc) -> ["Test NIF maps handling."]; -maps(suite) -> []; +%% Test NIF maps handling. maps(Config) when is_list(Config) -> TmpMem = tmpmem(), Pairs = [{adam, "bert"}] ++ @@ -492,31 +472,28 @@ maps(Config) when is_list(Config) -> ok. -api_macros(doc) -> ["Test macros enif_make_list<N> and enif_make_tuple<N>"]; -api_macros(suite) -> []; +%% Test macros enif_make_list<N> and enif_make_tuple<N> api_macros(Config) when is_list(Config) -> - ?line ensure_lib_loaded(Config, 1), + ensure_lib_loaded(Config, 1), Expected = {[lists:seq(1,N) || N <- lists:seq(1,9)], [list_to_tuple(lists:seq(1,N)) || N <- lists:seq(1,9)] }, - ?line Expected = macros(list_to_tuple(lists:seq(1,9))), + Expected = macros(list_to_tuple(lists:seq(1,9))), ok. -from_array(doc) -> ["enif_make_[tuple|list]_from_array"]; -from_array(suite) -> []; +%% enif_make_[tuple|list]_from_array from_array(Config) when is_list(Config) -> - ?line ensure_lib_loaded(Config, 1), + ensure_lib_loaded(Config, 1), lists:foreach(fun(Tpl) -> Lst = tuple_to_list(Tpl), - ?line {Lst,Tpl} = tuple_2_list_and_tuple(Tpl) + {Lst,Tpl} = tuple_2_list_and_tuple(Tpl) end, [{}, {1,2,3}, {[4,5],[],{},{6,7}}, {{}}, {[]}]), ok. -iolist_as_binary(doc) -> ["enif_inspect_iolist_as_binary"]; -iolist_as_binary(suite) -> []; +%% enif_inspect_iolist_as_binary iolist_as_binary(Config) when is_list(Config) -> - ?line ensure_lib_loaded(Config, 1), + ensure_lib_loaded(Config, 1), TmpMem = tmpmem(), List = [<<"hejsan">>, <<>>, [], [17], [<<>>], [127,128,255,0], @@ -525,18 +502,17 @@ iolist_as_binary(Config) when is_list(Config) -> lists:foreach(fun(IoL) -> B1 = erlang:iolist_to_binary(IoL), - ?line B2 = iolist_2_bin(IoL), - ?line B1 = B2 + B2 = iolist_2_bin(IoL), + B1 = B2 end, List), - ?line verify_tmpmem(TmpMem), + verify_tmpmem(TmpMem), ok. -resource(doc) -> ["Test memory managed objects, aka 'resources'"]; -resource(suite) -> []; +%% Test memory managed objects, aka 'resources' resource(Config) when is_list(Config) -> - ?line ensure_lib_loaded(Config, 1), - ?line Type = get_resource_type(0), + ensure_lib_loaded(Config, 1), + Type = get_resource_type(0), resource_hugo(Type), resource_otto(Type), resource_new(Type), @@ -546,76 +522,75 @@ resource(Config) when is_list(Config) -> resource_hugo(Type) -> DtorCall = resource_hugo_do(Type), erlang:garbage_collect(), - ?line DtorCall = last_resource_dtor_call(), + DtorCall = last_resource_dtor_call(), ok. resource_hugo_do(Type) -> HugoBin = <<"Hugo Hacker">>, - ?line HugoPtr = alloc_resource(Type, HugoBin), - ?line Hugo = make_resource(HugoPtr), - ?line <<>> = Hugo, + HugoPtr = alloc_resource(Type, HugoBin), + Hugo = make_resource(HugoPtr), + <<>> = Hugo, release_resource(HugoPtr), erlang:garbage_collect(), - ?line {HugoPtr,HugoBin} = get_resource(Type,Hugo), + {HugoPtr,HugoBin} = get_resource(Type,Hugo), Pid = spawn_link(fun() -> - receive {Pid, Type, Resource, Ptr, Bin} -> - Pid ! {self(), got_it}, - receive {Pid, check_it} -> - ?line {Ptr,Bin} = get_resource(Type,Resource), - Pid ! {self(), ok} - end - end - end), + receive {Pid, Type, Resource, Ptr, Bin} -> + Pid ! {self(), got_it}, + receive {Pid, check_it} -> + {Ptr,Bin} = get_resource(Type,Resource), + Pid ! {self(), ok} + end + end + end), Pid ! {self(), Type, Hugo, HugoPtr, HugoBin}, - ?line {Pid, got_it} = receive_any(), + {Pid, got_it} = receive_any(), erlang:garbage_collect(), % just to make our ProcBin move in memory Pid ! {self(), check_it}, - ?line {Pid, ok} = receive_any(), - ?line [] = last_resource_dtor_call(), - ?line {HugoPtr,HugoBin} = get_resource(Type,Hugo), + {Pid, ok} = receive_any(), + [] = last_resource_dtor_call(), + {HugoPtr,HugoBin} = get_resource(Type,Hugo), {HugoPtr, HugoBin, 1}. resource_otto(Type) -> {OttoPtr, OttoBin} = resource_otto_do(Type), erlang:garbage_collect(), - ?line [] = last_resource_dtor_call(), + [] = last_resource_dtor_call(), release_resource(OttoPtr), - ?line {OttoPtr,OttoBin,1} = last_resource_dtor_call(), + {OttoPtr,OttoBin,1} = last_resource_dtor_call(), ok. resource_otto_do(Type) -> OttoBin = <<"Otto Ordonnans">>, - ?line OttoPtr = alloc_resource(Type, OttoBin), - ?line Otto = make_resource(OttoPtr), - ?line <<>> = Otto, + OttoPtr = alloc_resource(Type, OttoBin), + Otto = make_resource(OttoPtr), + <<>> = Otto, %% forget resource term but keep referenced by NIF {OttoPtr, OttoBin}. resource_new(Type) -> - ?line {PtrB,BinB} = resource_new_do1(Type), + {PtrB,BinB} = resource_new_do1(Type), erlang:garbage_collect(), - ?line {PtrB,BinB,1} = last_resource_dtor_call(), + {PtrB,BinB,1} = last_resource_dtor_call(), ok. resource_new_do1(Type) -> - ?line {{PtrA,BinA}, {ResB,PtrB,BinB}} = resource_new_do2(Type), + {{PtrA,BinA}, {ResB,PtrB,BinB}} = resource_new_do2(Type), erlang:garbage_collect(), - ?line {PtrA,BinA,1} = last_resource_dtor_call(), - ?line {PtrB,BinB} = get_resource(Type, ResB), + {PtrA,BinA,1} = last_resource_dtor_call(), + {PtrB,BinB} = get_resource(Type, ResB), %% forget ResB and make it garbage {PtrB,BinB}. resource_new_do2(Type) -> BinA = <<"NewA">>, BinB = <<"NewB">>, - ?line ResA = make_new_resource(Type, BinA), - ?line ResB = make_new_resource(Type, BinB), - ?line <<>> = ResA, - ?line <<>> = ResB, - ?line {PtrA,BinA} = get_resource(Type, ResA), - ?line {PtrB,BinB} = get_resource(Type, ResB), - ?line true = (PtrA =/= PtrB), - ?line [] = last_resource_dtor_call(), + ResA = make_new_resource(Type, BinA), + ResB = make_new_resource(Type, BinB), + <<>> = ResA, + <<>> = ResB, + {PtrA,BinA} = get_resource(Type, ResA), + {PtrB,BinB} = get_resource(Type, ResB), + true = (PtrA =/= PtrB), %% forget ResA and make it garbage {{PtrA,BinA}, {ResB,PtrB,BinB}}. @@ -624,22 +599,21 @@ resource_neg(TypeA) -> catch exit(42), % dummy exception to purge saved stacktraces from earlier exception erlang:garbage_collect(), - ?line {_,_,2} = last_resource_dtor_call(), + {_,_,2} = last_resource_dtor_call(), ok. resource_neg_do(TypeA) -> TypeB = get_resource_type(1), ResA = make_new_resource(TypeA, <<"Arnold">>), ResB= make_new_resource(TypeB, <<"Bobo">>), - ?line {'EXIT',{badarg,_}} = (catch get_resource(TypeA, ResB)), - ?line {'EXIT',{badarg,_}} = (catch get_resource(TypeB, ResA)), + {'EXIT',{badarg,_}} = (catch get_resource(TypeA, ResB)), + {'EXIT',{badarg,_}} = (catch get_resource(TypeB, ResA)), ok. -resource_binary(doc) -> ["Test enif_make_resource_binary"]; -resource_binary(suite) -> []; +%% Test enif_make_resource_binary resource_binary(Config) when is_list(Config) -> - ?line ensure_lib_loaded(Config, 1), - ?line {Ptr,Bin} = resource_binary_do(), + ensure_lib_loaded(Config, 1), + {Ptr,Bin} = resource_binary_do(), erlang:garbage_collect(), Last = last_resource_dtor_call(), ?CHECK({Ptr,Bin,1}, Last), @@ -647,58 +621,57 @@ resource_binary(Config) when is_list(Config) -> resource_binary_do() -> Bin = <<"Hej Hopp i lingonskogen">>, - ?line {Ptr,ResBin1} = make_new_resource_binary(Bin), - ?line ResBin1 = Bin, - ?line ResInfo = {Ptr,_} = get_resource(binary_resource_type,ResBin1), + {Ptr,ResBin1} = make_new_resource_binary(Bin), + ResBin1 = Bin, + ResInfo = {Ptr,_} = get_resource(binary_resource_type,ResBin1), Papa = self(), Forwarder = spawn_link(fun() -> forwarder(Papa) end), io:format("sending to forwarder pid=~p\n",[Forwarder]), Forwarder ! ResBin1, ResBin2 = receive_any(), - ?line ResBin2 = ResBin1, - ?line ResInfo = get_resource(binary_resource_type,ResBin2), + ResBin2 = ResBin1, + ResInfo = get_resource(binary_resource_type,ResBin2), Forwarder ! terminate, - ?line {Forwarder, 1} = receive_any(), + {Forwarder, 1} = receive_any(), erlang:garbage_collect(), - ?line ResInfo = get_resource(binary_resource_type,ResBin1), - ?line ResInfo = get_resource(binary_resource_type,ResBin2), + ResInfo = get_resource(binary_resource_type,ResBin1), + ResInfo = get_resource(binary_resource_type,ResBin2), ResInfo. -define(RT_CREATE,1). -define(RT_TAKEOVER,2). -resource_takeover(doc) -> ["Test resource takeover by module reload and upgrade"]; -resource_takeover(suite) -> []; +%% Test resource takeover by module reload and upgrade resource_takeover(Config) when is_list(Config) -> TmpMem = tmpmem(), ensure_lib_loaded(Config), - ?line Data = ?config(data_dir, Config), - ?line File = filename:join(Data, "nif_mod"), - ?line {ok,nif_mod,ModBin} = compile:file(File, [binary,return_errors]), - ?line {module,nif_mod} = erlang:load_module(nif_mod,ModBin), - - ?line ok = nif_mod:load_nif_lib(Config, 1, - [{resource_type, 0, ?RT_CREATE, "resource_type_A",resource_dtor_A, - ?RT_CREATE}, - {resource_type, 1, ?RT_CREATE, "resource_type_null_A",null, - ?RT_CREATE}, - {resource_type, 2, ?RT_CREATE bor ?RT_TAKEOVER, "resource_type_A_null",resource_dtor_A, - ?RT_CREATE}, - {resource_type, 3, ?RT_CREATE, "resource_type_B_goneX",resource_dtor_B, - ?RT_CREATE}, - {resource_type, 4, ?RT_CREATE, "resource_type_null_goneX",null, - ?RT_CREATE}, - {resource_type, null, ?RT_TAKEOVER, "Pink unicorn", resource_dtor_A, - ?RT_TAKEOVER} - ]), - - ?line hold_nif_mod_priv_data(nif_mod:get_priv_data_ptr()), - ?line [{load,1,1,101},{get_priv_data_ptr,1,2,102}] = nif_mod_call_history(), + Data = proplists:get_value(data_dir, Config), + File = filename:join(Data, "nif_mod"), + {ok,nif_mod,ModBin} = compile:file(File, [binary,return_errors]), + {module,nif_mod} = erlang:load_module(nif_mod,ModBin), - ?line {Holder, _MRef} = spawn_opt(fun resource_holder/0, [link, monitor]), + ok = nif_mod:load_nif_lib(Config, 1, + [{resource_type, 0, ?RT_CREATE, "resource_type_A",resource_dtor_A, + ?RT_CREATE}, + {resource_type, 1, ?RT_CREATE, "resource_type_null_A",null, + ?RT_CREATE}, + {resource_type, 2, ?RT_CREATE bor ?RT_TAKEOVER, "resource_type_A_null",resource_dtor_A, + ?RT_CREATE}, + {resource_type, 3, ?RT_CREATE, "resource_type_B_goneX",resource_dtor_B, + ?RT_CREATE}, + {resource_type, 4, ?RT_CREATE, "resource_type_null_goneX",null, + ?RT_CREATE}, + {resource_type, null, ?RT_TAKEOVER, "Pink unicorn", resource_dtor_A, + ?RT_TAKEOVER} + ]), + + hold_nif_mod_priv_data(nif_mod:get_priv_data_ptr()), + [{load,1,1,101},{get_priv_data_ptr,1,2,102}] = nif_mod_call_history(), + + {Holder, _MRef} = spawn_opt(fun resource_holder/0, [link, monitor]), {A1,BinA1} = make_resource(0,Holder,"A1"), {A2,BinA2} = make_resource(0,Holder,"A2"), @@ -718,91 +691,91 @@ resource_takeover(Config) when is_list(Config) -> {NGX1,_BinNGX1} = make_resource(4,Holder,"NGX1"), {NGX2,_BinNGX2} = make_resource(4,Holder,"NGX2"), - ?line [] = nif_mod_call_history(), + [] = nif_mod_call_history(), - ?line ok = forget_resource(A1), - ?line [{{resource_dtor_A_v1,BinA1},1,3,103}] = nif_mod_call_history(), + ok = forget_resource(A1), + [{{resource_dtor_A_v1,BinA1},1,3,103}] = nif_mod_call_history(), - ?line ok = forget_resource(NA1), - ?line [] = nif_mod_call_history(), % no dtor + ok = forget_resource(NA1), + [] = nif_mod_call_history(), % no dtor - ?line ok = forget_resource(AN1), + ok = forget_resource(AN1), ?CHECK([{{resource_dtor_A_v1,BinAN1},1,4,104}] , nif_mod_call_history()), - ?line ok = forget_resource(BGX1), + ok = forget_resource(BGX1), ?CHECK([{{resource_dtor_B_v1,BinBGX1},1,5,105}], nif_mod_call_history()), - ?line ok = forget_resource(NGX1), + ok = forget_resource(NGX1), ?CHECK([], nif_mod_call_history()), % no dtor - ?line ok = nif_mod:load_nif_lib(Config, 2, - [{resource_type, 0, ?RT_TAKEOVER, "resource_type_A",resource_dtor_A, - ?RT_TAKEOVER}, - {resource_type, 1, ?RT_TAKEOVER bor ?RT_CREATE, "resource_type_null_A",resource_dtor_A, - ?RT_TAKEOVER}, - {resource_type, 2, ?RT_TAKEOVER, "resource_type_A_null",null, - ?RT_TAKEOVER}, - {resource_type, null, ?RT_TAKEOVER, "Pink unicorn", resource_dtor_A, - ?RT_TAKEOVER}, - {resource_type, null, ?RT_CREATE, "resource_type_B_goneX",resource_dtor_B, - ?RT_CREATE}, - {resource_type, null, ?RT_CREATE, "resource_type_null_goneX",null, - ?RT_CREATE}, - {resource_type, 3, ?RT_CREATE, "resource_type_B_goneY",resource_dtor_B, - ?RT_CREATE}, - {resource_type, 4, ?RT_CREATE, "resource_type_null_goneY",null, - ?RT_CREATE} - ]), + ok = nif_mod:load_nif_lib(Config, 2, + [{resource_type, 0, ?RT_TAKEOVER, "resource_type_A",resource_dtor_A, + ?RT_TAKEOVER}, + {resource_type, 1, ?RT_TAKEOVER bor ?RT_CREATE, "resource_type_null_A",resource_dtor_A, + ?RT_TAKEOVER}, + {resource_type, 2, ?RT_TAKEOVER, "resource_type_A_null",null, + ?RT_TAKEOVER}, + {resource_type, null, ?RT_TAKEOVER, "Pink unicorn", resource_dtor_A, + ?RT_TAKEOVER}, + {resource_type, null, ?RT_CREATE, "resource_type_B_goneX",resource_dtor_B, + ?RT_CREATE}, + {resource_type, null, ?RT_CREATE, "resource_type_null_goneX",null, + ?RT_CREATE}, + {resource_type, 3, ?RT_CREATE, "resource_type_B_goneY",resource_dtor_B, + ?RT_CREATE}, + {resource_type, 4, ?RT_CREATE, "resource_type_null_goneY",null, + ?RT_CREATE} + ]), ?CHECK([{reload,2,1,201}], nif_mod_call_history()), - ?line BinA2 = read_resource(0,A2), - ?line ok = forget_resource(A2), + BinA2 = read_resource(0,A2), + ok = forget_resource(A2), ?CHECK([{{resource_dtor_A_v2,BinA2},2,2,202}], nif_mod_call_history()), - ?line ok = forget_resource(NA2), + ok = forget_resource(NA2), ?CHECK([{{resource_dtor_A_v2,BinNA2},2,3,203}], nif_mod_call_history()), - ?line ok = forget_resource(AN2), + ok = forget_resource(AN2), ?CHECK([], nif_mod_call_history()), % no dtor - ?line ok = forget_resource(BGX2), % calling dtor in orphan library v1 still loaded + ok = forget_resource(BGX2), % calling dtor in orphan library v1 still loaded ?CHECK([{{resource_dtor_B_v1,BinBGX2},1,6,106}], nif_mod_call_history()), % How to test that lib v1 is closed here? - ?line ok = forget_resource(NGX2), + ok = forget_resource(NGX2), ?CHECK([], nif_mod_call_history()), % no dtor {BGY1,BinBGY1} = make_resource(3,Holder,"BGY1"), {NGY1,_BinNGY1} = make_resource(4,Holder,"NGY1"), %% Module upgrade with same lib-version - ?line {module,nif_mod} = erlang:load_module(nif_mod,ModBin), - ?line undefined = nif_mod:lib_version(), - ?line ok = nif_mod:load_nif_lib(Config, 2, - [{resource_type, 2, ?RT_TAKEOVER, "resource_type_A",resource_dtor_B, - ?RT_TAKEOVER}, - {resource_type, 0, ?RT_TAKEOVER bor ?RT_CREATE, "resource_type_null_A",null, - ?RT_TAKEOVER}, - {resource_type, 1, ?RT_TAKEOVER, "resource_type_A_null",resource_dtor_A, - ?RT_TAKEOVER}, - {resource_type, null, ?RT_TAKEOVER, "Pink elephant", resource_dtor_A, - ?RT_TAKEOVER}, - {resource_type, 3, ?RT_CREATE, "resource_type_B_goneZ",resource_dtor_B, - ?RT_CREATE}, - {resource_type, 4, ?RT_CREATE, "resource_type_null_goneZ",null, - ?RT_CREATE} - ]), - - ?line 2 = nif_mod:lib_version(), + {module,nif_mod} = erlang:load_module(nif_mod,ModBin), + undefined = nif_mod:lib_version(), + ok = nif_mod:load_nif_lib(Config, 2, + [{resource_type, 2, ?RT_TAKEOVER, "resource_type_A",resource_dtor_B, + ?RT_TAKEOVER}, + {resource_type, 0, ?RT_TAKEOVER bor ?RT_CREATE, "resource_type_null_A",null, + ?RT_TAKEOVER}, + {resource_type, 1, ?RT_TAKEOVER, "resource_type_A_null",resource_dtor_A, + ?RT_TAKEOVER}, + {resource_type, null, ?RT_TAKEOVER, "Pink elephant", resource_dtor_A, + ?RT_TAKEOVER}, + {resource_type, 3, ?RT_CREATE, "resource_type_B_goneZ",resource_dtor_B, + ?RT_CREATE}, + {resource_type, 4, ?RT_CREATE, "resource_type_null_goneZ",null, + ?RT_CREATE} + ]), + + 2 = nif_mod:lib_version(), ?CHECK([{upgrade,2,4,204},{lib_version,2,5,205}], nif_mod_call_history()), - ?line ok = forget_resource(A3), + ok = forget_resource(A3), ?CHECK([{{resource_dtor_B_v2,BinA3},2,6,206}], nif_mod_call_history()), - ?line ok = forget_resource(NA3), + ok = forget_resource(NA3), ?CHECK([], nif_mod_call_history()), - ?line ok = forget_resource(AN3), + ok = forget_resource(AN3), ?CHECK([{{resource_dtor_A_v2,BinAN3},2,7,207}], nif_mod_call_history()), {A4,BinA4} = make_resource(2,Holder, "A4"), @@ -812,19 +785,19 @@ resource_takeover(Config) when is_list(Config) -> {BGZ1,BinBGZ1} = make_resource(3,Holder,"BGZ1"), {NGZ1,_BinNGZ1} = make_resource(4,Holder,"NGZ1"), - ?line false = code:purge(nif_mod), - ?line [] = nif_mod_call_history(), + false = code:purge(nif_mod), + [] = nif_mod_call_history(), - ?line ok = forget_resource(NGY1), - ?line [] = nif_mod_call_history(), + ok = forget_resource(NGY1), + [] = nif_mod_call_history(), - ?line ok = forget_resource(BGY1), % calling dtor in orphan library v2 still loaded - ?line [{{resource_dtor_B_v2,BinBGY1},2,8,208},{unload,2,9,209}] = nif_mod_call_history(), + ok = forget_resource(BGY1), % calling dtor in orphan library v2 still loaded + [{{resource_dtor_B_v2,BinBGY1},2,8,208},{unload,2,9,209}] = nif_mod_call_history(), %% Module upgrade with other lib-version - ?line {module,nif_mod} = erlang:load_module(nif_mod,ModBin), - ?line undefined = nif_mod:lib_version(), - ?line ok = nif_mod:load_nif_lib(Config, 1, + {module,nif_mod} = erlang:load_module(nif_mod,ModBin), + undefined = nif_mod:lib_version(), + ok = nif_mod:load_nif_lib(Config, 1, [{resource_type, 2, ?RT_TAKEOVER, "resource_type_A",resource_dtor_A, ?RT_TAKEOVER}, {resource_type, 0, ?RT_TAKEOVER bor ?RT_CREATE, "resource_type_null_A",resource_dtor_A, @@ -835,28 +808,28 @@ resource_takeover(Config) when is_list(Config) -> ?RT_TAKEOVER} ]), - ?line 1 = nif_mod:lib_version(), - ?line [{upgrade,1,1,101},{lib_version,1,2,102}] = nif_mod_call_history(), + 1 = nif_mod:lib_version(), + [{upgrade,1,1,101},{lib_version,1,2,102}] = nif_mod_call_history(), - %%?line false= check_process_code(Pid, nif_mod), - ?line false = code:purge(nif_mod), + %%false= check_process_code(Pid, nif_mod), + false = code:purge(nif_mod), %% no unload here as we still have instances with destructors - ?line [] = nif_mod_call_history(), + [] = nif_mod_call_history(), - ?line ok = forget_resource(BGZ1), % calling dtor in orphan library v2 still loaded - ?line [{{resource_dtor_B_v2,BinBGZ1},2,10,210},{unload,2,11,211}] = nif_mod_call_history(), + ok = forget_resource(BGZ1), % calling dtor in orphan library v2 still loaded + [{{resource_dtor_B_v2,BinBGZ1},2,10,210},{unload,2,11,211}] = nif_mod_call_history(), - ?line ok = forget_resource(NGZ1), - ?line [] = nif_mod_call_history(), + ok = forget_resource(NGZ1), + [] = nif_mod_call_history(), - ?line ok = forget_resource(A4), - ?line [{{resource_dtor_A_v1,BinA4},1,3,103}] = nif_mod_call_history(), + ok = forget_resource(A4), + [{{resource_dtor_A_v1,BinA4},1,3,103}] = nif_mod_call_history(), - ?line ok = forget_resource(NA4), - ?line [{{resource_dtor_A_v1,BinNA4},1,4,104}] = nif_mod_call_history(), + ok = forget_resource(NA4), + [{{resource_dtor_A_v1,BinNA4},1,4,104}] = nif_mod_call_history(), - ?line ok = forget_resource(AN4), - ?line [] = nif_mod_call_history(), + ok = forget_resource(AN4), + [] = nif_mod_call_history(), %% @@ -978,8 +951,8 @@ resource_takeover(Config) when is_list(Config) -> {return, 0} % SUCCESS ]), - ?line hold_nif_mod_priv_data(nif_mod:get_priv_data_ptr()), - ?line [{load,1,1,101},{get_priv_data_ptr,1,2,102}] = nif_mod_call_history(), + hold_nif_mod_priv_data(nif_mod:get_priv_data_ptr()), + [{load,1,1,101},{get_priv_data_ptr,1,2,102}] = nif_mod_call_history(), {NA7,BinNA7} = make_resource(0, Holder, "NA7"), {AN7,BinAN7} = make_resource(1, Holder, "AN7"), @@ -990,15 +963,15 @@ resource_takeover(Config) when is_list(Config) -> ok = forget_resource(AN7), [] = nif_mod_call_history(), - ?line true = lists:member(?MODULE, erlang:system_info(taints)), - ?line true = lists:member(nif_mod, erlang:system_info(taints)), - ?line verify_tmpmem(TmpMem), + true = lists:member(?MODULE, erlang:system_info(taints)), + true = lists:member(nif_mod, erlang:system_info(taints)), + verify_tmpmem(TmpMem), ok. make_resource(Type,Holder,Str) when is_list(Str) -> Bin = list_to_binary(Str), A1 = make_resource_do(Type,Holder,Bin), - ?line Bin = read_resource(Type,A1), + Bin = read_resource(Type,A1), {A1,Bin}. make_resource_do(Type, Holder, Bin) -> @@ -1025,7 +998,7 @@ resource_holder(List) -> %%io:format("resource_holder got ~p with list = ~p\n", [Msg,List]), case Msg of {Pid, make, Type, Bin} -> - ?line Resource = nif_mod:make_new_resource(Type, Bin), + Resource = nif_mod:make_new_resource(Type, Bin), Id = {make_ref(),Bin}, Pid ! {self(), make_ok, Id}, resource_holder([{Id,Resource} | List]); @@ -1047,7 +1020,7 @@ resource_holder(Pid,Reply,List) -> resource_holder(List). -threading(doc) -> ["Test the threading API functions (reuse tests from driver API)"]; +%% Test the threading API functions (reuse tests from driver API) threading(Config) when is_list(Config) -> case erlang:system_info(threads) of true -> threading_do(Config); @@ -1055,53 +1028,53 @@ threading(Config) when is_list(Config) -> end. threading_do(Config) -> - ?line Data = ?config(data_dir, Config), - ?line File = filename:join(Data, "tester"), - ?line {ok,tester,ModBin} = compile:file(File, [binary,return_errors]), - ?line {module,tester} = erlang:load_module(tester,ModBin), + Data = proplists:get_value(data_dir, Config), + File = filename:join(Data, "tester"), + {ok,tester,ModBin} = compile:file(File, [binary,return_errors]), + {module,tester} = erlang:load_module(tester,ModBin), - ?line ok = tester:load_nif_lib(Config, "basic"), - ?line ok = tester:run(), + ok = tester:load_nif_lib(Config, "basic"), + ok = tester:run(), - ?line ok = tester:load_nif_lib(Config, "rwlock"), - ?line ok = tester:run(), + ok = tester:load_nif_lib(Config, "rwlock"), + ok = tester:run(), - ?line ok = tester:load_nif_lib(Config, "tsd"), - ?line ok = tester:run(). + ok = tester:load_nif_lib(Config, "tsd"), + ok = tester:run(). -send(doc) -> ["Test NIF message sending"]; +%% Test NIF message sending send(Config) when is_list(Config) -> ensure_lib_loaded(Config), N = 1500, List = lists:seq(1,N), - ?line {ok,1} = send_list_seq(N, self), - ?line {ok,1} = send_list_seq(N, self()), - ?line List = receive_any(), - ?line List = receive_any(), + {ok,1} = send_list_seq(N, self), + {ok,1} = send_list_seq(N, self()), + List = receive_any(), + List = receive_any(), Papa = self(), - spawn_link(fun() -> ?line {ok,1} = send_list_seq(N, Papa) end), - ?line List = receive_any(), + spawn_link(fun() -> {ok,1} = send_list_seq(N, Papa) end), + List = receive_any(), - ?line {ok, 1, BlobS} = send_new_blob(self(), other_term()), - ?line BlobR = receive_any(), + {ok, 1, BlobS} = send_new_blob(self(), other_term()), + BlobR = receive_any(), io:format("Sent ~p\nGot ~p\n", [BlobS, BlobR]), - ?line BlobR = BlobS, + BlobR = BlobS, %% send to dead pid {DeadPid, DeadMon} = spawn_monitor(fun() -> void end), - ?line {'DOWN', DeadMon, process, DeadPid, normal} = receive_any(), + {'DOWN', DeadMon, process, DeadPid, normal} = receive_any(), {ok,0} = send_list_seq(7, DeadPid), ok. -send2(doc) -> ["More NIF message sending"]; +%% More NIF message sending send2(Config) when is_list(Config) -> ensure_lib_loaded(Config), send2_do1(fun send_blob_dbg/2), ok. -send_threaded(doc) -> ["Send msg from user thread"]; +%% Send msg from user thread send_threaded(Config) when is_list(Config) -> case erlang:system_info(smp_support) of true -> @@ -1122,44 +1095,44 @@ send2_do1(SendBlobF) -> io:format("sending to forwarder pid=~p\n",[Forwarder]), send2_do2(SendBlobF, Forwarder), Forwarder ! terminate, - ?line {Forwarder, 4} = receive_any(), + {Forwarder, 4} = receive_any(), ok. send2_do2(SendBlobF, To) -> MsgEnv = alloc_msgenv(), repeat(50, fun(_) -> grow_blob(MsgEnv,other_term()) end, []), - ?line {ok,1,Blob0} = SendBlobF(MsgEnv, To), - ?line Blob1 = receive_any(), - ?line Blob1 = Blob0, + {ok,1,Blob0} = SendBlobF(MsgEnv, To), + Blob1 = receive_any(), + Blob1 = Blob0, clear_msgenv(MsgEnv), repeat(50, fun(_) -> grow_blob(MsgEnv,other_term()) end, []), - ?line {ok,1,Blob2} = SendBlobF(MsgEnv, To), - ?line Blob3 = receive_any(), - ?line Blob3 = Blob2, + {ok,1,Blob2} = SendBlobF(MsgEnv, To), + Blob3 = receive_any(), + Blob3 = Blob2, clear_msgenv(MsgEnv), repeat(50, fun(_) -> grow_blob(MsgEnv,other_term()) end, []), clear_msgenv(MsgEnv), repeat(50, fun(_) -> grow_blob(MsgEnv,other_term()) end, []), - ?line {ok,1,Blob4} = SendBlobF(MsgEnv, To), - ?line Blob5 = receive_any(), - ?line Blob5 = Blob4, + {ok,1,Blob4} = SendBlobF(MsgEnv, To), + Blob5 = receive_any(), + Blob5 = Blob4, clear_msgenv(MsgEnv), clear_msgenv(MsgEnv), repeat(50, fun(_) -> grow_blob(MsgEnv,other_term()) end, []), - ?line {ok,1,Blob6} = SendBlobF(MsgEnv, To), - ?line Blob7 = receive_any(), - ?line Blob7 = Blob6, + {ok,1,Blob6} = SendBlobF(MsgEnv, To), + Blob7 = receive_any(), + Blob7 = Blob6, ok. send_blob_thread_and_join(MsgEnv, To) -> - ?line {ok,Blob} = send_blob_thread_dbg(MsgEnv, To, no_join), - ?line {ok,SendRes} = join_send_thread(MsgEnv), + {ok,Blob} = send_blob_thread_dbg(MsgEnv, To, no_join), + {ok,SendRes} = join_send_thread(MsgEnv), {ok,SendRes,Blob}. send_blob_dbg(MsgEnv, To) -> @@ -1187,21 +1160,18 @@ forwarder(To, N) -> other_term() -> {fun(X,Y) -> X*Y end, make_ref()}. -send3(doc) -> ["Message sending stress test"]; +%% Message sending stress test send3(Config) when is_list(Config) -> %% Let a number of processes send random message blobs between each other %% using enif_send. Kill and spawn new ones randomly to keep a ~constant %% number of workers running. - Seed = {erlang:monotonic_time(), - erlang:time_offset(), - erlang:unique_integer()}, - io:format("seed: ~p\n",[Seed]), - random:seed(Seed), + rand:seed(exsplus), + io:format("seed: ~p\n",[rand:export_seed()]), ets:new(nif_SUITE,[named_table,public]), - ?line true = ets:insert(nif_SUITE,{send3,0,0,0,0}), + true = ets:insert(nif_SUITE,{send3,0,0,0,0}), timer:send_after(10000, timeout), % Run for 10 seconds SpawnCnt = send3_controller(0, [], [], 20), - ?line [{_,Rcv,SndOk,SndFail,Balance}] = ets:lookup(nif_SUITE,send3), + [{_,Rcv,SndOk,SndFail,Balance}] = ets:lookup(nif_SUITE,send3), io:format("spawns=~p received=~p, sent=~p send-failure=~p balance=~p\n", [SpawnCnt,Rcv,SndOk,SndFail,Balance]), ets:delete(nif_SUITE). @@ -1229,13 +1199,13 @@ send3_controller(SpawnCnt0, Mons0, Pids0, Tick) -> after Tick -> Max = 20, N = length(Pids0), - PidN = random:uniform(Max), + PidN = rand:uniform(Max), %%io:format("N=~p PidN=~p Pids0=~p\n", [N,PidN,Pids0]), case PidN > N of true -> {NewPid,Mon} = spawn_opt(fun send3_proc/0, [link,monitor]), lists:foreach(fun(P) -> P ! {is_born,NewPid} end, Pids0), - ?line Balance = ets:lookup_element(nif_SUITE,send3,5), + Balance = ets:lookup_element(nif_SUITE,send3,5), Inject = (Balance =< 0), case Inject of true -> ok; @@ -1261,7 +1231,7 @@ send3_proc(Pids0, Counters={Rcv,SndOk,SndFail}, State0) -> receive {pids, Pids1, Inject} -> %%io:format("~p: got ~p Inject=~p\n", [self(), Pids1, Inject]), - ?line Pids0 = [self()], + Pids0 = [self()], Pids2 = [self() | Pids1], case Inject of true -> send3_proc_send(Pids2, Counters, State0); @@ -1293,7 +1263,7 @@ send3_proc(Pids0, Counters={Rcv,SndOk,SndFail}, State0) -> end. send3_proc_send(Pids, {Rcv,SndOk,SndFail}, State0) -> - To = lists:nth(random:uniform(length(Pids)),Pids), + To = lists:nth(rand:uniform(length(Pids)),Pids), Blob = send3_make_blob(), State1 = send3_new_state(State0,Blob), case send3_send(To, Blob) of @@ -1305,12 +1275,12 @@ send3_proc_send(Pids, {Rcv,SndOk,SndFail}, State0) -> send3_make_blob() -> - case random:uniform(20)-1 of + case rand:uniform(20)-1 of 0 -> {term,[]}; N -> MsgEnv = alloc_msgenv(), repeat(N bsr 1, - fun(_) -> grow_blob(MsgEnv,other_term(),random:uniform(1 bsl 20)) + fun(_) -> grow_blob(MsgEnv,other_term(),rand:uniform(1 bsl 20)) end, void), case (N band 1) of 0 -> {term,copy_blob(MsgEnv)}; @@ -1320,7 +1290,7 @@ send3_make_blob() -> send3_send(Pid, Msg) -> %% 90% enif_send and 10% normal bang - case random:uniform(10) of + case rand:uniform(10) of 1 -> send3_send_bang(Pid,Msg); _ -> send3_send_nif(Pid,Msg) end. @@ -1341,103 +1311,105 @@ send3_send_bang(Pid, {msgenv,MsgEnv}) -> true. send3_new_state(State, Blob) -> - case random:uniform(5+2) of + case rand:uniform(5+2) of N when N =< 5-> setelement(N, State, Blob); _ -> State % Don't store blob end. -neg(doc) -> ["Negative testing of load_nif"]; +%% Negative testing of load_nif neg(Config) when is_list(Config) -> TmpMem = tmpmem(), - ?line {'EXIT',{badarg,_}} = (catch erlang:load_nif(badarg, 0)), - ?line {error,{load_failed,_}} = erlang:load_nif("pink_unicorn", 0), + {'EXIT',{badarg,_}} = (catch erlang:load_nif(badarg, 0)), + {error,{load_failed,_}} = erlang:load_nif("pink_unicorn", 0), - ?line Data = ?config(data_dir, Config), - ?line File = filename:join(Data, "nif_mod"), - ?line {ok,nif_mod,Bin} = compile:file(File, [binary,return_errors]), - ?line {module,nif_mod} = erlang:load_module(nif_mod,Bin), + Data = proplists:get_value(data_dir, Config), + File = filename:join(Data, "nif_mod"), + {ok,nif_mod,Bin} = compile:file(File, [binary,return_errors]), + {module,nif_mod} = erlang:load_module(nif_mod,Bin), - ?line {error,{bad_lib,_}} = nif_mod:load_nif_lib(Config, no_init), - ?line verify_tmpmem(TmpMem), - ?line ok. + {error,{bad_lib,_}} = nif_mod:load_nif_lib(Config, no_init), + verify_tmpmem(TmpMem), + ok. -is_checks(doc) -> ["Test all enif_is functions"]; +%% Test all enif_is functions is_checks(Config) when is_list(Config) -> - ?line ensure_lib_loaded(Config, 1), - ?line ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, + ensure_lib_loaded(Config, 1), + ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, self(), hd(erlang:ports()), [], [1,9,9,8], {hejsan, "hejsan", [$h,"ejs",<<"an">>]}, 12), - ?line ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, + ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, self(), hd(erlang:ports()), [], [1,9,9,8], {hejsan, "hejsan", [$h,"ejs",<<"an">>]}, -12), - ?line ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, + ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, self(), hd(erlang:ports()), [], [1,9,9,8], {hejsan, "hejsan", [$h,"ejs",<<"an">>]}, 18446744073709551617), - ?line ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, + ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, self(), hd(erlang:ports()), [], [1,9,9,8], {hejsan, "hejsan", [$h,"ejs",<<"an">>]}, -18446744073709551617), - ?line ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, + ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, self(), hd(erlang:ports()), [], [1,9,9,8], {hejsan, "hejsan", [$h,"ejs",<<"an">>]}, 99.146), - ?line ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, + ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, self(), hd(erlang:ports()), [], [1,9,9,8], {hejsan, "hejsan", [$h,"ejs",<<"an">>]}, -99.146), - ?line ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, + ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, self(), hd(erlang:ports()), [], [1,9,9,8], {hejsan, "hejsan", [$h,"ejs",<<"an">>]}, 18446744073709551616.2e2), - ?line ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, + ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, self(), hd(erlang:ports()), [], [1,9,9,8], {hejsan, "hejsan", [$h,"ejs",<<"an">>]}, -18446744073709551616.2e2), try - ?line check_is_exception(), - ?line throw(expected_badarg) + check_is_exception(), + throw(expected_badarg) catch error:badarg -> - ?line ok + ok end. -get_length(doc) -> ["Test all enif_get_length functions"]; +%% Test all enif_get_length functions get_length(Config) when is_list(Config) -> - ?line ensure_lib_loaded(Config, 1), - ?line ok = length_test(hejsan, "hejsan", [], [], not_a_list). + ensure_lib_loaded(Config, 1), + ok = length_test(hejsan, "hejsan", [], [], not_a_list, [1,2|3]). ensure_lib_loaded(Config) -> ensure_lib_loaded(Config, 1). ensure_lib_loaded(Config, Ver) -> - ?line case lib_version() of - undefined -> - ?line Path = ?config(data_dir, Config), - ?line Lib = "nif_SUITE." ++ integer_to_list(Ver), - ?line ok = erlang:load_nif(filename:join(Path,Lib), []); - Ver when is_integer(Ver) -> - ok - end. + Path = ?config(data_dir, Config), + case lib_version() of + undefined -> + Lib = "nif_SUITE." ++ integer_to_list(Ver), + ok = erlang:load_nif(filename:join(Path,Lib), []); + Ver when is_integer(Ver) -> + ok + end, + erl_ddll:try_load(Path, echo_drv, []), + ok. make_atom(Config) when is_list(Config) -> - ?line ensure_lib_loaded(Config, 1), + ensure_lib_loaded(Config, 1), An0Atom = an0atom, An0Atom0 = 'an\000atom\000', - ?line Atoms = make_atoms(), - ?line 7 = size(Atoms), - ?line Atoms = {An0Atom,An0Atom,An0Atom,An0Atom0,An0Atom,An0Atom,An0Atom0}. + Atoms = make_atoms(), + 7 = size(Atoms), + Atoms = {An0Atom,An0Atom,An0Atom,An0Atom0,An0Atom,An0Atom,An0Atom0}. make_string(Config) when is_list(Config) -> - ?line ensure_lib_loaded(Config, 1), - ?line Strings = make_strings(), - ?line 5 = size(Strings), + ensure_lib_loaded(Config, 1), + Strings = make_strings(), + 5 = size(Strings), A0String = "a0string", A0String0 = [$a,0,$s,$t,$r,$i,$n,$g,0], AStringWithAccents = [$E,$r,$l,$a,$n,$g,$ ,16#e4,$r,$ ,$e,$t,$t,$ ,$g,$e,$n,$e,$r,$e,$l,$l,$t,$ ,$p,$r,$o,$g,$r,$a,$m,$s,$p,$r,16#e5,$k], - ?line Strings = {A0String,A0String,A0String,A0String0, AStringWithAccents}. + Strings = {A0String,A0String,A0String,A0String0, AStringWithAccents}. reverse_list_test(Config) -> - ?line ensure_lib_loaded(Config, 1), + ensure_lib_loaded(Config, 1), List = lists:seq(1,100), RevList = lists:reverse(List), - ?line RevList = reverse_list(List), - ?line badarg = reverse_list(foo). + RevList = reverse_list(List), + badarg = reverse_list(foo). -otp_9668(doc) -> ["Memory leak of tmp-buffer when inspecting iolist or unaligned binary in unbound environment"]; +%% Memory leak of tmp-buffer when inspecting iolist or unaligned binary in unbound environment otp_9668(Config) -> ensure_lib_loaded(Config, 1), TmpMem = tmpmem(), @@ -1447,13 +1419,12 @@ otp_9668(Config) -> <<_:5/bitstring,UnalignedBin:10/binary,_/bitstring>> = <<"Abuse me as unaligned">>, otp_9668_nif(UnalignedBin), - ?line verify_tmpmem(TmpMem), + verify_tmpmem(TmpMem), ok. -otp_9828(doc) -> ["Copy of writable binary"]; +%% Copy of writable binary otp_9828(Config) -> ensure_lib_loaded(Config, 1), - otp_9828_loop(<<"I'm alive!">>, 1000). otp_9828_loop(Bin, 0) -> @@ -1472,68 +1443,68 @@ consume_timeslice(Config) when is_list(Config) -> Done = make_ref(), DummyMFA = {?MODULE,dummy_call,1}, P = spawn(fun () -> - receive Go -> ok end, - {reductions, R1} = process_info(self(), reductions), - 1 = consume_timeslice_nif(100, false), - dummy_call(111), - 0 = consume_timeslice_nif(90, false), - dummy_call(222), - 1 = consume_timeslice_nif(10, false), - dummy_call(333), - 0 = consume_timeslice_nif(25, false), - 0 = consume_timeslice_nif(25, false), - 0 = consume_timeslice_nif(25, false), - 1 = consume_timeslice_nif(25, false), - 0 = consume_timeslice_nif(25, false), - - ok = case consume_timeslice_nif(1, true) of - Cnt when Cnt > 70, Cnt < 80 -> ok; - Other -> Other - end, - dummy_call(444), - - {reductions, R2} = process_info(self(), reductions), - Me ! {RedDiff, R2 - R1}, - exit(Done) - end), + receive Go -> ok end, + {reductions, R1} = process_info(self(), reductions), + 1 = consume_timeslice_nif(100, false), + dummy_call(111), + 0 = consume_timeslice_nif(90, false), + dummy_call(222), + 1 = consume_timeslice_nif(10, false), + dummy_call(333), + 0 = consume_timeslice_nif(25, false), + 0 = consume_timeslice_nif(25, false), + 0 = consume_timeslice_nif(25, false), + 1 = consume_timeslice_nif(25, false), + 0 = consume_timeslice_nif(25, false), + + ok = case consume_timeslice_nif(1, true) of + Cnt when Cnt > 70, Cnt < 80 -> ok; + Other -> Other + end, + dummy_call(444), + + {reductions, R2} = process_info(self(), reductions), + Me ! {RedDiff, R2 - R1}, + exit(Done) + end), erlang:yield(), erlang:trace_pattern(DummyMFA, [], [local]), - ?line 1 = erlang:trace(P, true, [call, running, procs, {tracer, self()}]), + 1 = erlang:trace(P, true, [call, running, procs, {tracer, self()}]), P ! Go, %% receive Go -> ok end, - ?line {trace, P, in, _} = next_tmsg(P), + {trace, P, in, _} = next_tmsg(P), %% consume_timeslice_nif(100), %% dummy_call(111) - ?line {trace, P, out, _} = next_tmsg(P), - ?line {trace, P, in, _} = next_tmsg(P), - ?line {trace, P, call, {?MODULE,dummy_call,[111]}} = next_tmsg(P), + {trace, P, out, _} = next_tmsg(P), + {trace, P, in, _} = next_tmsg(P), + {trace, P, call, {?MODULE,dummy_call,[111]}} = next_tmsg(P), %% consume_timeslice_nif(90), %% dummy_call(222) - ?line {trace, P, call, {?MODULE,dummy_call,[222]}} = next_tmsg(P), + {trace, P, call, {?MODULE,dummy_call,[222]}} = next_tmsg(P), %% consume_timeslice_nif(10), %% dummy_call(333) - ?line {trace, P, out, _} = next_tmsg(P), - ?line {trace, P, in, _} = next_tmsg(P), - ?line {trace, P, call, {?MODULE,dummy_call,[333]}} = next_tmsg(P), + {trace, P, out, _} = next_tmsg(P), + {trace, P, in, _} = next_tmsg(P), + {trace, P, call, {?MODULE,dummy_call,[333]}} = next_tmsg(P), %% 25,25,25,25, 25 - ?line {trace, P, out, {?MODULE,consume_timeslice_nif,2}} = next_tmsg(P), - ?line {trace, P, in, {?MODULE,consume_timeslice_nif,2}} = next_tmsg(P), + {trace, P, out, {?MODULE,consume_timeslice_nif,2}} = next_tmsg(P), + {trace, P, in, {?MODULE,consume_timeslice_nif,2}} = next_tmsg(P), %% consume_timeslice(1,true) %% dummy_call(444) - ?line {trace, P, out, DummyMFA} = next_tmsg(P), - ?line {trace, P, in, DummyMFA} = next_tmsg(P), - ?line {trace, P, call, {?MODULE,dummy_call,[444]}} = next_tmsg(P), + {trace, P, out, DummyMFA} = next_tmsg(P), + {trace, P, in, DummyMFA} = next_tmsg(P), + {trace, P, call, {?MODULE,dummy_call,[444]}} = next_tmsg(P), %% exit(Done) - ?line {trace, P, exit, Done} = next_tmsg(P), + {trace, P, exit, Done} = next_tmsg(P), ExpReds = (100 + 90 + 10 + 25*5 + 75) * CONTEXT_REDS div 100, receive @@ -1541,7 +1512,7 @@ consume_timeslice(Config) when is_list(Config) -> io:format("Reductions = ~p~n", [Reductions]), ok; {RedDiff, Reductions} -> - ?t:fail({unexpected_reduction_count, Reductions}) + ct:fail({unexpected_reduction_count, Reductions}) end, none = next_msg(P), @@ -1598,38 +1569,38 @@ dirty_nif_send(Config) when is_list(Config) -> dirty_nif_exception(Config) when is_list(Config) -> try erlang:system_info(dirty_cpu_schedulers) of - N when is_integer(N) -> - ensure_lib_loaded(Config), - try - %% this checks that the expected exception occurs when the - %% dirty NIF returns the result of enif_make_badarg - %% directly - call_dirty_nif_exception(1), - ?t:fail(expected_badarg) - catch - error:badarg -> - [{?MODULE,call_dirty_nif_exception,[1],_}|_] = - erlang:get_stacktrace(), - ok - end, - try - %% this checks that the expected exception occurs when the - %% dirty NIF calls enif_make_badarg at some point but then - %% returns a value that isn't an exception - call_dirty_nif_exception(0), - ?t:fail(expected_badarg) - catch - error:badarg -> - [{?MODULE,call_dirty_nif_exception,[0],_}|_] = - erlang:get_stacktrace(), - ok - end, - %% this checks that a dirty NIF can raise various terms as - %% exceptions - ok = nif_raise_exceptions(call_dirty_nif_exception) + N when is_integer(N) -> + ensure_lib_loaded(Config), + try + %% this checks that the expected exception occurs when the + %% dirty NIF returns the result of enif_make_badarg + %% directly + call_dirty_nif_exception(1), + ct:fail(expected_badarg) + catch + error:badarg -> + [{?MODULE,call_dirty_nif_exception,[1],_}|_] = + erlang:get_stacktrace(), + ok + end, + try + %% this checks that the expected exception occurs when the + %% dirty NIF calls enif_make_badarg at some point but then + %% returns a value that isn't an exception + call_dirty_nif_exception(0), + ct:fail(expected_badarg) + catch + error:badarg -> + [{?MODULE,call_dirty_nif_exception,[0],_}|_] = + erlang:get_stacktrace(), + ok + end, + %% this checks that a dirty NIF can raise various terms as + %% exceptions + ok = nif_raise_exceptions(call_dirty_nif_exception) catch - error:badarg -> - {skipped,"No dirty scheduler support"} + error:badarg -> + {skipped,"No dirty scheduler support"} end. nif_exception(Config) when is_list(Config) -> @@ -1639,7 +1610,7 @@ nif_exception(Config) when is_list(Config) -> %% calls enif_make_badarg at some point but then tries to return a %% value that isn't an exception call_nif_exception(0), - ?t:fail(expected_badarg) + ct:fail(expected_badarg) catch error:badarg -> ok @@ -1652,21 +1623,21 @@ nif_nan_and_inf(Config) when is_list(Config) -> ensure_lib_loaded(Config), try call_nif_nan_or_inf(nan), - ?t:fail(expected_badarg) + ct:fail(expected_badarg) catch error:badarg -> ok end, try call_nif_nan_or_inf(inf), - ?t:fail(expected_badarg) + ct:fail(expected_badarg) catch error:badarg -> ok end, try call_nif_nan_or_inf(tuple), - ?t:fail(expected_badarg) + ct:fail(expected_badarg) catch error:badarg -> ok @@ -1676,14 +1647,14 @@ nif_atom_too_long(Config) when is_list(Config) -> ensure_lib_loaded(Config), try call_nif_atom_too_long(all), - ?t:fail(expected_badarg) + ct:fail(expected_badarg) catch error:badarg -> ok end, try call_nif_atom_too_long(len), - ?t:fail(expected_badarg) + ct:fail(expected_badarg) catch error:badarg -> ok @@ -1691,19 +1662,19 @@ nif_atom_too_long(Config) when is_list(Config) -> next_msg(_Pid) -> receive - M -> M + M -> M after 100 -> - none + none end. next_tmsg(Pid) -> receive TMsg when is_tuple(TMsg), - element(1, TMsg) == trace, - element(2, TMsg) == Pid -> - TMsg - after 100 -> - none - end. + element(1, TMsg) == trace, + element(2, TMsg) == Pid -> + TMsg + after 100 -> + none + end. dummy_call(_) -> ok. @@ -1713,7 +1684,9 @@ tmpmem() -> false -> undefined; MemInfo -> MSBCS = lists:foldl( - fun ({instance, _, L}, Acc) -> + fun ({instance, 0, _}, Acc) -> + Acc; % Ignore instance 0 + ({instance, _, L}, Acc) -> {value,{_,MBCS}} = lists:keysearch(mbcs, 1, L), {value,{_,SBCS}} = lists:keysearch(sbcs, 1, L), [MBCS,SBCS | Acc] @@ -1741,9 +1714,7 @@ verify_tmpmem(MemInfo) -> ok end; Other -> - io:format("Expected: ~p", [MemInfo]), - io:format("Actual: ~p", [Other]), - ?t:fail() + ct:fail("Expected: ~p\nActual: ~p", [MemInfo, Other]) end. call(Pid,Cmd) -> @@ -1771,17 +1742,282 @@ check(Exp,Got,Line) -> nif_raise_exceptions(NifFunc) -> ExcTerms = [{error, test}, "a string", <<"a binary">>, - 42, [1,2,3,4,5], [{p,1},{p,2},{p,3}]], + 42, [1,2,3,4,5], [{p,1},{p,2},{p,3}]], lists:foldl(fun(Term, ok) -> - try - erlang:apply(?MODULE,NifFunc,[Term]), - ?t:fail({expected,Term}) - catch - error:Term -> - [{?MODULE,NifFunc,[Term],_}|_] = erlang:get_stacktrace(), - ok - end - end, ok, ExcTerms). + try + erlang:apply(?MODULE,NifFunc,[Term]), + ct:fail({expected,Term}) + catch + error:Term -> + [{?MODULE,NifFunc,[Term],_}|_] = erlang:get_stacktrace(), + ok + end + end, ok, ExcTerms). + +-define(ERL_NIF_TIME_ERROR, -9223372036854775808). +-define(TIME_UNITS, [seconds, milli_seconds, micro_seconds, nano_seconds]). + +nif_monotonic_time(Config) -> + ?ERL_NIF_TIME_ERROR = monotonic_time(invalid_time_unit), + mtime_loop(1000000). + +mtime_loop(0) -> + ok; +mtime_loop(N) -> + chk_mtime(?TIME_UNITS), + mtime_loop(N-1). + +chk_mtime([]) -> + ok; +chk_mtime([TU|TUs]) -> + A = erlang:monotonic_time(TU), + B = monotonic_time(TU), + C = erlang:monotonic_time(TU), + try + true = A =< B, + true = B =< C + catch + _ : _ -> + ct:fail({monotonic_time_missmatch, TU, A, B, C}) + end, + chk_mtime(TUs). + +nif_time_offset(Config) -> + ?ERL_NIF_TIME_ERROR = time_offset(invalid_time_unit), + toffs_loop(1000000). + +toffs_loop(0) -> + ok; +toffs_loop(N) -> + chk_toffs(?TIME_UNITS), + toffs_loop(N-1). + +chk_toffs([]) -> + ok; +chk_toffs([TU|TUs]) -> + TO = erlang:time_offset(TU), + NifTO = time_offset(TU), + case TO =:= NifTO of + true -> + ok; + false -> + case erlang:system_info(time_warp_mode) of + no_time_warp -> + ct:fail({time_offset_mismatch, TU, TO, NifTO}); + _ -> + %% Most frequent time offset change + %% is currently only every 15:th + %% second so this should currently + %% work... + NTO = erlang:time_offset(TU), + case NifTO =:= NTO of + true -> + ok; + false -> + ct:fail({time_offset_mismatch, TU, TO, NifTO, NTO}) + end + end + end, + chk_toffs(TUs). + +nif_convert_time_unit(Config) -> + ?ERL_NIF_TIME_ERROR = convert_time_unit(0, seconds, invalid_time_unit), + ?ERL_NIF_TIME_ERROR = convert_time_unit(0, invalid_time_unit, seconds), + ?ERL_NIF_TIME_ERROR = convert_time_unit(0, invalid_time_unit, invalid_time_unit), + lists:foreach(fun (Offset) -> + lists:foreach(fun (Diff) -> + chk_ctu(Diff+(Offset*1000*1000*1000)) + end, + [999999999999, + 99999999999, + 9999999999, + 999999999, + 99999999, + 9999999, + 999999, + 99999, + 999, + 99, + 9, + 1, + 11, + 101, + 1001, + 10001, + 100001, + 1000001, + 10000001, + 100000001, + 1000000001, + 100000000001, + 1000000000001, + 5, + 50, + 500, + 5000, + 50000, + 500000, + 5000000, + 50000000, + 500000000, + 5000000000, + 50000000000, + 500000000000]) + end, + [-4711, -1000, -475, -5, -4, -3, -2, -1, 0, + 1, 2, 3, 4, 5, 475, 1000, 4711]), + ctu_loop(1000000). + +ctu_loop(0) -> + ok; +ctu_loop(N) -> + chk_ctu(erlang:monotonic_time(nano_seconds)), + ctu_loop(N-1). + +chk_ctu(Time) -> + chk_ctu(Time, ?TIME_UNITS). + +chk_ctu(_Time, []) -> + ok; +chk_ctu(Time, [FromTU|FromTUs]) -> + chk_ctu(Time, FromTU, ?TIME_UNITS), + chk_ctu(Time, FromTUs). + +chk_ctu(_Time, _FromTU, []) -> + ok; +chk_ctu(Time, FromTU, [ToTU|ToTUs]) -> + T = erlang:convert_time_unit(Time, nano_seconds, FromTU), + TE = erlang:convert_time_unit(T, FromTU, ToTU), + TN = convert_time_unit(T, FromTU, ToTU), + case TE =:= TN of + false -> + ct:fail({conversion_mismatch, FromTU, T, ToTU, TE, TN}); + true -> + chk_ctu(Time, FromTU, ToTUs) + end. + +nif_now_time(Config) -> + ensure_lib_loaded(Config), + + N1 = now(), + NifN1 = now_time(), + NifN2 = now_time(), + N2 = now(), + true = N1 < NifN1, + true = NifN1 < NifN2, + true = NifN2 < N2. + +nif_cpu_time(Config) -> + ensure_lib_loaded(Config), + + try cpu_time() of + {_, _, _} -> + ok + catch error:badarg -> + {comment, "cpu_time not supported"} + end. + +nif_unique_integer(Config) -> + ensure_lib_loaded(Config), + + UM1 = erlang:unique_integer([monotonic]), + UM2 = unique_integer_nif([monotonic]), + UM3 = erlang:unique_integer([monotonic]), + + true = UM1 < UM2, + true = UM2 < UM3, + + UMP1 = erlang:unique_integer([monotonic, positive]), + UMP2 = unique_integer_nif([monotonic, positive]), + UMP3 = erlang:unique_integer([monotonic, positive]), + + true = 0 =< UMP1, + true = UMP1 < UMP2, + true = UMP2 < UMP3, + + UP1 = erlang:unique_integer([positive]), + UP2 = unique_integer_nif([positive]), + UP3 = erlang:unique_integer([positive]), + + true = 0 =< UP1, + true = 0 =< UP2, + true = 0 =< UP3, + + true = is_integer(unique_integer_nif([])), + true = is_integer(unique_integer_nif([])), + true = is_integer(unique_integer_nif([])). + +nif_is_process_alive(Config) -> + ensure_lib_loaded(Config), + + {Pid,_} = spawn_monitor(fun() -> receive ok -> nok end end), + true = is_process_alive_nif(Pid), + exit(Pid, die), + receive _ -> ok end, %% Clear monitor + false = is_process_alive_nif(Pid). + +nif_is_port_alive(Config) -> + ensure_lib_loaded(Config), + + Port = open_port({spawn,echo_drv},[eof]), + true = is_port_alive_nif(Port), + port_close(Port), + false = is_port_alive_nif(Port). + +nif_term_to_binary(Config) -> + ensure_lib_loaded(Config), + T = {#{ok => nok}, <<0:8096>>, lists:seq(1,100)}, + Bin = term_to_binary(T), + ct:log("~p",[Bin]), + Bin = term_to_binary_nif(T, undefined), + true = term_to_binary_nif(T, self()), + receive Bin -> ok end. + +-define(ERL_NIF_BIN2TERM_SAFE, 16#20000000). + +nif_binary_to_term(Config) -> + ensure_lib_loaded(Config), + T = {#{ok => nok}, <<0:8096>>, lists:seq(1,100)}, + Bin = term_to_binary(T), + Len = byte_size(Bin), + {Len,T} = binary_to_term_nif(Bin, undefined, 0), + Len = binary_to_term_nif(Bin, self(), 0), + T = receive M -> M after 1000 -> timeout end, + + {Len, T} = binary_to_term_nif(Bin, undefined, ?ERL_NIF_BIN2TERM_SAFE), + false = binary_to_term_nif(<<131,100,0,14,"undefined_atom">>, + undefined, ?ERL_NIF_BIN2TERM_SAFE), + false = binary_to_term_nif(Bin, undefined, 1), + ok. + +nif_port_command(Config) -> + ensure_lib_loaded(Config), + + Port = open_port({spawn,echo_drv},[eof]), + true = port_command_nif(Port, "hello\n"), + receive {Port,{data,"hello\n"}} -> ok + after 1000 -> ct:fail(timeout) end, + + RefcBin = lists:flatten([lists:duplicate(100, "hello"),"\n"]), + true = port_command_nif(Port, iolist_to_binary(RefcBin)), + receive {Port,{data,RefcBin}} -> ok + after 1000 -> ct:fail(timeout) end, + + %% Test that invalid arguments correctly returns + %% badarg and that the port survives. + {'EXIT', {badarg, _}} = (catch port_command_nif(Port, [ok])), + + IoList = [lists:duplicate(100,<<"hello">>),"\n"], + true = port_command_nif(Port, [IoList]), + FlatIoList = binary_to_list(iolist_to_binary(IoList)), + receive {Port,{data,FlatIoList}} -> ok + after 1000 -> ct:fail(timeout) end, + + port_close(Port), + + {'EXIT', {badarg, _}} = (catch port_command_nif(Port, "hello\n")), + + ok. %% The NIFs: lib_version() -> undefined. @@ -1810,7 +2046,7 @@ last_resource_dtor_call() -> ?nif_stub. make_new_resource(_,_) -> ?nif_stub. check_is(_,_,_,_,_,_,_,_,_,_,_) -> ?nif_stub. check_is_exception() -> ?nif_stub. -length_test(_,_,_,_,_) -> ?nif_stub. +length_test(_,_,_,_,_,_) -> ?nif_stub. make_atoms() -> ?nif_stub. make_strings() -> ?nif_stub. make_new_resource_binary(_) -> ?nif_stub. @@ -1840,6 +2076,12 @@ call_dirty_nif_zero_args() -> ?nif_stub. call_nif_exception(_) -> ?nif_stub. call_nif_nan_or_inf(_) -> ?nif_stub. call_nif_atom_too_long(_) -> ?nif_stub. +unique_integer_nif(_) -> ?nif_stub. +is_process_alive_nif(_) -> ?nif_stub. +is_port_alive_nif(_) -> ?nif_stub. +term_to_binary_nif(_, _) -> ?nif_stub. +binary_to_term_nif(_, _, _) -> ?nif_stub. +port_command_nif(_, _) -> ?nif_stub. %% maps is_map_nif(_) -> ?nif_stub. @@ -1852,6 +2094,12 @@ make_map_remove_nif(_,_) -> ?nif_stub. maps_from_list_nif(_) -> ?nif_stub. sorted_list_from_maps_nif(_) -> ?nif_stub. +%% Time +monotonic_time(_) -> ?nif_stub. +time_offset(_) -> ?nif_stub. +convert_time_unit(_,_,_) -> ?nif_stub. +now_time() -> ?nif_stub. +cpu_time() -> ?nif_stub. nif_stub_error(Line) -> exit({nif_not_loaded,module,?MODULE,line,Line}). |