aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/test')
-rw-r--r--erts/emulator/test/alloc_SUITE_data/testcase_driver.h2
-rw-r--r--erts/emulator/test/code_SUITE.erl447
-rw-r--r--erts/emulator/test/code_SUITE_data/call_purged_fun_tester.erl186
-rw-r--r--erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c2
-rw-r--r--erts/emulator/test/driver_SUITE_data/chkio_drv.c14
-rw-r--r--erts/emulator/test/gc_SUITE.erl103
-rw-r--r--erts/emulator/test/hipe_SUITE.erl57
-rw-r--r--erts/emulator/test/match_spec_SUITE.erl10
-rw-r--r--erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c2
-rw-r--r--erts/emulator/test/nif_SUITE.erl120
-rw-r--r--erts/emulator/test/nif_SUITE_data/Makefile.src8
-rw-r--r--erts/emulator/test/nif_SUITE_data/hipe_compiled.erl6
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c27
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_api_2_0/README5
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_api_2_0/erl_drv_nif.h48
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_api_2_0/erl_nif.h206
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_api_2_0/erl_nif_api_funcs.h257
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_api_2_4/README6
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_api_2_4/erl_drv_nif.h48
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_api_2_4/erl_nif.h237
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_api_2_4/erl_nif_api_funcs.h503
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.1.2_0.c4
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.1.2_4.c4
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.2.2_0.c4
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.2.2_4.c4
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.3.2_0.c4
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.3.2_4.c4
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.c17
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.erl29
-rw-r--r--erts/emulator/test/nif_SUITE_data/testcase_driver.h2
-rw-r--r--erts/emulator/test/nif_SUITE_data/tester.c6
-rw-r--r--erts/emulator/test/num_bif_SUITE.erl84
-rw-r--r--erts/emulator/test/process_SUITE.erl2
-rw-r--r--erts/emulator/test/system_info_SUITE.erl70
-rw-r--r--erts/emulator/test/trace_call_time_SUITE_data/trace_nif.c9
-rw-r--r--erts/emulator/test/trace_nif_SUITE.erl12
-rw-r--r--erts/emulator/test/trace_nif_SUITE_data/trace_nif.c13
-rw-r--r--erts/emulator/test/tracer_SUITE_data/tracer_test.c2
38 files changed, 2062 insertions, 502 deletions
diff --git a/erts/emulator/test/alloc_SUITE_data/testcase_driver.h b/erts/emulator/test/alloc_SUITE_data/testcase_driver.h
index f0ca91bd06..2b742dd7e3 100644
--- a/erts/emulator/test/alloc_SUITE_data/testcase_driver.h
+++ b/erts/emulator/test/alloc_SUITE_data/testcase_driver.h
@@ -20,7 +20,7 @@
#ifndef TESTCASE_DRIVER_H__
#define TESTCASE_DRIVER_H__
-#include "erl_nif.h"
+#include <erl_nif.h>
#include <stdlib.h>
typedef struct {
diff --git a/erts/emulator/test/code_SUITE.erl b/erts/emulator/test/code_SUITE.erl
index 3ee14f2d1c..b29520ab9f 100644
--- a/erts/emulator/test/code_SUITE.erl
+++ b/erts/emulator/test/code_SUITE.erl
@@ -22,10 +22,9 @@
-export([all/0, suite/0, init_per_suite/1, end_per_suite/1,
versions/1,new_binary_types/1, call_purged_fun_code_gone/1,
call_purged_fun_code_reload/1, call_purged_fun_code_there/1,
- t_check_process_code/1,t_check_old_code/1,
- t_check_process_code_ets/1,
- external_fun/1,get_chunk/1,module_md5/1,make_stub/1,
- make_stub_many_funs/1,constant_pools/1,constant_refc_binaries/1,
+ multi_proc_purge/1, t_check_old_code/1,
+ external_fun/1,get_chunk/1,module_md5/1,
+ constant_pools/1,constant_refc_binaries/1,
false_dependency/1,coverage/1,fun_confusion/1,
t_copy_literals/1, t_copy_literals_frags/1]).
@@ -36,9 +35,9 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[versions, new_binary_types, call_purged_fun_code_gone,
- call_purged_fun_code_reload, call_purged_fun_code_there, t_check_process_code,
- t_check_process_code_ets, t_check_old_code, external_fun, get_chunk,
- module_md5, make_stub, make_stub_many_funs,
+ call_purged_fun_code_reload, call_purged_fun_code_there,
+ multi_proc_purge, t_check_old_code, external_fun, get_chunk,
+ module_md5,
constant_pools, constant_refc_binaries, false_dependency,
coverage, fun_confusion, t_copy_literals, t_copy_literals_frags].
@@ -154,218 +153,80 @@ call_purged_fun_code_there(Config) when is_list(Config) ->
ok.
call_purged_fun_test(Priv, Data, Type) ->
- File = filename:join(Data, "my_code_test2"),
- Code = filename:join(Priv, "my_code_test2"),
-
- catch erlang:purge_module(my_code_test2),
- catch erlang:delete_module(my_code_test2),
- catch erlang:purge_module(my_code_test2),
-
- {ok,my_code_test2} = c:c(File, [{outdir,Priv}]),
-
- T = ets:new(my_code_test2_fun_table, []),
- ets:insert(T, {my_fun,my_code_test2:make_fun(4711)}),
- ets:insert(T, {my_fun2,my_code_test2:make_fun2()}),
-
- spawn(fun () ->
- [{my_fun2,F2}] = ets:lookup(T, my_fun2),
- F2(fun () ->
- receive after infinity -> ok end
- end,
- fun () -> ok end),
- exit(completed)
- end),
-
- PurgeType = case Type of
- code_gone ->
- ok = file:delete(Code++".beam"),
- true;
- code_reload ->
- true;
- code_there ->
- false
- end,
-
- true = erlang:delete_module(my_code_test2),
-
- Purge = start_purge(my_code_test2, PurgeType),
-
- {P0, M0} = spawn_monitor(fun () ->
- [{my_fun,F}] = ets:lookup(T, my_fun),
- 4712 = F(1),
- exit(completed)
- end),
-
- wait_until(fun () ->
- {status, suspended}
- == process_info(P0, status)
- end),
-
- ok = continue_purge(Purge),
-
- {P1, M1} = spawn_monitor(fun () ->
- [{my_fun,F}] = ets:lookup(T, my_fun),
- 4713 = F(2),
- exit(completed)
- end),
- {P2, M2} = spawn_monitor(fun () ->
- [{my_fun,F}] = ets:lookup(T, my_fun),
- 4714 = F(3),
- exit(completed)
- end),
-
- wait_until(fun () ->
- {status, suspended}
- == process_info(P1, status)
- end),
- wait_until(fun () ->
- {status, suspended}
- == process_info(P2, status)
- end),
-
- {current_function,
- {erts_code_purger,
- pending_purge_lambda,
- 3}} = process_info(P0, current_function),
- {current_function,
- {erts_code_purger,
- pending_purge_lambda,
- 3}} = process_info(P1, current_function),
- {current_function,
- {erts_code_purger,
- pending_purge_lambda,
- 3}} = process_info(P2, current_function),
-
- case Type of
- code_there ->
- false = complete_purge(Purge);
- _ ->
- {true, true} = complete_purge(Purge)
- end,
-
- case Type of
- code_gone ->
- receive
- {'DOWN', M0, process, P0, Reason0} ->
- {undef, _} = Reason0
- end,
- receive
- {'DOWN', M1, process, P1, Reason1} ->
- {undef, _} = Reason1
- end,
- receive
- {'DOWN', M2, process, P2, Reason2} ->
- {undef, _} = Reason2
- end;
- _ ->
- receive
- {'DOWN', M0, process, P0, Reason0} ->
- completed = Reason0
- end,
- receive
- {'DOWN', M1, process, P1, Reason1} ->
- completed = Reason1
- end,
- receive
- {'DOWN', M2, process, P2, Reason2} ->
- completed = Reason2
- end,
- catch erlang:purge_module(my_code_test2),
- catch erlang:delete_module(my_code_test2),
- catch erlang:purge_module(my_code_test2)
- end,
- ok.
-
-t_check_process_code(Config) when is_list(Config) ->
- case check_process_code_handle(indirect_references) of
- false -> {skipped, "check_process_code() ignores funs"};
- true -> t_check_process_code_test(Config)
- end.
-
-t_check_process_code_test(Config) ->
- Priv = proplists:get_value(priv_dir, Config),
- Data = proplists:get_value(data_dir, Config),
- File = filename:join(Data, "my_code_test"),
- Code = filename:join(Priv, "my_code_test"),
+ OptsList = case erlang:system_info(hipe_architecture) of
+ undefined -> [[]];
+ _ -> [[], [native,{d,hipe}]]
+ end,
+ [call_purged_fun_test_do(Priv, Data, Type, CO, FO)
+ || CO <- OptsList, FO <- OptsList].
- catch erlang:purge_module(my_code_test),
- catch erlang:delete_module(my_code_test),
- catch erlang:purge_module(my_code_test),
-
- {ok,my_code_test} = c:c(File, [{outdir,Priv}]),
-
- MyFun = fun(X, Y) -> X + Y end, %Confuse things.
- F = my_code_test:make_fun(42),
- 2 = fun_refc(F),
- MyFun2 = fun(X, Y) -> X * Y end, %Confuse things.
- 44 = F(2),
- %% Delete the module and call the fun again.
- true = erlang:delete_module(my_code_test),
- 2 = fun_refc(F),
- 45 = F(3),
- {'EXIT',{undef,_}} = (catch my_code_test:make_fun(33)),
-
- %% The fun should still be there, preventing purge.
- true = erlang:check_process_code(self(), my_code_test),
- gc(),
- gc(), %Place funs on the old heap.
- true = erlang:check_process_code(self(), my_code_test),
-
- %% Using the funs here guarantees that they will not be prematurely garbed.
- 48 = F(6),
- 3 = MyFun(1, 2),
- 12 = MyFun2(3, 4),
-
- %% Kill all funs.
- t_check_process_code1(Code, []).
-
-%% The real fun was killed, but we have some fakes which look similar.
-
-t_check_process_code1(Code, Fakes) ->
- MyFun = fun(X, Y) -> X + Y + 1 end, %Confuse things.
- false = erlang:check_process_code(self(), my_code_test),
- 4 = MyFun(1, 2),
- t_check_process_code2(Code, Fakes).
-
-t_check_process_code2(Code, _) ->
- false = erlang:check_process_code(self(), my_code_test),
- true = erlang:purge_module(my_code_test),
-
- %% In the next test we will load the same module twice.
- {module,my_code_test} = code:load_abs(Code),
- F = my_code_test:make_fun(37),
- 2 = fun_refc(F),
- false = erlang:check_process_code(self(), my_code_test),
- {module,my_code_test} = code:load_abs(Code),
- 2 = fun_refc(F),
+call_purged_fun_test_do(Priv, Data, Type, CallerOpts, FunOpts) ->
+ io:format("Compile caller as ~p and funs as ~p\n", [CallerOpts, FunOpts]),
+ SrcFile = filename:join(Data, "call_purged_fun_tester.erl"),
+ ObjFile = filename:join(Priv, "call_purged_fun_tester.beam"),
+ {ok,Mod,Code} = compile:file(SrcFile, [binary, report | CallerOpts]),
+ {module,Mod} = code:load_binary(Mod, ObjFile, Code),
- %% Still false because the fun with the same identify is found
- %% in the current code.
- false = erlang:check_process_code(self(), my_code_test),
+ call_purged_fun_tester:do(Priv, Data, Type, FunOpts).
- %% Some fake funs in the same module should not do any difference.
- false = erlang:check_process_code(self(), my_code_test),
- 38 = F(1),
- t_check_process_code3(Code, F, []).
+multi_proc_purge(Config) when is_list(Config) ->
+ %%
+ %% Make sure purge requests aren't lost when
+ %% purger process is working.
+ %%
+ Priv = proplists:get_value(priv_dir, Config),
+ Data = proplists:get_value(data_dir, Config),
+ File1 = filename:join(Data, "my_code_test"),
+ File2 = filename:join(Data, "my_code_test2"),
+
+ {ok,my_code_test} = c:c(File1, [{outdir,Priv}]),
+ {ok,my_code_test2} = c:c(File2, [{outdir,Priv}]),
+ erlang:delete_module(my_code_test),
+ erlang:delete_module(my_code_test2),
-t_check_process_code3(Code, F, Fakes) ->
- Pid = spawn_link(fun() -> body(F, Fakes) end),
- true = erlang:purge_module(my_code_test),
- false = erlang:check_process_code(self(), my_code_test),
- false = erlang:check_process_code(Pid, my_code_test),
+ Self = self(),
- true = erlang:delete_module(my_code_test),
- true = erlang:check_process_code(self(), my_code_test),
- true = erlang:check_process_code(Pid, my_code_test),
- 39 = F(2),
- t_check_process_code4(Code, Pid).
-
-t_check_process_code4(_Code, Pid) ->
- Pid ! drop_funs,
- receive after 1 -> ok end,
- false = erlang:check_process_code(Pid, my_code_test),
+ Fun1 = fun () ->
+ erts_code_purger:purge(my_code_test),
+ Self ! {self(), done}
+ end,
+ Fun2 = fun () ->
+ erts_code_purger:soft_purge(my_code_test2),
+ Self ! {self(), done}
+ end,
+ Fun3 = fun () ->
+ erts_code_purger:purge('__nonexisting_module__'),
+ Self ! {self(), done}
+ end,
+ Fun4 = fun () ->
+ erts_code_purger:soft_purge('__another_nonexisting_module__'),
+ Self ! {self(), done}
+ end,
+
+ Pid1 = spawn_link(Fun1),
+ Pid2 = spawn_link(Fun2),
+ Pid3 = spawn_link(Fun3),
+ Pid4 = spawn_link(Fun4),
+ Pid5 = spawn_link(Fun1),
+ Pid6 = spawn_link(Fun2),
+ Pid7 = spawn_link(Fun3),
+ receive after 50 -> ok end,
+ Pid8 = spawn_link(Fun4),
+ Pid9 = spawn_link(Fun1),
+ Pid10 = spawn_link(Fun2),
+ Pid11 = spawn_link(Fun3),
+ Pid12 = spawn_link(Fun4),
+ Pid13 = spawn_link(Fun1),
+ receive after 50 -> ok end,
+ Pid14 = spawn_link(Fun2),
+ Pid15 = spawn_link(Fun3),
+ Pid16 = spawn_link(Fun4),
+
+ lists:foreach(fun (P) -> receive {P, done} -> ok end end,
+ [Pid1, Pid2, Pid3, Pid4, Pid5, Pid6, Pid7, Pid8,
+ Pid9, Pid10, Pid11, Pid12, Pid13, Pid14, Pid15, Pid16]),
ok.
body(F, Fakes) ->
@@ -388,72 +249,6 @@ gc() ->
gc1().
gc1() -> ok.
-%% Test check_process_code/2 in combination with a fun obtained from an ets table.
-t_check_process_code_ets(Config) when is_list(Config) ->
- case check_process_code_handle(indirect_references) of
- false ->
- {skipped, "check_process_code() ignores funs"};
- true ->
- case test_server:is_native(?MODULE) of
- true ->
- {skip,"Native code"};
- false ->
- do_check_process_code_ets(Config)
- end
- end.
-
-do_check_process_code_ets(Config) ->
- Priv = proplists:get_value(priv_dir, Config),
- Data = proplists:get_value(data_dir, Config),
- File = filename:join(Data, "my_code_test"),
-
- catch erlang:purge_module(my_code_test),
- catch erlang:delete_module(my_code_test),
- catch erlang:purge_module(my_code_test),
- {ok,my_code_test} = c:c(File, [{outdir,Priv}]),
-
- T = ets:new(my_code_test, []),
- ets:insert(T, {7,my_code_test:make_fun(107)}),
- ets:insert(T, {8,my_code_test:make_fun(108)}),
- erlang:delete_module(my_code_test),
- false = erlang:check_process_code(self(), my_code_test),
- Body = fun() ->
- [{7,F1}] = ets:lookup(T, 7),
- [{8,F2}] = ets:lookup(T, 8),
- IdleLoop = fun() -> receive _X -> ok end end,
- RecLoop = fun(Again) ->
- receive
- call -> 110 = F1(3),
- 100 = F2(-8),
- Again(Again);
- {drop_funs,To} ->
- To ! funs_dropped,
- IdleLoop()
- end
- end,
- true = erlang:check_process_code(self(), my_code_test),
- RecLoop(RecLoop)
- end,
- Pid = spawn_link(Body),
- receive after 1 -> ok end,
- true = erlang:check_process_code(Pid, my_code_test),
- Pid ! call,
- Pid ! {drop_funs,self()},
-
- receive
- funs_dropped -> ok;
- Other -> ct:fail({unexpected,Other})
- after 10000 ->
- ct:fail(no_funs_dropped_answer)
- end,
-
- false = erlang:check_process_code(Pid, my_code_test),
- ok.
-
-fun_refc(F) ->
- {refc,Count} = erlang:fun_info(F, refc),
- Count.
-
%% Test the erlang:check_old_code/1 BIF.
t_check_old_code(Config) when is_list(Config) ->
@@ -543,67 +338,6 @@ module_md5_ok(Code) ->
end.
-make_stub(Config) when is_list(Config) ->
- catch erlang:purge_module(my_code_test),
- MD5 = erlang:md5(<<>>),
-
- Data = proplists:get_value(data_dir, Config),
- File = filename:join(Data, "my_code_test"),
- {ok,my_code_test,Code} = compile:file(File, [binary]),
-
- my_code_test = code:make_stub_module(my_code_test, Code, {[],[],MD5}),
- true = erlang:delete_module(my_code_test),
- true = erlang:purge_module(my_code_test),
-
- my_code_test = code:make_stub_module(my_code_test,
- make_unaligned_sub_binary(Code),
- {[],[],MD5}),
- true = erlang:delete_module(my_code_test),
- true = erlang:purge_module(my_code_test),
-
- my_code_test = code:make_stub_module(my_code_test, zlib:gzip(Code),
- {[],[],MD5}),
- true = erlang:delete_module(my_code_test),
- true = erlang:purge_module(my_code_test),
-
- %% Should fail.
- {'EXIT',{badarg,_}} =
- (catch code:make_stub_module(my_code_test, <<"bad">>, {[],[],MD5})),
- {'EXIT',{badarg,_}} =
- (catch code:make_stub_module(my_code_test,
- bit_sized_binary(Code),
- {[],[],MD5})),
- {'EXIT',{badarg,_}} =
- (catch code:make_stub_module(my_code_test_with_wrong_name,
- Code, {[],[],MD5})),
- ok.
-
-make_stub_many_funs(Config) when is_list(Config) ->
- catch erlang:purge_module(many_funs),
- MD5 = erlang:md5(<<>>),
-
- Data = proplists:get_value(data_dir, Config),
- File = filename:join(Data, "many_funs"),
- {ok,many_funs,Code} = compile:file(File, [binary]),
-
- many_funs = code:make_stub_module(many_funs, Code, {[],[],MD5}),
- true = erlang:delete_module(many_funs),
- true = erlang:purge_module(many_funs),
- many_funs = code:make_stub_module(many_funs,
- make_unaligned_sub_binary(Code),
- {[],[],MD5}),
- true = erlang:delete_module(many_funs),
- true = erlang:purge_module(many_funs),
-
- %% Should fail.
- {'EXIT',{badarg,_}} =
- (catch code:make_stub_module(many_funs, <<"bad">>, {[],[],MD5})),
- {'EXIT',{badarg,_}} =
- (catch code:make_stub_module(many_funs,
- bit_sized_binary(Code),
- {[],[],MD5})),
- ok.
-
constant_pools(Config) when is_list(Config) ->
Data = proplists:get_value(data_dir, Config),
File = filename:join(Data, "literals"),
@@ -1137,38 +871,3 @@ flush() ->
id(I) -> I.
-check_process_code_handle(What) ->
- lists:member(What, erlang:system_info(check_process_code)).
-
-wait_until(Fun) ->
- case Fun() of
- true ->
- ok;
- false ->
- receive after 100 -> ok end,
- wait_until(Fun)
- end.
-
-start_purge(Mod, Type) when is_atom(Mod)
- andalso ((Type == true)
- orelse (Type == false)) ->
- Ref = make_ref(),
- erts_code_purger ! {test_purge, Mod, self(), Type, Ref},
- receive
- {started, Ref} ->
- Ref
- end.
-
-continue_purge(Ref) when is_reference(Ref) ->
- erts_code_purger ! {continue, Ref},
- receive
- {continued, Ref} ->
- ok
- end.
-
-complete_purge(Ref) when is_reference(Ref) ->
- erts_code_purger ! {complete, Ref},
- receive
- {test_purge, Res, Ref} ->
- Res
- end.
diff --git a/erts/emulator/test/code_SUITE_data/call_purged_fun_tester.erl b/erts/emulator/test/code_SUITE_data/call_purged_fun_tester.erl
new file mode 100644
index 0000000000..699f0c1161
--- /dev/null
+++ b/erts/emulator/test/code_SUITE_data/call_purged_fun_tester.erl
@@ -0,0 +1,186 @@
+-module(call_purged_fun_tester).
+
+-export([do/4]).
+
+%% Resurrect line macro when hipe compiled
+-ifdef(hipe).
+-define(line, put(the_line,?LINE),).
+do(Priv, Data, Type, Opts) ->
+ try do_it(Priv, Data, Type, Opts)
+ catch
+ C:E ->
+ ST = erlang:get_stacktrace(),
+ io:format("Caught exception from line ~p:\n~p\n",
+ [get(the_line), ST]),
+ io:format("Message queue: ~p\n", [process_info(self(), messages)]),
+ erlang:raise(C, E, ST)
+ end.
+-else.
+-define(line,).
+do(P,D,T,O) ->
+ do_it(P,D,T,O).
+-endif.
+
+
+do_it(Priv, Data, Type, Opts) ->
+ File = filename:join(Data, "my_code_test2"),
+ Code = filename:join(Priv, "my_code_test2"),
+
+ catch erlang:purge_module(my_code_test2),
+ catch erlang:delete_module(my_code_test2),
+ catch erlang:purge_module(my_code_test2),
+
+ ?line {ok,my_code_test2} = c:c(File, [{outdir,Priv} | Opts]),
+
+ ?line IsNative = lists:member(native,Opts),
+ ?line IsNative = code:is_module_native(my_code_test2),
+
+ ?line T = ets:new(my_code_test2_fun_table, []),
+ ets:insert(T, {my_fun,my_code_test2:make_fun(4711)}),
+ ets:insert(T, {my_fun2,my_code_test2:make_fun2()}),
+
+ Papa = self(),
+ {P0,M0} = spawn_monitor(fun () ->
+ [{my_fun2,F2}] = ets:lookup(T, my_fun2),
+ F2(fun () ->
+ Papa ! {self(),"going to sleep"},
+ receive {Papa,"wake up"} -> ok end
+ end,
+ fun () -> ok end),
+ exit(completed)
+ end),
+
+ ?line PurgeType = case Type of
+ code_gone ->
+ ok = file:delete(Code++".beam"),
+ true;
+ code_reload ->
+ true;
+ code_there ->
+ false
+ end,
+
+ ?line true = erlang:delete_module(my_code_test2),
+
+ ?line ok = receive {P0, "going to sleep"} -> ok
+ after 1000 -> timeout
+ end,
+
+ ?line Purge = start_purge(my_code_test2, PurgeType),
+
+ ?line {P1, M1} = spawn_monitor(fun () ->
+ ?line [{my_fun,F}] = ets:lookup(T, my_fun),
+ ?line 4712 = F(1),
+ exit(completed)
+ end),
+
+ ?line ok = wait_until(fun () ->
+ {status, suspended}
+ == process_info(P1, status)
+ end),
+
+ ?line ok = continue_purge(Purge),
+
+ ?line {P2, M2} = spawn_monitor(fun () ->
+ ?line [{my_fun,F}] = ets:lookup(T, my_fun),
+ ?line 4713 = F(2),
+ exit(completed)
+ end),
+ ?line {P3, M3} = spawn_monitor(fun () ->
+ ?line [{my_fun,F}] = ets:lookup(T, my_fun),
+ ?line 4714 = F(3),
+ exit(completed)
+ end),
+
+ ?line ok = wait_until(fun () ->
+ {status, suspended}
+ == process_info(P2, status)
+ end),
+ ?line ok = wait_until(fun () ->
+ {status, suspended}
+ == process_info(P3, status)
+ end),
+
+ ?line {current_function,
+ {erts_code_purger,
+ pending_purge_lambda,
+ 3}} = process_info(P1, current_function),
+ ?line {current_function,
+ {erts_code_purger,
+ pending_purge_lambda,
+ 3}} = process_info(P2, current_function),
+ ?line {current_function,
+ {erts_code_purger,
+ pending_purge_lambda,
+ 3}} = process_info(P3, current_function),
+
+ case Type of
+ code_there ->
+ ?line false = complete_purge(Purge),
+ P0 ! {self(), "wake up"},
+ ?line completed = wait_for_down(P0,M0);
+ _ ->
+ ?line {true, true} = complete_purge(Purge),
+ ?line killed = wait_for_down(P0,M0)
+ end,
+
+ case Type of
+ code_gone ->
+ ?line {undef, _} = wait_for_down(P1,M1),
+ ?line {undef, _} = wait_for_down(P2,M2),
+ ?line {undef, _} = wait_for_down(P3,M3);
+ _ ->
+ ?line completed = wait_for_down(P1,M1),
+ ?line completed = wait_for_down(P2,M2),
+ ?line completed = wait_for_down(P3,M3),
+ catch erlang:purge_module(my_code_test2),
+ catch erlang:delete_module(my_code_test2),
+ catch erlang:purge_module(my_code_test2)
+ end,
+ ok.
+
+wait_for_down(P,M) ->
+ receive
+ {'DOWN', M, process, P, Reason} ->
+ Reason
+ after 1000 ->
+ timeout
+ end.
+
+wait_until(Fun) ->
+ wait_until(Fun, 20).
+
+wait_until(Fun, N) ->
+ case {Fun(),N} of
+ {true, _} ->
+ ok;
+ {false, 0} ->
+ timeout;
+ {false, _} ->
+ receive after 100 -> ok end,
+ wait_until(Fun, N-1)
+ end.
+
+start_purge(Mod, Type) when is_atom(Mod)
+ andalso ((Type == true)
+ orelse (Type == false)) ->
+ Ref = make_ref(),
+ erts_code_purger ! {test_purge, Mod, self(), Type, Ref},
+ receive
+ {started, Ref} ->
+ Ref
+ end.
+
+continue_purge(Ref) when is_reference(Ref) ->
+ erts_code_purger ! {continue, Ref},
+ receive
+ {continued, Ref} ->
+ ok
+ end.
+
+complete_purge(Ref) when is_reference(Ref) ->
+ erts_code_purger ! {complete, Ref},
+ receive
+ {test_purge, Res, Ref} ->
+ Res
+ end.
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 08efa23c81..caf99c952f 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
@@ -17,7 +17,7 @@
*
* %CopyrightEnd%
*/
-#include "erl_nif.h"
+#include <erl_nif.h>
#include <assert.h>
#ifdef __WIN32__
#include <windows.h>
diff --git a/erts/emulator/test/driver_SUITE_data/chkio_drv.c b/erts/emulator/test/driver_SUITE_data/chkio_drv.c
index 614b68e865..8e5e81665c 100644
--- a/erts/emulator/test/driver_SUITE_data/chkio_drv.c
+++ b/erts/emulator/test/driver_SUITE_data/chkio_drv.c
@@ -1397,10 +1397,18 @@ static void assert_print(char* str, int line)
static void assert_failed(ErlDrvPort port, char* str, int line)
{
char buf[30];
+ size_t bufsz = sizeof(buf);
+
assert_print(str,line);
- snprintf(buf,sizeof(buf),"failed_at_line_%d",line);
- driver_failure_atom(port,buf);
- /*abort();*/
+
+ if (erl_drv_getenv("ERL_ABORT_ON_FAILURE", buf, &bufsz) == 0
+ && (strcmp("true", buf) == 0 || strcmp("yes", buf) == 0)) {
+ abort();
+ }
+ else {
+ snprintf(buf,sizeof(buf),"failed_at_line_%d",line);
+ driver_failure_atom(port,buf);
+ }
}
#define my_driver_select(PORT,FD,MODE,ON) \
diff --git a/erts/emulator/test/gc_SUITE.erl b/erts/emulator/test/gc_SUITE.erl
index 8a600b7d9f..35dd147550 100644
--- a/erts/emulator/test/gc_SUITE.erl
+++ b/erts/emulator/test/gc_SUITE.erl
@@ -23,15 +23,26 @@
-module(gc_SUITE).
-include_lib("common_test/include/ct.hrl").
+-include_lib("eunit/include/eunit.hrl").
+
-export([all/0, suite/0]).
--export([grow_heap/1, grow_stack/1, grow_stack_heap/1, max_heap_size/1]).
+-export([
+ grow_heap/1,
+ grow_stack/1,
+ grow_stack_heap/1,
+ max_heap_size/1,
+ minor_major_gc_option_async/1,
+ minor_major_gc_option_self/1
+]).
suite() ->
[{ct_hooks,[ts_install_cth]}].
all() ->
- [grow_heap, grow_stack, grow_stack_heap, max_heap_size].
+ [grow_heap, grow_stack, grow_stack_heap, max_heap_size,
+ minor_major_gc_option_self,
+ minor_major_gc_option_async].
%% Produce a growing list of elements,
@@ -190,3 +201,91 @@ long_receive() ->
after 10000 ->
ok
end.
+
+minor_major_gc_option_self(_Config) ->
+ Endless = fun Endless() ->
+ receive
+ {gc, Type} -> erlang:garbage_collect(self(), [{type, Type}])
+ after 100 -> ok end,
+ Endless()
+ end,
+
+ %% Try as major, a test process will self-trigger GC
+ P1 = spawn(Endless),
+ erlang:garbage_collect(P1, []),
+ erlang:trace(P1, true, [garbage_collection]),
+ P1 ! {gc, major},
+ expect_trace_messages(P1, [gc_major_start, gc_major_end]),
+ erlang:trace(P1, false, [garbage_collection]),
+ erlang:exit(P1, kill),
+
+ %% Try as minor, a test process will self-trigger GC
+ P2 = spawn(Endless),
+ erlang:garbage_collect(P2, []),
+ erlang:trace(P2, true, [garbage_collection]),
+ P2 ! {gc, minor},
+ expect_trace_messages(P2, [gc_minor_start, gc_minor_end]),
+ erlang:trace(P2, false, [garbage_collection]),
+ erlang:exit(P2, kill).
+
+minor_major_gc_option_async(_Config) ->
+ Endless = fun Endless() ->
+ receive after 100 -> ok end,
+ Endless()
+ end,
+
+ %% Try with default option, must be major gc
+ P1 = spawn(Endless),
+ erlang:garbage_collect(P1, []),
+ erlang:trace(P1, true, [garbage_collection]),
+ erlang:garbage_collect(P1, []),
+ expect_trace_messages(P1, [gc_major_start, gc_major_end]),
+ erlang:trace(P1, false, [garbage_collection]),
+ erlang:exit(P1, kill),
+
+ %% Try with the 'major' type
+ P2 = spawn(Endless),
+ erlang:garbage_collect(P2, []),
+ erlang:trace(P2, true, [garbage_collection]),
+ erlang:garbage_collect(P2, [{type, major}]),
+ expect_trace_messages(P2, [gc_major_start, gc_major_end]),
+ erlang:trace(P2, false, [garbage_collection]),
+ erlang:exit(P2, kill),
+
+ %% Try with 'minor' option, once
+ P3 = spawn(Endless),
+ erlang:garbage_collect(P3, []),
+ erlang:trace(P3, true, [garbage_collection]),
+ erlang:garbage_collect(P3, [{type, minor}]),
+ expect_trace_messages(P3, [gc_minor_start, gc_minor_end]),
+ erlang:trace(P3, false, [garbage_collection]),
+ erlang:exit(P3, kill),
+
+ %% Try with 'minor' option, once, async
+ P4 = spawn(Endless),
+ Ref = erlang:make_ref(),
+ erlang:garbage_collect(P4, []),
+ erlang:trace(P4, true, [garbage_collection]),
+ ?assertEqual(async,
+ erlang:garbage_collect(P4, [{type, minor}, {async, Ref}])),
+ expect_trace_messages(P4, [gc_minor_start, gc_minor_end]),
+ erlang:trace(P4, false, [garbage_collection]),
+ receive {garbage_collect, Ref, true} -> ok;
+ Other4 -> ct:pal("Unexpected message: ~p~n"
+ ++ "while waiting for async gc result", [Other4])
+ after 2000 -> ?assert(false)
+ end,
+ erlang:exit(P4, kill).
+
+%% Given a list of atoms, trace tags - receives messages and checks if they are
+%% trace events, and if the tag matches. Else will crash failing the test.
+expect_trace_messages(_Pid, []) -> ok;
+expect_trace_messages(Pid, [Tag | TraceTags]) ->
+ receive
+ {trace, Pid, Tag, _Data} -> ok;
+ AnythingElse ->
+ ct:pal("Unexpected message: ~p~nWhile expected {trace, _, ~p, _}",
+ [AnythingElse, Tag]),
+ ?assert(false)
+ end,
+ expect_trace_messages(Pid, TraceTags).
diff --git a/erts/emulator/test/hipe_SUITE.erl b/erts/emulator/test/hipe_SUITE.erl
index a556b4ddc0..0b44dd7fb7 100644
--- a/erts/emulator/test/hipe_SUITE.erl
+++ b/erts/emulator/test/hipe_SUITE.erl
@@ -19,12 +19,17 @@
%%
-module(hipe_SUITE).
--export([all/0, t_copy_literals/1]).
+-export([all/0
+ ,t_copy_literals/1
+ ,t_purge/1
+ ]).
all() ->
case erlang:system_info(hipe_architecture) of
undefined -> {skip, "HiPE is disabled"};
- _ -> [t_copy_literals]
+ _ -> [t_copy_literals
+ ,t_purge
+ ]
end.
t_copy_literals(doc) ->
@@ -65,3 +70,51 @@ t_copy_literals(Config) when is_list(Config) ->
true = erlang:delete_module(ref_cell),
true = erlang:purge_module(ref_cell),
ok.
+
+t_purge(doc) -> "Checks that native code is properly found and purged";
+t_purge(Config) when is_list(Config) ->
+ Data = proplists:get_value(data_dir, Config),
+ Priv = proplists:get_value(priv_dir, Config),
+ SrcFile = filename:join(Data, "ref_cell"),
+ BeamFile = filename:join(Priv, "ref_cell"),
+ {ok,ref_cell} = c:c(SrcFile, [{outdir,Priv},native]),
+ true = code:is_module_native(ref_cell),
+
+ PA = ref_cell:start_link(),
+
+ %% Unload, PA should still be running
+ true = erlang:delete_module(ref_cell),
+ %% Can't use ref_cel:call/2, it's in old code!
+ call(PA, {put_res_of, fun()-> hej end}),
+ hej = call(PA, get),
+
+ %% Load same module again
+ code:load_abs(BeamFile),
+ true = code:is_module_native(ref_cell),
+ PB = ref_cell:start_link(),
+
+ %% Purge old code, PA should be killed, PB should survive
+ unlink(PA),
+ ARef = monitor(process, PA),
+ true = erlang:purge_module(ref_cell),
+ receive {'DOWN', ARef, process, PA, killed} -> ok
+ after 1 -> ct:fail("PA was not killed")
+ end,
+
+ %% Unload, PB should still be running
+ true = erlang:delete_module(ref_cell),
+ call(PB, {put_res_of, fun()-> svejs end}),
+ svejs = call(PB, get),
+
+ unlink(PB),
+ BRef = monitor(process, PB),
+ true = erlang:purge_module(ref_cell),
+ receive {'DOWN', BRef, process, PB, killed} -> ok
+ after 1 -> ct:fail("PB was not killed")
+ end,
+
+ ok.
+
+call(Pid, Call) ->
+ Pid ! {Call, self()},
+ receive {Pid, Res} -> Res end.
diff --git a/erts/emulator/test/match_spec_SUITE.erl b/erts/emulator/test/match_spec_SUITE.erl
index 6733237b20..34e956bc21 100644
--- a/erts/emulator/test/match_spec_SUITE.erl
+++ b/erts/emulator/test/match_spec_SUITE.erl
@@ -427,13 +427,13 @@ silent_no_ms(Config) when is_list(Config) ->
%%
[{trace,Tracee,call,{?MODULE,f1,[start]}},
{trace,Tracee,return_to,
- {?MODULE,'-silent_no_ms/1-fun-2-',0}},
+ {?MODULE,'-silent_no_ms/1-fun-3-',0}},
{trace,Tracee,call,{?MODULE,f2,[f,g]}},
{trace,Tracee,return_to,
- {?MODULE,'-silent_no_ms/1-fun-2-',0}},
+ {?MODULE,'-silent_no_ms/1-fun-3-',0}},
{trace,Tracee,call,{erlang,integer_to_list,[2]}},
{trace,Tracee,return_to,
- {?MODULE,'-silent_no_ms/1-fun-2-',0}},
+ {?MODULE,'-silent_no_ms/1-fun-3-',0}},
{trace,Tracee,call,{?MODULE,f2,[h,i]}},
{trace,Tracee,return_to,{?MODULE,f3,2}}]
end).
@@ -484,7 +484,7 @@ ms_trace2(Config) when is_list(Config) ->
%%
%% Expected: (no return_to for global call trace)
%%
- Origin = {match_spec_SUITE,'-ms_trace2/1-fun-0-',1},
+ Origin = {match_spec_SUITE,'-ms_trace2/1-fun-1-',1},
[{trace_ts,Tracee,call,
{?MODULE,fn,
[[all],[call,return_to,{tracer,Tracer}]]},
@@ -574,7 +574,7 @@ ms_trace3(Config) when is_list(Config) ->
%%
%% Expected: (no return_to for global call trace)
%%
- Origin = {match_spec_SUITE,'-ms_trace3/1-fun-1-',2},
+ Origin = {match_spec_SUITE,'-ms_trace3/1-fun-2-',2},
[{trace_ts,Controller,call,
{?MODULE,fn,[TraceeName,[all],
[call,return_to,send,'receive',
diff --git a/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c b/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c
index e011aadce9..46ee8b5540 100644
--- a/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c
+++ b/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c
@@ -24,7 +24,7 @@
* Author: Rickard Green
*/
-#include "erl_nif.h"
+#include <erl_nif.h>
#ifdef __WIN32__
# ifndef WIN32_LEAN_AND_MEAN
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index 9c1694fa8a..0d3910b2e2 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -21,15 +21,17 @@
-module(nif_SUITE).
%%-define(line_trace,true).
--define(CHECK(Exp,Got), check(Exp,Got,?LINE)).
+-define(CHECK(Exp,Got), Exp = check(Exp,Got,?LINE)).
%%-define(CHECK(Exp,Got), Exp = Got).
-include_lib("common_test/include/ct.hrl").
--export([all/0, suite/0,
+-export([all/0, suite/0, groups/0,
+ 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,
+ basic/1, reload_error/1, upgrade/1, heap_frag/1,
t_on_load/1,
+ hipe/1,
types/1, many_args/1, binaries/1, get_string/1, get_atom/1,
maps/1,
api_macros/1,
@@ -52,27 +54,20 @@
-export([many_args_100/100]).
-
-%% -export([lib_version/0,call_history/0,hold_nif_mod_priv_data/1,nif_mod_call_history/0,
-%% list_seq/1,type_test/0,tuple_2_list/1,is_identical/2,compare/2,
-%% clone_bin/1,make_sub_bin/3,string_to_bin/2,atom_to_bin/2,macros/1,
-%% tuple_2_list_and_tuple/1,iolist_2_bin/1,get_resource_type/1,alloc_resource/2,
-%% make_resource/1,get_resource/2,release_resource/1,last_resource_dtor_call/0, suite/0,
-%% make_new_resource/2,make_new_resource_binary/1,send_list_seq/2,send_new_blob/2,
-%% alloc_msgenv/0,clear_msgenv/1,grow_blob/2,send_blob/2,send_blob_thread/3,
-%% join_send_thread/1]).
-
-
-define(nif_stub,nif_stub_error(?LINE)).
suite() -> [{ct_hooks,[ts_install_cth]}].
-all() ->
- [basic, reload, upgrade, heap_frag, types, many_args,
- t_on_load,
+all() ->
+ [basic]
+ ++
+ [{group, G} || G <- api_groups()]
+ ++
+ [reload_error, heap_frag, types, many_args,
+ hipe,
binaries, get_string, get_atom, maps, api_macros, from_array,
iolist_as_binary, resource, resource_binary,
- resource_takeover, threading, send, send2, send3,
+ threading, send, send2, send3,
send_threaded, neg, is_checks, get_length, make_atom,
make_string,reverse_list_test,
otp_9828,
@@ -85,9 +80,35 @@ all() ->
nif_port_command,
nif_snprintf].
+groups() ->
+ [{G, [], api_repeaters()} || G <- api_groups()].
+
+api_groups() -> [api_latest, api_2_4, api_2_0].
+
+api_repeaters() -> [upgrade, resource_takeover, t_on_load].
+
+init_per_group(api_latest, Config) -> Config;
+init_per_group(api_2_4, Config) ->
+ [{nif_api_version, ".2_4"} | Config];
+init_per_group(api_2_0, Config) ->
+ case {os:type(),erlang:system_info({wordsize, internal})} of
+ {{win32,_}, 8} ->
+ %% ERL_NIF_TERM was declared as 32-bit 'long' until 2.3
+ {skip, "API 2.0 buggy on Windows 64-bit"};
+ _ ->
+ [{nif_api_version, ".2_0"} | Config]
+ end.
+
+end_per_group(_,_) -> ok.
+
init_per_testcase(t_on_load, Config) ->
ets:new(nif_SUITE, [named_table]),
Config;
+init_per_testcase(hipe, Config) ->
+ case erlang:system_info(hipe_architecture) of
+ undefined -> {skip, "HiPE is disabled"};
+ _ -> Config
+ end;
init_per_testcase(_Case, Config) ->
Config.
@@ -112,8 +133,8 @@ basic(Config) when is_list(Config) ->
true = lists:member(?MODULE, erlang:system_info(taints)),
ok.
-%% Test reload callback in nif lib
-reload(Config) when is_list(Config) ->
+%% Test old reload feature now always fails
+reload_error(Config) when is_list(Config) ->
TmpMem = tmpmem(),
ensure_lib_loaded(Config),
@@ -127,20 +148,20 @@ reload(Config) when is_list(Config) ->
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(),
- 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(),
+ {error, {reload, _}} = nif_mod:load_nif_lib(Config, 2),
+ 1 = nif_mod:lib_version(),
+ [{lib_version,1,3,103}] = nif_mod_call_history(),
- ok = nif_mod:load_nif_lib(Config, 1),
+ {error, {reload, _}} = 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(),
+ [{lib_version,1,4,104}] = nif_mod_call_history(),
true = erlang:delete_module(nif_mod),
[] = 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(),
+ [{unload,1,5,105}] = nif_mod_call_history(),
true = lists:member(?MODULE, erlang:system_info(taints)),
true = lists:member(nif_mod, erlang:system_info(taints)),
@@ -148,7 +169,7 @@ reload(Config) when is_list(Config) ->
ok.
%% Test upgrade callback in nif lib
-upgrade(Config) when is_list(Config) ->
+upgrade(Config) when is_list(Config) ->
TmpMem = tmpmem(),
ensure_lib_loaded(Config),
@@ -299,6 +320,8 @@ t_on_load(Config) when is_list(Config) ->
%% Use ETS to tell nif_mod:on_load what to do
ets:insert(nif_SUITE, {data_dir, Data}),
ets:insert(nif_SUITE, {lib_version, 1}),
+ API = proplists:get_value(nif_api_version, Config, ""),
+ ets:insert(nif_SUITE, {nif_api_version, API}),
{module,nif_mod} = code:load_binary(nif_mod,File,Bin),
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(),
@@ -411,6 +434,17 @@ t_on_load(Config) when is_list(Config) ->
verify_tmpmem(TmpMem),
ok.
+hipe(Config) when is_list(Config) ->
+ Data = proplists:get_value(data_dir, Config),
+ Priv = proplists:get_value(priv_dir, Config),
+ Src = filename:join(Data, "hipe_compiled"),
+ {ok,hipe_compiled} = c:c(Src, [{outdir,Priv},native]),
+ true = code:is_module_native(hipe_compiled),
+ {error, {notsup,_}} = hipe_compiled:try_load_nif(),
+ true = code:delete(hipe_compiled),
+ false = code:purge(hipe_compiled),
+ ok.
+
%% Test NIF building heap fragments
heap_frag(Config) when is_list(Config) ->
@@ -828,7 +862,7 @@ resource_binary_do() ->
-define(RT_CREATE,1).
-define(RT_TAKEOVER,2).
-%% Test resource takeover by module reload and upgrade
+%% Test resource takeover by module upgrade
resource_takeover(Config) when is_list(Config) ->
TmpMem = tmpmem(),
ensure_lib_loaded(Config),
@@ -893,6 +927,7 @@ resource_takeover(Config) when is_list(Config) ->
ok = forget_resource(NGX1),
?CHECK([], nif_mod_call_history()), % no dtor
+ {module,nif_mod} = erlang:load_module(nif_mod,ModBin),
ok = nif_mod:load_nif_lib(Config, 2,
[{resource_type, 0, ?RT_TAKEOVER, "resource_type_A",resource_dtor_A,
?RT_TAKEOVER},
@@ -911,7 +946,9 @@ resource_takeover(Config) when is_list(Config) ->
{resource_type, 4, ?RT_CREATE, "resource_type_null_goneY",null,
?RT_CREATE}
]),
- ?CHECK([{reload,2,1,201}], nif_mod_call_history()),
+ ?CHECK([{upgrade,2,1,201}], nif_mod_call_history()),
+ true = erlang:purge_module(nif_mod),
+ ?CHECK([], nif_mod_call_history()), % BGX2 keeping lib loaded
BinA2 = read_resource(0,A2),
ok = forget_resource(A2),
@@ -924,8 +961,8 @@ resource_takeover(Config) when is_list(Config) ->
?CHECK([], nif_mod_call_history()), % no dtor
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?
+ ?CHECK([{{resource_dtor_B_v1,BinBGX2},1,6,106}, {unload,1,7,107}],
+ nif_mod_call_history()),
ok = forget_resource(NGX2),
?CHECK([], nif_mod_call_history()), % no dtor
@@ -1148,6 +1185,9 @@ resource_takeover(Config) when is_list(Config) ->
ok = forget_resource(AN7),
[] = nif_mod_call_history(),
+ true = erlang:delete_module(nif_mod),
+ true = erlang:purge_module(nif_mod),
+
true = lists:member(?MODULE, erlang:system_info(taints)),
true = lists:member(nif_mod, erlang:system_info(taints)),
verify_tmpmem(TmpMem),
@@ -1221,11 +1261,19 @@ threading_do(Config) ->
ok = tester:load_nif_lib(Config, "basic"),
ok = tester:run(),
+ erlang:load_module(tester,ModBin),
+ erlang:purge_module(tester),
ok = tester:load_nif_lib(Config, "rwlock"),
ok = tester:run(),
+ erlang:load_module(tester,ModBin),
+ erlang:purge_module(tester),
ok = tester:load_nif_lib(Config, "tsd"),
- ok = tester:run().
+ ok = tester:run(),
+
+ erlang:delete_module(tester),
+ erlang:purge_module(tester).
+
%% Test NIF message sending
send(Config) when is_list(Config) ->
@@ -1513,13 +1561,13 @@ send3_new_state(State, Blob) ->
neg(Config) when is_list(Config) ->
TmpMem = tmpmem(),
{'EXIT',{badarg,_}} = (catch erlang:load_nif(badarg, 0)),
- {error,{load_failed,_}} = erlang:load_nif("pink_unicorn", 0),
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),
+ {error,{load_failed,_}} = nif_mod:load_nif_lib(Config, 0),
{error,{bad_lib,_}} = nif_mod:load_nif_lib(Config, no_init),
verify_tmpmem(TmpMem),
ok.
@@ -1640,6 +1688,7 @@ consume_timeslice(Config) when is_list(Config) ->
end.
consume_timeslice_test(Config) when is_list(Config) ->
+ ensure_lib_loaded(Config),
CONTEXT_REDS = 2000,
Me = self(),
Go = make_ref(),
@@ -1716,7 +1765,7 @@ consume_timeslice_test(Config) when is_list(Config) ->
io:format("Reductions = ~p~n", [Reductions]),
ok;
{RedDiff, Reductions} ->
- ct:fail({unexpected_reduction_count, Reductions})
+ ct:fail({unexpected_reduction_count, Reductions, ExpReds})
end,
none = next_msg(P),
@@ -1870,7 +1919,8 @@ check(Exp,Got,Line) ->
case Got of
Exp -> Exp;
_ ->
- io:format("CHECK at ~p: Expected ~p but got ~p\n",[Line,Exp,Got]),
+ io:format("CHECK at line ~p\nExpected: ~p\nGot : ~p\n",
+ [Line,Exp,Got]),
Got
end.
diff --git a/erts/emulator/test/nif_SUITE_data/Makefile.src b/erts/emulator/test/nif_SUITE_data/Makefile.src
index fbb8978771..de06026780 100644
--- a/erts/emulator/test/nif_SUITE_data/Makefile.src
+++ b/erts/emulator/test/nif_SUITE_data/Makefile.src
@@ -2,7 +2,13 @@
NIF_LIBS = nif_SUITE.1@dll@ \
nif_mod.1@dll@ \
nif_mod.2@dll@ \
- nif_mod.3@dll@
+ nif_mod.3@dll@ \
+ nif_mod.1.2_0@dll@ \
+ nif_mod.2.2_0@dll@ \
+ nif_mod.3.2_0@dll@ \
+ nif_mod.1.2_4@dll@ \
+ nif_mod.2.2_4@dll@ \
+ nif_mod.3.2_4@dll@
all: $(NIF_LIBS) basic@dll@ rwlock@dll@ tsd@dll@ echo_drv@dll@
diff --git a/erts/emulator/test/nif_SUITE_data/hipe_compiled.erl b/erts/emulator/test/nif_SUITE_data/hipe_compiled.erl
new file mode 100644
index 0000000000..84ddbc8d63
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/hipe_compiled.erl
@@ -0,0 +1,6 @@
+-module(hipe_compiled).
+
+-export([try_load_nif/0]).
+
+try_load_nif() ->
+ erlang:load_nif("doesn't matter", 0).
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index f2b1ef9d24..2c93891852 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -17,7 +17,7 @@
*
* %CopyrightEnd%
*/
-#include "erl_nif.h"
+#include <erl_nif.h>
#include <stdio.h>
#include <string.h>
@@ -104,21 +104,24 @@ struct binary_resource {
static int get_pointer(ErlNifEnv* env, ERL_NIF_TERM term, void** pp)
{
- ErlNifUInt64 i64;
- int r = enif_get_uint64(env, term, &i64);
+ ErlNifBinary bin;
+ int r = enif_inspect_binary(env, term, &bin);
if (r) {
- *pp = (void*)i64;
+ *pp = *(void**)bin.data;
}
return r;
}
static ERL_NIF_TERM make_pointer(ErlNifEnv* env, void* p)
{
- ErlNifUInt64 i64 = (ErlNifUInt64) p;
- return enif_make_uint64(env, i64);
+ void** bin_data;
+ ERL_NIF_TERM res;
+ ADD_CALL("get_priv_data_ptr");
+ bin_data = (void**)enif_make_new_binary(env, sizeof(void*), &res);
+ *bin_data = p;
+ return res;
}
-
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
PrivData* data = enif_alloc(sizeof(PrivData));
@@ -184,14 +187,6 @@ static void resource_takeover(ErlNifEnv* env, PrivData* priv)
msgenv_resource_type = rt;
}
-static int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
-{
- PrivData* priv = (PrivData*) *priv_data;
- add_call(env, priv, "reload");
- resource_takeover(env,priv);
- return 0;
-}
-
static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)
{
PrivData* priv = (PrivData*) *old_priv_data;
@@ -2094,4 +2089,4 @@ static ErlNifFunc nif_funcs[] =
{"format_term_nif", 2, format_term}
};
-ERL_NIF_INIT(nif_SUITE,nif_funcs,load,reload,upgrade,unload)
+ERL_NIF_INIT(nif_SUITE,nif_funcs,load,NULL,upgrade,unload)
diff --git a/erts/emulator/test/nif_SUITE_data/nif_api_2_0/README b/erts/emulator/test/nif_SUITE_data/nif_api_2_0/README
new file mode 100644
index 0000000000..a6ed36f634
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/nif_api_2_0/README
@@ -0,0 +1,5 @@
+These are old genuine header files
+checked out from tag OTP_R14A c1e94fa9a6fe4ae717d35.
+
+I choose this API version (2.0) to test as it's
+before the addition of vm_variant in ErlNifEntry.
diff --git a/erts/emulator/test/nif_SUITE_data/nif_api_2_0/erl_drv_nif.h b/erts/emulator/test/nif_SUITE_data/nif_api_2_0/erl_drv_nif.h
new file mode 100644
index 0000000000..ea013a49a3
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/nif_api_2_0/erl_drv_nif.h
@@ -0,0 +1,48 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Common structures for both erl_driver.h and erl_nif.h
+ */
+
+#ifndef __ERL_DRV_NIF_H__
+#define __ERL_DRV_NIF_H__
+
+typedef struct {
+ int driver_major_version;
+ int driver_minor_version;
+ char *erts_version;
+ char *otp_release;
+ int thread_support;
+ int smp_support;
+ int async_threads;
+ int scheduler_threads;
+ int nif_major_version;
+ int nif_minor_version;
+} ErlDrvSysInfo;
+
+typedef struct {
+ int suggested_stack_size;
+} ErlDrvThreadOpts;
+
+#endif /* __ERL_DRV_NIF_H__ */
+
+
+
+
diff --git a/erts/emulator/test/nif_SUITE_data/nif_api_2_0/erl_nif.h b/erts/emulator/test/nif_SUITE_data/nif_api_2_0/erl_nif.h
new file mode 100644
index 0000000000..936f03bce1
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/nif_api_2_0/erl_nif.h
@@ -0,0 +1,206 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2009-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/* Include file for writers of Native Implemented Functions.
+*/
+
+#ifndef __ERL_NIF_H__
+#define __ERL_NIF_H__
+
+
+#include "erl_drv_nif.h"
+
+/* Version history:
+** 0.1: R13B03
+** 1.0: R13B04
+** 2.0: R14A
+*/
+#define ERL_NIF_MAJOR_VERSION 2
+#define ERL_NIF_MINOR_VERSION 0
+
+#include <stdlib.h>
+
+#ifdef SIZEOF_CHAR
+# define SIZEOF_CHAR_SAVED__ SIZEOF_CHAR
+# undef SIZEOF_CHAR
+#endif
+#ifdef SIZEOF_SHORT
+# define SIZEOF_SHORT_SAVED__ SIZEOF_SHORT
+# undef SIZEOF_SHORT
+#endif
+#ifdef SIZEOF_INT
+# define SIZEOF_INT_SAVED__ SIZEOF_INT
+# undef SIZEOF_INT
+#endif
+#ifdef SIZEOF_LONG
+# define SIZEOF_LONG_SAVED__ SIZEOF_LONG
+# undef SIZEOF_LONG
+#endif
+#ifdef SIZEOF_LONG_LONG
+# define SIZEOF_LONG_LONG_SAVED__ SIZEOF_LONG_LONG
+# undef SIZEOF_LONG_LONG
+#endif
+#ifdef HALFWORD_HEAP_EMULATOR
+# define HALFWORD_HEAP_EMULATOR_SAVED__ HALFWORD_HEAP_EMULATOR
+# undef HALFWORD_HEAP_EMULATOR
+#endif
+#include "erl_int_sizes_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HALFWORD_HEAP_EMULATOR
+typedef unsigned int ERL_NIF_TERM;
+#else
+typedef unsigned long ERL_NIF_TERM;
+#endif
+
+struct enif_environment_t;
+typedef struct enif_environment_t ErlNifEnv;
+
+typedef struct
+{
+ const char* name;
+ unsigned arity;
+ ERL_NIF_TERM (*fptr)(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+}ErlNifFunc;
+
+typedef struct enif_entry_t
+{
+ int major;
+ int minor;
+ const char* name;
+ int num_of_funcs;
+ ErlNifFunc* funcs;
+ int (*load) (ErlNifEnv*, void** priv_data, ERL_NIF_TERM load_info);
+ int (*reload) (ErlNifEnv*, void** priv_data, ERL_NIF_TERM load_info);
+ int (*upgrade)(ErlNifEnv*, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info);
+ void (*unload) (ErlNifEnv*, void* priv_data);
+}ErlNifEntry;
+
+
+
+typedef struct
+{
+ size_t size;
+ unsigned char* data;
+
+ /* Internals (avert your eyes) */
+ ERL_NIF_TERM bin_term;
+ void* ref_bin;
+}ErlNifBinary;
+
+typedef struct enif_resource_type_t ErlNifResourceType;
+typedef void ErlNifResourceDtor(ErlNifEnv*, void*);
+typedef enum
+{
+ ERL_NIF_RT_CREATE = 1,
+ ERL_NIF_RT_TAKEOVER = 2
+}ErlNifResourceFlags;
+
+typedef enum
+{
+ ERL_NIF_LATIN1 = 1
+}ErlNifCharEncoding;
+
+typedef struct
+{
+ ERL_NIF_TERM pid; /* internal, may change */
+}ErlNifPid;
+
+typedef ErlDrvSysInfo ErlNifSysInfo;
+
+typedef struct ErlDrvTid_ *ErlNifTid;
+typedef struct ErlDrvMutex_ ErlNifMutex;
+typedef struct ErlDrvCond_ ErlNifCond;
+typedef struct ErlDrvRWLock_ ErlNifRWLock;
+typedef int ErlNifTSDKey;
+
+typedef ErlDrvThreadOpts ErlNifThreadOpts;
+
+#if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_))
+# define ERL_NIF_API_FUNC_DECL(RET_TYPE, NAME, ARGS) RET_TYPE (*NAME) ARGS
+typedef struct {
+# include "erl_nif_api_funcs.h"
+} TWinDynNifCallbacks;
+extern TWinDynNifCallbacks WinDynNifCallbacks;
+# undef ERL_NIF_API_FUNC_DECL
+#endif
+
+#if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_)) && !defined(STATIC_ERLANG_DRIVER)
+# define ERL_NIF_API_FUNC_MACRO(NAME) (WinDynNifCallbacks.NAME)
+# include "erl_nif_api_funcs.h"
+/* note that we have to keep ERL_NIF_API_FUNC_MACRO defined */
+
+#else /* non windows or included from emulator itself */
+
+# define ERL_NIF_API_FUNC_DECL(RET_TYPE, NAME, ARGS) extern RET_TYPE NAME ARGS
+# include "erl_nif_api_funcs.h"
+# undef ERL_NIF_API_FUNC_DECL
+#endif
+
+
+#if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_))
+# define ERL_NIF_INIT_GLOB TWinDynNifCallbacks WinDynNifCallbacks;
+# define ERL_NIF_INIT_DECL(MODNAME) __declspec(dllexport) ErlNifEntry* nif_init(TWinDynNifCallbacks* callbacks)
+# define ERL_NIF_INIT_BODY memcpy(&WinDynNifCallbacks,callbacks,sizeof(TWinDynNifCallbacks))
+#else
+# define ERL_NIF_INIT_GLOB
+# define ERL_NIF_INIT_BODY
+# if defined(VXWORKS)
+# define ERL_NIF_INIT_DECL(MODNAME) ErlNifEntry* MODNAME ## _init(void)
+# else
+# define ERL_NIF_INIT_DECL(MODNAME) ErlNifEntry* nif_init(void)
+# endif
+#endif
+
+
+#ifdef __cplusplus
+}
+# define ERL_NIF_INIT_PROLOGUE extern "C" {
+# define ERL_NIF_INIT_EPILOGUE }
+#else
+# define ERL_NIF_INIT_PROLOGUE
+# define ERL_NIF_INIT_EPILOGUE
+#endif
+
+
+#define ERL_NIF_INIT(NAME, FUNCS, LOAD, RELOAD, UPGRADE, UNLOAD) \
+ERL_NIF_INIT_PROLOGUE \
+ERL_NIF_INIT_GLOB \
+ERL_NIF_INIT_DECL(NAME) \
+{ \
+ static ErlNifEntry entry = \
+ { \
+ ERL_NIF_MAJOR_VERSION, \
+ ERL_NIF_MINOR_VERSION, \
+ #NAME, \
+ sizeof(FUNCS) / sizeof(*FUNCS), \
+ FUNCS, \
+ LOAD, RELOAD, UPGRADE, UNLOAD \
+ }; \
+ ERL_NIF_INIT_BODY; \
+ return &entry; \
+} \
+ERL_NIF_INIT_EPILOGUE
+
+
+#endif /* __ERL_NIF_H__ */
+
diff --git a/erts/emulator/test/nif_SUITE_data/nif_api_2_0/erl_nif_api_funcs.h b/erts/emulator/test/nif_SUITE_data/nif_api_2_0/erl_nif_api_funcs.h
new file mode 100644
index 0000000000..ef4e9580b0
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/nif_api_2_0/erl_nif_api_funcs.h
@@ -0,0 +1,257 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2009-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#if !defined(ERL_NIF_API_FUNC_DECL) && !defined(ERL_NIF_API_FUNC_MACRO)
+# error This file should not be included directly
+#endif
+
+#ifdef ERL_NIF_API_FUNC_DECL
+ERL_NIF_API_FUNC_DECL(void*,enif_priv_data,(ErlNifEnv*));
+ERL_NIF_API_FUNC_DECL(void*,enif_alloc,(size_t size));
+ERL_NIF_API_FUNC_DECL(void,enif_free,(void* ptr));
+ERL_NIF_API_FUNC_DECL(int,enif_is_atom,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_is_binary,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_is_ref,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_inspect_binary,(ErlNifEnv*, ERL_NIF_TERM bin_term, ErlNifBinary* bin));
+ERL_NIF_API_FUNC_DECL(int,enif_alloc_binary,(size_t size, ErlNifBinary* bin));
+ERL_NIF_API_FUNC_DECL(int,enif_realloc_binary,(ErlNifBinary* bin, size_t size));
+ERL_NIF_API_FUNC_DECL(void,enif_release_binary,(ErlNifBinary* bin));
+ERL_NIF_API_FUNC_DECL(int,enif_get_int,(ErlNifEnv*, ERL_NIF_TERM term, int* ip));
+ERL_NIF_API_FUNC_DECL(int,enif_get_ulong,(ErlNifEnv*, ERL_NIF_TERM term, unsigned long* ip));
+ERL_NIF_API_FUNC_DECL(int,enif_get_double,(ErlNifEnv*, ERL_NIF_TERM term, double* dp));
+ERL_NIF_API_FUNC_DECL(int,enif_get_list_cell,(ErlNifEnv* env, ERL_NIF_TERM term, ERL_NIF_TERM* head, ERL_NIF_TERM* tail));
+ERL_NIF_API_FUNC_DECL(int,enif_get_tuple,(ErlNifEnv* env, ERL_NIF_TERM tpl, int* arity, const ERL_NIF_TERM** array));
+ERL_NIF_API_FUNC_DECL(int,enif_is_identical,(ERL_NIF_TERM lhs, ERL_NIF_TERM rhs));
+ERL_NIF_API_FUNC_DECL(int,enif_compare,(ERL_NIF_TERM lhs, ERL_NIF_TERM rhs));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_binary,(ErlNifEnv* env, ErlNifBinary* bin));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_badarg,(ErlNifEnv* env));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_int,(ErlNifEnv* env, int i));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_ulong,(ErlNifEnv* env, unsigned long i));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_double,(ErlNifEnv* env, double d));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_atom,(ErlNifEnv* env, const char* name));
+ERL_NIF_API_FUNC_DECL(int,enif_make_existing_atom,(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom, ErlNifCharEncoding));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_tuple,(ErlNifEnv* env, unsigned cnt, ...));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list,(ErlNifEnv* env, unsigned cnt, ...));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list_cell,(ErlNifEnv* env, ERL_NIF_TERM car, ERL_NIF_TERM cdr));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string,(ErlNifEnv* env, const char* string, ErlNifCharEncoding));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_ref,(ErlNifEnv* env));
+
+ERL_NIF_API_FUNC_DECL(ErlNifMutex*,enif_mutex_create,(char *name));
+ERL_NIF_API_FUNC_DECL(void,enif_mutex_destroy,(ErlNifMutex *mtx));
+ERL_NIF_API_FUNC_DECL(int,enif_mutex_trylock,(ErlNifMutex *mtx));
+ERL_NIF_API_FUNC_DECL(void,enif_mutex_lock,(ErlNifMutex *mtx));
+ERL_NIF_API_FUNC_DECL(void,enif_mutex_unlock,(ErlNifMutex *mtx));
+ERL_NIF_API_FUNC_DECL(ErlNifCond*,enif_cond_create,(char *name));
+ERL_NIF_API_FUNC_DECL(void,enif_cond_destroy,(ErlNifCond *cnd));
+ERL_NIF_API_FUNC_DECL(void,enif_cond_signal,(ErlNifCond *cnd));
+ERL_NIF_API_FUNC_DECL(void,enif_cond_broadcast,(ErlNifCond *cnd));
+ERL_NIF_API_FUNC_DECL(void,enif_cond_wait,(ErlNifCond *cnd, ErlNifMutex *mtx));
+ERL_NIF_API_FUNC_DECL(ErlNifRWLock*,enif_rwlock_create,(char *name));
+ERL_NIF_API_FUNC_DECL(void,enif_rwlock_destroy,(ErlNifRWLock *rwlck));
+ERL_NIF_API_FUNC_DECL(int,enif_rwlock_tryrlock,(ErlNifRWLock *rwlck));
+ERL_NIF_API_FUNC_DECL(void,enif_rwlock_rlock,(ErlNifRWLock *rwlck));
+ERL_NIF_API_FUNC_DECL(void,enif_rwlock_runlock,(ErlNifRWLock *rwlck));
+ERL_NIF_API_FUNC_DECL(int,enif_rwlock_tryrwlock,(ErlNifRWLock *rwlck));
+ERL_NIF_API_FUNC_DECL(void,enif_rwlock_rwlock,(ErlNifRWLock *rwlck));
+ERL_NIF_API_FUNC_DECL(void,enif_rwlock_rwunlock,(ErlNifRWLock *rwlck));
+ERL_NIF_API_FUNC_DECL(int,enif_tsd_key_create,(char *name, ErlNifTSDKey *key));
+ERL_NIF_API_FUNC_DECL(void,enif_tsd_key_destroy,(ErlNifTSDKey key));
+ERL_NIF_API_FUNC_DECL(void,enif_tsd_set,(ErlNifTSDKey key, void *data));
+ERL_NIF_API_FUNC_DECL(void*,enif_tsd_get,(ErlNifTSDKey key));
+ERL_NIF_API_FUNC_DECL(ErlNifThreadOpts*,enif_thread_opts_create,(char *name));
+ERL_NIF_API_FUNC_DECL(void,enif_thread_opts_destroy,(ErlNifThreadOpts *opts));
+ERL_NIF_API_FUNC_DECL(int,enif_thread_create,(char *name,ErlNifTid *tid,void * (*func)(void *),void *args,ErlNifThreadOpts *opts));
+ERL_NIF_API_FUNC_DECL(ErlNifTid,enif_thread_self,(void));
+ERL_NIF_API_FUNC_DECL(int,enif_equal_tids,(ErlNifTid tid1, ErlNifTid tid2));
+ERL_NIF_API_FUNC_DECL(void,enif_thread_exit,(void *resp));
+ERL_NIF_API_FUNC_DECL(int,enif_thread_join,(ErlNifTid, void **respp));
+
+ERL_NIF_API_FUNC_DECL(void*,enif_realloc,(void* ptr, size_t size));
+ERL_NIF_API_FUNC_DECL(void,enif_system_info,(ErlNifSysInfo *sip, size_t si_size));
+ERL_NIF_API_FUNC_DECL(int,enif_fprintf,(void/* FILE* */ *filep, const char *format, ...));
+ERL_NIF_API_FUNC_DECL(int,enif_inspect_iolist_as_binary,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifBinary* bin));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_sub_binary,(ErlNifEnv*, ERL_NIF_TERM bin_term, size_t pos, size_t size));
+ERL_NIF_API_FUNC_DECL(int,enif_get_string,(ErlNifEnv*, ERL_NIF_TERM list, char* buf, unsigned len, ErlNifCharEncoding));
+ERL_NIF_API_FUNC_DECL(int,enif_get_atom,(ErlNifEnv*, ERL_NIF_TERM atom, char* buf, unsigned len, ErlNifCharEncoding));
+ERL_NIF_API_FUNC_DECL(int,enif_is_fun,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_is_pid,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_is_port,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_get_uint,(ErlNifEnv*, ERL_NIF_TERM term, unsigned* ip));
+ERL_NIF_API_FUNC_DECL(int,enif_get_long,(ErlNifEnv*, ERL_NIF_TERM term, long* ip));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_uint,(ErlNifEnv*, unsigned i));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_long,(ErlNifEnv*, long i));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_tuple_from_array,(ErlNifEnv*, const ERL_NIF_TERM arr[], unsigned cnt));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list_from_array,(ErlNifEnv*, const ERL_NIF_TERM arr[], unsigned cnt));
+ERL_NIF_API_FUNC_DECL(int,enif_is_empty_list,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(ErlNifResourceType*,enif_open_resource_type,(ErlNifEnv*, const char* module_str, const char* name_str, void (*dtor)(ErlNifEnv*,void *), ErlNifResourceFlags flags, ErlNifResourceFlags* tried));
+ERL_NIF_API_FUNC_DECL(void*,enif_alloc_resource,(ErlNifResourceType* type, size_t size));
+ERL_NIF_API_FUNC_DECL(void,enif_release_resource,(void* obj));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_resource,(ErlNifEnv*, void* obj));
+ERL_NIF_API_FUNC_DECL(int,enif_get_resource,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifResourceType* type, void** objp));
+ERL_NIF_API_FUNC_DECL(size_t,enif_sizeof_resource,(void* obj));
+ERL_NIF_API_FUNC_DECL(unsigned char*,enif_make_new_binary,(ErlNifEnv*,size_t size,ERL_NIF_TERM* termp));
+ERL_NIF_API_FUNC_DECL(int,enif_is_list,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_is_tuple,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_get_atom_length,(ErlNifEnv*, ERL_NIF_TERM atom, unsigned* len, ErlNifCharEncoding));
+ERL_NIF_API_FUNC_DECL(int,enif_get_list_length,(ErlNifEnv* env, ERL_NIF_TERM term, unsigned* len));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM, enif_make_atom_len,(ErlNifEnv* env, const char* name, size_t len));
+ERL_NIF_API_FUNC_DECL(int, enif_make_existing_atom_len,(ErlNifEnv* env, const char* name, size_t len, ERL_NIF_TERM* atom, ErlNifCharEncoding));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string_len,(ErlNifEnv* env, const char* string, size_t len, ErlNifCharEncoding));
+ERL_NIF_API_FUNC_DECL(ErlNifEnv*,enif_alloc_env,(void));
+ERL_NIF_API_FUNC_DECL(void,enif_free_env,(ErlNifEnv* env));
+ERL_NIF_API_FUNC_DECL(void,enif_clear_env,(ErlNifEnv* env));
+ERL_NIF_API_FUNC_DECL(int,enif_send,(ErlNifEnv* env, const ErlNifPid* to_pid, ErlNifEnv* msg_env, ERL_NIF_TERM msg));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_copy,(ErlNifEnv* dst_env, ERL_NIF_TERM src_term));
+ERL_NIF_API_FUNC_DECL(ErlNifPid*,enif_self,(ErlNifEnv* caller_env, ErlNifPid* pid));
+ERL_NIF_API_FUNC_DECL(int,enif_get_local_pid,(ErlNifEnv* env, ERL_NIF_TERM, ErlNifPid* pid));
+ERL_NIF_API_FUNC_DECL(void,enif_keep_resource,(void* obj));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_resource_binary,(ErlNifEnv*,void* obj,const void* data, size_t size));
+
+/*
+** Add last to keep compatibility on Windows!!!
+*/
+#endif
+
+#ifdef ERL_NIF_API_FUNC_MACRO
+# define enif_priv_data ERL_NIF_API_FUNC_MACRO(enif_priv_data)
+# define enif_alloc ERL_NIF_API_FUNC_MACRO(enif_alloc)
+# define enif_free ERL_NIF_API_FUNC_MACRO(enif_free)
+# define enif_is_atom ERL_NIF_API_FUNC_MACRO(enif_is_atom)
+# define enif_is_binary ERL_NIF_API_FUNC_MACRO(enif_is_binary)
+# define enif_is_ref ERL_NIF_API_FUNC_MACRO(enif_is_ref)
+# define enif_inspect_binary ERL_NIF_API_FUNC_MACRO(enif_inspect_binary)
+# define enif_alloc_binary ERL_NIF_API_FUNC_MACRO(enif_alloc_binary)
+# define enif_realloc_binary ERL_NIF_API_FUNC_MACRO(enif_realloc_binary)
+# define enif_release_binary ERL_NIF_API_FUNC_MACRO(enif_release_binary)
+# define enif_get_int ERL_NIF_API_FUNC_MACRO(enif_get_int)
+# define enif_get_ulong ERL_NIF_API_FUNC_MACRO(enif_get_ulong)
+# define enif_get_double ERL_NIF_API_FUNC_MACRO(enif_get_double)
+# define enif_get_tuple ERL_NIF_API_FUNC_MACRO(enif_get_tuple)
+# define enif_get_list_cell ERL_NIF_API_FUNC_MACRO(enif_get_list_cell)
+# define enif_is_identical ERL_NIF_API_FUNC_MACRO(enif_is_identical)
+# define enif_compare ERL_NIF_API_FUNC_MACRO(enif_compare)
+
+# define enif_make_binary ERL_NIF_API_FUNC_MACRO(enif_make_binary)
+# define enif_make_badarg ERL_NIF_API_FUNC_MACRO(enif_make_badarg)
+# define enif_make_int ERL_NIF_API_FUNC_MACRO(enif_make_int)
+# define enif_make_ulong ERL_NIF_API_FUNC_MACRO(enif_make_ulong)
+# define enif_make_double ERL_NIF_API_FUNC_MACRO(enif_make_double)
+# define enif_make_atom ERL_NIF_API_FUNC_MACRO(enif_make_atom)
+# define enif_make_existing_atom ERL_NIF_API_FUNC_MACRO(enif_make_existing_atom)
+# define enif_make_tuple ERL_NIF_API_FUNC_MACRO(enif_make_tuple)
+# define enif_make_list ERL_NIF_API_FUNC_MACRO(enif_make_list)
+# define enif_make_list_cell ERL_NIF_API_FUNC_MACRO(enif_make_list_cell)
+# define enif_make_string ERL_NIF_API_FUNC_MACRO(enif_make_string)
+# define enif_make_ref ERL_NIF_API_FUNC_MACRO(enif_make_ref)
+
+# define enif_mutex_create ERL_NIF_API_FUNC_MACRO(enif_mutex_create)
+# define enif_mutex_destroy ERL_NIF_API_FUNC_MACRO(enif_mutex_destroy)
+# define enif_mutex_trylock ERL_NIF_API_FUNC_MACRO(enif_mutex_trylock)
+# define enif_mutex_lock ERL_NIF_API_FUNC_MACRO(enif_mutex_lock)
+# define enif_mutex_unlock ERL_NIF_API_FUNC_MACRO(enif_mutex_unlock)
+# define enif_cond_create ERL_NIF_API_FUNC_MACRO(enif_cond_create)
+# define enif_cond_destroy ERL_NIF_API_FUNC_MACRO(enif_cond_destroy)
+# define enif_cond_signal ERL_NIF_API_FUNC_MACRO(enif_cond_signal)
+# define enif_cond_broadcast ERL_NIF_API_FUNC_MACRO(enif_cond_broadcast)
+# define enif_cond_wait ERL_NIF_API_FUNC_MACRO(enif_cond_wait)
+# define enif_rwlock_create ERL_NIF_API_FUNC_MACRO(enif_rwlock_create)
+# define enif_rwlock_destroy ERL_NIF_API_FUNC_MACRO(enif_rwlock_destroy)
+# define enif_rwlock_tryrlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_tryrlock)
+# define enif_rwlock_rlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_rlock)
+# define enif_rwlock_runlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_runlock)
+# define enif_rwlock_tryrwlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_tryrwlock)
+# define enif_rwlock_rwlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_rwlock)
+# define enif_rwlock_rwunlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_rwunlock)
+# define enif_tsd_key_create ERL_NIF_API_FUNC_MACRO(enif_tsd_key_create)
+# define enif_tsd_key_destroy ERL_NIF_API_FUNC_MACRO(enif_tsd_key_destroy)
+# define enif_tsd_set ERL_NIF_API_FUNC_MACRO(enif_tsd_set)
+# define enif_tsd_get ERL_NIF_API_FUNC_MACRO(enif_tsd_get)
+# define enif_thread_opts_create ERL_NIF_API_FUNC_MACRO(enif_thread_opts_create)
+# define enif_thread_opts_destroy ERL_NIF_API_FUNC_MACRO(enif_thread_opts_destroy)
+# define enif_thread_create ERL_NIF_API_FUNC_MACRO(enif_thread_create)
+# define enif_thread_self ERL_NIF_API_FUNC_MACRO(enif_thread_self)
+# define enif_equal_tids ERL_NIF_API_FUNC_MACRO(enif_equal_tids)
+# define enif_thread_exit ERL_NIF_API_FUNC_MACRO(enif_thread_exit)
+# define enif_thread_join ERL_NIF_API_FUNC_MACRO(enif_thread_join)
+
+# define enif_realloc ERL_NIF_API_FUNC_MACRO(enif_realloc)
+# define enif_system_info ERL_NIF_API_FUNC_MACRO(enif_system_info)
+# define enif_fprintf ERL_NIF_API_FUNC_MACRO(enif_fprintf)
+# define enif_inspect_iolist_as_binary ERL_NIF_API_FUNC_MACRO(enif_inspect_iolist_as_binary)
+# define enif_make_sub_binary ERL_NIF_API_FUNC_MACRO(enif_make_sub_binary)
+# define enif_get_string ERL_NIF_API_FUNC_MACRO(enif_get_string)
+# define enif_get_atom ERL_NIF_API_FUNC_MACRO(enif_get_atom)
+# define enif_is_fun ERL_NIF_API_FUNC_MACRO(enif_is_fun)
+# define enif_is_pid ERL_NIF_API_FUNC_MACRO(enif_is_pid)
+# define enif_is_port ERL_NIF_API_FUNC_MACRO(enif_is_port)
+# define enif_get_uint ERL_NIF_API_FUNC_MACRO(enif_get_uint)
+# define enif_get_long ERL_NIF_API_FUNC_MACRO(enif_get_long)
+# define enif_make_uint ERL_NIF_API_FUNC_MACRO(enif_make_uint)
+# define enif_make_long ERL_NIF_API_FUNC_MACRO(enif_make_long)
+# define enif_make_tuple_from_array ERL_NIF_API_FUNC_MACRO(enif_make_tuple_from_array)
+# define enif_make_list_from_array ERL_NIF_API_FUNC_MACRO(enif_make_list_from_array)
+# define enif_is_empty_list ERL_NIF_API_FUNC_MACRO(enif_is_empty_list)
+# define enif_open_resource_type ERL_NIF_API_FUNC_MACRO(enif_open_resource_type)
+# define enif_alloc_resource ERL_NIF_API_FUNC_MACRO(enif_alloc_resource)
+# define enif_release_resource ERL_NIF_API_FUNC_MACRO(enif_release_resource)
+# define enif_make_resource ERL_NIF_API_FUNC_MACRO(enif_make_resource)
+# define enif_get_resource ERL_NIF_API_FUNC_MACRO(enif_get_resource)
+# define enif_sizeof_resource ERL_NIF_API_FUNC_MACRO(enif_sizeof_resource)
+# define enif_make_new_binary ERL_NIF_API_FUNC_MACRO(enif_make_new_binary)
+# define enif_is_list ERL_NIF_API_FUNC_MACRO(enif_is_list)
+# define enif_is_tuple ERL_NIF_API_FUNC_MACRO(enif_is_tuple)
+# define enif_get_atom_length ERL_NIF_API_FUNC_MACRO(enif_get_atom_length)
+# define enif_get_list_length ERL_NIF_API_FUNC_MACRO(enif_get_list_length)
+# define enif_make_atom_len ERL_NIF_API_FUNC_MACRO(enif_make_atom_len)
+# define enif_make_existing_atom_len ERL_NIF_API_FUNC_MACRO(enif_make_existing_atom_len)
+# define enif_make_string_len ERL_NIF_API_FUNC_MACRO(enif_make_string_len)
+# define enif_alloc_env ERL_NIF_API_FUNC_MACRO(enif_alloc_env)
+# define enif_free_env ERL_NIF_API_FUNC_MACRO(enif_free_env)
+# define enif_clear_env ERL_NIF_API_FUNC_MACRO(enif_clear_env)
+# define enif_send ERL_NIF_API_FUNC_MACRO(enif_send)
+# define enif_make_copy ERL_NIF_API_FUNC_MACRO(enif_make_copy)
+# define enif_self ERL_NIF_API_FUNC_MACRO(enif_self)
+# define enif_get_local_pid ERL_NIF_API_FUNC_MACRO(enif_get_local_pid)
+# define enif_keep_resource ERL_NIF_API_FUNC_MACRO(enif_keep_resource)
+# define enif_make_resource_binary ERL_NIF_API_FUNC_MACRO(enif_make_resource_binary)
+#endif
+
+#ifndef enif_make_list1
+# define enif_make_list1(ENV,E1) enif_make_list(ENV,1,E1)
+# define enif_make_list2(ENV,E1,E2) enif_make_list(ENV,2,E1,E2)
+# define enif_make_list3(ENV,E1,E2,E3) enif_make_list(ENV,3,E1,E2,E3)
+# define enif_make_list4(ENV,E1,E2,E3,E4) enif_make_list(ENV,4,E1,E2,E3,E4)
+# define enif_make_list5(ENV,E1,E2,E3,E4,E5) enif_make_list(ENV,5,E1,E2,E3,E4,E5)
+# define enif_make_list6(ENV,E1,E2,E3,E4,E5,E6) enif_make_list(ENV,6,E1,E2,E3,E4,E5,E6)
+# define enif_make_list7(ENV,E1,E2,E3,E4,E5,E6,E7) enif_make_list(ENV,7,E1,E2,E3,E4,E5,E6,E7)
+# define enif_make_list8(ENV,E1,E2,E3,E4,E5,E6,E7,E8) enif_make_list(ENV,8,E1,E2,E3,E4,E5,E6,E7,E8)
+# define enif_make_list9(ENV,E1,E2,E3,E4,E5,E6,E7,E8,E9) enif_make_list(ENV,9,E1,E2,E3,E4,E5,E6,E7,E8,E9)
+# define enif_make_tuple1(ENV,E1) enif_make_tuple(ENV,1,E1)
+# define enif_make_tuple2(ENV,E1,E2) enif_make_tuple(ENV,2,E1,E2)
+# define enif_make_tuple3(ENV,E1,E2,E3) enif_make_tuple(ENV,3,E1,E2,E3)
+# define enif_make_tuple4(ENV,E1,E2,E3,E4) enif_make_tuple(ENV,4,E1,E2,E3,E4)
+# define enif_make_tuple5(ENV,E1,E2,E3,E4,E5) enif_make_tuple(ENV,5,E1,E2,E3,E4,E5)
+# define enif_make_tuple6(ENV,E1,E2,E3,E4,E5,E6) enif_make_tuple(ENV,6,E1,E2,E3,E4,E5,E6)
+# define enif_make_tuple7(ENV,E1,E2,E3,E4,E5,E6,E7) enif_make_tuple(ENV,7,E1,E2,E3,E4,E5,E6,E7)
+# define enif_make_tuple8(ENV,E1,E2,E3,E4,E5,E6,E7,E8) enif_make_tuple(ENV,8,E1,E2,E3,E4,E5,E6,E7,E8)
+# define enif_make_tuple9(ENV,E1,E2,E3,E4,E5,E6,E7,E8,E9) enif_make_tuple(ENV,9,E1,E2,E3,E4,E5,E6,E7,E8,E9)
+
+# define enif_make_pid(ENV, PID) ((const ERL_NIF_TERM)((PID)->pid))
+#endif
+
diff --git a/erts/emulator/test/nif_SUITE_data/nif_api_2_4/README b/erts/emulator/test/nif_SUITE_data/nif_api_2_4/README
new file mode 100644
index 0000000000..7abd0319a6
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/nif_api_2_4/README
@@ -0,0 +1,6 @@
+These are old genuine header files
+checked out from tag OTP_R16B 05f11890bdfec4bfc3a78e191
+
+I choose this API version (2.4) to test, as it's before
+the addition of 'options' in ErlNifEntry and 'flags' in ErlNifFunc
+and without include of generated erl_native_features_config.h.
diff --git a/erts/emulator/test/nif_SUITE_data/nif_api_2_4/erl_drv_nif.h b/erts/emulator/test/nif_SUITE_data/nif_api_2_4/erl_drv_nif.h
new file mode 100644
index 0000000000..ea013a49a3
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/nif_api_2_4/erl_drv_nif.h
@@ -0,0 +1,48 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Common structures for both erl_driver.h and erl_nif.h
+ */
+
+#ifndef __ERL_DRV_NIF_H__
+#define __ERL_DRV_NIF_H__
+
+typedef struct {
+ int driver_major_version;
+ int driver_minor_version;
+ char *erts_version;
+ char *otp_release;
+ int thread_support;
+ int smp_support;
+ int async_threads;
+ int scheduler_threads;
+ int nif_major_version;
+ int nif_minor_version;
+} ErlDrvSysInfo;
+
+typedef struct {
+ int suggested_stack_size;
+} ErlDrvThreadOpts;
+
+#endif /* __ERL_DRV_NIF_H__ */
+
+
+
+
diff --git a/erts/emulator/test/nif_SUITE_data/nif_api_2_4/erl_nif.h b/erts/emulator/test/nif_SUITE_data/nif_api_2_4/erl_nif.h
new file mode 100644
index 0000000000..8006741a63
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/nif_api_2_4/erl_nif.h
@@ -0,0 +1,237 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2009-2013. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/* Include file for writers of Native Implemented Functions.
+*/
+
+#ifndef __ERL_NIF_H__
+#define __ERL_NIF_H__
+
+
+#include "erl_drv_nif.h"
+
+/* Version history:
+** 0.1: R13B03
+** 1.0: R13B04
+** 2.0: R14A
+** 2.1: R14B02 "vm_variant"
+** 2.2: R14B03 enif_is_exception
+** 2.3: R15 enif_make_reverse_list, enif_is_number
+** 2.4: R16 enif_consume_timeslice
+*/
+#define ERL_NIF_MAJOR_VERSION 2
+#define ERL_NIF_MINOR_VERSION 4
+
+#include <stdlib.h>
+
+#ifdef SIZEOF_CHAR
+# define SIZEOF_CHAR_SAVED__ SIZEOF_CHAR
+# undef SIZEOF_CHAR
+#endif
+#ifdef SIZEOF_SHORT
+# define SIZEOF_SHORT_SAVED__ SIZEOF_SHORT
+# undef SIZEOF_SHORT
+#endif
+#ifdef SIZEOF_INT
+# define SIZEOF_INT_SAVED__ SIZEOF_INT
+# undef SIZEOF_INT
+#endif
+#ifdef SIZEOF_LONG
+# define SIZEOF_LONG_SAVED__ SIZEOF_LONG
+# undef SIZEOF_LONG
+#endif
+#ifdef SIZEOF_LONG_LONG
+# define SIZEOF_LONG_LONG_SAVED__ SIZEOF_LONG_LONG
+# undef SIZEOF_LONG_LONG
+#endif
+#ifdef HALFWORD_HEAP_EMULATOR
+# define HALFWORD_HEAP_EMULATOR_SAVED__ HALFWORD_HEAP_EMULATOR
+# undef HALFWORD_HEAP_EMULATOR
+#endif
+#include "erl_int_sizes_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_))
+typedef unsigned __int64 ErlNifUInt64;
+typedef __int64 ErlNifSInt64;
+#elif SIZEOF_LONG == 8
+typedef unsigned long ErlNifUInt64;
+typedef long ErlNifSInt64;
+#elif SIZEOF_LONG_LONG == 8
+typedef unsigned long long ErlNifUInt64;
+typedef long long ErlNifSInt64;
+#else
+#error No 64-bit integer type
+#endif
+
+#ifdef HALFWORD_HEAP_EMULATOR
+# define ERL_NIF_VM_VARIANT "beam.halfword"
+typedef unsigned int ERL_NIF_TERM;
+#else
+# define ERL_NIF_VM_VARIANT "beam.vanilla"
+# if SIZEOF_LONG == SIZEOF_VOID_P
+typedef unsigned long ERL_NIF_TERM;
+# elif SIZEOF_LONG_LONG == SIZEOF_VOID_P
+typedef unsigned long long ERL_NIF_TERM;
+# endif
+#endif
+
+struct enif_environment_t;
+typedef struct enif_environment_t ErlNifEnv;
+
+typedef struct
+{
+ const char* name;
+ unsigned arity;
+ ERL_NIF_TERM (*fptr)(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+}ErlNifFunc;
+
+typedef struct enif_entry_t
+{
+ int major;
+ int minor;
+ const char* name;
+ int num_of_funcs;
+ ErlNifFunc* funcs;
+ int (*load) (ErlNifEnv*, void** priv_data, ERL_NIF_TERM load_info);
+ int (*reload) (ErlNifEnv*, void** priv_data, ERL_NIF_TERM load_info);
+ int (*upgrade)(ErlNifEnv*, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info);
+ void (*unload) (ErlNifEnv*, void* priv_data);
+ const char* vm_variant;
+}ErlNifEntry;
+
+
+
+typedef struct
+{
+ size_t size;
+ unsigned char* data;
+
+ /* Internals (avert your eyes) */
+ ERL_NIF_TERM bin_term;
+ void* ref_bin;
+}ErlNifBinary;
+
+typedef struct enif_resource_type_t ErlNifResourceType;
+typedef void ErlNifResourceDtor(ErlNifEnv*, void*);
+typedef enum
+{
+ ERL_NIF_RT_CREATE = 1,
+ ERL_NIF_RT_TAKEOVER = 2
+}ErlNifResourceFlags;
+
+typedef enum
+{
+ ERL_NIF_LATIN1 = 1
+}ErlNifCharEncoding;
+
+typedef struct
+{
+ ERL_NIF_TERM pid; /* internal, may change */
+}ErlNifPid;
+
+typedef ErlDrvSysInfo ErlNifSysInfo;
+
+typedef struct ErlDrvTid_ *ErlNifTid;
+typedef struct ErlDrvMutex_ ErlNifMutex;
+typedef struct ErlDrvCond_ ErlNifCond;
+typedef struct ErlDrvRWLock_ ErlNifRWLock;
+typedef int ErlNifTSDKey;
+
+typedef ErlDrvThreadOpts ErlNifThreadOpts;
+
+#if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_))
+# define ERL_NIF_API_FUNC_DECL(RET_TYPE, NAME, ARGS) RET_TYPE (*NAME) ARGS
+typedef struct {
+# include "erl_nif_api_funcs.h"
+} TWinDynNifCallbacks;
+extern TWinDynNifCallbacks WinDynNifCallbacks;
+# undef ERL_NIF_API_FUNC_DECL
+#endif
+
+#if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_)) && !defined(STATIC_ERLANG_DRIVER)
+# define ERL_NIF_API_FUNC_MACRO(NAME) (WinDynNifCallbacks.NAME)
+# include "erl_nif_api_funcs.h"
+/* note that we have to keep ERL_NIF_API_FUNC_MACRO defined */
+
+#else /* non windows or included from emulator itself */
+
+# define ERL_NIF_API_FUNC_DECL(RET_TYPE, NAME, ARGS) extern RET_TYPE NAME ARGS
+# include "erl_nif_api_funcs.h"
+# undef ERL_NIF_API_FUNC_DECL
+#endif
+
+
+#if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_))
+# define ERL_NIF_INIT_GLOB TWinDynNifCallbacks WinDynNifCallbacks;
+# define ERL_NIF_INIT_DECL(MODNAME) __declspec(dllexport) ErlNifEntry* nif_init(TWinDynNifCallbacks* callbacks)
+# define ERL_NIF_INIT_BODY memcpy(&WinDynNifCallbacks,callbacks,sizeof(TWinDynNifCallbacks))
+#else
+# define ERL_NIF_INIT_GLOB
+# define ERL_NIF_INIT_BODY
+# define ERL_NIF_INIT_DECL(MODNAME) ErlNifEntry* nif_init(void)
+#endif
+
+
+#ifdef __cplusplus
+}
+# define ERL_NIF_INIT_PROLOGUE extern "C" {
+# define ERL_NIF_INIT_EPILOGUE }
+#else
+# define ERL_NIF_INIT_PROLOGUE
+# define ERL_NIF_INIT_EPILOGUE
+#endif
+
+
+#define ERL_NIF_INIT(NAME, FUNCS, LOAD, RELOAD, UPGRADE, UNLOAD) \
+ERL_NIF_INIT_PROLOGUE \
+ERL_NIF_INIT_GLOB \
+ERL_NIF_INIT_DECL(NAME); \
+ERL_NIF_INIT_DECL(NAME) \
+{ \
+ static ErlNifEntry entry = \
+ { \
+ ERL_NIF_MAJOR_VERSION, \
+ ERL_NIF_MINOR_VERSION, \
+ #NAME, \
+ sizeof(FUNCS) / sizeof(*FUNCS), \
+ FUNCS, \
+ LOAD, RELOAD, UPGRADE, UNLOAD, \
+ ERL_NIF_VM_VARIANT \
+ }; \
+ ERL_NIF_INIT_BODY; \
+ return &entry; \
+} \
+ERL_NIF_INIT_EPILOGUE
+
+#if defined(USE_DYNAMIC_TRACE) && (defined(USE_DTRACE) || defined(USE_SYSTEMTAP))
+#define HAVE_USE_DTRACE 1
+#endif
+
+#ifdef HAVE_USE_DTRACE
+ERL_NIF_TERM erl_nif_user_trace_s1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM erl_nif_user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM erl_nif_user_trace_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+#endif
+
+#endif /* __ERL_NIF_H__ */
+
diff --git a/erts/emulator/test/nif_SUITE_data/nif_api_2_4/erl_nif_api_funcs.h b/erts/emulator/test/nif_SUITE_data/nif_api_2_4/erl_nif_api_funcs.h
new file mode 100644
index 0000000000..2f841645e1
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/nif_api_2_4/erl_nif_api_funcs.h
@@ -0,0 +1,503 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2009-2013. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#if !defined(ERL_NIF_API_FUNC_DECL) && !defined(ERL_NIF_API_FUNC_MACRO)
+# error This file should not be included directly
+#endif
+
+/*
+** WARNING: add new ERL_NIF_API_FUNC_DECL entries at the bottom of the list
+** to keep compatibility on Windows!!!
+**
+** And don't forget to increase ERL_NIF_MINOR_VERSION in erl_nif.h
+** when adding functions to the API.
+*/
+#ifdef ERL_NIF_API_FUNC_DECL
+ERL_NIF_API_FUNC_DECL(void*,enif_priv_data,(ErlNifEnv*));
+ERL_NIF_API_FUNC_DECL(void*,enif_alloc,(size_t size));
+ERL_NIF_API_FUNC_DECL(void,enif_free,(void* ptr));
+ERL_NIF_API_FUNC_DECL(int,enif_is_atom,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_is_binary,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_is_ref,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_inspect_binary,(ErlNifEnv*, ERL_NIF_TERM bin_term, ErlNifBinary* bin));
+ERL_NIF_API_FUNC_DECL(int,enif_alloc_binary,(size_t size, ErlNifBinary* bin));
+ERL_NIF_API_FUNC_DECL(int,enif_realloc_binary,(ErlNifBinary* bin, size_t size));
+ERL_NIF_API_FUNC_DECL(void,enif_release_binary,(ErlNifBinary* bin));
+ERL_NIF_API_FUNC_DECL(int,enif_get_int,(ErlNifEnv*, ERL_NIF_TERM term, int* ip));
+ERL_NIF_API_FUNC_DECL(int,enif_get_ulong,(ErlNifEnv*, ERL_NIF_TERM term, unsigned long* ip));
+ERL_NIF_API_FUNC_DECL(int,enif_get_double,(ErlNifEnv*, ERL_NIF_TERM term, double* dp));
+ERL_NIF_API_FUNC_DECL(int,enif_get_list_cell,(ErlNifEnv* env, ERL_NIF_TERM term, ERL_NIF_TERM* head, ERL_NIF_TERM* tail));
+ERL_NIF_API_FUNC_DECL(int,enif_get_tuple,(ErlNifEnv* env, ERL_NIF_TERM tpl, int* arity, const ERL_NIF_TERM** array));
+ERL_NIF_API_FUNC_DECL(int,enif_is_identical,(ERL_NIF_TERM lhs, ERL_NIF_TERM rhs));
+ERL_NIF_API_FUNC_DECL(int,enif_compare,(ERL_NIF_TERM lhs, ERL_NIF_TERM rhs));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_binary,(ErlNifEnv* env, ErlNifBinary* bin));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_badarg,(ErlNifEnv* env));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_int,(ErlNifEnv* env, int i));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_ulong,(ErlNifEnv* env, unsigned long i));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_double,(ErlNifEnv* env, double d));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_atom,(ErlNifEnv* env, const char* name));
+ERL_NIF_API_FUNC_DECL(int,enif_make_existing_atom,(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom, ErlNifCharEncoding));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_tuple,(ErlNifEnv* env, unsigned cnt, ...));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list,(ErlNifEnv* env, unsigned cnt, ...));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list_cell,(ErlNifEnv* env, ERL_NIF_TERM car, ERL_NIF_TERM cdr));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string,(ErlNifEnv* env, const char* string, ErlNifCharEncoding));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_ref,(ErlNifEnv* env));
+
+ERL_NIF_API_FUNC_DECL(ErlNifMutex*,enif_mutex_create,(char *name));
+ERL_NIF_API_FUNC_DECL(void,enif_mutex_destroy,(ErlNifMutex *mtx));
+ERL_NIF_API_FUNC_DECL(int,enif_mutex_trylock,(ErlNifMutex *mtx));
+ERL_NIF_API_FUNC_DECL(void,enif_mutex_lock,(ErlNifMutex *mtx));
+ERL_NIF_API_FUNC_DECL(void,enif_mutex_unlock,(ErlNifMutex *mtx));
+ERL_NIF_API_FUNC_DECL(ErlNifCond*,enif_cond_create,(char *name));
+ERL_NIF_API_FUNC_DECL(void,enif_cond_destroy,(ErlNifCond *cnd));
+ERL_NIF_API_FUNC_DECL(void,enif_cond_signal,(ErlNifCond *cnd));
+ERL_NIF_API_FUNC_DECL(void,enif_cond_broadcast,(ErlNifCond *cnd));
+ERL_NIF_API_FUNC_DECL(void,enif_cond_wait,(ErlNifCond *cnd, ErlNifMutex *mtx));
+ERL_NIF_API_FUNC_DECL(ErlNifRWLock*,enif_rwlock_create,(char *name));
+ERL_NIF_API_FUNC_DECL(void,enif_rwlock_destroy,(ErlNifRWLock *rwlck));
+ERL_NIF_API_FUNC_DECL(int,enif_rwlock_tryrlock,(ErlNifRWLock *rwlck));
+ERL_NIF_API_FUNC_DECL(void,enif_rwlock_rlock,(ErlNifRWLock *rwlck));
+ERL_NIF_API_FUNC_DECL(void,enif_rwlock_runlock,(ErlNifRWLock *rwlck));
+ERL_NIF_API_FUNC_DECL(int,enif_rwlock_tryrwlock,(ErlNifRWLock *rwlck));
+ERL_NIF_API_FUNC_DECL(void,enif_rwlock_rwlock,(ErlNifRWLock *rwlck));
+ERL_NIF_API_FUNC_DECL(void,enif_rwlock_rwunlock,(ErlNifRWLock *rwlck));
+ERL_NIF_API_FUNC_DECL(int,enif_tsd_key_create,(char *name, ErlNifTSDKey *key));
+ERL_NIF_API_FUNC_DECL(void,enif_tsd_key_destroy,(ErlNifTSDKey key));
+ERL_NIF_API_FUNC_DECL(void,enif_tsd_set,(ErlNifTSDKey key, void *data));
+ERL_NIF_API_FUNC_DECL(void*,enif_tsd_get,(ErlNifTSDKey key));
+ERL_NIF_API_FUNC_DECL(ErlNifThreadOpts*,enif_thread_opts_create,(char *name));
+ERL_NIF_API_FUNC_DECL(void,enif_thread_opts_destroy,(ErlNifThreadOpts *opts));
+ERL_NIF_API_FUNC_DECL(int,enif_thread_create,(char *name,ErlNifTid *tid,void * (*func)(void *),void *args,ErlNifThreadOpts *opts));
+ERL_NIF_API_FUNC_DECL(ErlNifTid,enif_thread_self,(void));
+ERL_NIF_API_FUNC_DECL(int,enif_equal_tids,(ErlNifTid tid1, ErlNifTid tid2));
+ERL_NIF_API_FUNC_DECL(void,enif_thread_exit,(void *resp));
+ERL_NIF_API_FUNC_DECL(int,enif_thread_join,(ErlNifTid, void **respp));
+
+ERL_NIF_API_FUNC_DECL(void*,enif_realloc,(void* ptr, size_t size));
+ERL_NIF_API_FUNC_DECL(void,enif_system_info,(ErlNifSysInfo *sip, size_t si_size));
+ERL_NIF_API_FUNC_DECL(int,enif_fprintf,(void/* FILE* */ *filep, const char *format, ...));
+ERL_NIF_API_FUNC_DECL(int,enif_inspect_iolist_as_binary,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifBinary* bin));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_sub_binary,(ErlNifEnv*, ERL_NIF_TERM bin_term, size_t pos, size_t size));
+ERL_NIF_API_FUNC_DECL(int,enif_get_string,(ErlNifEnv*, ERL_NIF_TERM list, char* buf, unsigned len, ErlNifCharEncoding));
+ERL_NIF_API_FUNC_DECL(int,enif_get_atom,(ErlNifEnv*, ERL_NIF_TERM atom, char* buf, unsigned len, ErlNifCharEncoding));
+ERL_NIF_API_FUNC_DECL(int,enif_is_fun,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_is_pid,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_is_port,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_get_uint,(ErlNifEnv*, ERL_NIF_TERM term, unsigned* ip));
+ERL_NIF_API_FUNC_DECL(int,enif_get_long,(ErlNifEnv*, ERL_NIF_TERM term, long* ip));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_uint,(ErlNifEnv*, unsigned i));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_long,(ErlNifEnv*, long i));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_tuple_from_array,(ErlNifEnv*, const ERL_NIF_TERM arr[], unsigned cnt));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list_from_array,(ErlNifEnv*, const ERL_NIF_TERM arr[], unsigned cnt));
+ERL_NIF_API_FUNC_DECL(int,enif_is_empty_list,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(ErlNifResourceType*,enif_open_resource_type,(ErlNifEnv*, const char* module_str, const char* name_str, void (*dtor)(ErlNifEnv*,void *), ErlNifResourceFlags flags, ErlNifResourceFlags* tried));
+ERL_NIF_API_FUNC_DECL(void*,enif_alloc_resource,(ErlNifResourceType* type, size_t size));
+ERL_NIF_API_FUNC_DECL(void,enif_release_resource,(void* obj));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_resource,(ErlNifEnv*, void* obj));
+ERL_NIF_API_FUNC_DECL(int,enif_get_resource,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifResourceType* type, void** objp));
+ERL_NIF_API_FUNC_DECL(size_t,enif_sizeof_resource,(void* obj));
+ERL_NIF_API_FUNC_DECL(unsigned char*,enif_make_new_binary,(ErlNifEnv*,size_t size,ERL_NIF_TERM* termp));
+ERL_NIF_API_FUNC_DECL(int,enif_is_list,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_is_tuple,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_get_atom_length,(ErlNifEnv*, ERL_NIF_TERM atom, unsigned* len, ErlNifCharEncoding));
+ERL_NIF_API_FUNC_DECL(int,enif_get_list_length,(ErlNifEnv* env, ERL_NIF_TERM term, unsigned* len));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM, enif_make_atom_len,(ErlNifEnv* env, const char* name, size_t len));
+ERL_NIF_API_FUNC_DECL(int, enif_make_existing_atom_len,(ErlNifEnv* env, const char* name, size_t len, ERL_NIF_TERM* atom, ErlNifCharEncoding));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string_len,(ErlNifEnv* env, const char* string, size_t len, ErlNifCharEncoding));
+ERL_NIF_API_FUNC_DECL(ErlNifEnv*,enif_alloc_env,(void));
+ERL_NIF_API_FUNC_DECL(void,enif_free_env,(ErlNifEnv* env));
+ERL_NIF_API_FUNC_DECL(void,enif_clear_env,(ErlNifEnv* env));
+ERL_NIF_API_FUNC_DECL(int,enif_send,(ErlNifEnv* env, const ErlNifPid* to_pid, ErlNifEnv* msg_env, ERL_NIF_TERM msg));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_copy,(ErlNifEnv* dst_env, ERL_NIF_TERM src_term));
+ERL_NIF_API_FUNC_DECL(ErlNifPid*,enif_self,(ErlNifEnv* caller_env, ErlNifPid* pid));
+ERL_NIF_API_FUNC_DECL(int,enif_get_local_pid,(ErlNifEnv* env, ERL_NIF_TERM, ErlNifPid* pid));
+ERL_NIF_API_FUNC_DECL(void,enif_keep_resource,(void* obj));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_resource_binary,(ErlNifEnv*,void* obj,const void* data, size_t size));
+#if SIZEOF_LONG != 8
+ERL_NIF_API_FUNC_DECL(int,enif_get_int64,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifSInt64* ip));
+ERL_NIF_API_FUNC_DECL(int,enif_get_uint64,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifUInt64* ip));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_int64,(ErlNifEnv*, ErlNifSInt64));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_uint64,(ErlNifEnv*, ErlNifUInt64));
+#endif
+ERL_NIF_API_FUNC_DECL(int,enif_is_exception,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_make_reverse_list,(ErlNifEnv*, ERL_NIF_TERM term, ERL_NIF_TERM *list));
+ERL_NIF_API_FUNC_DECL(int,enif_is_number,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(void*,enif_dlopen,(const char* lib, void (*err_handler)(void*,const char*), void* err_arg));
+ERL_NIF_API_FUNC_DECL(void*,enif_dlsym,(void* handle, const char* symbol, void (*err_handler)(void*,const char*), void* err_arg));
+ERL_NIF_API_FUNC_DECL(int,enif_consume_timeslice,(ErlNifEnv*, int percent));
+
+/*
+** Add new entries here to keep compatibility on Windows!!!
+*/
+#endif
+
+/*
+** Please keep the ERL_NIF_API_FUNC_MACRO list below in the same order
+** as the ERL_NIF_API_FUNC_DECL list above
+*/
+#ifdef ERL_NIF_API_FUNC_MACRO
+# define enif_priv_data ERL_NIF_API_FUNC_MACRO(enif_priv_data)
+# define enif_alloc ERL_NIF_API_FUNC_MACRO(enif_alloc)
+# define enif_free ERL_NIF_API_FUNC_MACRO(enif_free)
+# define enif_is_atom ERL_NIF_API_FUNC_MACRO(enif_is_atom)
+# define enif_is_binary ERL_NIF_API_FUNC_MACRO(enif_is_binary)
+# define enif_is_ref ERL_NIF_API_FUNC_MACRO(enif_is_ref)
+# define enif_inspect_binary ERL_NIF_API_FUNC_MACRO(enif_inspect_binary)
+# define enif_alloc_binary ERL_NIF_API_FUNC_MACRO(enif_alloc_binary)
+# define enif_realloc_binary ERL_NIF_API_FUNC_MACRO(enif_realloc_binary)
+# define enif_release_binary ERL_NIF_API_FUNC_MACRO(enif_release_binary)
+# define enif_get_int ERL_NIF_API_FUNC_MACRO(enif_get_int)
+# define enif_get_ulong ERL_NIF_API_FUNC_MACRO(enif_get_ulong)
+# define enif_get_double ERL_NIF_API_FUNC_MACRO(enif_get_double)
+# define enif_get_tuple ERL_NIF_API_FUNC_MACRO(enif_get_tuple)
+# define enif_get_list_cell ERL_NIF_API_FUNC_MACRO(enif_get_list_cell)
+# define enif_is_identical ERL_NIF_API_FUNC_MACRO(enif_is_identical)
+# define enif_compare ERL_NIF_API_FUNC_MACRO(enif_compare)
+
+# define enif_make_binary ERL_NIF_API_FUNC_MACRO(enif_make_binary)
+# define enif_make_badarg ERL_NIF_API_FUNC_MACRO(enif_make_badarg)
+# define enif_make_int ERL_NIF_API_FUNC_MACRO(enif_make_int)
+# define enif_make_ulong ERL_NIF_API_FUNC_MACRO(enif_make_ulong)
+# define enif_make_double ERL_NIF_API_FUNC_MACRO(enif_make_double)
+# define enif_make_atom ERL_NIF_API_FUNC_MACRO(enif_make_atom)
+# define enif_make_existing_atom ERL_NIF_API_FUNC_MACRO(enif_make_existing_atom)
+# define enif_make_tuple ERL_NIF_API_FUNC_MACRO(enif_make_tuple)
+# define enif_make_list ERL_NIF_API_FUNC_MACRO(enif_make_list)
+# define enif_make_list_cell ERL_NIF_API_FUNC_MACRO(enif_make_list_cell)
+# define enif_make_string ERL_NIF_API_FUNC_MACRO(enif_make_string)
+# define enif_make_ref ERL_NIF_API_FUNC_MACRO(enif_make_ref)
+
+# define enif_mutex_create ERL_NIF_API_FUNC_MACRO(enif_mutex_create)
+# define enif_mutex_destroy ERL_NIF_API_FUNC_MACRO(enif_mutex_destroy)
+# define enif_mutex_trylock ERL_NIF_API_FUNC_MACRO(enif_mutex_trylock)
+# define enif_mutex_lock ERL_NIF_API_FUNC_MACRO(enif_mutex_lock)
+# define enif_mutex_unlock ERL_NIF_API_FUNC_MACRO(enif_mutex_unlock)
+# define enif_cond_create ERL_NIF_API_FUNC_MACRO(enif_cond_create)
+# define enif_cond_destroy ERL_NIF_API_FUNC_MACRO(enif_cond_destroy)
+# define enif_cond_signal ERL_NIF_API_FUNC_MACRO(enif_cond_signal)
+# define enif_cond_broadcast ERL_NIF_API_FUNC_MACRO(enif_cond_broadcast)
+# define enif_cond_wait ERL_NIF_API_FUNC_MACRO(enif_cond_wait)
+# define enif_rwlock_create ERL_NIF_API_FUNC_MACRO(enif_rwlock_create)
+# define enif_rwlock_destroy ERL_NIF_API_FUNC_MACRO(enif_rwlock_destroy)
+# define enif_rwlock_tryrlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_tryrlock)
+# define enif_rwlock_rlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_rlock)
+# define enif_rwlock_runlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_runlock)
+# define enif_rwlock_tryrwlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_tryrwlock)
+# define enif_rwlock_rwlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_rwlock)
+# define enif_rwlock_rwunlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_rwunlock)
+# define enif_tsd_key_create ERL_NIF_API_FUNC_MACRO(enif_tsd_key_create)
+# define enif_tsd_key_destroy ERL_NIF_API_FUNC_MACRO(enif_tsd_key_destroy)
+# define enif_tsd_set ERL_NIF_API_FUNC_MACRO(enif_tsd_set)
+# define enif_tsd_get ERL_NIF_API_FUNC_MACRO(enif_tsd_get)
+# define enif_thread_opts_create ERL_NIF_API_FUNC_MACRO(enif_thread_opts_create)
+# define enif_thread_opts_destroy ERL_NIF_API_FUNC_MACRO(enif_thread_opts_destroy)
+# define enif_thread_create ERL_NIF_API_FUNC_MACRO(enif_thread_create)
+# define enif_thread_self ERL_NIF_API_FUNC_MACRO(enif_thread_self)
+# define enif_equal_tids ERL_NIF_API_FUNC_MACRO(enif_equal_tids)
+# define enif_thread_exit ERL_NIF_API_FUNC_MACRO(enif_thread_exit)
+# define enif_thread_join ERL_NIF_API_FUNC_MACRO(enif_thread_join)
+
+# define enif_realloc ERL_NIF_API_FUNC_MACRO(enif_realloc)
+# define enif_system_info ERL_NIF_API_FUNC_MACRO(enif_system_info)
+# define enif_fprintf ERL_NIF_API_FUNC_MACRO(enif_fprintf)
+# define enif_inspect_iolist_as_binary ERL_NIF_API_FUNC_MACRO(enif_inspect_iolist_as_binary)
+# define enif_make_sub_binary ERL_NIF_API_FUNC_MACRO(enif_make_sub_binary)
+# define enif_get_string ERL_NIF_API_FUNC_MACRO(enif_get_string)
+# define enif_get_atom ERL_NIF_API_FUNC_MACRO(enif_get_atom)
+# define enif_is_fun ERL_NIF_API_FUNC_MACRO(enif_is_fun)
+# define enif_is_pid ERL_NIF_API_FUNC_MACRO(enif_is_pid)
+# define enif_is_port ERL_NIF_API_FUNC_MACRO(enif_is_port)
+# define enif_get_uint ERL_NIF_API_FUNC_MACRO(enif_get_uint)
+# define enif_get_long ERL_NIF_API_FUNC_MACRO(enif_get_long)
+# define enif_make_uint ERL_NIF_API_FUNC_MACRO(enif_make_uint)
+# define enif_make_long ERL_NIF_API_FUNC_MACRO(enif_make_long)
+# define enif_make_tuple_from_array ERL_NIF_API_FUNC_MACRO(enif_make_tuple_from_array)
+# define enif_make_list_from_array ERL_NIF_API_FUNC_MACRO(enif_make_list_from_array)
+# define enif_is_empty_list ERL_NIF_API_FUNC_MACRO(enif_is_empty_list)
+# define enif_open_resource_type ERL_NIF_API_FUNC_MACRO(enif_open_resource_type)
+# define enif_alloc_resource ERL_NIF_API_FUNC_MACRO(enif_alloc_resource)
+# define enif_release_resource ERL_NIF_API_FUNC_MACRO(enif_release_resource)
+# define enif_make_resource ERL_NIF_API_FUNC_MACRO(enif_make_resource)
+# define enif_get_resource ERL_NIF_API_FUNC_MACRO(enif_get_resource)
+# define enif_sizeof_resource ERL_NIF_API_FUNC_MACRO(enif_sizeof_resource)
+# define enif_make_new_binary ERL_NIF_API_FUNC_MACRO(enif_make_new_binary)
+# define enif_is_list ERL_NIF_API_FUNC_MACRO(enif_is_list)
+# define enif_is_tuple ERL_NIF_API_FUNC_MACRO(enif_is_tuple)
+# define enif_get_atom_length ERL_NIF_API_FUNC_MACRO(enif_get_atom_length)
+# define enif_get_list_length ERL_NIF_API_FUNC_MACRO(enif_get_list_length)
+# define enif_make_atom_len ERL_NIF_API_FUNC_MACRO(enif_make_atom_len)
+# define enif_make_existing_atom_len ERL_NIF_API_FUNC_MACRO(enif_make_existing_atom_len)
+# define enif_make_string_len ERL_NIF_API_FUNC_MACRO(enif_make_string_len)
+# define enif_alloc_env ERL_NIF_API_FUNC_MACRO(enif_alloc_env)
+# define enif_free_env ERL_NIF_API_FUNC_MACRO(enif_free_env)
+# define enif_clear_env ERL_NIF_API_FUNC_MACRO(enif_clear_env)
+# define enif_send ERL_NIF_API_FUNC_MACRO(enif_send)
+# define enif_make_copy ERL_NIF_API_FUNC_MACRO(enif_make_copy)
+# define enif_self ERL_NIF_API_FUNC_MACRO(enif_self)
+# define enif_get_local_pid ERL_NIF_API_FUNC_MACRO(enif_get_local_pid)
+# define enif_keep_resource ERL_NIF_API_FUNC_MACRO(enif_keep_resource)
+# define enif_make_resource_binary ERL_NIF_API_FUNC_MACRO(enif_make_resource_binary)
+#if SIZEOF_LONG != 8
+# define enif_get_int64 ERL_NIF_API_FUNC_MACRO(enif_get_int64)
+# define enif_get_uint64 ERL_NIF_API_FUNC_MACRO(enif_get_uint64)
+# define enif_make_int64 ERL_NIF_API_FUNC_MACRO(enif_make_int64)
+# define enif_make_uint64 ERL_NIF_API_FUNC_MACRO(enif_make_uint64)
+#endif
+
+# define enif_is_exception ERL_NIF_API_FUNC_MACRO(enif_is_exception)
+# define enif_make_reverse_list ERL_NIF_API_FUNC_MACRO(enif_make_reverse_list)
+# define enif_is_number ERL_NIF_API_FUNC_MACRO(enif_is_number)
+# define enif_dlopen ERL_NIF_API_FUNC_MACRO(enif_dlopen)
+# define enif_dlsym ERL_NIF_API_FUNC_MACRO(enif_dlsym)
+# define enif_consume_timeslice ERL_NIF_API_FUNC_MACRO(enif_consume_timeslice)
+
+/*
+** Add new entries here
+*/
+#endif
+
+
+#if defined(__GNUC__) && !(defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_))
+
+/* Inline functions for compile time type checking of arguments to
+ variadic functions.
+*/
+
+# define ERL_NIF_INLINE __inline__
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_tuple1(ErlNifEnv* env,
+ ERL_NIF_TERM e1)
+{
+ return enif_make_tuple(env, 1, e1);
+}
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_tuple2(ErlNifEnv* env,
+ ERL_NIF_TERM e1,
+ ERL_NIF_TERM e2)
+{
+ return enif_make_tuple(env, 2, e1, e2);
+}
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_tuple3(ErlNifEnv* env,
+ ERL_NIF_TERM e1,
+ ERL_NIF_TERM e2,
+ ERL_NIF_TERM e3)
+{
+ return enif_make_tuple(env, 3, e1, e2, e3);
+}
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_tuple4(ErlNifEnv* env,
+ ERL_NIF_TERM e1,
+ ERL_NIF_TERM e2,
+ ERL_NIF_TERM e3,
+ ERL_NIF_TERM e4)
+{
+ return enif_make_tuple(env, 4, e1, e2, e3, e4);
+}
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_tuple5(ErlNifEnv* env,
+ ERL_NIF_TERM e1,
+ ERL_NIF_TERM e2,
+ ERL_NIF_TERM e3,
+ ERL_NIF_TERM e4,
+ ERL_NIF_TERM e5)
+{
+ return enif_make_tuple(env, 5, e1, e2, e3, e4, e5);
+}
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_tuple6(ErlNifEnv* env,
+ ERL_NIF_TERM e1,
+ ERL_NIF_TERM e2,
+ ERL_NIF_TERM e3,
+ ERL_NIF_TERM e4,
+ ERL_NIF_TERM e5,
+ ERL_NIF_TERM e6)
+{
+ return enif_make_tuple(env, 6, e1, e2, e3, e4, e5, e6);
+}
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_tuple7(ErlNifEnv* env,
+ ERL_NIF_TERM e1,
+ ERL_NIF_TERM e2,
+ ERL_NIF_TERM e3,
+ ERL_NIF_TERM e4,
+ ERL_NIF_TERM e5,
+ ERL_NIF_TERM e6,
+ ERL_NIF_TERM e7)
+{
+ return enif_make_tuple(env, 7, e1, e2, e3, e4, e5, e6, e7);
+}
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_tuple8(ErlNifEnv* env,
+ ERL_NIF_TERM e1,
+ ERL_NIF_TERM e2,
+ ERL_NIF_TERM e3,
+ ERL_NIF_TERM e4,
+ ERL_NIF_TERM e5,
+ ERL_NIF_TERM e6,
+ ERL_NIF_TERM e7,
+ ERL_NIF_TERM e8)
+{
+ return enif_make_tuple(env, 8, e1, e2, e3, e4, e5, e6, e7, e8);
+}
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_tuple9(ErlNifEnv* env,
+ ERL_NIF_TERM e1,
+ ERL_NIF_TERM e2,
+ ERL_NIF_TERM e3,
+ ERL_NIF_TERM e4,
+ ERL_NIF_TERM e5,
+ ERL_NIF_TERM e6,
+ ERL_NIF_TERM e7,
+ ERL_NIF_TERM e8,
+ ERL_NIF_TERM e9)
+{
+ return enif_make_tuple(env, 9, e1, e2, e3, e4, e5, e6, e7, e8, e9);
+}
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_list1(ErlNifEnv* env,
+ ERL_NIF_TERM e1)
+{
+ return enif_make_list(env, 1, e1);
+}
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_list2(ErlNifEnv* env,
+ ERL_NIF_TERM e1,
+ ERL_NIF_TERM e2)
+{
+ return enif_make_list(env, 2, e1, e2);
+}
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_list3(ErlNifEnv* env,
+ ERL_NIF_TERM e1,
+ ERL_NIF_TERM e2,
+ ERL_NIF_TERM e3)
+{
+ return enif_make_list(env, 3, e1, e2, e3);
+}
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_list4(ErlNifEnv* env,
+ ERL_NIF_TERM e1,
+ ERL_NIF_TERM e2,
+ ERL_NIF_TERM e3,
+ ERL_NIF_TERM e4)
+{
+ return enif_make_list(env, 4, e1, e2, e3, e4);
+}
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_list5(ErlNifEnv* env,
+ ERL_NIF_TERM e1,
+ ERL_NIF_TERM e2,
+ ERL_NIF_TERM e3,
+ ERL_NIF_TERM e4,
+ ERL_NIF_TERM e5)
+{
+ return enif_make_list(env, 5, e1, e2, e3, e4, e5);
+}
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_list6(ErlNifEnv* env,
+ ERL_NIF_TERM e1,
+ ERL_NIF_TERM e2,
+ ERL_NIF_TERM e3,
+ ERL_NIF_TERM e4,
+ ERL_NIF_TERM e5,
+ ERL_NIF_TERM e6)
+{
+ return enif_make_list(env, 6, e1, e2, e3, e4, e5, e6);
+}
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_list7(ErlNifEnv* env,
+ ERL_NIF_TERM e1,
+ ERL_NIF_TERM e2,
+ ERL_NIF_TERM e3,
+ ERL_NIF_TERM e4,
+ ERL_NIF_TERM e5,
+ ERL_NIF_TERM e6,
+ ERL_NIF_TERM e7)
+{
+ return enif_make_list(env, 7, e1, e2, e3, e4, e5, e6, e7);
+}
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_list8(ErlNifEnv* env,
+ ERL_NIF_TERM e1,
+ ERL_NIF_TERM e2,
+ ERL_NIF_TERM e3,
+ ERL_NIF_TERM e4,
+ ERL_NIF_TERM e5,
+ ERL_NIF_TERM e6,
+ ERL_NIF_TERM e7,
+ ERL_NIF_TERM e8)
+{
+ return enif_make_list(env, 8, e1, e2, e3, e4, e5, e6, e7, e8);
+}
+
+static ERL_NIF_INLINE ERL_NIF_TERM enif_make_list9(ErlNifEnv* env,
+ ERL_NIF_TERM e1,
+ ERL_NIF_TERM e2,
+ ERL_NIF_TERM e3,
+ ERL_NIF_TERM e4,
+ ERL_NIF_TERM e5,
+ ERL_NIF_TERM e6,
+ ERL_NIF_TERM e7,
+ ERL_NIF_TERM e8,
+ ERL_NIF_TERM e9)
+{
+ return enif_make_list(env, 9, e1, e2, e3, e4, e5, e6, e7, e8, e9);
+}
+
+# undef ERL_NIF_INLINE
+
+#else /* fallback with macros */
+
+#ifndef enif_make_list1
+# define enif_make_list1(ENV,E1) enif_make_list(ENV,1,E1)
+# define enif_make_list2(ENV,E1,E2) enif_make_list(ENV,2,E1,E2)
+# define enif_make_list3(ENV,E1,E2,E3) enif_make_list(ENV,3,E1,E2,E3)
+# define enif_make_list4(ENV,E1,E2,E3,E4) enif_make_list(ENV,4,E1,E2,E3,E4)
+# define enif_make_list5(ENV,E1,E2,E3,E4,E5) enif_make_list(ENV,5,E1,E2,E3,E4,E5)
+# define enif_make_list6(ENV,E1,E2,E3,E4,E5,E6) enif_make_list(ENV,6,E1,E2,E3,E4,E5,E6)
+# define enif_make_list7(ENV,E1,E2,E3,E4,E5,E6,E7) enif_make_list(ENV,7,E1,E2,E3,E4,E5,E6,E7)
+# define enif_make_list8(ENV,E1,E2,E3,E4,E5,E6,E7,E8) enif_make_list(ENV,8,E1,E2,E3,E4,E5,E6,E7,E8)
+# define enif_make_list9(ENV,E1,E2,E3,E4,E5,E6,E7,E8,E9) enif_make_list(ENV,9,E1,E2,E3,E4,E5,E6,E7,E8,E9)
+# define enif_make_tuple1(ENV,E1) enif_make_tuple(ENV,1,E1)
+# define enif_make_tuple2(ENV,E1,E2) enif_make_tuple(ENV,2,E1,E2)
+# define enif_make_tuple3(ENV,E1,E2,E3) enif_make_tuple(ENV,3,E1,E2,E3)
+# define enif_make_tuple4(ENV,E1,E2,E3,E4) enif_make_tuple(ENV,4,E1,E2,E3,E4)
+# define enif_make_tuple5(ENV,E1,E2,E3,E4,E5) enif_make_tuple(ENV,5,E1,E2,E3,E4,E5)
+# define enif_make_tuple6(ENV,E1,E2,E3,E4,E5,E6) enif_make_tuple(ENV,6,E1,E2,E3,E4,E5,E6)
+# define enif_make_tuple7(ENV,E1,E2,E3,E4,E5,E6,E7) enif_make_tuple(ENV,7,E1,E2,E3,E4,E5,E6,E7)
+# define enif_make_tuple8(ENV,E1,E2,E3,E4,E5,E6,E7,E8) enif_make_tuple(ENV,8,E1,E2,E3,E4,E5,E6,E7,E8)
+# define enif_make_tuple9(ENV,E1,E2,E3,E4,E5,E6,E7,E8,E9) enif_make_tuple(ENV,9,E1,E2,E3,E4,E5,E6,E7,E8,E9)
+#endif
+
+#endif /* __GNUC__ && !WIN32 */
+
+#ifndef enif_make_pid
+
+# define enif_make_pid(ENV, PID) ((const ERL_NIF_TERM)((PID)->pid))
+
+#if SIZEOF_LONG == 8
+# define enif_get_int64 enif_get_long
+# define enif_get_uint64 enif_get_ulong
+# define enif_make_int64 enif_make_long
+# define enif_make_uint64 enif_make_ulong
+#endif
+
+#endif
+
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.1.2_0.c b/erts/emulator/test/nif_SUITE_data/nif_mod.1.2_0.c
new file mode 100644
index 0000000000..a554cc7f25
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.1.2_0.c
@@ -0,0 +1,4 @@
+#include "nif_api_2_0/erl_nif.h"
+
+#define NIF_LIB_VER 1
+#include "nif_mod.c"
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.1.2_4.c b/erts/emulator/test/nif_SUITE_data/nif_mod.1.2_4.c
new file mode 100644
index 0000000000..6d28dbb8ba
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.1.2_4.c
@@ -0,0 +1,4 @@
+#include "nif_api_2_4/erl_nif.h"
+
+#define NIF_LIB_VER 1
+#include "nif_mod.c"
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.2.2_0.c b/erts/emulator/test/nif_SUITE_data/nif_mod.2.2_0.c
new file mode 100644
index 0000000000..0731e6b5d0
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.2.2_0.c
@@ -0,0 +1,4 @@
+#include "nif_api_2_0/erl_nif.h"
+
+#define NIF_LIB_VER 2
+#include "nif_mod.c"
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.2.2_4.c b/erts/emulator/test/nif_SUITE_data/nif_mod.2.2_4.c
new file mode 100644
index 0000000000..628fd42b52
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.2.2_4.c
@@ -0,0 +1,4 @@
+#include "nif_api_2_4/erl_nif.h"
+
+#define NIF_LIB_VER 2
+#include "nif_mod.c"
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.3.2_0.c b/erts/emulator/test/nif_SUITE_data/nif_mod.3.2_0.c
new file mode 100644
index 0000000000..d7e676b668
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.3.2_0.c
@@ -0,0 +1,4 @@
+#include "nif_api_2_0/erl_nif.h"
+
+#define NIF_LIB_VER 3
+#include "nif_mod.c"
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.3.2_4.c b/erts/emulator/test/nif_SUITE_data/nif_mod.3.2_4.c
new file mode 100644
index 0000000000..bdbe8cf381
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.3.2_4.c
@@ -0,0 +1,4 @@
+#include "nif_api_2_4/erl_nif.h"
+
+#define NIF_LIB_VER 3
+#include "nif_mod.c"
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.c b/erts/emulator/test/nif_SUITE_data/nif_mod.c
index fd8a0d0595..e6106b6036 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_mod.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.c
@@ -17,7 +17,7 @@
*
* %CopyrightEnd%
*/
-#include "erl_nif.h"
+#include <erl_nif.h>
#include <string.h>
#include <stdio.h>
@@ -237,10 +237,22 @@ static ERL_NIF_TERM lib_version(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
return enif_make_int(env, NIF_LIB_VER);
}
+static ERL_NIF_TERM nif_api_version(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ /*ADD_CALL("nif_api_version");*/
+ return enif_make_tuple2(env,
+ enif_make_int(env, ERL_NIF_MAJOR_VERSION),
+ enif_make_int(env, ERL_NIF_MINOR_VERSION));
+}
+
static ERL_NIF_TERM get_priv_data_ptr(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
+ NifModPrivData** bin_data;
+ ERL_NIF_TERM res;
ADD_CALL("get_priv_data_ptr");
- return enif_make_uint64(env, (ErlNifUInt64)priv_data(env));
+ bin_data = (NifModPrivData**)enif_make_new_binary(env, sizeof(void*), &res);
+ *bin_data = priv_data(env);
+ return res;
}
static ERL_NIF_TERM make_new_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -279,6 +291,7 @@ static ERL_NIF_TERM get_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
static ErlNifFunc nif_funcs[] =
{
{"lib_version", 0, lib_version},
+ {"nif_api_version", 0, nif_api_version},
{"get_priv_data_ptr", 0, get_priv_data_ptr},
{"make_new_resource", 2, make_new_resource},
{"get_resource", 2, get_resource}
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.erl b/erts/emulator/test/nif_SUITE_data/nif_mod.erl
index 1fcc33faa4..8019cfcf82 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_mod.erl
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.erl
@@ -22,7 +22,7 @@
-include_lib("common_test/include/ct.hrl").
--export([load_nif_lib/2, load_nif_lib/3, start/0, lib_version/0, call_history/0,
+-export([load_nif_lib/2, load_nif_lib/3, start/0, lib_version/0,
get_priv_data_ptr/0, make_new_resource/2, get_resource/2]).
-export([loop/0, upgrade/1]).
@@ -35,21 +35,32 @@
on_load() ->
[{data_dir, Path}] = ets:lookup(nif_SUITE, data_dir),
[{lib_version, Ver}] = ets:lookup(nif_SUITE, lib_version),
- erlang:load_nif(filename:join(Path,libname(Ver)), []).
+ [{nif_api_version, API}] = ets:lookup(nif_SUITE, nif_api_version),
+ R = erlang:load_nif(filename:join(Path,libname(Ver,API)), []),
+ check_api_version(R, API).
-endif.
+check_api_version(Err, _) when Err =/= ok -> Err;
+check_api_version(ok, []) -> ok;
+check_api_version(ok, [$., MajC, $_ | MinS]) ->
+ {Maj, Min} = {list_to_integer([MajC]), list_to_integer(MinS)},
+ {Maj, Min} = nif_api_version(),
+ ok.
+
load_nif_lib(Config, Ver) ->
load_nif_lib(Config, Ver, []).
load_nif_lib(Config, Ver, LoadInfo) ->
Path = proplists:get_value(data_dir, Config),
- erlang:load_nif(filename:join(Path,libname(Ver)), LoadInfo).
-
-libname(no_init) -> libname(3);
-libname(Ver) when is_integer(Ver) ->
- "nif_mod." ++ integer_to_list(Ver).
+ API = proplists:get_value(nif_api_version, Config, ""),
+ R = erlang:load_nif(filename:join(Path,libname(Ver,API)), LoadInfo),
+ check_api_version(R, API).
+libname(no_init,API) -> libname(3,API);
+libname(Ver,API) when is_integer(Ver) ->
+ "nif_mod." ++ integer_to_list(Ver) ++ API.
+
start() ->
spawn_opt(?MODULE,loop,[],
[link, monitor]).
@@ -72,7 +83,9 @@ upgrade(Pid) ->
lib_version() -> % NIF
undefined.
-call_history() -> ?nif_stub.
+nif_api_version() -> %NIF
+ {undefined,undefined}.
+
get_priv_data_ptr() -> ?nif_stub.
make_new_resource(_,_) -> ?nif_stub.
get_resource(_,_) -> ?nif_stub.
diff --git a/erts/emulator/test/nif_SUITE_data/testcase_driver.h b/erts/emulator/test/nif_SUITE_data/testcase_driver.h
index e32e63069a..feb10ecaea 100644
--- a/erts/emulator/test/nif_SUITE_data/testcase_driver.h
+++ b/erts/emulator/test/nif_SUITE_data/testcase_driver.h
@@ -20,7 +20,7 @@
#ifndef TESTCASE_DRIVER_H__
#define TESTCASE_DRIVER_H__
-#include "erl_nif.h"
+#include <erl_nif.h>
#include <stdlib.h>
#include <stdio.h>
diff --git a/erts/emulator/test/nif_SUITE_data/tester.c b/erts/emulator/test/nif_SUITE_data/tester.c
index 257b116322..ea4afd924d 100644
--- a/erts/emulator/test/nif_SUITE_data/tester.c
+++ b/erts/emulator/test/nif_SUITE_data/tester.c
@@ -1,4 +1,4 @@
-#include "erl_nif.h"
+#include <erl_nif.h>
#include <stdio.h>
#include <stdarg.h>
@@ -53,7 +53,7 @@ void testcase_free(void *ptr)
void testcase_run(TestCaseState_t *tcs);
-static int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
+static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)
{
return 0;
}
@@ -70,5 +70,5 @@ static ErlNifFunc nif_funcs[] =
{"run", 0, run}
};
-ERL_NIF_INIT(tester,nif_funcs,NULL,reload,NULL,NULL)
+ERL_NIF_INIT(tester,nif_funcs,NULL,NULL,upgrade,NULL)
diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl
index d1c9648017..1a1ab0e5e0 100644
--- a/erts/emulator/test/num_bif_SUITE.erl
+++ b/erts/emulator/test/num_bif_SUITE.erl
@@ -32,6 +32,8 @@
%% list_to_integer/1
%% round/1
%% trunc/1
+%% floor/1
+%% ceil/1
%% integer_to_binary/1
%% integer_to_binary/2
%% binary_to_integer/1
@@ -41,7 +43,7 @@
t_float_to_string/1, t_integer_to_string/1,
t_string_to_integer/1, t_list_to_integer_edge_cases/1,
t_string_to_float_safe/1, t_string_to_float_risky/1,
- t_round/1, t_trunc/1
+ t_round/1, t_trunc_and_friends/1
]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -49,7 +51,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[t_abs, t_float, t_float_to_string, t_integer_to_string,
{group, t_string_to_float}, t_string_to_integer, t_round,
- t_trunc, t_list_to_integer_edge_cases].
+ t_trunc_and_friends, t_list_to_integer_edge_cases].
groups() ->
[{t_string_to_float, [],
@@ -295,30 +297,78 @@ t_round(Config) when is_list(Config) ->
-4294967297 = -round(id(4294967296.9)),
ok.
-t_trunc(Config) when is_list(Config) ->
- 0 = trunc(id(0.0)),
- 5 = trunc(id(5.3333)),
- -10 = trunc(id(-10.978987)),
+%% Test trunc/1, floor/1, ceil/1, and round/1.
+t_trunc_and_friends(_Config) ->
+ MinusZero = 0.0 / (-1.0),
+ 0 = trunc_and_friends(MinusZero),
+ 0 = trunc_and_friends(0.0),
+ 5 = trunc_and_friends(5.3333),
+ -10 = trunc_and_friends(-10.978987),
- % The largest smallnum, converted to float (OTP-3722):
+ %% The largest smallnum, converted to float (OTP-3722):
X = id((1 bsl 27) - 1),
- F = id(X + 0.0),
+ F = X + 0.0,
io:format("X = ~p/~w/~w, F = ~p/~w/~w, trunc(F) = ~p/~w/~w~n",
[X, X, binary_to_list(term_to_binary(X)),
F, F, binary_to_list(term_to_binary(F)),
- trunc(F), trunc(F), binary_to_list(term_to_binary(trunc(F)))]),
- X = trunc(F),
- X = trunc(F+1)-1,
- X = trunc(F-1)+1,
- X = -trunc(-F),
- X = -trunc(-F-1)-1,
- X = -trunc(-F+1)+1,
+ trunc_and_friends(F),
+ trunc_and_friends(F),
+ binary_to_list(term_to_binary(trunc_and_friends(F)))]),
+ X = trunc_and_friends(F),
+ X = trunc_and_friends(F+1)-1,
+ X = trunc_and_friends(F-1)+1,
+ X = -trunc_and_friends(-F),
+ X = -trunc_and_friends(-F-1)-1,
+ X = -trunc_and_friends(-F+1)+1,
%% Bignums.
- 4294967305 = trunc(id(4294967305.7)),
- -4294967305 = trunc(id(-4294967305.7)),
+ 4294967305 = trunc_and_friends(4294967305.7),
+ -4294967305 = trunc_and_friends(-4294967305.7),
+ 18446744073709551616 = trunc_and_friends(float(1 bsl 64)),
+ -18446744073709551616 = trunc_and_friends(-float(1 bsl 64)),
+
+ %% Random.
+ t_trunc_and_friends_rand(100),
ok.
+t_trunc_and_friends_rand(0) ->
+ ok;
+t_trunc_and_friends_rand(N) ->
+ F0 = rand:uniform() * math:pow(10, 50*rand:normal()),
+ F = case rand:uniform() of
+ U when U < 0.5 -> -F0;
+ _ -> F0
+ end,
+ _ = trunc_and_friends(F),
+ t_trunc_and_friends_rand(N-1).
+
+trunc_and_friends(F) ->
+ Trunc = trunc(F),
+ Floor = floor(F),
+ Ceil = ceil(F),
+ Round = round(F),
+
+ Trunc = trunc(Trunc),
+ Floor = floor(Floor),
+ Ceil = ceil(Ceil),
+ Round = round(Round),
+
+ Trunc = trunc(float(Trunc)),
+ Floor = floor(float(Floor)),
+ Ceil = ceil(float(Ceil)),
+ Round = round(float(Round)),
+
+ true = Floor =< Trunc andalso Trunc =< Ceil,
+ true = Ceil - Floor =< 1,
+ true = Round =:= Floor orelse Round =:= Ceil,
+
+ if
+ F < 0 ->
+ Trunc = Ceil;
+ true ->
+ Trunc = Floor
+ end,
+ Trunc.
%% Tests integer_to_binary/1.
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index 0a6eb7ffac..5712c9fa74 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -2449,7 +2449,7 @@ no_priority_inversion2(Config) when is_list(Config) ->
request_gc(Pid, Prio) ->
Ref = make_ref(),
- erts_internal:request_system_task(Pid, Prio, {garbage_collect, Ref}),
+ erts_internal:request_system_task(Pid, Prio, {garbage_collect, Ref, major}),
Ref.
system_task_blast(Config) when is_list(Config) ->
diff --git a/erts/emulator/test/system_info_SUITE.erl b/erts/emulator/test/system_info_SUITE.erl
index a4aedb31f6..6a772bf7c9 100644
--- a/erts/emulator/test/system_info_SUITE.erl
+++ b/erts/emulator/test/system_info_SUITE.erl
@@ -36,7 +36,8 @@
-export([all/0, suite/0]).
-export([process_count/1, system_version/1, misc_smoke_tests/1,
- heap_size/1, wordsize/1, memory/1, ets_limit/1]).
+ heap_size/1, wordsize/1, memory/1, ets_limit/1, atom_limit/1,
+ atom_count/1]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -44,7 +45,7 @@ suite() ->
all() ->
[process_count, system_version, misc_smoke_tests,
- heap_size, wordsize, memory, ets_limit].
+ heap_size, wordsize, memory, ets_limit, atom_limit, atom_count].
%%%
%%% The test cases -------------------------------------------------------------
@@ -472,6 +473,17 @@ mapn(_Fun, 0) ->
mapn(Fun, N) ->
[Fun(N) | mapn(Fun, N-1)].
+
+get_node_name(Config) ->
+ list_to_atom(atom_to_list(?MODULE)
+ ++ "-"
+ ++ atom_to_list(proplists:get_value(testcase, Config))
+ ++ "-"
+ ++ integer_to_list(erlang:system_time(second))
+ ++ "-"
+ ++ integer_to_list(erlang:unique_integer([positive]))).
+
+
%% Verify system_info(ets_limit) reflects max ETS table settings.
ets_limit(Config0) when is_list(Config0) ->
Config = [{testcase,ets_limit}|Config0],
@@ -486,7 +498,7 @@ get_ets_limit(Config, EtsMax) ->
0 -> [];
_ -> [{"ERL_MAX_ETS_TABLES", integer_to_list(EtsMax)}]
end,
- {ok, Node} = start_node(Config, Envs),
+ {ok, Node} = start_node_ets(Config, Envs),
Me = self(),
Ref = make_ref(),
spawn_link(Node,
@@ -502,16 +514,50 @@ get_ets_limit(Config, EtsMax) ->
stop_node(Node),
Res.
-start_node(Config, Envs) when is_list(Config) ->
+start_node_ets(Config, Envs) when is_list(Config) ->
+ Pa = filename:dirname(code:which(?MODULE)),
+ test_server:start_node(get_node_name(Config), peer,
+ [{args, "-pa "++Pa}, {env, Envs}]).
+
+start_node_atm(Config, AtomsMax) when is_list(Config) ->
Pa = filename:dirname(code:which(?MODULE)),
- Name = list_to_atom(atom_to_list(?MODULE)
- ++ "-"
- ++ atom_to_list(proplists:get_value(testcase, Config))
- ++ "-"
- ++ integer_to_list(erlang:system_time(second))
- ++ "-"
- ++ integer_to_list(erlang:unique_integer([positive]))),
- test_server:start_node(Name, peer, [{args, "-pa "++Pa}, {env, Envs}]).
+ test_server:start_node(get_node_name(Config), peer,
+ [{args, "-pa "++ Pa ++ AtomsMax}]).
stop_node(Node) ->
test_server:stop_node(Node).
+
+
+%% Verify system_info(atom_limit) reflects max atoms settings
+%% (using " +t").
+atom_limit(Config0) when is_list(Config0) ->
+ Config = [{testcase,atom_limit}|Config0],
+ 2186042 = get_atom_limit(Config, " +t 2186042 "),
+ ok.
+
+get_atom_limit(Config, AtomsMax) ->
+ {ok, Node} = start_node_atm(Config, AtomsMax),
+ Me = self(),
+ Ref = make_ref(),
+ spawn_link(Node,
+ fun() ->
+ Res = erlang:system_info(atom_limit),
+ unlink(Me),
+ Me ! {Ref, Res}
+ end),
+ receive
+ {Ref, Res} ->
+ Res
+ end,
+ stop_node(Node),
+ Res.
+
+%% Verify that system_info(atom_count) works.
+atom_count(Config) when is_list(Config) ->
+ Limit = erlang:system_info(atom_limit),
+ Count1 = erlang:system_info(atom_count),
+ list_to_atom(integer_to_list(erlang:unique_integer())),
+ Count2 = erlang:system_info(atom_count),
+ true = Limit >= Count2,
+ true = Count2 > Count1,
+ ok.
diff --git a/erts/emulator/test/trace_call_time_SUITE_data/trace_nif.c b/erts/emulator/test/trace_call_time_SUITE_data/trace_nif.c
index 33b346aab7..786be35c9c 100644
--- a/erts/emulator/test/trace_call_time_SUITE_data/trace_nif.c
+++ b/erts/emulator/test/trace_call_time_SUITE_data/trace_nif.c
@@ -1,4 +1,4 @@
-#include "erl_nif.h"
+#include <erl_nif.h>
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
@@ -6,11 +6,6 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
return 0;
}
-static int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
-{
- return 0;
-}
-
static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)
{
return 0;
@@ -34,4 +29,4 @@ static ErlNifFunc nif_funcs[] =
{"nif_dec", 1, nif_dec_1}
};
-ERL_NIF_INIT(trace_call_time_SUITE,nif_funcs,load,reload,upgrade,unload)
+ERL_NIF_INIT(trace_call_time_SUITE,nif_funcs,load,NULL,upgrade,unload)
diff --git a/erts/emulator/test/trace_nif_SUITE.erl b/erts/emulator/test/trace_nif_SUITE.erl
index 8d5bff2a48..7ac6fce234 100644
--- a/erts/emulator/test/trace_nif_SUITE.erl
+++ b/erts/emulator/test/trace_nif_SUITE.erl
@@ -265,10 +265,16 @@ nif_process() ->
nif_process().
load_nif(Config) ->
- Path = proplists:get_value(data_dir, Config),
-
- ok = erlang:load_nif(filename:join(Path,"trace_nif"), 0).
+ case is_nif_loaded() of
+ true ->
+ ok;
+ false ->
+ Path = proplists:get_value(data_dir, Config),
+ ok = erlang:load_nif(filename:join(Path,"trace_nif"), 0)
+ end.
+is_nif_loaded() ->
+ false.
nif() ->
{"Stub0",[]}. %exit("nif/0 stub called").
diff --git a/erts/emulator/test/trace_nif_SUITE_data/trace_nif.c b/erts/emulator/test/trace_nif_SUITE_data/trace_nif.c
index 26f2420b8b..1afb5ee919 100644
--- a/erts/emulator/test/trace_nif_SUITE_data/trace_nif.c
+++ b/erts/emulator/test/trace_nif_SUITE_data/trace_nif.c
@@ -1,4 +1,4 @@
-#include "erl_nif.h"
+#include <erl_nif.h>
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
@@ -6,18 +6,18 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
return 0;
}
-static int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
+static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)
{
return 0;
}
-static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)
+static void unload(ErlNifEnv* env, void* priv_data)
{
- return 0;
}
-static void unload(ErlNifEnv* env, void* priv_data)
+static ERL_NIF_TERM is_nif_loaded(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
+ return enif_make_atom(env,"true");
}
static ERL_NIF_TERM nif_0(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -38,9 +38,10 @@ static ERL_NIF_TERM nif_1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
static ErlNifFunc nif_funcs[] =
{
+ {"is_nif_loaded", 0, is_nif_loaded},
{"nif", 0, nif_0},
{"nif", 1, nif_1}
};
-ERL_NIF_INIT(trace_nif_SUITE,nif_funcs,load,reload,upgrade,unload)
+ERL_NIF_INIT(trace_nif_SUITE,nif_funcs,load,NULL,upgrade,unload)
diff --git a/erts/emulator/test/tracer_SUITE_data/tracer_test.c b/erts/emulator/test/tracer_SUITE_data/tracer_test.c
index d9543b7ab9..1555a95d9a 100644
--- a/erts/emulator/test/tracer_SUITE_data/tracer_test.c
+++ b/erts/emulator/test/tracer_SUITE_data/tracer_test.c
@@ -18,7 +18,7 @@
* %CopyrightEnd%
*/
-#include "erl_nif.h"
+#include <erl_nif.h>
#include <stdio.h>
#include <string.h>