aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/common_test/doc/src/common_test_app.xml2
-rw-r--r--lib/common_test/doc/src/ct_hooks.xml8
-rw-r--r--lib/common_test/doc/src/ct_hooks_chapter.xml19
-rw-r--r--lib/common_test/doc/src/run_test_chapter.xml2
-rw-r--r--lib/common_test/src/ct_framework.erl12
-rw-r--r--lib/common_test/src/ct_hooks.erl143
-rw-r--r--lib/common_test/src/ct_run.erl25
-rw-r--r--lib/common_test/test/ct_hooks_SUITE.erl80
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_cth_prio_SUITE.erl62
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl11
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/prio_cth.erl74
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/state_update_cth.erl2
-rw-r--r--lib/dialyzer/src/dialyzer_dataflow.erl13
-rw-r--r--lib/dialyzer/src/dialyzer_typesig.erl9
-rw-r--r--lib/dialyzer/test/Makefile2
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/results/asn12
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/results/inets23
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/results/mnesia5
-rw-r--r--lib/dialyzer/test/race_SUITE_data/results/extract_translations4
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/flatten2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/binary_lc_bug.erl8
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/codec_can.erl35
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/file_open_encoding.erl4
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/list_to_bitstring.erl21
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/no_return_bug.erl42
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/nowarnunused.erl7
-rw-r--r--lib/diameter/doc/src/diameter_dict.xml9
-rw-r--r--lib/diameter/src/compiler/diameter_codegen.erl78
-rw-r--r--lib/diameter/src/compiler/diameter_spec_util.erl50
-rw-r--r--lib/diameter/test/Makefile2
-rw-r--r--lib/docbuilder/src/docb_gen.erl4
-rw-r--r--lib/docbuilder/src/docb_transform.erl2
-rw-r--r--lib/docbuilder/src/docb_xml_check.erl1
-rw-r--r--lib/docbuilder/vsn.mk2
-rw-r--r--lib/edoc/src/edoc_specs.erl3
-rw-r--r--lib/eunit/doc/overview.edoc2
-rw-r--r--lib/eunit/include/eunit.hrl102
-rw-r--r--lib/eunit/src/eunit.app.src16
-rw-r--r--lib/eunit/src/eunit.erl2
-rw-r--r--lib/eunit/src/eunit_data.erl70
-rw-r--r--lib/eunit/src/eunit_server.erl7
-rw-r--r--lib/eunit/src/eunit_surefire.erl2
-rw-r--r--lib/eunit/src/eunit_test.erl72
-rw-r--r--lib/eunit/src/eunit_tests.erl26
-rw-r--r--lib/eunit/vsn.mk2
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl5
-rw-r--r--lib/hipe/main/hipe.hrl.src7
-rw-r--r--lib/ic/src/ic_pp.erl16
-rw-r--r--lib/inets/src/http_server/httpd_file.erl2
-rw-r--r--lib/kernel/doc/src/gen_sctp.xml146
-rw-r--r--lib/kernel/doc/src/gen_tcp.xml25
-rw-r--r--lib/kernel/doc/src/gen_udp.xml21
-rw-r--r--lib/kernel/doc/src/inet.xml58
-rw-r--r--lib/kernel/src/code_server.erl17
-rw-r--r--lib/kernel/src/gen_sctp.erl174
-rw-r--r--lib/kernel/src/gen_tcp.erl120
-rw-r--r--lib/kernel/src/gen_udp.erl87
-rw-r--r--lib/kernel/src/inet.erl147
-rw-r--r--lib/kernel/src/inet_res.erl4
-rw-r--r--lib/kernel/test/application_SUITE.erl44
-rw-r--r--lib/kernel/test/code_SUITE.erl18
-rw-r--r--lib/kernel/test/disk_log_SUITE.erl4
-rw-r--r--lib/kernel/test/erl_prim_loader_SUITE.erl2
-rw-r--r--lib/kernel/test/gen_tcp_api_SUITE.erl8
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl14
-rw-r--r--lib/kernel/test/global_group_SUITE.erl16
-rw-r--r--lib/kernel/test/init_SUITE.erl2
-rw-r--r--lib/kernel/test/ram_file_SUITE.erl4
-rw-r--r--lib/kernel/test/zlib_SUITE.erl8
-rw-r--r--lib/observer/src/Makefile9
-rw-r--r--lib/odbc/c_src/odbcserver.c1
-rw-r--r--lib/odbc/test/odbc_data_type_SUITE.erl6
-rw-r--r--lib/odbc/test/odbc_test_lib.erl9
-rw-r--r--lib/parsetools/doc/src/yecc.xml8
-rw-r--r--lib/percept/src/percept_db.erl11
-rw-r--r--lib/sasl/doc/src/release_handler.xml28
-rw-r--r--lib/sasl/examples/src/Makefile2
-rw-r--r--lib/sasl/src/release_handler.erl52
-rw-r--r--lib/sasl/src/release_handler_1.erl93
-rw-r--r--lib/sasl/src/systools_make.erl6
-rw-r--r--lib/sasl/test/Makefile2
-rw-r--r--lib/sasl/test/release_handler_SUITE.erl307
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/Makefile.src71
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/README19
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.appup7
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/ebin/many_mods.app17
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m.erl11
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m1.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m10.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m2.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m3.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m4.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m5.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m6.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m7.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m8.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m9.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.app17
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.appup22
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m.erl11
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m1.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m10.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m2.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m3.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m4.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m5.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m6.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m7.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m8.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m9.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.app7
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.appup24
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/src/m.erl11
-rw-r--r--lib/sasl/test/systools_SUITE.erl46
-rw-r--r--lib/snmp/test/test_config/Makefile18
-rw-r--r--lib/ssh/doc/src/notes.xml14
-rw-r--r--lib/ssh/src/ssh.appup.src10
-rwxr-xr-xlib/ssh/src/ssh_sftp.erl12
-rw-r--r--lib/ssh/test/Makefile2
-rw-r--r--lib/ssh/vsn.mk2
-rw-r--r--lib/ssl/src/ssl.erl32
-rw-r--r--lib/ssl/src/ssl_connection.erl10
-rw-r--r--lib/ssl/src/ssl_handshake.erl14
-rw-r--r--lib/ssl/src/ssl_internal.hrl3
-rw-r--r--lib/ssl/src/ssl_manager.erl12
-rw-r--r--lib/ssl/src/ssl_session.erl4
-rw-r--r--lib/ssl/src/ssl_session_cache.erl4
-rw-r--r--lib/stdlib/doc/src/dets.xml2
-rw-r--r--lib/stdlib/doc/src/gen_fsm.xml6
-rw-r--r--lib/stdlib/doc/src/supervisor.xml9
-rw-r--r--lib/stdlib/src/dets.erl13
-rw-r--r--lib/stdlib/src/erl_internal.erl1
-rw-r--r--lib/stdlib/src/escript.erl6
-rw-r--r--lib/stdlib/src/eval_bits.erl8
-rw-r--r--lib/stdlib/src/io_lib.erl4
-rw-r--r--lib/stdlib/src/otp_internal.erl8
-rw-r--r--lib/stdlib/src/proplists.erl3
-rw-r--r--lib/stdlib/src/sofs.erl5
-rw-r--r--lib/stdlib/src/supervisor.erl7
-rw-r--r--lib/stdlib/src/sys.erl4
-rw-r--r--lib/stdlib/test/beam_lib_SUITE.erl16
-rw-r--r--lib/stdlib/test/dets_SUITE.erl8
-rw-r--r--lib/stdlib/test/epp_SUITE.erl4
-rw-r--r--lib/stdlib/test/erl_eval_SUITE.erl2
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl2
-rw-r--r--lib/stdlib/test/file_sorter_SUITE.erl16
-rw-r--r--lib/stdlib/test/filelib_SUITE.erl4
-rw-r--r--lib/stdlib/test/string_SUITE.erl4
-rw-r--r--lib/stdlib/test/supervisor_SUITE.erl35
-rw-r--r--lib/stdlib/test/supervisor_bridge_SUITE.erl2
-rw-r--r--lib/stdlib/test/sys_SUITE.erl2
-rw-r--r--lib/stdlib/test/tar_SUITE.erl18
-rw-r--r--lib/test_server/src/ts_install_cth.erl17
-rw-r--r--lib/test_server/test/Makefile2
-rw-r--r--lib/tools/emacs/erlang.el84
-rw-r--r--lib/webtool/priv/Makefile8
-rw-r--r--lib/wx/test/wxt.erl4
-rw-r--r--lib/xmerl/test/Makefile2
158 files changed, 2476 insertions, 862 deletions
diff --git a/lib/common_test/doc/src/common_test_app.xml b/lib/common_test/doc/src/common_test_app.xml
index c92566de37..57b032b3fd 100644
--- a/lib/common_test/doc/src/common_test_app.xml
+++ b/lib/common_test/doc/src/common_test_app.xml
@@ -144,7 +144,7 @@
<v> UserData = term()</v>
<v> Conns = [atom()]</v>
<v> CSSFile = string()</v>
- <v> CTHs = [CTHModule | {CTHModule, CTHInitArgs}]</v>
+ <v> CTHs = [CTHModule | {CTHModule, CTHInitArgs} | {CTHModule, CTHInitArgs, CTHPriority}]</v>
<v> CTHModule = atom()</v>
<v> CTHInitArgs = term()</v>
</type>
diff --git a/lib/common_test/doc/src/ct_hooks.xml b/lib/common_test/doc/src/ct_hooks.xml
index 7d5c9f4750..0ece3199bb 100644
--- a/lib/common_test/doc/src/ct_hooks.xml
+++ b/lib/common_test/doc/src/ct_hooks.xml
@@ -81,12 +81,14 @@
<funcs>
<func>
- <name>Module:init(Id, Opts) -&gt; State</name>
+ <name>Module:init(Id, Opts) -&gt; {ok, State} |
+ {ok, State, Priority}</name>
<fsummary>Initiates the Common Test Hook</fsummary>
<type>
<v>Id = reference() | term()</v>
<v>Opts = term()</v>
<v>State = term()</v>
+ <v>Priority = integer()</v>
</type>
<desc>
@@ -103,6 +105,10 @@
if <seealso marker="#Module:id-1">id/1</seealso> is not implemented.
</p>
+ <p><c>Priority</c> is the relative priority of this hook. Hooks with a
+ lower priority will be executed first. If no priority is given,
+ it will be set to 0. </p>
+
<p>For details about when init is called see
<seealso marker="ct_hooks_chapter#scope">scope</seealso>
in the User's Guide.</p>
diff --git a/lib/common_test/doc/src/ct_hooks_chapter.xml b/lib/common_test/doc/src/ct_hooks_chapter.xml
index fc5ab48e1b..dbb4310040 100644
--- a/lib/common_test/doc/src/ct_hooks_chapter.xml
+++ b/lib/common_test/doc/src/ct_hooks_chapter.xml
@@ -94,9 +94,11 @@
<seealso marker="common_test#Module:init_per_group-2">
init_per_group/2</seealso>. <c>CTH</c> in this case can be either
only the module name of the CTH or a tuple with the module name and the
- initial arguments to the CTH. Eg:
+ initial arguments and optionally the hook priority of the CTH. Eg:
<c>{ct_hooks,[my_cth_module]}</c> or
- <c>{ct_hooks,[{my_cth_module,[{debug,true}]}]}</c></p>
+ <c>{ct_hooks,[{my_cth_module,[{debug,true}]}]}</c> or
+ <c>{ct_hooks,[{my_cth_module,[{debug,true}],500}]}</c>
+ </p>
<section>
<title>Overriding CTHs</title>
@@ -109,7 +111,16 @@
<c>id</c> in both places, Common Test knows that this CTH
has already been installed and will not try to install it again.</p>
</section>
-
+
+ <section>
+ <title>CTH Priority</title>
+ <p>By default each CTH installed will be executed in the order which
+ they are installed. This is not always wanted so common_test allows
+ the user to specify a priority for each hook. The priority can either
+ be specified in the CTH <seealso marker="ct_hooks#Module:init-2">init/2
+ </seealso> function or when installing the hook. The priority given at
+ installation will override the priority returned by the CTH. </p>
+ </section>
</section>
<marker id="scope"/>
@@ -331,7 +342,7 @@ id(Opts) ->
%% any common state.
init(Id, Opts) ->
{ok,D} = file:open(Id,[write]),
- #state{ file_handle = D, total = 0, data = [] }.
+ {ok, #state{ file_handle = D, total = 0, data = [] }}.
%% @doc Called before init_per_suite is called.
pre_init_per_suite(Suite,Config,State) ->
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index e6fb85634f..e668568795 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -488,7 +488,7 @@
LogDir = string()
EventHandlers = atom() | [atom()]
InitArgs = [term()]
- CTHModules = [CTHModule | {CTHModule, CTHInitArgs}]
+ CTHModules = [CTHModule | {CTHModule, CTHInitArgs} | {CTHModule, CTHInitArgs, CTHPriority}]
CTHModule = atom()
CTHInitArgs = term()
DirRef = DirAlias | Dir
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 809616d8e3..9e597edf38 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -240,7 +240,8 @@ add_defaults(Mod,Func,FuncInfo,DoInit) ->
case (catch Mod:suite()) of
{'EXIT',{undef,_}} ->
SuiteInfo = merge_with_suite_defaults(Mod,[]),
- case add_defaults1(Mod,Func,FuncInfo,SuiteInfo,DoInit) of
+ SuiteInfoNoCTH = [I || I <- SuiteInfo, element(1,I) =/= ct_hooks],
+ case add_defaults1(Mod,Func,FuncInfo,SuiteInfoNoCTH,DoInit) of
Error = {error,_} -> {SuiteInfo,Error};
MergedInfo -> {SuiteInfo,MergedInfo}
end;
@@ -251,10 +252,11 @@ add_defaults(Mod,Func,FuncInfo,DoInit) ->
(_) -> false
end, SuiteInfo) of
true ->
- SuiteInfoNoCTH =
- lists:keydelete(ct_hooks,1,SuiteInfo),
- SuiteInfo1 = merge_with_suite_defaults(Mod,SuiteInfoNoCTH),
- case add_defaults1(Mod,Func,FuncInfo,SuiteInfo1,DoInit) of
+ SuiteInfo1 = merge_with_suite_defaults(Mod,SuiteInfo),
+ SuiteInfoNoCTH = [I || I <- SuiteInfo1,
+ element(1,I) =/= ct_hooks],
+ case add_defaults1(Mod,Func,FuncInfo,
+ SuiteInfoNoCTH,DoInit) of
Error = {error,_} -> {SuiteInfo1,Error};
MergedInfo -> {SuiteInfo1,MergedInfo}
end;
diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl
index 984e04b90f..f243b87f54 100644
--- a/lib/common_test/src/ct_hooks.erl
+++ b/lib/common_test/src/ct_hooks.erl
@@ -31,11 +31,11 @@
-export([on_tc_skip/2]).
-export([on_tc_fail/2]).
--type proplist() :: [{atom(),term()}].
-
%% If you change this, remember to update ct_util:look -> stop clause as well.
-define(config_name, ct_hooks).
+-record(ct_hook_config, {id, module, prio, scope, opts = [], state = []}).
+
%% -------------------------------------------------------------------------
%% API Functions
%% -------------------------------------------------------------------------
@@ -44,22 +44,22 @@
-spec init(State :: term()) -> ok |
{error, Reason :: term()}.
init(Opts) ->
- call([{Hook, call_id, undefined} || Hook <- get_new_hooks(Opts)],
- ok, init, []).
+ call(get_new_hooks(Opts, undefined), ok, init, []).
%% @doc Called after all suites are done.
-spec terminate(Hooks :: term()) ->
ok.
terminate(Hooks) ->
- call([{HookId, fun call_terminate/3} || {HookId,_,_} <- Hooks],
+ call([{HookId, fun call_terminate/3}
+ || #ct_hook_config{id = HookId} <- Hooks],
ct_hooks_terminate_dummy, terminate, Hooks),
ok.
%% @doc Called as each test case is started. This includes all configuration
%% tests.
-spec init_tc(Mod :: atom(), Func :: atom(), Args :: list()) ->
- NewConfig :: proplist() |
+ NewConfig :: proplists:proplist() |
{skip, Reason :: term()} |
{auto_skip, Reason :: term()} |
{fail, Reason :: term()}.
@@ -68,11 +68,11 @@ init_tc(ct_framework, _Func, Args) ->
init_tc(Mod, init_per_suite, Config) ->
Info = try proplists:get_value(ct_hooks, Mod:suite(),[]) of
List when is_list(List) ->
- [{ct_hooks,List}];
+ [{?config_name,List}];
CTHook when is_atom(CTHook) ->
- [{ct_hooks,[CTHook]}]
+ [{?config_name,[CTHook]}]
catch error:undef ->
- [{ct_hooks,[]}]
+ [{?config_name,[]}]
end,
call(fun call_generic/3, Config ++ Info, [pre_init_per_suite, Mod]);
init_tc(Mod, end_per_suite, Config) ->
@@ -92,7 +92,7 @@ init_tc(_Mod, TC, Config) ->
Args :: list(),
Result :: term(),
Resturn :: term()) ->
- NewConfig :: proplist() |
+ NewConfig :: proplists:proplist() |
{skip, Reason :: term()} |
{auto_skip, Reason :: term()} |
{fail, Reason :: term()} |
@@ -131,36 +131,48 @@ on_tc_fail(_How, {Suite, Case, Reason}) ->
%% -------------------------------------------------------------------------
%% Internal Functions
%% -------------------------------------------------------------------------
-call_id(Mod, Config, Meta) when is_atom(Mod) ->
- call_id({Mod, []}, Config, Meta);
-call_id({Mod, Opts}, Config, Scope) ->
+call_id(#ct_hook_config{ module = Mod, opts = Opts} = Hook, Config, Scope) ->
Id = catch_apply(Mod,id,[Opts], make_ref()),
- {Config, {Id, scope(Scope), {Mod, {Id,Opts}}}}.
+ {Config, Hook#ct_hook_config{ id = Id, scope = scope(Scope)}}.
-call_init({Mod,{Id,Opts}},Config,_Meta) ->
- NewState = Mod:init(Id, Opts),
- {Config, {Mod, NewState}}.
-
-call_terminate({Mod, State}, _, _) ->
+call_init(#ct_hook_config{ module = Mod, opts = Opts, id = Id, prio = P} = Hook,
+ Config,_Meta) ->
+ case Mod:init(Id, Opts) of
+ {ok, NewState} when P =:= undefined ->
+ {Config, Hook#ct_hook_config{ state = NewState, prio = 0 } };
+ {ok, NewState} ->
+ {Config, Hook#ct_hook_config{ state = NewState } };
+ {ok, NewState, Prio} when P =:= undefined ->
+ %% Only set prio if not already set when installing hook
+ {Config, Hook#ct_hook_config{ state = NewState, prio = Prio } };
+ {ok, NewState, _} ->
+ {Config, Hook#ct_hook_config{ state = NewState } };
+ NewState -> %% Keep for backward compatability reasons
+ {Config, Hook#ct_hook_config{ state = NewState } }
+ end.
+
+call_terminate(#ct_hook_config{ module = Mod, state = State} = Hook, _, _) ->
catch_apply(Mod,terminate,[State], ok),
- {[],{Mod,State}}.
+ {[],Hook}.
-call_cleanup({Mod, State}, Reason, [Function, _Suite | Args]) ->
+call_cleanup(#ct_hook_config{ module = Mod, state = State} = Hook,
+ Reason, [Function, _Suite | Args]) ->
NewState = catch_apply(Mod,Function, Args ++ [Reason, State],
State),
- {Reason, {Mod, NewState}}.
+ {Reason, Hook#ct_hook_config{ state = NewState } }.
-call_generic({Mod, State}, Value, [Function | Args]) ->
+call_generic(#ct_hook_config{ module = Mod, state = State} = Hook,
+ Value, [Function | Args]) ->
{NewValue, NewState} = catch_apply(Mod, Function, Args ++ [Value, State],
{Value,State}),
- {NewValue, {Mod, NewState}}.
+ {NewValue, Hook#ct_hook_config{ state = NewState } }.
%% Generic call function
call(Fun, Config, Meta) ->
maybe_lock(),
Hooks = get_hooks(),
- Res = call([{HookId,Fun} || {HookId,_, _} <- Hooks] ++
- get_new_hooks(Config, Fun),
+ Res = call(get_new_hooks(Config, Fun) ++
+ [{HookId,Fun} || #ct_hook_config{id = HookId} <- Hooks],
remove(?config_name,Config), Meta, Hooks),
maybe_unlock(),
Res.
@@ -173,19 +185,20 @@ call(Fun, Config, Meta, NoChangeRet) when is_function(Fun) ->
call([{Hook, call_id, NextFun} | Rest], Config, Meta, Hooks) ->
try
- {Config, {NewId, _, _} = NewHook} = call_id(Hook, Config, Meta),
+ {Config, #ct_hook_config{ id = NewId } = NewHook} =
+ call_id(Hook, Config, Meta),
{NewHooks, NewRest} =
- case lists:keyfind(NewId, 1, Hooks) of
+ case lists:keyfind(NewId, #ct_hook_config.id, Hooks) of
false when NextFun =:= undefined ->
{Hooks ++ [NewHook],
- [{NewId, fun call_init/3} | Rest]};
+ [{NewId, call_init} | Rest]};
ExistingHook when is_tuple(ExistingHook) ->
{Hooks, Rest};
_ ->
{Hooks ++ [NewHook],
- [{NewId, fun call_init/3},{NewId,NextFun} | Rest]}
+ [{NewId, call_init}, {NewId,NextFun} | Rest]}
end,
- call(NewRest, Config, Meta, NewHooks)
+ call(resort(NewRest,NewHooks), Config, Meta, NewHooks)
catch Error:Reason ->
Trace = erlang:get_stacktrace(),
ct_logs:log("Suite Hook","Failed to start a CTH: ~p:~p",
@@ -193,13 +206,16 @@ call([{Hook, call_id, NextFun} | Rest], Config, Meta, Hooks) ->
call([], {fail,"Failed to start CTH"
", see the CT Log for details"}, Meta, Hooks)
end;
+call([{HookId, call_init} | Rest], Config, Meta, Hooks) ->
+ call([{HookId, fun call_init/3} | Rest], Config, Meta, Hooks);
call([{HookId, Fun} | Rest], Config, Meta, Hooks) ->
try
- {_,Scope,ModState} = lists:keyfind(HookId, 1, Hooks),
- {NewConf, NewHookInfo} = Fun(ModState, Config, Meta),
+ Hook = lists:keyfind(HookId, #ct_hook_config.id, Hooks),
+ {NewConf, NewHook} = Fun(Hook, Config, Meta),
NewCalls = get_new_hooks(NewConf, Fun),
- NewHooks = lists:keyreplace(HookId, 1, Hooks, {HookId, Scope, NewHookInfo}),
- call(NewCalls ++ Rest, remove(?config_name, NewConf), Meta,
+ NewHooks = lists:keyreplace(HookId, #ct_hook_config.id, Hooks, NewHook),
+ call(resort(NewCalls ++ Rest,NewHooks), %% Resort if call_init changed prio
+ remove(?config_name, NewConf), Meta,
terminate_if_scope_ends(HookId, Meta, NewHooks))
catch throw:{error_in_cth_call,Reason} ->
call(Rest, {fail, Reason}, Meta,
@@ -237,19 +253,26 @@ terminate_if_scope_ends(HookId, [on_tc_skip,Suite,end_per_suite], Hooks) ->
terminate_if_scope_ends(HookId, [Function,Tag|T], Hooks) when T =/= [] ->
terminate_if_scope_ends(HookId,[Function,Tag],Hooks);
terminate_if_scope_ends(HookId, Function, Hooks) ->
- case lists:keyfind(HookId, 1, Hooks) of
- {HookId, Function, _ModState} = Hook ->
+ case lists:keyfind(HookId, #ct_hook_config.id, Hooks) of
+ #ct_hook_config{ id = HookId, scope = Function} = Hook ->
terminate([Hook]),
- lists:keydelete(HookId, 1, Hooks);
+ lists:keydelete(HookId, #ct_hook_config.id, Hooks);
_ ->
Hooks
end.
%% Fetch hook functions
get_new_hooks(Config, Fun) ->
- lists:foldl(fun(NewHook, Acc) ->
- [{NewHook, call_id, Fun} | Acc]
- end, [], get_new_hooks(Config)).
+ lists:map(fun(NewHook) when is_atom(NewHook) ->
+ {#ct_hook_config{ module = NewHook }, call_id, Fun};
+ ({NewHook,Opts}) ->
+ {#ct_hook_config{ module = NewHook,
+ opts = Opts}, call_id, Fun};
+ ({NewHook,Opts,Prio}) ->
+ {#ct_hook_config{ module = NewHook,
+ opts = Opts,
+ prio = Prio }, call_id, Fun}
+ end, get_new_hooks(Config)).
get_new_hooks(Config) when is_list(Config) ->
lists:flatmap(fun({?config_name, HookConfigs}) ->
@@ -264,7 +287,43 @@ save_suite_data_async(Hooks) ->
ct_util:save_suite_data_async(?config_name, Hooks).
get_hooks() ->
- ct_util:read_suite_data(?config_name).
+ lists:keysort(#ct_hook_config.prio,ct_util:read_suite_data(?config_name)).
+
+%% Sort all calls in this order:
+%% call_id < call_init < Hook Priority 1 < .. < Hook Priority N
+%% If Hook Priority is equal, check when it has been installed and
+%% sort on that instead.
+resort(Calls, Hooks) ->
+ lists:sort(
+ fun({_,_,_},_) ->
+ true;
+ (_,{_,_,_}) ->
+ false;
+ ({_,call_init},_) ->
+ true;
+ (_,{_,call_init}) ->
+ false;
+ ({Id1,_},{Id2,_}) ->
+ P1 = (lists:keyfind(Id1, #ct_hook_config.id, Hooks))#ct_hook_config.prio,
+ P2 = (lists:keyfind(Id2, #ct_hook_config.id, Hooks))#ct_hook_config.prio,
+ if
+ P1 == P2 ->
+ %% If priorities are equal, we check the position in the
+ %% hooks list
+ pos(Id1,Hooks) < pos(Id2,Hooks);
+ true ->
+ P1 < P2
+ end
+ end,Calls).
+
+pos(Id,Hooks) ->
+ pos(Id,Hooks,0).
+pos(Id,[#ct_hook_config{ id = Id}|_],Num) ->
+ Num;
+pos(Id,[_|Rest],Num) ->
+ pos(Id,Rest,Num+1).
+
+
catch_apply(M,F,A, Default) ->
try
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index c01e97b358..877ec9c7dd 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -521,8 +521,8 @@ script_usage() ->
"\n\t[-silent_connections [ConnType1 ConnType2 .. ConnTypeN]]"
"\n\t[-stylesheet CSSFile]"
"\n\t[-cover CoverCfgFile]"
- "\n\t[-event_handler EvHandler1 EvHandler2 .. EvHandlerN]"
- "\n\t[-ct_hooks CTHook1 CTHook2 .. CTHookN]"
+ "\n\t[-event_handler EvHandler1 and EvHandler2 .. EvHandlerN]"
+ "\n\t[-ct_hooks CTHook1 and CTHook2 .. CTHookN]"
"\n\t[-include InclDir1 InclDir2 .. InclDirN]"
"\n\t[-no_auto_compile]"
"\n\t[-multiply_timetraps N]"
@@ -540,8 +540,8 @@ script_usage() ->
"\n\t[-silent_connections [ConnType1 ConnType2 .. ConnTypeN]]"
"\n\t[-stylesheet CSSFile]"
"\n\t[-cover CoverCfgFile]"
- "\n\t[-event_handler EvHandler1 EvHandler2 .. EvHandlerN]"
- "\n\t[-ct_hooks CTHook1 CTHook2 .. CTHookN]"
+ "\n\t[-event_handler EvHandler1 and EvHandler2 .. EvHandlerN]"
+ "\n\t[-ct_hooks CTHook1 and CTHook2 .. CTHookN]"
"\n\t[-include InclDir1 InclDir2 .. InclDirN]"
"\n\t[-no_auto_compile]"
"\n\t[-multiply_timetraps N]"
@@ -2070,15 +2070,21 @@ ct_hooks_args2opts(Args) ->
ct_hooks_args2opts(
proplists:get_value(ct_hooks, Args, []),[]).
+ct_hooks_args2opts([CTH,Arg,Prio,"and"| Rest],Acc) ->
+ ct_hooks_args2opts(Rest,[{list_to_atom(CTH),
+ parse_cth_args(Arg),
+ parse_cth_args(Prio)}|Acc]);
ct_hooks_args2opts([CTH,Arg,"and"| Rest],Acc) ->
ct_hooks_args2opts(Rest,[{list_to_atom(CTH),
- parse_cth_args(Arg)}|Acc]);
+ parse_cth_args(Arg)}|Acc]);
ct_hooks_args2opts([CTH], Acc) ->
ct_hooks_args2opts([CTH,"and"],Acc);
ct_hooks_args2opts([CTH, "and" | Rest], Acc) ->
ct_hooks_args2opts(Rest,[list_to_atom(CTH)|Acc]);
ct_hooks_args2opts([CTH, Args], Acc) ->
ct_hooks_args2opts([CTH, Args, "and"],Acc);
+ct_hooks_args2opts([CTH, Args, Prio], Acc) ->
+ ct_hooks_args2opts([CTH, Args, Prio, "and"],Acc);
ct_hooks_args2opts([],Acc) ->
lists:reverse(Acc).
@@ -2225,7 +2231,14 @@ opts2args(EnvStartOpts) ->
({ct_hooks,CTHs}) when is_list(CTHs) ->
io:format(user,"ct_hooks: ~p",[CTHs]),
Strs = lists:flatmap(
- fun({CTH,Arg}) ->
+ fun({CTH,Arg,Prio}) ->
+ [atom_to_list(CTH),
+ lists:flatten(
+ io_lib:format("~p",[Arg])),
+ lists:flatten(
+ io_lib:format("~p",[Prio])),
+ "and"];
+ ({CTH,Arg}) ->
[atom_to_list(CTH),
lists:flatten(
io_lib:format("~p",[Arg])),
diff --git a/lib/common_test/test/ct_hooks_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE.erl
index 8574d7aabc..5c99f0f9f7 100644
--- a/lib/common_test/test/ct_hooks_SUITE.erl
+++ b/lib/common_test/test/ct_hooks_SUITE.erl
@@ -83,7 +83,7 @@ all(suite) ->
fail_post_suite_cth, skip_pre_suite_cth,
skip_post_suite_cth, recover_post_suite_cth, update_config_cth,
state_update_cth, options_cth, same_id_cth,
- fail_n_skip_with_minimal_cth
+ fail_n_skip_with_minimal_cth, prio_cth
]
)
.
@@ -209,6 +209,11 @@ fail_n_skip_with_minimal_cth(Config) when is_list(Config) ->
do_test(fail_n_skip_with_minimal_cth, "ct_cth_fail_one_skip_one_SUITE.erl",
[minimal_terminate_cth],Config).
+prio_cth(Config) when is_list(Config) ->
+ do_test(prio_cth, "ct_cth_prio_SUITE.erl",
+ [{empty_cth,[1000],1000},{empty_cth,[900],900},
+ {prio_cth,[1100,100],100},{prio_cth,[1100]}],Config).
+
%%%-----------------------------------------------------------------
%%% HELP FUNCTIONS
%%%-----------------------------------------------------------------
@@ -296,9 +301,9 @@ test_events(two_empty_cth) ->
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,cth,{'_',id,[[]]}},
- {?eh,cth,{'_',init,['_',[]]}},
{?eh,cth,{'_',id,[[]]}},
{?eh,cth,{'_',init,['_',[]]}},
+ {?eh,cth,{'_',init,['_',[]]}},
{?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}},
{?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}},
{?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}},
@@ -365,9 +370,9 @@ test_events(minimal_and_maximal_cth) ->
[
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{'_',id,[[]]}},
{negative,{?eh,cth,{'_',id,['_',[]]}},
{?eh,cth,{'_',init,['_',[]]}}},
- {?eh,cth,{'_',id,[[]]}},
{?eh,cth,{'_',init,['_',[]]}},
{?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}},
{?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}},
@@ -954,8 +959,8 @@ test_events(same_id_cth) ->
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,cth,{'_',id,[[]]}},
- {?eh,cth,{'_',init,[same_id_cth,[]]}},
{?eh,cth,{'_',id,[[]]}},
+ {?eh,cth,{'_',init,[same_id_cth,[]]}},
{?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}},
{?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}},
{negative,
@@ -1001,6 +1006,73 @@ test_events(fail_n_skip_with_minimal_cth) ->
{?eh,stop_logging,[]}
];
+test_events(prio_cth) ->
+
+ GenPre = fun(Func,States) ->
+ [{?eh,cth,{'_',Func,['_','_',State]}} ||
+ State <- States]
+ end,
+
+ GenPost = fun(Func,States) ->
+ [{?eh,cth,{'_',Func,['_','_','_',State]}} ||
+ State <- States]
+ end,
+
+ [{?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}] ++
+
+ [{?eh,tc_start,{ct_cth_prio_SUITE,init_per_suite}}] ++
+ GenPre(pre_init_per_suite,
+ [[1100,100],[800],[900],[1000],[1200,1050],[1100],[1200]]) ++
+ GenPost(post_init_per_suite,
+ [[1100,100],[600,200],[600,600],[700],[800],[900],[1000],
+ [1200,1050],[1100],[1200]]) ++
+ [{?eh,tc_done,{ct_cth_prio_SUITE,init_per_suite,ok}},
+
+
+ [{?eh,tc_start,{ct_cth_prio_SUITE,{init_per_group,'_',[]}}}] ++
+ GenPre(pre_init_per_group,
+ [[1100,100],[600,200],[600,600],[700],[800],
+ [900],[1000],[1200,1050],[1100],[1200]]) ++
+ GenPost(post_init_per_group,
+ [[1100,100],[600,200],[600,600],[600],[700],[800],
+ [900],[900,900],[500,900],[1000],[1200,1050],
+ [1100],[1200]]) ++
+ [{?eh,tc_done,{ct_cth_prio_SUITE,{init_per_group,'_',[]},ok}}] ++
+
+ [{?eh,tc_start,{ct_cth_prio_SUITE,test_case}}] ++
+ GenPre(pre_init_per_testcase,
+ [[1100,100],[600,200],[600,600],[600],[700],[800],
+ [900],[900,900],[500,900],[1000],[1200,1050],
+ [1100],[1200]]) ++
+ GenPost(post_end_per_testcase,
+ [[1100,100],[600,200],[600,600],[600],[700],[800],
+ [900],[900,900],[500,900],[1000],[1200,1050],
+ [1100],[1200]]) ++
+ [{?eh,tc_done,{ct_cth_prio_SUITE,test_case,ok}},
+
+ {?eh,tc_start,{ct_cth_prio_SUITE,{end_per_group,'_',[]}}}] ++
+ GenPre(pre_end_per_group,
+ [[1100,100],[600,200],[600,600],[600],[700],[800],
+ [900],[900,900],[500,900],[1000],[1200,1050],
+ [1100],[1200]]) ++
+ GenPost(post_end_per_group,
+ [[1100,100],[600,200],[600,600],[600],[700],[800],
+ [900],[900,900],[500,900],[1000],[1200,1050],
+ [1100],[1200]]) ++
+ [{?eh,tc_done,{ct_cth_prio_SUITE,{end_per_group,'_',[]},ok}}],
+
+ {?eh,tc_start,{ct_cth_prio_SUITE,end_per_suite}}] ++
+ GenPre(pre_end_per_suite,
+ [[1100,100],[600,200],[600,600],[700],[800],[900],[1000],
+ [1200,1050],[1100],[1200]]) ++
+ GenPost(post_end_per_suite,
+ [[1100,100],[600,200],[600,600],[700],[800],[900],[1000],
+ [1200,1050],[1100],[1200]]) ++
+ [{?eh,tc_done,{ct_cth_prio_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+
test_events(ok) ->
ok.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_cth_prio_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_cth_prio_SUITE.erl
new file mode 100644
index 0000000000..d564398cd0
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_cth_prio_SUITE.erl
@@ -0,0 +1,62 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2011. 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%
+%%
+
+-module(ct_cth_prio_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include("ct.hrl").
+
+suite() ->
+ ([{timetrap, {minutes, 10}},
+ {ct_hooks, [{empty_cth,[800],800},
+ {prio_cth,[1200]},{prio_cth,[1200,1050],1050}]}]).
+
+%% Test server callback functions
+init_per_suite(Config) ->
+ [{ct_hooks, [{empty_cth,[700],700},
+ {prio_cth,[600,600]},
+ {prio_cth,[600,200],200}]}|Config].
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_G, Config) ->
+ [{ct_hooks, [{empty_cth,[600],600},
+ {prio_cth,[900,900]},{prio_cth,[500,900],900}]}|Config].
+
+end_per_group(_G, _Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+all() ->
+ [{group,test_group}].
+
+groups() ->
+ [{test_group,[],[test_case]}].
+
+%% Test cases starts here.
+test_case(Config) when is_list(Config) ->
+ ok.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl
index ebebfd18a9..7befcfa57c 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl
@@ -59,8 +59,7 @@
-include_lib("common_test/src/ct_util.hrl").
-include_lib("common_test/include/ct_event.hrl").
--type proplist() :: list({atom(),term()}).
--type config() :: proplist().
+-type config() :: proplists:proplist().
-type reason() :: term().
-type skip_or_fail() :: {skip, reason()} |
{auto_skip, reason()} |
@@ -71,17 +70,17 @@
%% @doc Always called before any other callback function. Use this to initiate
%% any common state. It should return an state for this CTH.
--spec init(Id :: term(), Opts :: proplist()) ->
- State :: #state{}.
+-spec init(Id :: term(), Opts :: proplists:proplist()) ->
+ {ok, State :: #state{}}.
init(Id, Opts) ->
gen_event:notify(?CT_EVMGR_REF, #event{ name = cth, node = node(),
data = {?MODULE, init, [Id, Opts]}}),
- Opts.
+ {ok,Opts}.
%% @doc The ID is used to uniquly identify an CTH instance, if two CTH's
%% return the same ID the seconds CTH is ignored. This function should NOT
%% have any side effects as it might be called multiple times by common test.
--spec id(Opts :: proplist()) ->
+-spec id(Opts :: proplists:proplist()) ->
Id :: term().
id(Opts) ->
gen_event:notify(?CT_EVMGR_REF, #event{ name = cth, node = node(),
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/prio_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/prio_cth.erl
new file mode 100644
index 0000000000..82511ab0d3
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/prio_cth.erl
@@ -0,0 +1,74 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2011. 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%
+%%
+
+
+-module(prio_cth).
+
+
+-include_lib("common_test/src/ct_util.hrl").
+
+
+%% CT Hooks
+-compile(export_all).
+
+id(Opts) ->
+ empty_cth:id(Opts).
+
+init(Id, Opts) ->
+ {ok, [Prio|_] = State} = empty_cth:init(Id, Opts),
+ {ok, State, Prio}.
+
+pre_init_per_suite(Suite, Config, State) ->
+ empty_cth:pre_init_per_suite(Suite,Config,State).
+
+post_init_per_suite(Suite,Config,Return,State) ->
+ empty_cth:post_init_per_suite(Suite,Config,Return,State).
+
+pre_end_per_suite(Suite,Config,State) ->
+ empty_cth:pre_end_per_suite(Suite,Config,State).
+
+post_end_per_suite(Suite,Config,Return,State) ->
+ empty_cth:post_end_per_suite(Suite,Config,Return,State).
+
+pre_init_per_group(Group,Config,State) ->
+ empty_cth:pre_init_per_group(Group,Config,State).
+
+post_init_per_group(Group,Config,Return,State) ->
+ empty_cth:post_init_per_group(Group,Config,Return,State).
+
+pre_end_per_group(Group,Config,State) ->
+ empty_cth:pre_end_per_group(Group,Config,State).
+
+post_end_per_group(Group,Config,Return,State) ->
+ empty_cth:post_end_per_group(Group,Config,Return,State).
+
+pre_init_per_testcase(TC,Config,State) ->
+ empty_cth:pre_init_per_testcase(TC,Config,State).
+
+post_end_per_testcase(TC,Config,Return,State) ->
+ empty_cth:post_end_per_testcase(TC,Config,Return,State).
+
+on_tc_fail(TC, Reason, State) ->
+ empty_cth:on_tc_fail(TC,Reason,State).
+
+on_tc_skip(TC, Reason, State) ->
+ empty_cth:on_tc_skip(TC,Reason,State).
+
+terminate(State) ->
+ empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/state_update_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/state_update_cth.erl
index 35c990c0be..9da48d3a4c 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/state_update_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/state_update_cth.erl
@@ -29,7 +29,7 @@
init(Id, Opts) ->
State = empty_cth:init(Id, Opts),
- [init|State].
+ {ok, [init|State]}.
pre_init_per_suite(Suite, Config, State) ->
empty_cth:pre_init_per_suite(Suite,Config,State),
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index 7137dbc036..8cb16d8f09 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -1414,6 +1414,17 @@ do_clause(C, Arg, ArgType0, OrigArgType, Map,
false ->
true
end;
+ [Pat0, Pat1] -> % binary comprehension
+ case cerl:is_c_cons(Pat0) of
+ true ->
+ not (cerl:is_c_var(cerl:cons_hd(Pat0)) andalso
+ cerl:is_c_var(cerl:cons_tl(Pat0)) andalso
+ cerl:is_c_var(Pat1) andalso
+ cerl:is_literal(Guard) andalso
+ (cerl:concrete(Guard) =:= true));
+ false ->
+ true
+ end;
_ -> true
end;
false ->
@@ -2915,7 +2926,7 @@ state__get_warnings(#state{tree_map = TreeMap, fun_tab = FunTab,
{Warn, Msg} =
case dialyzer_callgraph:lookup_name(FunLbl, Callgraph) of
error -> {true, {unused_fun, []}};
- {ok, {_M, F, A}} = MFA ->
+ {ok, {_M, F, A} = MFA} ->
{not sets:is_element(MFA, NoWarnUnused),
{unused_fun, [F, A]}}
end,
diff --git a/lib/dialyzer/src/dialyzer_typesig.erl b/lib/dialyzer/src/dialyzer_typesig.erl
index c45615d670..65c2ff76bb 100644
--- a/lib/dialyzer/src/dialyzer_typesig.erl
+++ b/lib/dialyzer/src/dialyzer_typesig.erl
@@ -1684,11 +1684,14 @@ solve_scc(SCC, Map, State, TryingUnit) ->
true ->
?debug("SCC ~w reached fixpoint\n", [SCC]),
NewTypes = unsafe_lookup_type_list(Funs, Map2),
- case lists:all(fun(T) -> t_is_none(t_fun_range(T)) end, NewTypes)
+ case erl_types:any_none([t_fun_range(T) || T <- NewTypes])
andalso TryingUnit =:= false of
true ->
- UnitTypes = [t_fun(state__fun_arity(F, State), t_unit())
- || F <- Funs],
+ UnitTypes =
+ [case t_is_none(t_fun_range(T)) of
+ false -> T;
+ true -> t_fun(t_fun_args(T), t_unit())
+ end || T <- NewTypes],
Map3 = enter_type_lists(Funs, UnitTypes, Map2),
solve_scc(SCC, Map3, State, true);
false ->
diff --git a/lib/dialyzer/test/Makefile b/lib/dialyzer/test/Makefile
index 69a8fd742e..47deb17f1d 100644
--- a/lib/dialyzer/test/Makefile
+++ b/lib/dialyzer/test/Makefile
@@ -26,7 +26,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_tests_spec:
$(INSTALL_DIR) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
$(INSTALL_DATA) $(AUXILIARY_FILES) $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
cd $(RELSYSDIR);\
diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/asn1 b/lib/dialyzer/test/r9c_SUITE_data/results/asn1
index ac83366bc8..571e562d0d 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/results/asn1
+++ b/lib/dialyzer/test/r9c_SUITE_data/results/asn1
@@ -2,7 +2,7 @@
asn1ct.erl:1500: The variable Err can never match since previous clauses completely covered the type #type{}
asn1ct.erl:1596: The variable _ can never match since previous clauses completely covered the type 'ber_bin_v2'
asn1ct.erl:1673: The pattern 'all' can never match the type 'asn1_module' | 'exclusive_decode' | 'partial_decode'
-asn1ct.erl:672: The pattern <{'false', Result}, _, _> can never match the type <{'true','true'},atom() | binary() | [atom() | binary() | [atom() | binary() | [any()] | char()] | char()],[any()]>
+asn1ct.erl:672: The pattern <{'false', Result}, _, _> can never match the type <{'true','true'},atom() | binary() | [atom() | [any()] | char()],[any()]>
asn1ct.erl:909: Guard test is_atom(Ext::[49 | 97 | 98 | 100 | 110 | 115]) can never succeed
asn1ct_check.erl:1698: The pattern {'error', _} can never match the type [any()]
asn1ct_check.erl:2733: The pattern {'type', Tag, _, _, _, _} can never match the type 'ASN1_OPEN_TYPE' | {_,_} | {'fixedtypevaluefield',_,_}
diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/inets b/lib/dialyzer/test/r9c_SUITE_data/results/inets
index fd5e36a3cd..6b16dba2ff 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/results/inets
+++ b/lib/dialyzer/test/r9c_SUITE_data/results/inets
@@ -7,9 +7,6 @@ http_lib.erl:286: The call http_lib:close('ip_comm' | {'ssl',_},any()) will neve
http_lib.erl:424: The variable _ can never match since previous clauses completely covered the type any()
http_lib.erl:438: The variable _ can never match since previous clauses completely covered the type any()
http_lib.erl:99: Function getHeaderValue/2 will never be called
-httpc_handler.erl:322: Function status_continue/2 has no local return
-httpc_handler.erl:37: Function init_connection/2 has no local return
-httpc_handler.erl:65: Function next_response_with_request/2 has no local return
httpc_handler.erl:660: Function exit_session_ok/2 has no local return
httpc_manager.erl:145: The pattern {ErrorReply, State2} can never match the type {{'ok',number()},number(),#state{reqid::number()}}
httpc_manager.erl:160: The pattern {ErrorReply, State2} can never match the type {{'ok',number()},number(),#state{reqid::number()}}
@@ -27,7 +24,7 @@ httpd_manager.erl:933: Function acceptor_status/1 will never be called
httpd_request_handler.erl:374: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 66 | 98 | 100 | 103 | 105 | 111 | 116 | 121,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
httpd_request_handler.erl:378: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
httpd_request_handler.erl:401: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
-httpd_request_handler.erl:644: The call lists:reverse(Fields0::{'error',_} | {'ok',[[any()]]}) will never return since it differs in the 1st argument from the success typing arguments: ([any()])
+httpd_request_handler.erl:644: The call lists:reverse(Fields0::{'error',_} | {'ok',_}) will never return since it differs in the 1st argument from the success typing arguments: ([any()])
httpd_request_handler.erl:645: Function will never be called
httpd_sup.erl:63: The variable Else can never match since previous clauses completely covered the type {'error',_} | {'ok',[any()],_,_}
httpd_sup.erl:88: The pattern {'error', Reason} can never match the type {'ok',_,_}
@@ -38,17 +35,17 @@ mod_auth_plain.erl:100: The variable _ can never match since previous clauses co
mod_auth_plain.erl:159: The variable _ can never match since previous clauses completely covered the type [any()]
mod_auth_plain.erl:83: The variable O can never match since previous clauses completely covered the type [any()]
mod_cgi.erl:372: The pattern {'http_response', NewAccResponse} can never match the type 'ok'
-mod_dir.erl:101: The call lists:flatten(nonempty_improper_list(atom() | binary() | [any()] | char(),atom())) will never return since it differs in the 1st argument from the success typing arguments: ([any()])
+mod_dir.erl:101: The call lists:flatten(nonempty_improper_list(atom() | [any()] | char(),atom())) will never return since it differs in the 1st argument from the success typing arguments: ([any()])
mod_dir.erl:72: The pattern {'error', Reason} can never match the type {'ok',[[[any()] | char()],...]}
-mod_get.erl:135: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | binary() | [any()] | char()]>
-mod_head.erl:80: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | binary() | [atom() | binary() | [any()] | char()] | char()]>
+mod_get.erl:135: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | [any()] | char()]>
+mod_head.erl:80: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | [any()] | char()]>
mod_htaccess.erl:460: The pattern {'error', BadData} can never match the type {'ok',_}
-mod_include.erl:193: The pattern {_, Name, {[], []}} can never match the type {[any()],[any()],maybe_improper_list()}
-mod_include.erl:195: The pattern {_, Name, {PathInfo, []}} can never match the type {[any()],[any()],maybe_improper_list()}
-mod_include.erl:197: The pattern {_, Name, {PathInfo, QueryString}} can never match the type {[any()],[any()],maybe_improper_list()}
-mod_include.erl:201: The variable Gurka can never match since previous clauses completely covered the type {[any()],[any()],maybe_improper_list()}
-mod_include.erl:692: The pattern <{'read', Reason}, Info, Path> can never match the type <{'open',atom()},#mod{},atom() | binary() | [atom() | binary() | [atom() | binary() | [any()] | char()] | char()]>
-mod_include.erl:706: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | binary() | [atom() | binary() | [any()] | char()] | char()]>
+mod_include.erl:193: The pattern {_, Name, {[], []}} can never match the type {[any()],[any()],string()}
+mod_include.erl:195: The pattern {_, Name, {PathInfo, []}} can never match the type {[any()],[any()],string()}
+mod_include.erl:197: The pattern {_, Name, {PathInfo, QueryString}} can never match the type {[any()],[any()],string()}
+mod_include.erl:201: The variable Gurka can never match since previous clauses completely covered the type {[any()],[any()],string()}
+mod_include.erl:692: The pattern <{'read', Reason}, Info, Path> can never match the type <{'open',atom()},#mod{},atom() | binary() | [atom() | [any()] | char()]>
+mod_include.erl:706: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | [any()] | char()]>
mod_include.erl:716: Function read_error/3 will never be called
mod_include.erl:719: Function read_error/4 will never be called
mod_security_server.erl:386: The variable O can never match since previous clauses completely covered the type [any()]
diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/mnesia b/lib/dialyzer/test/r9c_SUITE_data/results/mnesia
index e199581a0e..b0f4d12ae5 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/results/mnesia
+++ b/lib/dialyzer/test/r9c_SUITE_data/results/mnesia
@@ -6,6 +6,9 @@ mnesia_bup.erl:111: The created fun has no local return
mnesia_bup.erl:574: Function fallback_receiver/2 has no local return
mnesia_bup.erl:967: Function uninstall_fallback_master/2 has no local return
mnesia_checkpoint.erl:1014: The variable Error can never match since previous clauses completely covered the type {'ok',#checkpoint_args{nodes::[any()],retainers::[any(),...]}}
+mnesia_checkpoint.erl:1209: Function system_continue/3 has no local return
+mnesia_checkpoint.erl:792: Function retainer_loop/1 has no local return
+mnesia_checkpoint.erl:894: The call sys:handle_system_msg(Msg::any(),From::any(),'no_parent','mnesia_checkpoint',[],Cp::#checkpoint_args{}) breaks the contract (Msg,From,Parent,Module,Debug,Misc) -> Void when is_subtype(Msg,term()), is_subtype(From,{pid(),Tag::_}), is_subtype(Parent,pid()), is_subtype(Module,module()), is_subtype(Debug,[dbg_opt()]), is_subtype(Misc,term()), is_subtype(Void,term())
mnesia_controller.erl:1666: The variable Tab can never match since previous clauses completely covered the type [any()]
mnesia_controller.erl:1679: The pattern {'stop', Reason, Reply, State2} can never match the type {'noreply',_} | {'reply',_,_} | {'stop','shutdown',#state{}}
mnesia_controller.erl:1685: The pattern {'noreply', State2, _Timeout} can never match the type {'reply',_,_}
@@ -15,6 +18,7 @@ mnesia_frag.erl:294: The call mnesia_frag:remote_collect(Ref::reference(),{'erro
mnesia_frag.erl:304: The call mnesia_frag:remote_collect(Ref::reference(),{'error',{'node_not_running',_}},[],OldSelectFun::fun(() -> [any()])) will never return since it differs in the 2nd argument from the success typing arguments: (reference(),'ok',[any()],fun(() -> [any()]))
mnesia_frag.erl:312: The call mnesia_frag:remote_collect(Ref::reference(),LocalRes::{'error',_},[],OldSelectFun::fun(() -> [any()])) will never return since it differs in the 2nd argument from the success typing arguments: (reference(),'ok',[any()],fun(() -> [any()]))
mnesia_index.erl:52: The call mnesia_lib:other_val(Var::{_,'commit_work' | 'index' | 'setorbag' | 'storage_type' | {'index',_}},_ReASoN_::any()) will never return since it differs in the 1st argument from the success typing arguments: ({_,'active_replicas' | 'where_to_read' | 'where_to_write'},any())
+mnesia_lib.erl:1028: The pattern {'EXIT', Reason} can never match the type [any()] | {'error',_}
mnesia_lib.erl:957: The pattern {'ok', {0, _}} can never match the type 'eof' | {'error',atom()} | {'ok',binary() | string()}
mnesia_lib.erl:959: The pattern {'ok', {_, Bin}} can never match the type 'eof' | {'error',atom()} | {'ok',binary() | string()}
mnesia_loader.erl:36: The call mnesia_lib:other_val(Var::{_,'access_mode' | 'cstruct' | 'db_nodes' | 'setorbag' | 'snmp' | 'storage_type'},Reason::any()) will never return since it differs in the 1st argument from the success typing arguments: ({_,'active_replicas' | 'where_to_read' | 'where_to_write'},any())
@@ -30,5 +34,6 @@ mnesia_schema.erl:1258: Guard test FromS::'disc_copies' | 'disc_only_copies' | '
mnesia_schema.erl:1639: The pattern {'false', 'mandatory'} can never match the type {'false','optional'}
mnesia_schema.erl:2434: The variable Reason can never match since previous clauses completely covered the type {'error',_} | {'ok',_}
mnesia_schema.erl:451: Guard test UseDirAnyway::'false' == 'true' can never succeed
+mnesia_text.erl:180: The variable T can never match since previous clauses completely covered the type {'error',{integer(),atom() | tuple(),_}} | {'ok',_}
mnesia_tm.erl:1522: Function commit_participant/5 has no local return
mnesia_tm.erl:2169: Function system_terminate/4 has no local return
diff --git a/lib/dialyzer/test/race_SUITE_data/results/extract_translations b/lib/dialyzer/test/race_SUITE_data/results/extract_translations
index f7d5abc6f5..62aa1aa511 100644
--- a/lib/dialyzer/test/race_SUITE_data/results/extract_translations
+++ b/lib/dialyzer/test/race_SUITE_data/results/extract_translations
@@ -1,5 +1,5 @@
-extract_translations.erl:140: The call ets:insert('files',{atom() | binary() | [atom() | binary() | [atom() | binary() | [any()] | char()] | char()]}) might have an unintended effect due to a possible race condition caused by its combination with the ets:lookup('files',File::atom() | binary() | [atom() | binary() | [atom() | binary() | [any()] | char()] | char()]) call in extract_translations.erl on line 135
+extract_translations.erl:140: The call ets:insert('files',{atom() | binary() | [atom() | [any()] | char()]}) might have an unintended effect due to a possible race condition caused by its combination with the ets:lookup('files',File::atom() | binary() | [atom() | [any()] | char()]) call in extract_translations.erl on line 135
extract_translations.erl:146: The call ets:insert('translations',{_,[]}) might have an unintended effect due to a possible race condition caused by its combination with the ets:lookup('translations',Str::any()) call in extract_translations.erl on line 126
-extract_translations.erl:152: The call ets:insert('files',{atom() | binary() | [atom() | binary() | [atom() | binary() | [any()] | char()] | char()]}) might have an unintended effect due to a possible race condition caused by its combination with the ets:lookup('files',File::atom() | binary() | [atom() | binary() | [atom() | binary() | [any()] | char()] | char()]) call in extract_translations.erl on line 148
+extract_translations.erl:152: The call ets:insert('files',{atom() | binary() | [atom() | [any()] | char()]}) might have an unintended effect due to a possible race condition caused by its combination with the ets:lookup('files',File::atom() | binary() | [atom() | [any()] | char()]) call in extract_translations.erl on line 148
extract_translations.erl:154: The call ets:insert('translations',{_,[]}) might have an unintended effect due to a possible race condition caused by its combination with the ets:lookup('translations',Str::any()) call in extract_translations.erl on line 126
diff --git a/lib/dialyzer/test/small_SUITE_data/results/flatten b/lib/dialyzer/test/small_SUITE_data/results/flatten
index 4571214e49..8aa44dd002 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/flatten
+++ b/lib/dialyzer/test/small_SUITE_data/results/flatten
@@ -1,2 +1,2 @@
-flatten.erl:17: The call lists:flatten(nonempty_improper_list(atom() | binary() | [any()] | char(),atom())) will never return since it differs in the 1st argument from the success typing arguments: ([any()])
+flatten.erl:17: The call lists:flatten(nonempty_improper_list(atom() | [any()] | char(),atom())) will never return since it differs in the 1st argument from the success typing arguments: ([any()])
diff --git a/lib/dialyzer/test/small_SUITE_data/src/binary_lc_bug.erl b/lib/dialyzer/test/small_SUITE_data/src/binary_lc_bug.erl
new file mode 100644
index 0000000000..c1e82bfa59
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/binary_lc_bug.erl
@@ -0,0 +1,8 @@
+-module(test).
+
+-export([bin_compr/0]).
+
+bin_compr() ->
+% [ 0 || {N, V} <- [{a, b}] ]. % Works ok
+ << <<>> || {A, B} <- [{a, b}] >>. % Complains
+% << <<>> || X <- [{a, b}] >>. % Works ok
diff --git a/lib/dialyzer/test/small_SUITE_data/src/codec_can.erl b/lib/dialyzer/test/small_SUITE_data/src/codec_can.erl
new file mode 100644
index 0000000000..8abf872b37
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/codec_can.erl
@@ -0,0 +1,35 @@
+%%---------------------------------------------------------------------
+%% From: Peer Stritzinger
+%% Date: 1 May 2011
+%% Subject: Dialyzer v2.2.0 crash
+%%
+%% Binaries of the form <<_:N,_:_*M>> in specs resulted in a crash:
+%% dialyzer: Analysis failed with error: {{case_clause,8},
+%% [{erl_types,t_form_to_string,1},
+%% {erl_types,t_form_to_string,1},
+%% {dialyzer_contracts,contract_to_string_1,1},
+%% {dialyzer_contracts,extra_contract_warning,6},
+%% {dialyzer_contracts,picky_contract_check,7},
+%% because function erl_types:t_form_to_string/1 was not the inverse
+%% of erl_types:t_to_string/2.
+%%
+%% Fixed on the same date and send to OTP for inclusion.
+%%---------------------------------------------------------------------
+-module(codec_can).
+
+-export([recv/3, decode/1]).
+
+-record(can_pkt, {id, data :: binary(), timestamp}).
+
+-type can_pkt() :: #can_pkt{}.
+-type channel() :: atom() | pid() | {atom(),_}.
+
+-spec recv(<<_:64,_:_*8>>, fun((can_pkt()) -> R), channel()) -> R.
+recv(Packet, Fun, Chan) ->
+ #can_pkt{id = Can_id, data = Can_data} = P = decode(Packet),
+ Fun(P).
+
+-spec decode(<<_:64,_:_*8>>) -> #can_pkt{id::<<_:11>>,timestamp::char()}.
+decode(<<_:12, Len:4, Timestamp:16, 0:3, Id:11/bitstring, 0:18,
+ Data:Len/binary, _/binary>>) ->
+ #can_pkt{id = Id, data = Data, timestamp = Timestamp}.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/file_open_encoding.erl b/lib/dialyzer/test/small_SUITE_data/src/file_open_encoding.erl
index 4f1268eba8..086df3464b 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/file_open_encoding.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/file_open_encoding.erl
@@ -6,9 +6,7 @@
-export([parse/1]).
--type proplist() :: [{atom(), any()}].
-
--spec parse(string()) -> proplist().
+-spec parse(string()) -> proplists:proplist().
parse(FileName) ->
{ok, IoDevice} = file:open(FileName, [read, binary, {encoding, utf8}]),
do_parse(IoDevice, []).
diff --git a/lib/dialyzer/test/small_SUITE_data/src/list_to_bitstring.erl b/lib/dialyzer/test/small_SUITE_data/src/list_to_bitstring.erl
new file mode 100644
index 0000000000..2da708cb15
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/list_to_bitstring.erl
@@ -0,0 +1,21 @@
+%%=====================================================================
+%% From: Ken Robinson
+%% Date: 28/04/2011, 17:26
+%%
+%% Program that produced borus "Function has no local return" warnings
+%% due to erlang:list_to_bitstring/1 having erroneous hard coded type
+%% information, namely accepting iolist() instead of bitstrlist().
+%% Fixed 29/04/2011.
+%%=====================================================================
+
+-module(list_to_bitstring).
+
+-export([l2bs/0, l2bs_ok/0]).
+
+%% This function was producing a warning
+l2bs() ->
+ erlang:list_to_bitstring([<<42>>, <<42:13>>]).
+
+%% while this one was ok.
+l2bs_ok() ->
+ erlang:list_to_bitstring([<<42>>, <<42,42>>]).
diff --git a/lib/dialyzer/test/small_SUITE_data/src/no_return_bug.erl b/lib/dialyzer/test/small_SUITE_data/src/no_return_bug.erl
new file mode 100644
index 0000000000..5c24902590
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/no_return_bug.erl
@@ -0,0 +1,42 @@
+%% Dialyzer couldn't infer that monitor_diskspace would go in an infinite loop
+%% instead of crashing due to the existence of list comprehensions that have a
+%% normal success typing. These were added to the monitor_diskspace's SCC and
+%% dialyzer_typesig didn't try to assign unit() to monitor_diskspace, as it
+%% required all the members of the SCC to return none().
+%%
+%% Testcase was submitted in erlang-questions mailing list by Prashanth Mundkur
+%% (http://erlang.org/pipermail/erlang-questions/2011-May/058063.html)
+
+-module(no_return_bug).
+-export([diskspace/1, monitor_diskspace/2, refresh_tags/1, monitor_launch/0]).
+
+-type diskinfo() :: {non_neg_integer(), non_neg_integer()}.
+
+-spec diskspace(nonempty_string()) -> {'ok', diskinfo()} | {'error', term()}.
+diskspace(Path) ->
+ case Path of
+ "a" -> {ok, {0,0}};
+ _ -> {error, error}
+ end.
+
+-spec monitor_diskspace(nonempty_string(),
+ [{diskinfo(), nonempty_string()}]) ->
+ no_return().
+monitor_diskspace(Root, Vols) ->
+ Df = fun(VolName) ->
+ diskspace(filename:join([Root, VolName]))
+ end,
+ NewVols = [{Space, VolName}
+ || {VolName, {ok, Space}}
+ <- [{VolName, Df(VolName)}
+ || {_OldSpace, VolName} <- Vols]],
+ monitor_diskspace(Root, NewVols).
+
+-spec refresh_tags(nonempty_string()) -> no_return().
+refresh_tags(Root) ->
+ {ok, _} = diskspace(Root),
+ refresh_tags(Root).
+
+monitor_launch() ->
+ spawn_link(fun() -> refresh_tags("abc") end),
+ spawn_link(fun() -> monitor_diskspace("root", [{{0,0}, "a"}]) end).
diff --git a/lib/dialyzer/test/small_SUITE_data/src/nowarnunused.erl b/lib/dialyzer/test/small_SUITE_data/src/nowarnunused.erl
new file mode 100644
index 0000000000..63daeee9e3
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/nowarnunused.erl
@@ -0,0 +1,7 @@
+-module(nowarnunused).
+
+-compile({nowarn_unused_function, return_error/2}).
+
+-spec return_error(integer(), any()) -> no_return().
+return_error(Line, Message) ->
+ throw({error, {Line, ?MODULE, Message}}).
diff --git a/lib/diameter/doc/src/diameter_dict.xml b/lib/diameter/doc/src/diameter_dict.xml
index a87f59bad5..e7c530f1b8 100644
--- a/lib/diameter/doc/src/diameter_dict.xml
+++ b/lib/diameter/doc/src/diameter_dict.xml
@@ -105,7 +105,7 @@ quantity is insignificant.</p>
<p>
The tags, their arguments and the contents of each corresponding
section are as follows.
-Each section can occur only once unless otherwise specified.
+Each section can occur at most once unless otherwise specified.
The order in which sections are specified is unimportant.</p>
<taglist>
@@ -115,6 +115,7 @@ The order in which sections are specified is unimportant.</p>
<p>
Defines the integer Number as the Diameter Application Id of the
application in question.
+Required if the dictionary defines <c>@messages</c>.
The section has empty content.</p>
<p>
@@ -370,7 +371,11 @@ Integer values can be prefixed with 0x to be interpreted as
hexidecimal.</p>
<p>
-Can occur 0 or more times (with different values of Name).</p>
+Can occur 0 or more times (with different values of Name).
+The AVP in question can be defined in an inherited dictionary in order
+to introduce additional values.
+An AVP so extended must be referenced by in a <c>@messages</c> or
+<c>@grouped</c> section.</p>
<p>
Example:</p>
diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl
index 213ba0d22c..30caebc544 100644
--- a/lib/diameter/src/compiler/diameter_codegen.erl
+++ b/lib/diameter/src/compiler/diameter_codegen.erl
@@ -250,9 +250,14 @@ f_name(Name) ->
%%% ------------------------------------------------------------------------
f_id(Spec) ->
- Id = orddict:fetch(id, Spec),
{?function, id, 0,
- [{?clause, [], [], [?INTEGER(Id)]}]}.
+ [c_id(orddict:find(id, Spec))]}.
+
+c_id({ok, Id}) ->
+ {?clause, [], [], [?INTEGER(Id)]};
+
+c_id(error) ->
+ ?UNEXPECTED(0).
%%% ------------------------------------------------------------------------
%%% # vendor_id/0
@@ -454,9 +459,10 @@ avp(Spec) ->
Native = get_value(avp_types, Spec),
Custom = get_value(custom_types, Spec),
Imported = get_value(import_avps, Spec),
- avp([{N,T} || {N,_,T,_,_} <- Native], Imported, Custom).
+ Enums = get_value(enums, Spec),
+ avp([{N,T} || {N,_,T,_,_} <- Native], Imported, Custom, Enums).
-avp(Native, Imported, Custom) ->
+avp(Native, Imported, Custom, Enums) ->
Dict = orddict:from_list(Native),
report(native, Dict),
@@ -470,8 +476,8 @@ avp(Native, Imported, Custom) ->
false == lists:member(N, CustomNames)
end,
Native))
- ++ lists:flatmap(fun c_imported_avp/1, Imported)
- ++ lists:flatmap(fun(C) -> c_custom_avp(C, Dict) end, Custom).
+ ++ lists:flatmap(fun(I) -> cs_imported_avp(I, Enums) end, Imported)
+ ++ lists:flatmap(fun(C) -> cs_custom_avp(C, Dict) end, Custom).
c_base_avp({AvpName, T}) ->
{?clause, [?VAR('T'), ?VAR('Data'), ?ATOM(AvpName)],
@@ -487,23 +493,35 @@ base_avp(AvpName, 'Grouped') ->
base_avp(_, Type) ->
?APPLY(diameter_types, Type, [?VAR('T'), ?VAR('Data')]).
-c_imported_avp({Mod, Avps}) ->
- lists:map(fun(A) -> imported_avp(Mod, A) end, Avps).
+cs_imported_avp({Mod, Avps}, Enums) ->
+ lists:map(fun(A) -> imported_avp(Mod, A, Enums) end, Avps).
-imported_avp(_Mod, {AvpName, _, 'Grouped' = T, _, _}) ->
+imported_avp(_Mod, {AvpName, _, 'Grouped' = T, _, _}, _) ->
c_base_avp({AvpName, T});
-imported_avp(Mod, {AvpName, _, _, _, _}) ->
+imported_avp(Mod, {AvpName, _, 'Enumerated' = T, _, _}, Enums) ->
+ case lists:keymember(AvpName, 1, Enums) of
+ true ->
+ c_base_avp({AvpName, T});
+ false ->
+ c_imported_avp(Mod, AvpName)
+ end;
+
+imported_avp(Mod, {AvpName, _, _, _, _}, _) ->
+ c_imported_avp(Mod, AvpName).
+
+c_imported_avp(Mod, AvpName) ->
{?clause, [?VAR('T'), ?VAR('Data'), ?ATOM(AvpName)],
[],
[?APPLY(Mod, avp, [?VAR('T'),
?VAR('Data'),
?ATOM(AvpName)])]}.
-c_custom_avp({Mod, Avps}, Dict) ->
- lists:map(fun(N) -> custom_avp(Mod, N, orddict:fetch(N, Dict)) end, Avps).
+cs_custom_avp({Mod, Avps}, Dict) ->
+ lists:map(fun(N) -> c_custom_avp(Mod, N, orddict:fetch(N, Dict)) end,
+ Avps).
-custom_avp(Mod, AvpName, Type) ->
+c_custom_avp(Mod, AvpName, Type) ->
{?clause, [?VAR('T'), ?VAR('Data'), ?ATOM(AvpName)],
[],
[?APPLY(Mod, AvpName, [?VAR('T'), ?ATOM(Type), ?VAR('Data')])]}.
@@ -516,9 +534,25 @@ f_enumerated_avp(Spec) ->
{?function, enumerated_avp, 3, enumerated_avp(Spec) ++ [?UNEXPECTED(3)]}.
enumerated_avp(Spec) ->
- lists:flatmap(fun c_enumerated_avp/1, get_value(enums, Spec)).
+ Enums = get_value(enums, Spec),
+ lists:flatmap(fun cs_enumerated_avp/1, Enums)
+ ++ lists:flatmap(fun({M,Es}) -> enumerated_avp(M, Es, Enums) end,
+ get_value(import_enums, Spec)).
+
+enumerated_avp(Mod, Es, Enums) ->
+ lists:flatmap(fun({N,_}) ->
+ cs_enumerated_avp(lists:keymember(N, 1, Enums),
+ Mod,
+ N)
+ end,
+ Es).
-c_enumerated_avp({AvpName, Values}) ->
+cs_enumerated_avp(true, Mod, Name) ->
+ [c_imported_avp(Mod, Name)];
+cs_enumerated_avp(false, _, _) ->
+ [].
+
+cs_enumerated_avp({AvpName, Values}) ->
lists:flatmap(fun(V) -> c_enumerated_avp(AvpName, V) end, Values).
c_enumerated_avp(AvpName, {I,_}) ->
@@ -537,10 +571,14 @@ f_msg_header(Spec) ->
{?function, msg_header, 1, msg_header(Spec) ++ [?UNEXPECTED(1)]}.
msg_header(Spec) ->
+ msg_header(get_value(messages, Spec), Spec).
+
+msg_header([], _) ->
+ [];
+msg_header(Msgs, Spec) ->
ApplId = orddict:fetch(id, Spec),
- lists:map(fun({M,C,F,_,_}) -> c_msg_header(M, C, F, ApplId) end,
- get_value(messages, Spec)).
+ lists:map(fun({M,C,F,_,_}) -> c_msg_header(M, C, F, ApplId) end, Msgs).
%% Note that any application id in the message header spec is ignored.
@@ -616,10 +654,12 @@ f_empty_value(Spec) ->
{?function, empty_value, 1, empty_value(Spec)}.
empty_value(Spec) ->
+ Imported = lists:flatmap(fun avps/1, get_value(import_enums, Spec)),
Groups = get_value(grouped, Spec)
++ lists:flatmap(fun avps/1, get_value(import_groups, Spec)),
- Enums = get_value(enums, Spec)
- ++ lists:flatmap(fun avps/1, get_value(import_enums, Spec)),
+ Enums = [T || {N,_} = T <- get_value(enums, Spec),
+ not lists:keymember(N, 1, Imported)]
+ ++ Imported,
lists:map(fun c_empty_value/1, Groups ++ Enums)
++ [{?clause, [?VAR('Name')], [], [?CALL(empty, [?VAR('Name')])]}].
diff --git a/lib/diameter/src/compiler/diameter_spec_util.erl b/lib/diameter/src/compiler/diameter_spec_util.erl
index 322d53a199..b60886b678 100644
--- a/lib/diameter/src/compiler/diameter_spec_util.erl
+++ b/lib/diameter/src/compiler/diameter_spec_util.erl
@@ -39,11 +39,11 @@ parse(Path, Options) ->
{ok, B} = file:read_file(Path),
Chunks = chunk(B),
Spec = make_spec(Chunks),
- true = enums_defined(Spec), %% sanity checks
- true = groups_defined(Spec), %%
+ true = groups_defined(Spec), %% sanity checks
true = customs_defined(Spec), %%
Full = import_enums(import_groups(import_avps(insert_codes(Spec),
Options))),
+ true = enums_defined(Full), %% sanity checks
true = v_flags_set(Spec),
Full.
@@ -243,35 +243,48 @@ get_value(Key, Spec) ->
%% with an appropriate type.
enums_defined(Spec) ->
- is_defined(Spec, 'Enumerated', enums).
+ Avps = get_value(avp_types, Spec),
+ Import = get_value(import_enums, Spec),
+ lists:all(fun({N,_}) ->
+ true = enum_defined(N, Avps, Import)
+ end,
+ get_value(enums, Spec)).
-groups_defined(Spec) ->
- is_defined(Spec, 'Grouped', grouped).
+enum_defined(Name, Avps, Import) ->
+ case lists:keyfind(Name, 1, Avps) of
+ {Name, _, 'Enumerated', _, _} ->
+ true;
+ {Name, _, T, _, _} ->
+ ?ERROR({avp_has_wrong_type, Name, 'Enumerated', T});
+ false ->
+ lists:any(fun({_,Is}) -> lists:keymember(Name, 1, Is) end, Import)
+ orelse ?ERROR({avp_not_defined, Name, 'Enumerated'})
+ end.
+%% Note that an AVP is imported only if referenced by a message or
+%% grouped AVP, so the final branch will fail if an enum definition is
+%% extended without this being the case.
-is_defined(Spec, Type, Key) ->
+groups_defined(Spec) ->
Avps = get_value(avp_types, Spec),
- lists:all(fun(T) -> true = is_local(name(Key, T), Type, Avps) end,
- get_value(Key, Spec)).
+ lists:all(fun({N,_,_,_}) -> true = group_defined(N, Avps) end,
+ get_value(grouped, Spec)).
-name(enums, {N,_}) -> N;
-name(grouped, {N,_,_,_}) -> N.
-
-is_local(Name, Type, Avps) ->
+group_defined(Name, Avps) ->
case lists:keyfind(Name, 1, Avps) of
- {Name, _, Type, _, _} ->
+ {Name, _, 'Grouped', _, _} ->
true;
{Name, _, T, _, _} ->
- ?ERROR({avp_has_wrong_type, Name, Type, T});
+ ?ERROR({avp_has_wrong_type, Name, 'Grouped', T});
false ->
- ?ERROR({avp_not_defined, Name, Type})
+ ?ERROR({avp_not_defined, Name, 'Grouped'})
end.
customs_defined(Spec) ->
Avps = get_value(avp_types, Spec),
- lists:all(fun(A) -> true = is_local(A, Avps) end,
+ lists:all(fun(A) -> true = custom_defined(A, Avps) end,
lists:flatmap(fun last/1, get_value(custom_types, Spec))).
-is_local(Name, Avps) ->
+custom_defined(Name, Avps) ->
case lists:keyfind(Name, 1, Avps) of
{Name, _, T, _, _} when T == 'Grouped';
T == 'Enumerated' ->
@@ -510,6 +523,9 @@ choose(false, _, X) -> X.
%% ------------------------------------------------------------------------
%% import_groups/1
%% import_enums/1
+%%
+%% For each inherited module, store the content of imported AVP's of
+%% type grouped/enumerated in a new key.
import_groups(Spec) ->
orddict:store(import_groups, import(grouped, Spec), Spec).
diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile
index 823e2f0311..b3648c7bb1 100644
--- a/lib/diameter/test/Makefile
+++ b/lib/diameter/test/Makefile
@@ -404,5 +404,5 @@ release_tests_spec: tests
# $(HRL_FILES) $(ERL_FILES) \
# $(RELSYSDIR)
#
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
diff --git a/lib/docbuilder/src/docb_gen.erl b/lib/docbuilder/src/docb_gen.erl
index 0d8d640324..75494314f1 100644
--- a/lib/docbuilder/src/docb_gen.erl
+++ b/lib/docbuilder/src/docb_gen.erl
@@ -18,6 +18,10 @@
-module(docb_gen).
-export([module/1, module/2, users_guide/1, users_guide/2]).
+-deprecated([{module,1,next_major_release},
+ {module,2,next_major_release},
+ {users_guide,1,next_major_release},
+ {users_guide,2,next_major_release}]).
-record(args, {suffix=".xml",
layout=docb_edoc_xml_cb,
diff --git a/lib/docbuilder/src/docb_transform.erl b/lib/docbuilder/src/docb_transform.erl
index 9c7561b07b..736ac92274 100644
--- a/lib/docbuilder/src/docb_transform.erl
+++ b/lib/docbuilder/src/docb_transform.erl
@@ -18,6 +18,8 @@
-module(docb_transform).
-export([file/1, file/2]).
+-deprecated([{file,1,next_major_release},
+ {file,2,next_major_release}]).
%% file(File) -> ok | {error, Reason}
%% file(File, Opts) -> ok | {error, Reason}
diff --git a/lib/docbuilder/src/docb_xml_check.erl b/lib/docbuilder/src/docb_xml_check.erl
index 8ae5cd2eac..5912e22e7b 100644
--- a/lib/docbuilder/src/docb_xml_check.erl
+++ b/lib/docbuilder/src/docb_xml_check.erl
@@ -18,6 +18,7 @@
-module(docb_xml_check).
-export([validate/1]).
+-deprecated([{validate,1,next_major_release}]).
%% validate(File) -> ok | error | {error, badfile}
%% File = string(), file name with or without ".xml" extension
diff --git a/lib/docbuilder/vsn.mk b/lib/docbuilder/vsn.mk
index 2475966ec2..6df438a537 100644
--- a/lib/docbuilder/vsn.mk
+++ b/lib/docbuilder/vsn.mk
@@ -1 +1 @@
-DOCB_VSN = 0.9.8.10
+DOCB_VSN = 0.9.8.11
diff --git a/lib/edoc/src/edoc_specs.erl b/lib/edoc/src/edoc_specs.erl
index bfb17515be..5acf8ac0d5 100644
--- a/lib/edoc/src/edoc_specs.erl
+++ b/lib/edoc/src/edoc_specs.erl
@@ -27,7 +27,6 @@
-include("edoc.hrl").
-include("edoc_types.hrl").
--type proplist() :: [proplists:property()].
-type syntaxTree() :: erl_syntax:syntaxTree().
-define(TOP_TYPE, term).
@@ -99,7 +98,7 @@ docs(Forms, CommentFun) ->
-type entry() :: #entry{}.
-type module_info() :: #module{}.
-type entries() :: [entry()].
--spec add_data(Entries::entries(), Options::proplist(),
+-spec add_data(Entries::entries(), Options::proplists:proplist(),
File::file:filename(), Module::module_info()) -> entries().
%% @doc Create tags a la EDoc for Erlang specifications and types.
diff --git a/lib/eunit/doc/overview.edoc b/lib/eunit/doc/overview.edoc
index be05a13fba..2583f0be25 100644
--- a/lib/eunit/doc/overview.edoc
+++ b/lib/eunit/doc/overview.edoc
@@ -913,7 +913,7 @@ To make the descriptions simpler, we first list some definitions:
<td>`CleanupX'</td><td>`(X::any(), R::any()) -> any()'</td>
</tr>
<tr>
-<td>`Instantiator'</td><td>`((R::any()) -> Tests | {with, [AbstractTestFun::((any()) -> any())]}'</td>
+<td>`Instantiator'</td><td>`((R::any()) -> Tests) | {with, [AbstractTestFun::((any()) -> any())]}'</td>
</tr>
<tr>
<td>`Where'</td><td>`local | spawn | {spawn, Node::atom()}'</td>
diff --git a/lib/eunit/include/eunit.hrl b/lib/eunit/include/eunit.hrl
index 82ba982f03..493ba60a2d 100644
--- a/lib/eunit/include/eunit.hrl
+++ b/lib/eunit/include/eunit.hrl
@@ -39,6 +39,7 @@
-ifndef(EUNIT_HRL).
-define(EUNIT_HRL, true).
+
%% allow defining TEST to override NOTEST
-ifdef(TEST).
-undef(NOTEST).
@@ -164,7 +165,7 @@
%% This is mostly a convenience which gives more detailed reports.
%% Note: Guard is a guarded pattern, and can not be used for value.
-ifdef(NOASSERT).
--define(assertMatch(Guard,Expr),ok).
+-define(assertMatch(Guard, Expr), ok).
-else.
-define(assertMatch(Guard, Expr),
((fun () ->
@@ -174,17 +175,37 @@
[{module, ?MODULE},
{line, ?LINE},
{expression, (??Expr)},
- {expected, (??Guard)},
+ {pattern, (??Guard)},
{value, __V}]})
end
end)())).
-endif.
-define(_assertMatch(Guard, Expr), ?_test(?assertMatch(Guard, Expr))).
+%% This is the inverse case of assertMatch, for convenience.
+-ifdef(NOASSERT).
+-define(assertNotMatch(Guard, Expr), ok).
+-else.
+-define(assertNotMatch(Guard, Expr),
+ ((fun () ->
+ __V = (Expr),
+ case __V of
+ Guard -> .erlang:error({assertNotMatch_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??Expr)},
+ {pattern, (??Guard)},
+ {value, __V}]});
+ _ -> ok
+ end
+ end)())).
+-endif.
+-define(_assertNotMatch(Guard, Expr), ?_test(?assertNotMatch(Guard, Expr))).
+
%% This is a convenience macro which gives more detailed reports when
%% the expected LHS value is not a pattern, but a computed value
-ifdef(NOASSERT).
--define(assertEqual(Expect,Expr),ok).
+-define(assertEqual(Expect, Expr), ok).
-else.
-define(assertEqual(Expect, Expr),
((fun (__X) ->
@@ -201,9 +222,29 @@
-endif.
-define(_assertEqual(Expect, Expr), ?_test(?assertEqual(Expect, Expr))).
+%% This is the inverse case of assertEqual, for convenience.
+-ifdef(NOASSERT).
+-define(assertNotEqual(Unexpected, Expr), ok).
+-else.
+-define(assertNotEqual(Unexpected, Expr),
+ ((fun (__X) ->
+ case (Expr) of
+ __X -> .erlang:error({assertNotEqual_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??Expr)},
+ {value, __X}]});
+ _ -> ok
+ end
+ end)(Unexpected))).
+-endif.
+-define(_assertNotEqual(Unexpected, Expr),
+ ?_test(?assertNotEqual(Unexpected, Expr))).
+
%% Note: Class and Term are patterns, and can not be used for value.
+%% Term can be a guarded pattern, but Class cannot.
-ifdef(NOASSERT).
--define(assertException(Class, Term, Expr),ok).
+-define(assertException(Class, Term, Expr), ok).
-else.
-define(assertException(Class, Term, Expr),
((fun () ->
@@ -212,7 +253,7 @@
[{module, ?MODULE},
{line, ?LINE},
{expression, (??Expr)},
- {expected,
+ {pattern,
"{ "++(??Class)++" , "++(??Term)
++" , [...] }"},
{unexpected_success, __V}]})
@@ -223,7 +264,7 @@
[{module, ?MODULE},
{line, ?LINE},
{expression, (??Expr)},
- {expected,
+ {pattern,
"{ "++(??Class)++" , "++(??Term)
++" , [...] }"},
{unexpected_exception,
@@ -243,6 +284,43 @@
-define(_assertExit(Term, Expr), ?_assertException(exit, Term, Expr)).
-define(_assertThrow(Term, Expr), ?_assertException(throw, Term, Expr)).
+%% This is the inverse case of assertException, for convenience.
+%% Note: Class and Term are patterns, and can not be used for value.
+%% Both Class and Term can be guarded patterns.
+-ifdef(NOASSERT).
+-define(assertNotException(Class, Term, Expr), ok).
+-else.
+-define(assertNotException(Class, Term, Expr),
+ ((fun () ->
+ try (Expr) of
+ _ -> ok
+ catch
+ __C:__T ->
+ case __C of
+ Class ->
+ case __T of
+ Term ->
+ .erlang:error({assertNotException_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??Expr)},
+ {pattern,
+ "{ "++(??Class)++" , "
+ ++(??Term)++" , [...] }"},
+ {unexpected_exception,
+ {__C, __T,
+ .erlang:get_stacktrace()
+ }}]});
+ _ -> ok
+ end;
+ _ -> ok
+ end
+ end
+ end)())).
+-endif.
+-define(_assertNotException(Class, Term, Expr),
+ ?_test(?assertNotException(Class, Term, Expr))).
+
%% Macros for running operating system commands. (Note that these
%% require EUnit to be present at runtime, or at least eunit_lib.)
@@ -267,7 +345,7 @@
%% these are only used for testing; they always return 'ok' on success,
%% and have no effect if debugging/testing is turned off
-ifdef(NOASSERT).
--define(assertCmdStatus(N, Cmd),ok).
+-define(assertCmdStatus(N, Cmd), ok).
-else.
-define(assertCmdStatus(N, Cmd),
((fun () ->
@@ -285,7 +363,7 @@
-define(assertCmd(Cmd), ?assertCmdStatus(0, Cmd)).
-ifdef(NOASSERT).
--define(assertCmdOutput(T, Cmd),ok).
+-define(assertCmdOutput(T, Cmd), ok).
-else.
-define(assertCmdOutput(T, Cmd),
((fun () ->
@@ -313,11 +391,12 @@
-define(debugHere, ok).
-define(debugFmt(S, As), ok).
-define(debugVal(E), (E)).
--define(debugTime(S,E), (E)).
+-define(debugTime(S, E), (E)).
-else.
-define(debugMsg(S),
(begin
- .io:fwrite(user, <<"~s:~w: ~s\n">>, [?FILE, ?LINE, S]),
+ .io:fwrite(user, <<"~s:~w:~w: ~s\n">>,
+ [?FILE, ?LINE, self(), S]),
ok
end)).
-define(debugHere, (?debugMsg("<-"))).
@@ -327,7 +406,7 @@
?debugFmt(<<"~s = ~P">>, [(??E), __V, 15]),
__V
end)(E))).
--define(debugTime(S,E),
+-define(debugTime(S, E),
((fun () ->
{__T0, _} = statistics(wall_clock),
__V = (E),
@@ -337,4 +416,5 @@
end)())).
-endif.
+
-endif. % EUNIT_HRL
diff --git a/lib/eunit/src/eunit.app.src b/lib/eunit/src/eunit.app.src
index 4fd76588c3..5e16dfa2ce 100644
--- a/lib/eunit/src/eunit.app.src
+++ b/lib/eunit/src/eunit.app.src
@@ -5,17 +5,17 @@
{vsn, "%VSN%"},
{modules, [eunit,
eunit_autoexport,
- eunit_striptests,
- eunit_server,
+ eunit_data,
+ eunit_lib,
+ eunit_listener,
eunit_proc,
eunit_serial,
+ eunit_server,
+ eunit_striptests,
+ eunit_surefire,
eunit_test,
eunit_tests,
- eunit_lib,
- eunit_listener,
- eunit_data,
- eunit_tty,
- eunit_surefire]},
+ eunit_tty]},
{registered,[]},
- {applications, [stdlib]},
+ {applications, [kernel,stdlib]},
{env, []}]}.
diff --git a/lib/eunit/src/eunit.erl b/lib/eunit/src/eunit.erl
index da35c5c2ec..15fc3bdf32 100644
--- a/lib/eunit/src/eunit.erl
+++ b/lib/eunit/src/eunit.erl
@@ -16,7 +16,7 @@
%% $Id: eunit.erl 339 2009-04-05 14:10:47Z rcarlsson $
%%
%% @copyright 2004-2009 Micka�l R�mond, Richard Carlsson
-%% @author Micka&euml;l R&eacute;mond <[email protected]>
+%% @author Micka�l R�mond <[email protected]>
%% [http://www.process-one.net/]
%% @author Richard Carlsson <[email protected]>
%% [http://user.it.uu.se/~richardc/]
diff --git a/lib/eunit/src/eunit_data.erl b/lib/eunit/src/eunit_data.erl
index 0543b6c543..288dd74ddf 100644
--- a/lib/eunit/src/eunit_data.erl
+++ b/lib/eunit/src/eunit_data.erl
@@ -146,8 +146,10 @@ iter_next(I = #iter{next = [T | Ts]}) ->
iter_prev(#iter{prev = []}) ->
none;
-iter_prev(#iter{prev = [T | Ts], next = Next, pos = Pos} = I) ->
- {T, I#iter{prev = Ts, next = [T | Next], pos = Pos - 1}}.
+iter_prev(#iter{prev = [T | Ts]} = I) ->
+ {T, I#iter{prev = Ts,
+ next = [T | I#iter.next],
+ pos = I#iter.pos - 1}}.
%% ---------------------------------------------------------------------
@@ -363,7 +365,8 @@ parse({file, F} = T) when is_list(F) ->
parse({dir, D}=T) when is_list(D) ->
case eunit_lib:is_string(D) of
true ->
- {data, {"directory \"" ++ D ++ "\"", get_directory_modules(D)}};
+ {data, {"directory \"" ++ D ++ "\"",
+ get_directory_module_tests(D)}};
false ->
bad_test(T)
end;
@@ -385,10 +388,10 @@ parse({S, T1} = T) when is_list(S) ->
end;
parse({S, T1}) when is_binary(S) ->
group(#group{tests = T1, desc = S});
-parse(T) when tuple_size(T) > 2, is_list(element(1, T)) ->
+parse(T) when is_tuple(T), size(T) > 2, is_list(element(1, T)) ->
[S | Es] = tuple_to_list(T),
parse({S, list_to_tuple(Es)});
-parse(T) when tuple_size(T) > 2, is_binary(element(1, T)) ->
+parse(T) when is_tuple(T), size(T) > 2, is_binary(element(1, T)) ->
[S | Es] = tuple_to_list(T),
parse({S, list_to_tuple(Es)});
parse(M) when is_atom(M) ->
@@ -596,7 +599,7 @@ testfuns(Es, M, TestSuffix, GeneratorSuffix) ->
%% ---------------------------------------------------------------------
-%% Getting a test set from a file
+%% Getting a test set from a file (text file or object file)
%% @throws {file_read_error, {Reason::atom(), Message::string(),
%% fileName()}}
@@ -625,17 +628,23 @@ get_file_tests(F) ->
is_module_filename(F) ->
filename:extension(F) =:= code:objfile_extension().
+objfile_test({M, File}) ->
+ {setup,
+ fun () ->
+ %% TODO: better error/stacktrace for this internal fun
+ code:purge(M),
+ {module,M} = code:load_abs(filename:rootname(File)),
+ ok
+ end,
+ {module, M}};
objfile_test(File) ->
+ objfile_test({objfile_module(File), File}).
+
+objfile_module(File) ->
try
- {module, M} = lists:keyfind(module, 1, beam_lib:info(File)),
- {setup,
- fun () ->
- %% TODO: better error/stacktrace for this internal fun
- code:purge(M),
- {module,M} = code:load_abs(filename:rootname(File)),
- ok
- end,
- {module, M}}
+ {value, {module, M}} = lists:keysearch(module, 1,
+ beam_lib:info(File)),
+ M
catch
_:_ ->
throw({file_read_error,
@@ -644,15 +653,34 @@ objfile_test(File) ->
%% ---------------------------------------------------------------------
-%% Getting a list of module names from object files in a directory
-
-%% @throws {file_read_error, {Reason::atom(), Message::string(),
-%% fileName()}}
+%% Getting a set of module tests from the object files in a directory
+
+%% @throws {file_read_error,
+%% {Reason::atom(), Message::string(), fileName()}}
+
+get_directory_module_tests(D) ->
+ Ms = get_directory_modules(D),
+ %% for all 'm' in the set, remove 'm_tests' if present
+ F = fun ({M,_}, S) ->
+ Name = atom_to_list(M),
+ case lists:suffix(?DEFAULT_TESTMODULE_SUFFIX, Name) of
+ false ->
+ Name1 = Name ++ ?DEFAULT_TESTMODULE_SUFFIX,
+ M1 = list_to_atom(Name1),
+ dict:erase(M1, S);
+ true ->
+ S
+ end
+ end,
+ [objfile_test(Obj)
+ || Obj <- dict:to_list(lists:foldl(F, dict:from_list(Ms), Ms))].
%% TODO: handle packages (recursive search for files)
-
get_directory_modules(D) ->
- [objfile_test(filename:join(D, F))
+ [begin
+ F1 = filename:join(D, F),
+ {objfile_module(F1), F1}
+ end
|| F <- eunit_lib:list_dir(D), is_module_filename(F)].
diff --git a/lib/eunit/src/eunit_server.erl b/lib/eunit/src/eunit_server.erl
index bf1bb9bcef..2cdfef2668 100644
--- a/lib/eunit/src/eunit_server.erl
+++ b/lib/eunit/src/eunit_server.erl
@@ -59,8 +59,9 @@ watch(Server, Module, Opts) when is_atom(Module) ->
watch_path(Server, Path, Opts) ->
command(Server, {watch, {path, filename:flatten(Path)}, Opts}).
+%% note that the user must use $ at the end to match whole paths only
watch_regexp(Server, Regex, Opts) ->
- case regexp:parse(Regex) of
+ case re:compile(Regex,[anchored]) of
{ok, R} ->
command(Server, {watch, {regexp, R}, Opts});
{error, _}=Error ->
@@ -278,8 +279,8 @@ is_watched(Path, St) ->
match_any(sets:to_list(St#state.regexps), Path).
match_any([R | Rs], Str) ->
- case regexp:first_match(Str, R) of
- {match, _, _} -> true;
+ case re:run(Str, R, [{capture,none}]) of
+ match -> true;
_ -> match_any(Rs, Str)
end;
match_any([], _Str) -> false.
diff --git a/lib/eunit/src/eunit_surefire.erl b/lib/eunit/src/eunit_surefire.erl
index 25b5cde09c..6e0a447105 100644
--- a/lib/eunit/src/eunit_surefire.erl
+++ b/lib/eunit/src/eunit_surefire.erl
@@ -15,7 +15,7 @@
%%
%% $Id: $
%%
-%% @author Micka&euml;l R&eacute;mond <[email protected]>
+%% @author Micka�l R�mond <[email protected]>
%% @copyright 2009 Micka�l R�mond, Paul Guyot
%% @see eunit
%% @doc Surefire reports for EUnit (Format used by Maven and Atlassian
diff --git a/lib/eunit/src/eunit_test.erl b/lib/eunit/src/eunit_test.erl
index d322c4b420..9ac1d1e7d9 100644
--- a/lib/eunit/src/eunit_test.erl
+++ b/lib/eunit/src/eunit_test.erl
@@ -131,12 +131,27 @@ macro_test_() ->
[{module,_},
{line,_},
{expression,_},
- {expected,"[ _ ]"},
+ {pattern,"[ _ ]"},
{value,[]}]},
_}}
= run_testfun(F)
end),
?_test(begin
+ {?LINE, F} = ?_assertNotMatch(ok, error),
+ {ok, ok} = run_testfun(F)
+ end),
+ ?_test(begin
+ {?LINE, F} = ?_assertNotMatch([_], [42]),
+ {error,{error,{assertNotMatch_failed,
+ [{module,_},
+ {line,_},
+ {expression,_},
+ {pattern,"[ _ ]"},
+ {value,[42]}]},
+ _}}
+ = run_testfun(F)
+ end),
+ ?_test(begin
{?LINE, F} = ?_assertEqual(ok, ok),
{ok, ok} = run_testfun(F)
end),
@@ -152,6 +167,20 @@ macro_test_() ->
= run_testfun(F)
end),
?_test(begin
+ {?LINE, F} = ?_assertNotEqual(1, 0),
+ {ok, ok} = run_testfun(F)
+ end),
+ ?_test(begin
+ {?LINE, F} = ?_assertNotEqual(2, 1+1),
+ {error,{error,{assertNotEqual_failed,
+ [{module,_},
+ {line,_},
+ {expression,_},
+ {value,2}]},
+ _}}
+ = run_testfun(F)
+ end),
+ ?_test(begin
{?LINE, F} = ?_assertException(error, badarith,
erlang:error(badarith)),
{ok, ok} = run_testfun(F)
@@ -162,7 +191,7 @@ macro_test_() ->
[{module,_},
{line,_},
{expression,_},
- {expected,_},
+ {pattern,_},
{unexpected_success,ok}]},
_}}
= run_testfun(F)
@@ -174,15 +203,48 @@ macro_test_() ->
[{module,_},
{line,_},
{expression,_},
- {expected,_},
+ {pattern,_},
+ {unexpected_exception,
+ {error,badarith,_}}]},
+ _}}
+ = run_testfun(F)
+ end),
+ ?_test(begin
+ {?LINE, F} = ?_assertError(badarith,
+ erlang:error(badarith)),
+ {ok, ok} = run_testfun(F)
+ end),
+ ?_test(begin
+ {?LINE, F} = ?_assertExit(normal, exit(normal)),
+ {ok, ok} = run_testfun(F)
+ end),
+ ?_test(begin
+ {?LINE, F} = ?_assertThrow(foo, throw(foo)),
+ {ok, ok} = run_testfun(F)
+ end),
+ ?_test(begin
+ {?LINE, F} = ?_assertNotException(error, badarith, 42),
+ {ok, ok} = run_testfun(F)
+ end),
+ ?_test(begin
+ {?LINE, F} = ?_assertNotException(error, badarith,
+ erlang:error(badarg)),
+ {ok, ok} = run_testfun(F)
+ end),
+ ?_test(begin
+ {?LINE, F} = ?_assertNotException(error, badarith,
+ erlang:error(badarith)),
+ {error,{error,{assertNotException_failed,
+ [{module,_},
+ {line,_},
+ {expression,_},
+ {pattern,_},
{unexpected_exception,
{error,badarith,_}}]},
_}}
= run_testfun(F)
end)
]}.
-
-under_eunit_test() -> ?assert(?UNDER_EUNIT).
-endif.
diff --git a/lib/eunit/src/eunit_tests.erl b/lib/eunit/src/eunit_tests.erl
index 37c0b4d6ae..a63d102d98 100644
--- a/lib/eunit/src/eunit_tests.erl
+++ b/lib/eunit/src/eunit_tests.erl
@@ -26,17 +26,17 @@
-include("eunit.hrl").
-ifdef(TEST).
-%% Cause all the other modules to be tested as well as this one.
-full_test_() ->
- %%{application, eunit}. % this currently causes a loop
- %% We use the below until loop detection is implemented
- [eunit_autoexport,
- eunit_striptests,
- eunit_server,
- eunit_proc,
- eunit_serial,
- eunit_test,
- eunit_lib,
- eunit_data,
- eunit_tty].
+id(X) -> X. % for suppressing compiler warnings
-endif.
+
+under_eunit_test() -> ?assert(?UNDER_EUNIT).
+
+let_test() -> ?assertEqual(42, ?LET(X, 17, X+25)).
+
+if_test_() ->
+ [?_assertEqual(17, ?IF(id(1) > 0, 17, 42)),
+ ?_assertEqual(42, ?IF(id(1) < 0, 17, 42))].
+
+matches_test_() ->
+ [?_assert(?MATCHES("hel"++_, "hello")),
+ ?_assertNot(?MATCHES("hal"++_, "hello"))].
diff --git a/lib/eunit/vsn.mk b/lib/eunit/vsn.mk
index d7edd7977b..d933085bbc 100644
--- a/lib/eunit/vsn.mk
+++ b/lib/eunit/vsn.mk
@@ -1 +1 @@
-EUNIT_VSN = 2.1.7
+EUNIT_VSN = 2.2.0
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index f1be658054..82e3675938 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -672,6 +672,9 @@ type(erlang, call_on_load_function, 1, Xs) ->
type(erlang, cancel_timer, 1, Xs) ->
strict(arg_types(erlang, cancel_timer, 1), Xs,
fun (_) -> t_sup(t_integer(), t_atom('false')) end);
+type(erlang, check_old_code, 1, Xs) ->
+ strict(arg_types(erlang, check_old_code, 1), Xs,
+ fun (_) -> t_boolean() end);
type(erlang, check_process_code, 2, Xs) ->
strict(arg_types(erlang, check_process_code, 2), Xs,
fun (_) -> t_boolean() end);
@@ -3395,6 +3398,8 @@ arg_types(erlang, call_on_load_function, 1) ->
[t_atom()];
arg_types(erlang, cancel_timer, 1) ->
[t_reference()];
+arg_types(erlang, check_old_code, 1) ->
+ [t_atom()];
arg_types(erlang, check_process_code, 2) ->
[t_pid(), t_atom()];
arg_types(erlang, concat_binary, 1) ->
diff --git a/lib/hipe/main/hipe.hrl.src b/lib/hipe/main/hipe.hrl.src
index a1fbeda9cf..ec55c707ef 100644
--- a/lib/hipe/main/hipe.hrl.src
+++ b/lib/hipe/main/hipe.hrl.src
@@ -50,9 +50,8 @@
%% Flags:
%% DEBUG - Turns on debugging. (Can be defined to a integer
%% value to determine the level of debugging)
-%% VERBOSE - More info is printed...
%% HIPE_LOGGING - Turn on logging of messages with erl_logger.
-%% DO_ASSERT - Turn on Assertions.
+%% DO_ASSERT - Turn on assertions.
%% TIMING - Turn on timing.
%% HIPE_INSTRUMENT_COMPILER - Turn on instrumentation of the compiler.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -107,13 +106,9 @@
%%
%% Define the exit macro
%%
--ifdef(VERBOSE).
--define(EXIT(Reason), erlang:error({?MODULE,?LINE,Reason})).
--else.
-define(EXIT(Reason),
?msg("EXITED with reason ~w @~w:~w\n", [Reason,?MODULE,?LINE]),
erlang:error({?MODULE,?LINE,Reason})).
--endif.
%%
%% Assertions.
diff --git a/lib/ic/src/ic_pp.erl b/lib/ic/src/ic_pp.erl
index 6f09d049da..8b53473caa 100644
--- a/lib/ic/src/ic_pp.erl
+++ b/lib/ic/src/ic_pp.erl
@@ -776,7 +776,7 @@ expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, chec
expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err2, War2, L+Nl, FN);
{{ifndef, false}, Macro, Rem2, Err2, War2, Nl} ->
Out2 = lists:duplicate(Nl,$\n) ++ Out,
- Mio2 = update_mio({ifudef, Macro}, Mio),
+ Mio2 = update_mio({ifndef, Macro}, Mio),
expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, Err2, War2, L+Nl, FN);
{endif, Rem2, Err2, War2, Nl} ->
@@ -2171,20 +2171,20 @@ update_mio({include, FileName}, #mio{included=Inc}=Mio) ->
update_mio(_, #mio{valid=false, depth=0, cmacro=undefined}=Mio) ->
Mio;
-%% if valid=true, there is no non-whitespace tokens before this ifudef
-update_mio({'ifudef', Macro}, #mio{valid=true, depth=0, cmacro=undefined}=Mio) ->
+%% if valid=true, there is no non-whitespace tokens before this ifndef
+update_mio({'ifndef', Macro}, #mio{valid=true, depth=0, cmacro=undefined}=Mio) ->
Mio#mio{valid=false, cmacro=Macro, depth=1};
-%% detect any tokens before top level #ifudef
+%% detect any tokens before top level #ifndef
update_mio(_, #mio{valid=true, depth=0, cmacro=undefined}=Mio) ->
Mio#mio{valid=false};
%% If cmacro is alreay set, this is after the top level #endif
-update_mio({'ifudef', _}, #mio{valid=true, depth=0}=Mio) ->
+update_mio({'ifndef', _}, #mio{valid=true, depth=0}=Mio) ->
Mio#mio{valid=false, cmacro=undefined};
%% non-top level conditional, just update depth
-update_mio({'ifudef', _}, #mio{depth=D}=Mio) when D > 0 ->
+update_mio({'ifndef', _}, #mio{depth=D}=Mio) when D > 0 ->
Mio#mio{depth=D+1};
update_mio('ifdef', #mio{depth=D}=Mio) ->
Mio#mio{depth=D+1};
@@ -2202,8 +2202,8 @@ update_mio('elif', Mio) ->
Mio;
%% AT exit to top level, if the controlling macro is not set, this could be the
-%% end of a non-ifudef conditional block, or there were tokens before entering
-%% the #ifudef block. In either way, this invalidates the MIO
+%% end of a non-ifndef conditional block, or there were tokens before entering
+%% the #ifndef block. In either way, this invalidates the MIO
%%
%% It doesn't matter if `valid` is true at the time of exiting, it is set to
%% true. This will be used to detect if more tokens are following the top
diff --git a/lib/inets/src/http_server/httpd_file.erl b/lib/inets/src/http_server/httpd_file.erl
index ccc1f7874a..e8a8ab6411 100644
--- a/lib/inets/src/http_server/httpd_file.erl
+++ b/lib/inets/src/http_server/httpd_file.erl
@@ -33,7 +33,7 @@ handle_error(enotdir, Op, ModData, Path) ->
handle_error(404, Op, ModData, Path,
": A component of the file name is not a directory");
handle_error(emfile, Op, _ModData, Path) ->
- handle_error(500, Op, none, Path, ": To many open files");
+ handle_error(500, Op, none, Path, ": Too many open files");
handle_error({enfile,_}, Op, _ModData, Path) ->
handle_error(500, Op, none, Path, ": File table overflow");
handle_error(_Reason, Op, ModData, Path) ->
diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml
index b761b6bd83..cc49090386 100644
--- a/lib/kernel/doc/src/gen_sctp.xml
+++ b/lib/kernel/doc/src/gen_sctp.xml
@@ -63,14 +63,13 @@
<item><seealso marker="#options">SCTP SOCKET OPTIONS</seealso></item>
<item><seealso marker="#examples">SCTP EXAMPLES</seealso></item>
<item><seealso marker="#seealso">SEE ALSO</seealso></item>
- <item><seealso marker="#authors">AUTHORS</seealso></item>
</list>
<marker id="types"></marker>
</section>
<datatypes>
<datatype>
- <name name="assoc_id"/>
+ <name><marker id="type-assoc_id">assoc_id()</marker></name>
<desc>
<p>An opaque term returned in for example #sctp_paddr_change{}
that identifies an association for an SCTP socket. The term
@@ -80,36 +79,18 @@
</desc>
</datatype>
<datatype>
- <name name="hostname"/>
- </datatype>
- <datatype>
- <name name="ip_address"/>
- <desc>
- <p>Represents an address of an SCTP socket.
- It is a tuple as explained in
- <seealso marker="inet">inet(3)</seealso>.</p>
- </desc>
- </datatype>
- <datatype>
- <name name="port_number"/>
- </datatype>
- <datatype>
- <name name="posix"/>
- <desc>
- <p>See <seealso marker="inet#error_codes">
- inet(3); POSIX Error Codes</seealso>.</p>
- </desc>
- </datatype>
- <datatype>
- <name name="sctp_option"/>
+ <name name="option"/>
<desc>
<p>One of the
<seealso marker="#options">SCTP Socket Options.</seealso></p>
- <marker id="type-sctp_socket"></marker>
</desc>
</datatype>
<datatype>
- <name name="sctp_socket"/>
+ <name name="option_name"/>
+ <desc><marker id="type-sctp_socket"></marker></desc>
+ </datatype>
+ <datatype>
+ <name><marker id="type-sctp_socket">sctp_socket()</marker></name>
<desc>
<p>Socket identifier returned from <c>open/*</c>.</p>
<marker id="exports"></marker>
@@ -175,8 +156,8 @@
#sctp_assoc_change{
state = atom(),
error = atom(),
- outbound_streams = int(),
- inbound_streams = int(),
+ outbound_streams = integer(),
+ inbound_streams = integer(),
assoc_id = assoc_id()
} </pre>
<p>The number of outbound and inbound streams can be set by
@@ -300,6 +281,19 @@
The default <c><anno>IP</anno></c> and <c><anno>Port</anno></c> are <c>any</c>
and <c>0</c>, meaning bind to all local addresses on any
one free port.</p>
+
+ <p>Other options are:</p>
+ <taglist>
+ <tag><c>inet6</c></tag>
+ <item>
+ <p>Set up the socket for IPv6.</p>
+ </item>
+ <tag><c>inet</c></tag>
+ <item>
+ <p>Set up the socket for IPv4. This is the default.</p>
+ </item>
+ </taglist>
+
<p>A default set of socket <seealso marker="#options">options</seealso>
is used. In particular, the socket is opened in
<seealso marker="#option-binary">binary</seealso> and
@@ -350,7 +344,7 @@
#sctp_paddr_change{
addr = {ip_address(),port()},
state = atom(),
- error = int(),
+ error = integer(),
assoc_id = assoc_id()
} </pre>
<p>Indicates change of the status of the peer's IP address given by
@@ -387,7 +381,7 @@
<pre>
#sctp_send_failed{
flags = true | false,
- error = int(),
+ error = integer(),
info = #sctp_sndrcvinfo{},
assoc_id = assoc_id()
data = binary()
@@ -407,7 +401,7 @@
<item>
<pre>
#sctp_adaptation_event{
- adaptation_ind = int(),
+ adaptation_ind = integer(),
assoc_id = assoc_id()
} </pre>
<p>Delivered when a peer sends an Adaptation Layer Indication
@@ -505,7 +499,7 @@
</list>
<marker id="option-buffer"></marker>
</item>
- <tag><c>{buffer, int()}</c></tag>
+ <tag><c>{buffer, integer()}</c></tag>
<item>
<p>Determines the size of the user-level software buffer used by
the SCTP driver. Not to be confused with <c>sndbuf</c>
@@ -515,7 +509,7 @@
In fact, the <c>val(buffer)</c> is automatically set to
the above maximum when <c>sndbuf</c> or <c>recbuf</c> values are set.</p>
</item>
- <tag><c>{tos, int()}</c></tag>
+ <tag><c>{tos, integer()}</c></tag>
<item>
<p>Sets the Type-Of-Service field on the IP datagrams being sent,
to the given value, which effectively determines a prioritization
@@ -523,7 +517,7 @@
are system-dependent. TODO: we do not provide
symbolic names for these values yet.</p>
</item>
- <tag><c>{priority, int()}</c></tag>
+ <tag><c>{priority, integer()}</c></tag>
<item>
<p>A protocol-independent equivalent of <c>tos</c> above. Setting
priority implies setting tos as well.</p>
@@ -542,7 +536,7 @@
required for high-throughput servers).</p>
<marker id="option-linger"></marker>
</item>
- <tag><c>{linger, {true|false, int()}</c></tag>
+ <tag><c>{linger, {true|false, integer()}</c></tag>
<item>
<p>Determines the timeout in seconds for flushing unsent data in the
<c>gen_sctp:close/1</c> socket call. If the 1st component of the value
@@ -552,14 +546,14 @@
the flushing time-out in seconds.</p>
<marker id="option-sndbuf"></marker>
</item>
- <tag><c>{sndbuf, int()}</c></tag>
+ <tag><c>{sndbuf, integer()}</c></tag>
<item>
<p>The size, in bytes, of the *kernel* send buffer for this socket.
Sending errors would occur for datagrams larger than
<c>val(sndbuf)</c>. Setting this option also adjusts
the size of the driver buffer (see <c>buffer</c> above).</p>
</item>
- <tag><c>{recbuf, int()}</c></tag>
+ <tag><c>{recbuf, integer()}</c></tag>
<item>
<p>The size, in bytes, of the *kernel* recv buffer for this socket.
Sending errors would occur for datagrams larger than
@@ -571,9 +565,9 @@
<pre>
#sctp_rtoinfo{
assoc_id = assoc_id(),
- initial = int(),
- max = int(),
- min = int()
+ initial = integer(),
+ max = integer(),
+ min = integer()
} </pre>
<p>Determines re-transmission time-out parameters, in milliseconds,
for the association(s) given by <c>assoc_id</c>.
@@ -586,11 +580,11 @@
<pre>
#sctp_assocparams{
assoc_id = assoc_id(),
- asocmaxrxt = int(),
- number_peer_destinations = int(),
- peer_rwnd = int(),
- local_rwnd = int(),
- cookie_life = int()
+ asocmaxrxt = integer(),
+ number_peer_destinations = integer(),
+ peer_rwnd = integer(),
+ local_rwnd = integer(),
+ cookie_life = integer()
} </pre>
<p>Determines association parameters for the association(s) given by
<c>assoc_id</c>. <c>assoc_id = 0</c> (default) indicates
@@ -601,10 +595,10 @@
<item>
<pre>
#sctp_initmsg{
- num_ostreams = int(),
- max_instreams = int(),
- max_attempts = int(),
- max_init_timeo = int()
+ num_ostreams = integer(),
+ max_instreams = integer(),
+ max_attempts = integer(),
+ max_init_timeo = integer()
} </pre>
<p>Determines the default parameters which this socket attempts
to negotiate with its peer while establishing an association with it.
@@ -630,10 +624,11 @@
</list>
<p></p>
</item>
- <tag><c>{sctp_autoclose, int()|infinity}</c></tag>
+ <tag><c>{sctp_autoclose, integer() >= 0}</c></tag>
<item>
<p>Determines the time (in seconds) after which an idle association is
- automatically closed.</p>
+ automatically closed. <c>0</c> means that the association is
+ never automatically closed.</p>
</item>
<tag><c>{sctp_nodelay, true|false}</c></tag>
<item>
@@ -655,7 +650,7 @@
<p>Turns on|off automatic mapping of IPv4 addresses into IPv6 ones
(if the socket address family is AF_INET6).</p>
</item>
- <tag><c>{sctp_maxseg, int()}</c></tag>
+ <tag><c>{sctp_maxseg, integer()}</c></tag>
<item>
<p>Determines the maximum chunk size if message fragmentation is used.
If <c>0</c>, the chunk size is limited by the Path MTU only.</p>
@@ -693,7 +688,7 @@
<marker id="record-sctp_setadaptation"></marker>
<pre>
#sctp_setadaptation{
- adaptation_ind = int()
+ adaptation_ind = integer()
} </pre>
<p>When set, requests that the local endpoint uses the value given by
<c>adaptation_ind</c> as the Adaptation Indication parameter for
@@ -707,10 +702,10 @@
#sctp_paddrparams{
assoc_id = assoc_id(),
address = {IP, Port},
- hbinterval = int(),
- pathmaxrxt = int(),
- pathmtu = int(),
- sackdelay = int(),
+ hbinterval = integer(),
+ pathmaxrxt = integer(),
+ pathmtu = integer(),
+ sackdelay = integer(),
flags = list()
}
IP = ip_address()
@@ -771,14 +766,14 @@
<marker id="record-sctp_sndrcvinfo"></marker>
<pre>
#sctp_sndrcvinfo{
- stream = int(),
- ssn = int(),
+ stream = integer(),
+ ssn = integer(),
flags = list(),
- ppid = int(),
- context = int(),
- timetolive = int(),
- tsn = int(),
- cumtsn = int(),
+ ppid = integer(),
+ context = integer(),
+ timetolive = integer(),
+ tsn = integer(),
+ cumtsn = integer(),
assoc_id = assoc_id()
} </pre>
<p><c>#sctp_sndrcvinfo{}</c> is used both in this socket option, and as
@@ -853,7 +848,7 @@
<pre>
#sctp_assoc_value{
assoc_id = assoc_id(),
- assoc_value = int()
+ assoc_value = integer()
} </pre>
<p>Rarely used. Determines the ACK time
(given by <c>assoc_value</c> in milliseconds) for
@@ -866,12 +861,12 @@
#sctp_status{
assoc_id = assoc_id(),
state = atom(),
- rwnd = int(),
- unackdata = int(),
- penddata = int(),
- instrms = int(),
- outstrms = int(),
- fragmentation_point = int(),
+ rwnd = integer(),
+ unackdata = integer(),
+ penddata = integer(),
+ instrms = integer(),
+ outstrms = integer(),
+ fragmentation_point = integer(),
primary = #sctp_paddrinfo{}
} </pre>
<p>This option is read-only. It determines the status of
@@ -946,10 +941,10 @@
assoc_id = assoc_id(),
address = {IP, Port},
state = inactive | active,
- cwnd = int(),
- srtt = int(),
- rto = int(),
- mtu = int()
+ cwnd = integer(),
+ srtt = integer(),
+ rto = integer(),
+ mtu = integer()
}
IP = ip_address()
Port = port_number() </pre>
@@ -1119,7 +1114,6 @@ client_loop(S, Peer1, Port1, AssocId1, Peer2, Port2, AssocId2) -&gt;
<seealso marker="gen_udp">gen_udp(3)</seealso>,
<url href="http://www.rfc-archive.org/getrfc.php?rfc=2960">RFC2960</url> (Stream Control Transmission Protocol),
<url href="http://tools.ietf.org/html/draft-ietf-tsvwg-sctpsocket-13">Sockets API Extensions for SCTP.</url></p>
- <marker id="authors"></marker>
</section>
</erlref>
diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml
index f1d42d9faa..8a5d40bb16 100644
--- a/lib/kernel/doc/src/gen_tcp.xml
+++ b/lib/kernel/doc/src/gen_tcp.xml
@@ -37,7 +37,7 @@
binary and closing the connection:</p>
<code type="none">
client() ->
- SomeHostInNet = "localhost" % to make it runnable on one machine
+ SomeHostInNet = "localhost", % to make it runnable on one machine
{ok, Sock} = gen_tcp:connect(SomeHostInNet, 5678,
[binary, {packet, 0}]),
ok = gen_tcp:send(Sock, "Some Data"),
@@ -65,25 +65,16 @@ do_recv(Sock, Bs) ->
<datatypes>
<datatype>
- <name name="hostname"/>
+ <name name="option"/>
</datatype>
<datatype>
- <name name="ip_address"/>
- <desc>
- <p>Represents an address of a TCP socket.
- It is a tuple as explained in
- <seealso marker="inet">inet(3)</seealso>.</p>
- </desc>
+ <name name="option_name"/>
</datatype>
<datatype>
- <name name="port_number"/>
+ <name name="connect_option"/>
</datatype>
<datatype>
- <name name="posix"/>
- <desc>
- <p>See <seealso marker="inet#error_codes">
- inet(3); POSIX Error Codes</seealso>.</p>
- </desc>
+ <name name="listen_option"/>
</datatype>
<datatype>
<name><marker id="type-socket">socket()</marker></name>
@@ -122,7 +113,7 @@ do_recv(Sock, Bs) ->
<item>
<p>Specify which local port number to use.</p>
</item>
- <tag><c>{fd, int()}</c></tag>
+ <tag><c>{fd, integer() >= 0}</c></tag>
<item>
<p>If a socket has somehow been connected without using
<c>gen_tcp</c>, use this option to pass the file
@@ -196,6 +187,10 @@ do_recv(Sock, Bs) ->
<p>If the host has several network interfaces, this option
specifies which one to listen on.</p>
</item>
+ <tag><c>{port, Port}</c></tag>
+ <item>
+ <p>Specify which local port number to use.</p>
+ </item>
<tag><c>{fd, Fd}</c></tag>
<item>
<p>If a socket has somehow been connected without using
diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml
index c0e783f508..daa9b7d887 100644
--- a/lib/kernel/doc/src/gen_udp.xml
+++ b/lib/kernel/doc/src/gen_udp.xml
@@ -36,25 +36,10 @@
<datatypes>
<datatype>
- <name name="hostname"/>
+ <name name="option"/>
</datatype>
<datatype>
- <name name="ip_address"/>
- <desc>
- <p>Represents an address of a TCP socket.
- It is a tuple as explained in
- <seealso marker="inet">inet(3)</seealso>.</p>
- </desc>
- </datatype>
- <datatype>
- <name name="port_number"/>
- </datatype>
- <datatype>
- <name name="posix"/>
- <desc>
- <p>See <seealso marker="inet#error_codes">
- inet(3); POSIX Error Codes</seealso>.</p>
- </desc>
+ <name name="option_name"/>
</datatype>
<datatype>
<name><marker id="type-socket">socket()</marker></name>
@@ -87,7 +72,7 @@
<p>If the host has several network interfaces, this option
specifies which one to use.</p>
</item>
- <tag><c>{fd, int()}</c></tag>
+ <tag><c>{fd, integer() >= 0}</c></tag>
<item>
<p>If a socket has somehow been opened without using
<c>gen_udp</c>, use this option to pass the file
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index fd843b00d9..b36c28e027 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -105,6 +105,9 @@ fe80::204:acff:fe17:bf38
<name name="ip6_address"/>
</datatype>
<datatype>
+ <name name="port_number"/>
+ </datatype>
+ <datatype>
<name name="posix"/>
<desc><p>An atom which is named from the Posix error codes
used in Unix, and in the runtime libraries of most
@@ -119,7 +122,7 @@ fe80::204:acff:fe17:bf38
</desc>
</datatype>
<datatype>
- <name name="family_option"/>
+ <name name="address_family"/>
</datatype>
</datatypes>
@@ -250,26 +253,15 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name>getopts(Socket, Options) -> {ok, OptionValues} | {error, posix()}</name>
+ <name name="getopts" arity="2"/>
<fsummary>Get one or more options for a socket</fsummary>
- <type>
- <v>Socket = term()</v>
- <v>Options = [Opt | RawOptReq]</v>
- <v>Opt = atom()</v>
- <v>RawOptReq = {raw, Protocol, OptionNum, ValueSpec}</v>
- <v>Protocol = integer()</v>
- <v>OptionNum = integer()</v>
- <v>ValueSpec = ValueSize | ValueBin</v>
- <v>ValueSize = integer()</v>
- <v>ValueBin = binary()</v>
- <v>OptionValues = [{Opt, Val} | {raw, Protocol, OptionNum, ValueBin}]</v>
- </type>
<type name="socket_getopt"/>
+ <type name="socket_setopt"/>
<desc>
<p>Gets one or more options for a socket.
See <seealso marker="#setopts/2">setopts/2</seealso>
for a list of available options.</p>
- <p>The number of elements in the returned <c>OptionValues</c>
+ <p>The number of elements in the returned <c><anno>OptionValues</anno></c>
list does not necessarily correspond to the number of options
asked for. If the operating system fails to support an option,
it is simply left out in the returned list. An error tuple is only
@@ -277,12 +269,12 @@ fe80::204:acff:fe17:bf38
(i.e. the socket is closed or the buffer size in a raw request
is too large). This behavior is kept for backward
compatibility reasons.</p>
- <p>A <c>RawOptReq</c> can be used to get information about
+ <p>A raw option request <c>RawOptReq = {raw, Protocol, OptionNum, ValueSpec}</c> can be used to get information about
socket options not (explicitly) supported by the emulator. The
use of raw socket options makes the code non portable, but
allows the Erlang programmer to take advantage of unusual features
present on the current platform.</p>
- <p>The <c>RawOptReq</c> consists of the tag <c>raw</c> followed
+ <p>The <c>RawOptReq</c> consists of the tag <c>raw</c> followed
by the protocol level, the option number and either a binary
or the size, in bytes, of the
buffer in which the option value is to be stored. A binary
@@ -325,19 +317,14 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name>getstat(Socket)</name>
- <name>getstat(Socket, Options) -> {ok, OptionValues} | {error, posix()}</name>
+ <name name="getstat" arity="1"/>
+ <name name="getstat" arity="2"/>
<fsummary>Get one or more statistic options for a socket</fsummary>
- <type>
- <v>Socket = term()</v>
- <v>Options = [Opt]</v>
- <v>OptionValues = [{Opt, Val}]</v>
- <v>&nbsp;Opt, Val -- see below</v>
- </type>
+ <type name="stat_option"/>
<desc>
<p>Gets one or more statistic options for a socket.</p>
- <p><c>getstat(Socket)</c> is equivalent to
- <c>getstat(Socket,&nbsp;[recv_avg,&nbsp;recv_cnt,&nbsp;recv_dvi,&nbsp;recv_max,&nbsp;recv_oct,&nbsp;send_avg,&nbsp;send_cnt,&nbsp;send_dvi,&nbsp;send_max,&nbsp;send_oct])</c></p>
+ <p><c>getstat(<anno>Socket</anno>)</c> is equivalent to
+ <c>getstat(<anno>Socket</anno>,&nbsp;[recv_avg,&nbsp;recv_cnt,&nbsp;recv_dvi,&nbsp;recv_max,&nbsp;recv_oct,&nbsp;send_avg,&nbsp;send_cnt,&nbsp;send_dvi,&nbsp;send_max,&nbsp;send_oct])</c></p>
<p>The following options are available:</p>
<taglist>
<tag><c>recv_avg</c></tag>
@@ -394,12 +381,8 @@ fe80::204:acff:fe17:bf38
</desc>
</func>
<func>
- <name>port(Socket) -> {ok, Port} | {error, any()}</name>
+ <name name="port" arity="1"/>
<fsummary>Return the local port number for a socket</fsummary>
- <type>
- <v>Socket = socket()</v>
- <v>Port = integer()</v>
- </type>
<desc>
<p>Returns the local port number for a socket.</p>
</desc>
@@ -412,16 +395,9 @@ fe80::204:acff:fe17:bf38
</desc>
</func>
<func>
- <name>setopts(Socket, Options) -> ok | {error, posix()}</name>
+ <name name="setopts" arity="2"/>
<fsummary>Set one or more options for a socket</fsummary>
- <type>
- <v>Socket = term()</v>
- <v>Options = [{Opt, Val} | {raw, Protocol, Option, ValueBin}]</v>
- <v>Protocol = integer()</v>
- <v>OptionNum = integer()</v>
- <v>ValueBin = binary()</v>
- <v>&nbsp;Opt, Val -- see below</v>
- </type>
+ <type name="socket_setopt"/>
<desc>
<p>Sets one or more options for a socket. The following options
are available:</p>
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index 4a1fc7df34..85bbff9cc3 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -1379,8 +1379,12 @@ absname_vr([[X, $:]|Name], _, _AbsBase) ->
%% Kill all processes running code from *old* Module, and then purge the
%% module. Return true if any processes killed, else false.
-do_purge(Mod) ->
- do_purge(processes(), to_atom(Mod), false).
+do_purge(Mod0) ->
+ Mod = to_atom(Mod0),
+ case erlang:check_old_code(Mod) of
+ false -> false;
+ true -> do_purge(processes(), Mod, false)
+ end.
do_purge([P|Ps], Mod, Purged) ->
case erlang:check_process_code(P, Mod) of
@@ -1399,16 +1403,19 @@ do_purge([], Mod, Purged) ->
Purged.
%% do_soft_purge(Module)
-%% Purge old code only if no procs remain that run old code
+%% Purge old code only if no procs remain that run old code.
%% Return true in that case, false if procs remain (in this
%% case old code is not purged)
do_soft_purge(Mod) ->
- catch do_soft_purge(processes(), Mod).
+ case erlang:check_old_code(Mod) of
+ false -> true;
+ true -> do_soft_purge(processes(), Mod)
+ end.
do_soft_purge([P|Ps], Mod) ->
case erlang:check_process_code(P, Mod) of
- true -> throw(false);
+ true -> false;
false -> do_soft_purge(Ps, Mod)
end;
do_soft_purge([], Mod) ->
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index 004f03f231..6cebb7ab97 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -33,55 +33,85 @@
-export([error_string/1]).
-export([controlling_process/2]).
--opaque assoc_id() :: term().
--type hostname() :: inet:hostname().
--type ip_address() :: inet:ip_address().
--type port_number() :: 0..65535.
--type posix() :: inet:posix().
--type sctp_option() ::
- {mode, list | binary} | list | binary
- | {active, true | false | once}
- | {buffer, non_neg_integer()}
- | {tos, integer()}
- | {priority, integer()}
- | {dontroute, boolean()}
- | {reuseaddr, boolean()}
- | {linger, {boolean(), non_neg_integer()}}
- | {sndbuf, non_neg_integer()}
- | {recbuf, non_neg_integer()}
- | {sctp_rtoinfo, #sctp_rtoinfo{}}
- | {sctp_associnfo, #sctp_assocparams{}}
- | {sctp_initmsg, #sctp_initmsg{}}
- | {sctp_autoclose, timeout()}
- | {sctp_nodelay, boolean()}
- | {sctp_disable_fragments, boolean()}
- | {sctp_i_want_mapped_v4_addr, boolean()}
- | {sctp_maxseg, non_neg_integer()}
- | {sctp_primary_addr, #sctp_prim{}}
- | {sctp_set_peer_primary_addr, #sctp_setpeerprim{}}
- | {sctp_adaptation_layer, #sctp_setadaptation{}}
- | {sctp_peer_addr_params, #sctp_paddrparams{}}
- | {sctp_default_send_param, #sctp_sndrcvinfo{}}
- | {sctp_events, #sctp_event_subscribe{}}
- | {sctp_delayed_ack_time, #sctp_assoc_value{}}
- | {sctp_status, #sctp_status{}}
- | {sctp_get_peer_addr_info, #sctp_paddrinfo{}}.
--opaque sctp_socket() :: port().
-
--spec open() -> {ok, Socket} | {error, posix()} when
+-type assoc_id() :: term().
+-type option() ::
+ {active, true | false | once} |
+ {buffer, non_neg_integer()} |
+ {dontroute, boolean()} |
+ {linger, {boolean(), non_neg_integer()}} |
+ {mode, list | binary} | list | binary |
+ {priority, non_neg_integer()} |
+ {recbuf, non_neg_integer()} |
+ {reuseaddr, boolean()} |
+ {sctp_adaptation_layer, #sctp_setadaptation{}} |
+ {sctp_associnfo, #sctp_assocparams{}} |
+ {sctp_autoclose, non_neg_integer()} |
+ {sctp_default_send_param, #sctp_sndrcvinfo{}} |
+ {sctp_delayed_ack_time, #sctp_assoc_value{}} |
+ {sctp_disable_fragments, boolean()} |
+ {sctp_events, #sctp_event_subscribe{}} |
+ {sctp_get_peer_addr_info, #sctp_paddrinfo{}} |
+ {sctp_i_want_mapped_v4_addr, boolean()} |
+ {sctp_initmsg, #sctp_initmsg{}} |
+ {sctp_maxseg, non_neg_integer()} |
+ {sctp_nodelay, boolean()} |
+ {sctp_peer_addr_params, #sctp_paddrparams{}} |
+ {sctp_primary_addr, #sctp_prim{}} |
+ {sctp_rtoinfo, #sctp_rtoinfo{}} |
+ {sctp_set_peer_primary_addr, #sctp_setpeerprim{}} |
+ {sctp_status, #sctp_status{}} |
+ {sndbuf, non_neg_integer()} |
+ {tos, non_neg_integer()}.
+-type option_name() ::
+ active |
+ buffer |
+ dontroute |
+ linger |
+ mode |
+ priority |
+ recbuf |
+ reuseaddr |
+ sctp_adaptation_layer |
+ sctp_associnfo |
+ sctp_autoclose |
+ sctp_default_send_param |
+ sctp_delayed_ack_time |
+ sctp_disable_fragments |
+ sctp_events |
+ sctp_get_peer_addr_info |
+ sctp_i_want_mapped_v4_addr |
+ sctp_initmsg |
+ sctp_maxseg |
+ sctp_nodelay |
+ sctp_peer_addr_params |
+ sctp_primary_addr |
+ sctp_rtoinfo |
+ sctp_set_peer_primary_addr |
+ sctp_status |
+ sndbuf |
+ tos.
+-type sctp_socket() :: port().
+
+-export_type([assoc_id/0, option/0, option_name/0, sctp_socket/0]).
+
+-spec open() -> {ok, Socket} | {error, inet:posix()} when
Socket :: sctp_socket().
open() ->
open([]).
--spec open(Port) -> {ok, Socket} | {error, posix()} when
- Port :: port_number(),
+-spec open(Port) -> {ok, Socket} | {error, inet:posix()} when
+ Port :: inet:port_number(),
Socket :: sctp_socket();
- (Opts) -> {ok, Socket} | {error, posix()} when
+ (Opts) -> {ok, Socket} | {error, inet:posix()} when
Opts :: [Opt],
- Opt :: {ip,IP} | {ifaddr,IP} | {port,Port} | sctp_option(),
- IP :: ip_address() | any | loopback,
- Port :: port_number(),
+ Opt :: {ip,IP}
+ | {ifaddr,IP}
+ | inet:address_family()
+ | {port,Port}
+ | option(),
+ IP :: inet:ip_address() | any | loopback,
+ Port :: inet:port_number(),
Socket :: sctp_socket().
open(Opts) when is_list(Opts) ->
@@ -98,11 +128,15 @@ open(Port) when is_integer(Port) ->
open(X) ->
erlang:error(badarg, [X]).
--spec open(Port, Opts) -> {ok, Socket} | {error, posix()} when
+-spec open(Port, Opts) -> {ok, Socket} | {error, inet:posix()} when
Opts :: [Opt],
- Opt :: {ip,IP} | {ifaddr,IP} | {port,Port} | sctp_option(),
- IP :: ip_address() | any | loopback,
- Port :: port_number(),
+ Opt :: {ip,IP}
+ | {ifaddr,IP}
+ | inet:address_family()
+ | {port,Port}
+ | option(),
+ IP :: inet:ip_address() | any | loopback,
+ Port :: inet:port_number(),
Socket :: sctp_socket().
open(Port, Opts) when is_integer(Port), is_list(Opts) ->
@@ -110,7 +144,7 @@ open(Port, Opts) when is_integer(Port), is_list(Opts) ->
open(Port, Opts) ->
erlang:error(badarg, [Port,Opts]).
--spec close(Socket) -> ok | {error, posix()} when
+-spec close(Socket) -> ok | {error, inet:posix()} when
Socket :: sctp_socket().
close(S) when is_port(S) ->
@@ -138,22 +172,22 @@ listen(S, Flag) when is_port(S), is_boolean(Flag) ->
listen(S, Flag) ->
erlang:error(badarg, [S,Flag]).
--spec connect(Socket, Addr, Port, Opts) -> {ok, Assoc} | {error, posix()} when
+-spec connect(Socket, Addr, Port, Opts) -> {ok, Assoc} | {error, inet:posix()} when
Socket :: sctp_socket(),
- Addr :: ip_address() | hostname(),
- Port :: port_number(),
- Opts :: [Opt :: sctp_option()],
+ Addr :: inet:ip_address() | inet:hostname(),
+ Port :: inet:port_number(),
+ Opts :: [Opt :: option()],
Assoc :: #sctp_assoc_change{}.
connect(S, Addr, Port, Opts) ->
connect(S, Addr, Port, Opts, infinity).
-spec connect(Socket, Addr, Port, Opts, Timeout) ->
- {ok, Assoc} | {error, posix()} when
+ {ok, Assoc} | {error, inet:posix()} when
Socket :: sctp_socket(),
- Addr :: ip_address() | hostname(),
- Port :: port_number(),
- Opts :: [Opt :: sctp_option()],
+ Addr :: inet:ip_address() | inet:hostname(),
+ Port :: inet:port_number(),
+ Opts :: [Opt :: option()],
Timeout :: timeout(),
Assoc :: #sctp_assoc_change{}.
@@ -166,21 +200,21 @@ connect(S, Addr, Port, Opts, Timeout) ->
end.
-spec connect_init(Socket, Addr, Port, Opts) ->
- ok | {error, posix()} when
+ ok | {error, inet:posix()} when
Socket :: sctp_socket(),
- Addr :: ip_address() | hostname(),
- Port :: port_number(),
- Opts :: [sctp_option()].
+ Addr :: inet:ip_address() | inet:hostname(),
+ Port :: inet:port_number(),
+ Opts :: [option()].
connect_init(S, Addr, Port, Opts) ->
connect_init(S, Addr, Port, Opts, infinity).
-spec connect_init(Socket, Addr, Port, Opts, Timeout) ->
- ok | {error, posix()} when
+ ok | {error, inet:posix()} when
Socket :: sctp_socket(),
- Addr :: ip_address() | hostname(),
- Port :: port_number(),
- Opts :: [sctp_option()],
+ Addr :: inet:ip_address() | inet:hostname(),
+ Port :: inet:port_number(),
+ Opts :: [option()],
Timeout :: timeout().
connect_init(S, Addr, Port, Opts, Timeout) ->
@@ -232,7 +266,7 @@ eof(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) ->
eof(S, Assoc) ->
erlang:error(badarg, [S,Assoc]).
--spec abort(Socket, Assoc) -> ok | {error, posix()} when
+-spec abort(Socket, Assoc) -> ok | {error, inet:posix()} when
Socket :: sctp_socket(),
Assoc :: #sctp_assoc_change{}.
@@ -294,13 +328,13 @@ send(S, AssocChange, Stream, Data) ->
-spec recv(Socket) -> {ok, {FromIP, FromPort, AncData, Data}}
| {error, Reason} when
Socket :: sctp_socket(),
- FromIP :: ip_address(),
- FromPort :: port_number(),
+ FromIP :: inet:ip_address(),
+ FromPort :: inet:port_number(),
AncData :: [#sctp_sndrcvinfo{}],
Data :: binary() | string() | #sctp_sndrcvinfo{}
| #sctp_assoc_change{} | #sctp_paddr_change{}
| #sctp_adaptation_event{},
- Reason :: posix() | #sctp_send_failed{} | #sctp_paddr_change{}
+ Reason :: inet:posix() | #sctp_send_failed{} | #sctp_paddr_change{}
| #sctp_pdapi_event{} | #sctp_remote_error{}
| #sctp_shutdown_event{}.
@@ -311,13 +345,13 @@ recv(S) ->
| {error, Reason} when
Socket :: sctp_socket(),
Timeout :: timeout(),
- FromIP :: ip_address(),
- FromPort :: port_number(),
+ FromIP :: inet:ip_address(),
+ FromPort :: inet:port_number(),
AncData :: [#sctp_sndrcvinfo{}],
Data :: binary() | string() | #sctp_sndrcvinfo{}
| #sctp_assoc_change{} | #sctp_paddr_change{}
| #sctp_adaptation_event{},
- Reason :: posix() | #sctp_send_failed{} | #sctp_paddr_change{}
+ Reason :: inet:posix() | #sctp_send_failed{} | #sctp_paddr_change{}
| #sctp_pdapi_event{} | #sctp_remote_error{}
| #sctp_shutdown_event{}.
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index bee61ca84a..8ab18c01b4 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -28,34 +28,108 @@
-include("inet_int.hrl").
--type hostname() :: inet:hostname().
--type ip_address() :: inet:ip_address().
--type port_number() :: 0..65535.
--type posix() :: inet:posix().
+-type option() ::
+ {active, true | false | once} |
+ {bit8, clear | set | on | off} |
+ {buffer, non_neg_integer()} |
+ {delay_send, boolean()} |
+ {deliver, port | term} |
+ {dontroute, boolean()} |
+ {exit_on_close, boolean()} |
+ {header, non_neg_integer()} |
+ {high_watermark, non_neg_integer()} |
+ {keepalive, boolean()} |
+ {linger, {boolean(), non_neg_integer()}} |
+ {low_watermark, non_neg_integer()} |
+ {mode, list | binary} | list | binary |
+ {nodelay, boolean()} |
+ {packet,
+ 0 | 1 | 2 | 4 | raw | sunrm | asn1 |
+ cdr | fcgi | line | tpkt | http | httph | http_bin | httph_bin } |
+ {packet_size, non_neg_integer()} |
+ {priority, non_neg_integer()} |
+ {raw,
+ Protocol :: non_neg_integer(),
+ OptionNum :: non_neg_integer(),
+ ValueBin :: binary()} |
+ {recbuf, non_neg_integer()} |
+ {reuseaddr, boolean()} |
+ {send_timeout, non_neg_integer() | infinity} |
+ {send_timeout_close, boolean()} |
+ {sndbuf, non_neg_integer()} |
+ {tos, non_neg_integer()}.
+-type option_name() ::
+ active |
+ bit8 |
+ buffer |
+ delay_send |
+ deliver |
+ dontroute |
+ exit_on_close |
+ header |
+ high_watermark |
+ keepalive |
+ linger |
+ low_watermark |
+ mode |
+ nodelay |
+ packet |
+ packet_size |
+ priority |
+ {raw,
+ Protocol :: non_neg_integer(),
+ OptionNum :: non_neg_integer(),
+ ValueSpec :: (ValueSize :: non_neg_integer()) |
+ (ValueBin :: binary())} |
+ recbuf |
+ reuseaddr |
+ send_timeout |
+ send_timeout_close |
+ sndbuf |
+ tos.
+-type connect_option() ::
+ {ip, inet:ip_address()} |
+ {fd, Fd :: non_neg_integer()} |
+ {ifaddr, inet:ip_address()} |
+ inet:address_family() |
+ {port, inet:port_number()} |
+ {tcp_module, module()} |
+ option().
+-type listen_option() ::
+ {ip, inet:ip_address()} |
+ {fd, Fd :: non_neg_integer()} |
+ {ifaddr, inet:ip_address()} |
+ inet:address_family() |
+ {port, inet:port_number()} |
+ {backlog, B :: non_neg_integer()} |
+ {tcp_module, module()} |
+ option().
-type socket() :: port().
+-export_type([option/0, option_name/0, connect_option/0, listen_option/0]).
+
%%
%% Connect a socket
%%
-spec connect(Address, Port, Options) -> {ok, Socket} | {error, Reason} when
- Address :: ip_address() | hostname(),
- Port :: port_number(),
- Options :: [Opt :: term()],
+ Address :: inet:ip_address() | inet:hostname(),
+ Port :: inet:port_number(),
+ Options :: [connect_option()],
Socket :: socket(),
- Reason :: posix().
+ Reason :: inet:posix().
connect(Address, Port, Opts) ->
connect(Address,Port,Opts,infinity).
-spec connect(Address, Port, Options, Timeout) ->
{ok, Socket} | {error, Reason} when
- Address :: ip_address() | hostname(),
- Port :: port_number(),
- Options :: [Opt :: term()],
+ Address :: inet:ip_address() | inet:hostname(),
+ Port :: inet:port_number(),
+ Options :: [connect_option()],
Timeout :: timeout(),
Socket :: socket(),
- Reason :: posix().
+ Reason :: inet:posix().
connect(Address, Port, Opts, Time) ->
Timer = inet:start_timer(Time),
@@ -97,10 +171,10 @@ try_connect([], _Port, _Opts, _Timer, _Mod, Err) ->
%%
-spec listen(Port, Options) -> {ok, ListenSocket} | {error, Reason} when
- Port :: port_number(),
- Options :: [Opt :: term()],
+ Port :: inet:port_number(),
+ Options :: [listen_option()],
ListenSocket :: socket(),
- Reason :: posix().
+ Reason :: inet:posix().
listen(Port, Opts) ->
Mod = mod(Opts, undefined),
@@ -119,7 +193,7 @@ listen(Port, Opts) ->
-spec accept(ListenSocket) -> {ok, Socket} | {error, Reason} when
ListenSocket :: socket(),
Socket :: socket(),
- Reason :: closed | timeout | posix().
+ Reason :: closed | timeout | inet:posix().
accept(S) ->
case inet_db:lookup_socket(S) of
@@ -133,7 +207,7 @@ accept(S) ->
ListenSocket :: socket(),
Timeout :: timeout(),
Socket :: socket(),
- Reason :: closed | timeout | posix().
+ Reason :: closed | timeout | inet:posix().
accept(S, Time) when is_port(S) ->
case inet_db:lookup_socket(S) of
@@ -150,7 +224,7 @@ accept(S, Time) when is_port(S) ->
-spec shutdown(Socket, How) -> ok | {error, Reason} when
Socket :: socket(),
How :: read | write | read_write,
- Reason :: posix().
+ Reason :: inet:posix().
shutdown(S, How) when is_port(S) ->
case inet_db:lookup_socket(S) of
@@ -176,8 +250,8 @@ close(S) ->
-spec send(Socket, Packet) -> ok | {error, Reason} when
Socket :: socket(),
- Packet :: string() | binary(),
- Reason :: posix().
+ Packet :: iodata(),
+ Reason :: inet:posix().
send(S, Packet) when is_port(S) ->
case inet_db:lookup_socket(S) of
@@ -195,7 +269,7 @@ send(S, Packet) when is_port(S) ->
Socket :: socket(),
Length :: non_neg_integer(),
Packet :: string() | binary() | HttpPacket,
- Reason :: closed | posix(),
+ Reason :: closed | inet:posix(),
HttpPacket :: term().
recv(S, Length) when is_port(S) ->
@@ -211,7 +285,7 @@ recv(S, Length) when is_port(S) ->
Length :: non_neg_integer(),
Timeout :: timeout(),
Packet :: string() | binary() | HttpPacket,
- Reason :: closed | posix(),
+ Reason :: closed | inet:posix(),
HttpPacket :: term().
recv(S, Length, Time) when is_port(S) ->
@@ -237,7 +311,7 @@ unrecv(S, Data) when is_port(S) ->
-spec controlling_process(Socket, Pid) -> ok | {error, Reason} when
Socket :: socket(),
Pid :: pid(),
- Reason :: closed | not_owner | posix().
+ Reason :: closed | not_owner | inet:posix().
controlling_process(S, NewOwner) ->
case inet_db:lookup_socket(S) of
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index 7d14615c04..8688799ae9 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -25,25 +25,74 @@
-include("inet_int.hrl").
--type hostname() :: inet:hostname().
--type ip_address() :: inet:ip_address().
--type port_number() :: 0..65535.
--type posix() :: inet:posix().
+-type option() ::
+ {active, true | false | once} |
+ {add_membership, {inet:ip_address(), inet:ip_address()}} |
+ {broadcast, boolean()} |
+ {buffer, non_neg_integer()} |
+ {deliver, port | term} |
+ {dontroute, boolean()} |
+ {drop_membership, {inet:ip_address(), inet:ip_address()}} |
+ {header, non_neg_integer()} |
+ {mode, list | binary} | list | binary |
+ {multicast_if, inet:ip_address()} |
+ {multicast_loop, boolean()} |
+ {multicast_ttl, non_neg_integer()} |
+ {priority, non_neg_integer()} |
+ {raw,
+ Protocol :: non_neg_integer(),
+ OptionNum :: non_neg_integer(),
+ ValueBin :: binary()} |
+ {read_packets, non_neg_integer()} |
+ {recbuf, non_neg_integer()} |
+ {reuseaddr, boolean()} |
+ {sndbuf, non_neg_integer()} |
+ {tos, non_neg_integer()}.
+-type option_name() ::
+ active |
+ broadcast |
+ buffer |
+ deliver |
+ dontroute |
+ header |
+ mode |
+ multicast_if |
+ multicast_loop |
+ multicast_ttl |
+ priority |
+ {raw,
+ Protocol :: non_neg_integer(),
+ OptionNum :: non_neg_integer(),
+ ValueSpec :: (ValueSize :: non_neg_integer()) |
+ (ValueBin :: binary())} |
+ read_packets |
+ recbuf |
+ reuseaddr |
+ sndbuf |
+ tos.
-type socket() :: port().
+-export_type([option/0, option_name/0]).
+
-spec open(Port) -> {ok, Socket} | {error, Reason} when
- Port :: port_number(),
+ Port :: inet:port_number(),
Socket :: socket(),
- Reason :: posix().
+ Reason :: inet:posix().
open(Port) ->
open(Port, []).
-spec open(Port, Opts) -> {ok, Socket} | {error, Reason} when
- Port :: port_number(),
- Opts :: [Opt :: term()],
+ Port :: inet:port_number(),
+ Opts :: [Option],
+ Option :: {ip, inet:ip_address()}
+ | {fd, non_neg_integer()}
+ | {ifaddr, inet:ip_address()}
+ | inet:address_family()
+ | {port, inet:port_number()}
+ | option(),
Socket :: socket(),
- Reason :: posix().
+ Reason :: inet:posix().
open(Port, Opts) ->
Mod = mod(Opts, undefined),
@@ -58,10 +107,10 @@ close(S) ->
-spec send(Socket, Address, Port, Packet) -> ok | {error, Reason} when
Socket :: socket(),
- Address :: ip_address() | hostname(),
- Port :: port_number(),
- Packet :: string() | binary(),
- Reason :: not_owner | posix().
+ Address :: inet:ip_address() | inet:hostname(),
+ Port :: inet:port_number(),
+ Packet :: iodata(),
+ Reason :: not_owner | inet:posix().
send(S, Address, Port, Packet) when is_port(S) ->
case inet_db:lookup_socket(S) of
@@ -92,10 +141,10 @@ send(S, Packet) when is_port(S) ->
{ok, {Address, Port, Packet}} | {error, Reason} when
Socket :: socket(),
Length :: non_neg_integer(),
- Address :: ip_address(),
- Port :: port_number(),
+ Address :: inet:ip_address(),
+ Port :: inet:port_number(),
Packet :: string() | binary(),
- Reason :: not_owner | posix().
+ Reason :: not_owner | inet:posix().
recv(S,Len) when is_port(S), is_integer(Len) ->
case inet_db:lookup_socket(S) of
@@ -110,10 +159,10 @@ recv(S,Len) when is_port(S), is_integer(Len) ->
Socket :: socket(),
Length :: non_neg_integer(),
Timeout :: timeout(),
- Address :: ip_address(),
- Port :: port_number(),
+ Address :: inet:ip_address(),
+ Port :: inet:port_number(),
Packet :: string() | binary(),
- Reason :: not_owner | posix().
+ Reason :: not_owner | inet:posix().
recv(S,Len,Time) when is_port(S) ->
case inet_db:lookup_socket(S) of
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 5649188c38..48a6f3db65 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -63,8 +63,9 @@
%% timer interface
-export([start_timer/1, timeout/1, timeout/2, stop_timer/1]).
--export_type([family_option/0, hostent/0, hostname/0, ip4_address/0,
- ip6_address/0, ip_address/0, posix/0, socket/0]).
+-export_type([address_family/0, hostent/0, hostname/0, ip4_address/0,
+ ip6_address/0, ip_address/0, posix/0, socket/0,
+ port_number/0]).
%% imports
-import(lists, [append/1, duplicate/2, filter/2, foldl/3]).
@@ -87,98 +88,15 @@
-type ip6_address() :: {0..65535,0..65535,0..65535,0..65535,
0..65535,0..65535,0..65535,0..65535}.
-type ip_address() :: ip4_address() | ip6_address().
--type ip_port() :: 0..65535.
+-type port_number() :: 0..65535.
-type posix() :: exbadport | exbadseq | file:posix().
-type socket() :: port().
-type socket_setopt() ::
- {'raw', non_neg_integer(), non_neg_integer(), binary()} |
- %% TCP/UDP options
- {'reuseaddr', boolean()} |
- {'keepalive', boolean()} |
- {'dontroute', boolean()} |
- {'linger', {boolean(), non_neg_integer()}} |
- {'broadcast', boolean()} |
- {'sndbuf', non_neg_integer()} |
- {'recbuf', non_neg_integer()} |
- {'priority', non_neg_integer()} |
- {'tos', non_neg_integer()} |
- {'nodelay', boolean()} |
- {'multicast_ttl', non_neg_integer()} |
- {'multicast_loop', boolean()} |
- {'multicast_if', ip_address()} |
- {'add_membership', {ip_address(), ip_address()}} |
- {'drop_membership', {ip_address(), ip_address()}} |
- {'header', non_neg_integer()} |
- {'buffer', non_neg_integer()} |
- {'active', boolean() | 'once'} |
- {'packet',
- 0 | 1 | 2 | 4 | 'raw' | 'sunrm' | 'asn1' |
- 'cdr' | 'fcgi' | 'line' | 'tpkt' | 'http' | 'httph' | 'http_bin' | 'httph_bin' } |
- {'mode', 'list' | 'binary'} |
- {'port', 'port', 'term'} |
- {'exit_on_close', boolean()} |
- {'low_watermark', non_neg_integer()} |
- {'high_watermark', non_neg_integer()} |
- {'bit8', 'clear' | 'set' | 'on' | 'off'} |
- {'send_timeout', non_neg_integer() | 'infinity'} |
- {'send_timeout_close', boolean()} |
- {'delay_send', boolean()} |
- {'packet_size', non_neg_integer()} |
- {'read_packets', non_neg_integer()} |
- %% SCTP options
- {'sctp_rtoinfo', #sctp_rtoinfo{}} |
- {'sctp_associnfo', #sctp_assocparams{}} |
- {'sctp_initmsg', #sctp_initmsg{}} |
- {'sctp_nodelay', boolean()} |
- {'sctp_autoclose', non_neg_integer()} |
- {'sctp_disable_fragments', boolean()} |
- {'sctp_i_want_mapped_v4_addr', boolean()} |
- {'sctp_maxseg', non_neg_integer()} |
- {'sctp_primary_addr', #sctp_prim{}} |
- {'sctp_set_peer_primary_addr', #sctp_setpeerprim{}} |
- {'sctp_adaptation_layer', #sctp_setadaptation{}} |
- {'sctp_peer_addr_params', #sctp_paddrparams{}} |
- {'sctp_default_send_param', #sctp_sndrcvinfo{}} |
- {'sctp_events', #sctp_event_subscribe{}} |
- {'sctp_delayed_ack_time', #sctp_assoc_value{}}.
+ gen_sctp:option() | gen_tcp:option() | gen_udp:option().
-type socket_getopt() ::
- {'raw',
- non_neg_integer(), non_neg_integer(), binary()|non_neg_integer()} |
- %% TCP/UDP options
- 'reuseaddr' | 'keepalive' | 'dontroute' | 'linger' |
- 'broadcast' | 'sndbuf' | 'recbuf' | 'priority' | 'tos' | 'nodelay' |
- 'multicast_ttl' | 'multicast_loop' | 'multicast_if' |
- 'add_membership' | 'drop_membership' |
- 'header' | 'buffer' | 'active' | 'packet' | 'mode' | 'port' |
- 'exit_on_close' | 'low_watermark' | 'high_watermark' | 'bit8' |
- 'send_timeout' | 'send_timeout_close' |
- 'delay_send' | 'packet_size' | 'read_packets' |
- %% SCTP options
- {'sctp_status', #sctp_status{}} |
- 'sctp_get_peer_addr_info' |
- {'sctp_get_peer_addr_info', #sctp_status{}} |
- 'sctp_rtoinfo' |
- {'sctp_rtoinfo', #sctp_rtoinfo{}} |
- 'sctp_associnfo' |
- {'sctp_associnfo', #sctp_assocparams{}} |
- 'sctp_initmsg' |
- {'sctp_initmsg', #sctp_initmsg{}} |
- 'sctp_nodelay' | 'sctp_autoclose' | 'sctp_disable_fragments' |
- 'sctp_i_want_mapped_v4_addr' | 'sctp_maxseg' |
- {'sctp_primary_addr', #sctp_prim{}} |
- {'sctp_set_peer_primary_addr', #sctp_setpeerprim{}} |
- 'sctp_adaptation_layer' |
- {'sctp_adaptation_layer', #sctp_setadaptation{}} |
- {'sctp_peer_addr_params', #sctp_paddrparams{}} |
- 'sctp_default_send_param' |
- {'sctp_default_send_param', #sctp_sndrcvinfo{}} |
- 'sctp_events' |
- {'sctp_events', #sctp_event_subscribe{}} |
- 'sctp_delayed_ack_time' |
- {'sctp_delayed_ack_time', #sctp_assoc_value{}}.
-
+ gen_sctp:option_name() | gen_tcp:option_name() | gen_udp:option_name().
-type ether_address() :: [0..255].
-type if_setopt() ::
@@ -196,7 +114,7 @@
'addr' | 'broadaddr' | 'dstaddr' |
'mtu' | 'netmask' | 'flags' |'hwaddr'.
--type family_option() :: 'inet' | 'inet6'.
+-type address_family() :: 'inet' | 'inet6'.
-type protocol_option() :: 'tcp' | 'udp' | 'sctp'.
-type stat_option() ::
'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' |
@@ -229,7 +147,7 @@ close(Socket) ->
peername(Socket) ->
prim_inet:peername(Socket).
--spec setpeername(Socket :: socket(), Address :: {ip_address(), ip_port()}) ->
+-spec setpeername(Socket :: socket(), Address :: {ip_address(), port_number()}) ->
'ok' | {'error', any()}.
setpeername(Socket, {IP,Port}) ->
@@ -246,7 +164,7 @@ setpeername(Socket, undefined) ->
sockname(Socket) ->
prim_inet:sockname(Socket).
--spec setsockname(Socket :: socket(), Address :: {ip_address(), ip_port()}) ->
+-spec setsockname(Socket :: socket(), Address :: {ip_address(), port_number()}) ->
'ok' | {'error', any()}.
setsockname(Socket, {IP,Port}) ->
@@ -254,7 +172,9 @@ setsockname(Socket, {IP,Port}) ->
setsockname(Socket, undefined) ->
prim_inet:setsockname(Socket, undefined).
--spec port(Socket :: socket()) -> {'ok', ip_port()} | {'error', any()}.
+-spec port(Socket) -> {'ok', Port} | {'error', any()} when
+ Socket :: socket(),
+ Port :: port_number().
port(Socket) ->
case prim_inet:sockname(Socket) of
@@ -268,16 +188,18 @@ port(Socket) ->
send(Socket, Packet) ->
prim_inet:send(Socket, Packet).
--spec setopts(Socket :: socket(), Opts :: [socket_setopt()]) ->
- 'ok' | {'error', posix()}.
+-spec setopts(Socket, Options) -> ok | {error, posix()} when
+ Socket :: socket(),
+ Options :: [socket_setopt()].
setopts(Socket, Opts) ->
prim_inet:setopts(Socket, Opts).
-spec getopts(Socket, Options) ->
- {'ok', [socket_setopt()]} | {'error', posix()} when
+ {'ok', OptionValues} | {'error', posix()} when
Socket :: socket(),
- Options :: [socket_getopt()].
+ Options :: [socket_getopt()],
+ OptionValues :: [socket_setopt()].
getopts(Socket, Opts) ->
prim_inet:getopts(Socket, Opts).
@@ -419,14 +341,19 @@ gethostname() ->
gethostname(Socket) ->
prim_inet:gethostname(Socket).
--spec getstat(Socket :: socket()) ->
- {'ok', [{stat_option(), integer()}]} | {'error', posix()}.
+-spec getstat(Socket) ->
+ {ok, OptionValues} | {error, posix()} when
+ Socket :: socket(),
+ OptionValues :: [{stat_option(), integer()}].
getstat(Socket) ->
prim_inet:getstat(Socket, stats()).
--spec getstat(Socket :: socket(), Statoptions :: [stat_option()]) ->
- {'ok', [{stat_option(), integer()}]} | {'error', posix()}.
+-spec getstat(Socket, Options) ->
+ {ok, OptionValues} | {error, posix()} when
+ Socket :: socket(),
+ Options :: [stat_option()],
+ OptionValues :: [{stat_option(), integer()}].
getstat(Socket,What) ->
prim_inet:getstat(Socket, What).
@@ -441,14 +368,14 @@ gethostbyname(Name) ->
-spec gethostbyname(Hostname, Family) ->
{ok, Hostent} | {error, posix()} when
Hostname :: hostname(),
- Family :: family_option(),
+ Family :: address_family(),
Hostent :: hostent().
gethostbyname(Name,Family) ->
gethostbyname_tm(Name, Family, false).
-spec gethostbyname(Name :: hostname(),
- Family :: family_option(),
+ Family :: address_family(),
Timeout :: non_neg_integer() | 'infinity') ->
{'ok', #hostent{}} | {'error', posix()}.
@@ -527,14 +454,14 @@ getfd(Socket) ->
-spec getaddr(Host, Family) -> {ok, Address} | {error, posix()} when
Host :: ip_address() | hostname(),
- Family :: family_option(),
+ Family :: address_family(),
Address :: ip_address().
getaddr(Address, Family) ->
getaddr(Address, Family, infinity).
-spec getaddr(Host :: ip_address() | hostname(),
- Family :: family_option(),
+ Family :: address_family(),
Timeout :: non_neg_integer() | 'infinity') ->
{'ok', ip_address()} | {'error', posix()}.
@@ -553,14 +480,14 @@ getaddr_tm(Address, Family, Timer) ->
-spec getaddrs(Host, Family) ->
{ok, Addresses} | {error, posix()} when
Host :: ip_address() | hostname(),
- Family :: family_option(),
+ Family :: address_family(),
Addresses :: [ip_address()].
getaddrs(Address, Family) ->
getaddrs(Address, Family, infinity).
-spec getaddrs(Host :: ip_address() | string() | atom(),
- Family :: family_option(),
+ Family :: address_family(),
Timeout :: non_neg_integer() | 'infinity') ->
{'ok', [ip_address()]} | {'error', posix()}.
@@ -570,7 +497,7 @@ getaddrs(Address, Family, Timeout) ->
stop_timer(Timer),
Res.
--spec getservbyport(Port :: ip_port(), Protocol :: atom() | string()) ->
+-spec getservbyport(Port :: port_number(), Protocol :: atom() | string()) ->
{'ok', string()} | {'error', posix()}.
getservbyport(Port, Proto) ->
@@ -584,7 +511,7 @@ getservbyport(Port, Proto) ->
-spec getservbyname(Name :: atom() | string(),
Protocol :: atom() | string()) ->
- {'ok', ip_port()} | {'error', posix()}.
+ {'ok', port_number()} | {'error', posix()}.
getservbyname(Name, Protocol) when is_atom(Name) ->
case inet_udp:open(0, []) of
@@ -1067,7 +994,7 @@ gethostbyaddr_tm_native(Addr, Timer, Opts) ->
-spec open(Fd :: integer(),
Addr :: ip_address(),
- Port :: ip_port(),
+ Port :: port_number(),
Opts :: [socket_setopt()],
Protocol :: protocol_option(),
Family :: 'inet' | 'inet6',
@@ -1108,7 +1035,7 @@ open(Fd, _Addr, _Port, Opts, Protocol, Family, Module) ->
-spec fdopen(Fd :: non_neg_integer(),
Opts :: [socket_setopt()],
Protocol :: protocol_option(),
- Family :: family_option(),
+ Family :: address_family(),
Module :: atom()) ->
{'ok', socket()} | {'error', posix()}.
diff --git a/lib/kernel/src/inet_res.erl b/lib/kernel/src/inet_res.erl
index d1f5644ff7..59ba408d7a 100644
--- a/lib/kernel/src/inet_res.erl
+++ b/lib/kernel/src/inet_res.erl
@@ -407,7 +407,7 @@ gethostbyname(Name) ->
-spec gethostbyname(Name, Family) -> {ok, Hostent} | {error, Reason} when
Name :: dns_name(),
Hostent :: inet:hostent(),
- Family :: inet:family_option(),
+ Family :: inet:address_family(),
Reason :: inet:posix() | res_error().
gethostbyname(Name,Family) ->
@@ -418,7 +418,7 @@ gethostbyname(Name,Family) ->
Name :: dns_name(),
Hostent :: inet:hostent(),
Timeout :: timeout(),
- Family :: inet:family_option(),
+ Family :: inet:address_family(),
Reason :: inet:posix() | res_error().
gethostbyname(Name,Family,Timeout) ->
diff --git a/lib/kernel/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl
index 4ae4151004..2c5b8ccb66 100644
--- a/lib/kernel/test/application_SUITE.erl
+++ b/lib/kernel/test/application_SUITE.erl
@@ -967,7 +967,7 @@ otp_1586(doc) ->
["Test recursive load of applications."];
otp_1586(Conf) when is_list(Conf) ->
Dir = ?config(priv_dir,Conf),
- {ok, Fd} = file:open(filename:join(Dir, "app5.app"), write),
+ {ok, Fd} = file:open(filename:join(Dir, "app5.app"), [write]),
w_app5(Fd),
file:close(Fd),
?line code:add_patha(Dir),
@@ -1021,10 +1021,10 @@ otp_2012(Conf) when is_list(Conf) ->
?line yes = global:register_name(conf_change, CcPid),
% Write a .app file
- {ok, Fd} = file:open("app1.app", write),
+ {ok, Fd} = file:open("app1.app", [write]),
w_app1(Fd),
file:close(Fd),
- {ok, Fd2} = file:open("app2.app", write),
+ {ok, Fd2} = file:open("app2.app", [write]),
w_app1(Fd2),
file:close(Fd2),
@@ -1096,7 +1096,7 @@ otp_2973(doc) ->
["Test of two processes simultanously starting the same application."];
otp_2973(Conf) when is_list(Conf) ->
% Write a .app file
- {ok, Fd} = file:open("app0.app", write),
+ {ok, Fd} = file:open("app0.app", [write]),
w_app(Fd, app0()),
file:close(Fd),
@@ -1138,7 +1138,7 @@ otp_2973(Conf) when is_list(Conf) ->
% Write a .app file
- ?line {ok, Fda} = file:open("app_start_error.app", write),
+ ?line {ok, Fda} = file:open("app_start_error.app", [write]),
?line w_app_start_error(Fda),
?line file:close(Fda),
@@ -1273,12 +1273,12 @@ otp_4066(Conf) when is_list(Conf) ->
App1Nodes = {app1, AllNodes},
Dir = ?config(priv_dir,Conf),
- ?line {ok, FdC} = file:open(filename:join(Dir, "otp_4066.config"), write),
+ ?line {ok, FdC} = file:open(filename:join(Dir, "otp_4066.config"), [write]),
?line write_config(FdC, config_4066(AllNodes, 5000, [App1Nodes])),
?line file:close(FdC),
% Write the app1.app file
- ?line {ok, FdA12} = file:open(filename:join(Dir, "app1.app"), write),
+ ?line {ok, FdA12} = file:open(filename:join(Dir, "app1.app"), [write]),
?line w_app1(FdA12),
?line file:close(FdA12),
@@ -1441,7 +1441,7 @@ otp_5606(Conf) when is_list(Conf) ->
%% Write a config file
Dir = ?config(priv_dir, Conf),
- {ok, Fd} = file:open(filename:join(Dir, "sys.config"), write),
+ {ok, Fd} = file:open(filename:join(Dir, "sys.config"), [write]),
NodeNames = [Ncp1, Ncp2] = node_names([cp1, cp2], Conf),
(config4(NodeNames))(Fd, 10000),
file:close(Fd),
@@ -2436,7 +2436,7 @@ start_node_config_sf(Name, SysConfigFun, Conf) ->
write_config_file(SysConfigFun, Conf) ->
Dir = ?config(priv_dir, Conf),
- {ok, Fd} = file:open(filename:join(Dir, "sys.config"), write),
+ {ok, Fd} = file:open(filename:join(Dir, "sys.config"), [write]),
SysConfigFun(Fd),
file:close(Fd),
filename:join(Dir,"sys").
@@ -2571,15 +2571,15 @@ cc(List) ->
create_app() ->
?line Dir = "./",
?line App1 = Dir ++ "app1",
- ?line {ok, Fd1} = file:open(App1++".app",write),
+ ?line {ok, Fd1} = file:open(App1++".app",[write]),
?line io:format(Fd1, "~p. \n", [app1()]),
?line file:close(Fd1),
?line App2 = Dir ++ "app2",
- ?line {ok, Fd2} = file:open(App2++".app",write),
+ ?line {ok, Fd2} = file:open(App2++".app",[write]),
?line io:format(Fd2, "~p. \n", [app2()]),
?line file:close(Fd2),
?line App3 = Dir ++ "app_sp",
- ?line {ok, Fd3} = file:open(App3++".app",write),
+ ?line {ok, Fd3} = file:open(App3++".app",[write]),
?line io:format(Fd3, "~p. \n", [app_sp()]),
?line file:close(Fd3),
ok.
@@ -2591,7 +2591,7 @@ create_script(ScriptName) ->
?line Apps = which_applications(),
?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps),
?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps),
- ?line {ok,Fd} = file:open(Name++".rel",write),
+ ?line {ok,Fd} = file:open(Name++".rel",[write]),
?line io:format(Fd,
"{release, {\"Test release 3\", \"LATEST\"}, \n"
" {erts, \"4.4\"}, \n"
@@ -2610,7 +2610,7 @@ create_script_dc(ScriptName) ->
?line Apps = which_applications(),
?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps),
?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps),
- ?line {ok,Fd} = file:open(Name++".rel",write),
+ ?line {ok,Fd} = file:open(Name++".rel",[write]),
?line io:format(Fd,
"{release, {\"Test release 3\", \"LATEST\"}, \n"
" {erts, \"4.4\"}, \n"
@@ -2630,7 +2630,7 @@ create_script_3002(ScriptName) ->
?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps),
?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps),
?line {value,{_,_,SaslVer}} = lists:keysearch(sasl,1,Apps),
- ?line {ok,Fd} = file:open(Name++".rel",write),
+ ?line {ok,Fd} = file:open(Name++".rel",[write]),
?line io:format(Fd,
"{release, {\"Test release 3\", \"LATEST\"}, \n"
" {erts, \"4.4\"}, \n"
@@ -2646,22 +2646,22 @@ create_script_3002(ScriptName) ->
distr_changed_prep(Conf) when is_list(Conf) ->
% Write .app files
- ?line {ok, Fd1} = file:open("app1.app", write),
+ ?line {ok, Fd1} = file:open("app1.app", [write]),
?line w_app1(Fd1),
?line file:close(Fd1),
- ?line {ok, Fd2} = file:open("app2.app", write),
+ ?line {ok, Fd2} = file:open("app2.app", [write]),
?line w_app2(Fd2),
?line file:close(Fd2),
- ?line {ok, Fd3} = file:open("app3.app", write),
+ ?line {ok, Fd3} = file:open("app3.app", [write]),
?line w_app3(Fd3),
?line file:close(Fd3),
- ?line {ok, Fd4} = file:open("app6.app", write),
+ ?line {ok, Fd4} = file:open("app6.app", [write]),
?line w_app6(Fd4),
?line file:close(Fd4),
- ?line {ok, Fd5} = file:open("app7.app", write),
+ ?line {ok, Fd5} = file:open("app7.app", [write]),
?line w_app7(Fd5),
?line file:close(Fd5),
- ?line {ok, Fd6} = file:open("app8.app", write),
+ ?line {ok, Fd6} = file:open("app8.app", [write]),
?line w_app8(Fd6),
?line file:close(Fd6),
@@ -2683,7 +2683,7 @@ distr_changed_prep(Conf) when is_list(Conf) ->
WithSyncTime = config_fun(config_dc(NodeNames)),
?line Dir = ?config(priv_dir,Conf),
- ?line {ok, Fd_dc2} = file:open(filename:join(Dir, "sys2.config"), write),
+ ?line {ok, Fd_dc2} = file:open(filename:join(Dir, "sys2.config"), [write]),
?line (config_dc2(NodeNames))(Fd_dc2),
?line file:close(Fd_dc2),
?line Config2 = filename:join(Dir, "sys2"),
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 3ad49254f1..86cccebc29 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -258,8 +258,8 @@ replace_path(Config) when is_list(Config) ->
%% Add a completly new application.
- NewAppName = "blurf_blarfer",
- ?line NewAppDir = filename:join(Cwd, NewAppName ++ "-6.33.1"),
+ NewAppName = 'blurf_blarfer',
+ ?line NewAppDir = filename:join(Cwd, atom_to_list(NewAppName) ++ "-6.33.1"),
?line ok = file:make_dir(NewAppDir),
?line true = code:replace_path(NewAppName, NewAppDir),
?line NewAppDir = code:lib_dir(NewAppName),
@@ -410,8 +410,10 @@ all_loaded_1() ->
?line Loaded2 = match_and_remove(Preloaded, Loaded1),
ObjExt = code:objfile_extension(),
- ?line [] = lists:filter(fun({Mod,AbsName}) when is_atom(Mod), is_list(AbsName) ->
- Mod =:= filename:basename(AbsName, ObjExt);
+ ?line [] = lists:filter(fun({Mod,AbsName}) when is_atom(Mod),
+ is_list(AbsName) ->
+ Mod =/= list_to_atom(filename:basename(AbsName,
+ ObjExt));
(_) -> true
end,
Loaded2),
@@ -1023,8 +1025,8 @@ mult_lib_roots(Config) when is_list(Config) ->
"my_dummy_app-c/ebin/code_SUITE_mult_root_module"),
%% Set up ERL_LIBS and start a slave node.
- ErlLibs = filename:join(DataDir, first_root) ++ mult_lib_sep() ++
- filename:join(DataDir, second_root),
+ ErlLibs = filename:join(DataDir, "first_root") ++ mult_lib_sep() ++
+ filename:join(DataDir, "second_root"),
?line {ok,Node} =
?t:start_node(mult_lib_roots, slave,
@@ -1344,7 +1346,7 @@ create_script(Config) ->
?line Apps = application_controller:which_applications(),
?line {value,{_,_,KernelVer}} = lists:keysearch(kernel, 1, Apps),
?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib, 1, Apps),
- ?line {ok,Fd} = file:open(Name ++ ".rel", write),
+ ?line {ok,Fd} = file:open(Name ++ ".rel", [write]),
?line io:format(Fd,
"{release, {\"Test release 3\", \"P2A\"}, \n"
" {erts, \"9.42\"}, \n"
@@ -1409,7 +1411,7 @@ create_big_script(Config,Local) ->
%% Now we should have only "real" applications...
?line [application:load(list_to_atom(Y)) || {match,[Y]} <- [ re:run(X,code:lib_dir()++"/"++"([^/-]*).*/ebin",[{capture,[1],list}]) || X <- code:get_path()],filter_app(Y,Local)],
?line Apps = [ {N,V} || {N,_,V} <- application:loaded_applications()],
- ?line {ok,Fd} = file:open(Name ++ ".rel", write),
+ ?line {ok,Fd} = file:open(Name ++ ".rel", [write]),
?line io:format(Fd,
"{release, {\"Test release 3\", \"P2A\"}, \n"
" {erts, \"9.42\"}, \n"
diff --git a/lib/kernel/test/disk_log_SUITE.erl b/lib/kernel/test/disk_log_SUITE.erl
index 4ae47b4762..ee1e2319b5 100644
--- a/lib/kernel/test/disk_log_SUITE.erl
+++ b/lib/kernel/test/disk_log_SUITE.erl
@@ -4917,7 +4917,7 @@ mark(FileName, What) ->
ok = file:close(Fd).
crash(File, Where) ->
- {ok, Fd} = file:open(File, read_write),
+ {ok, Fd} = file:open(File, [read,write]),
file:position(Fd, Where),
ok = file:write(Fd, [10]),
ok = file:close(Fd).
@@ -4933,7 +4933,7 @@ writable(Fname) ->
file:write_file_info(Fname, Info#file_info{mode = Mode}).
truncate(File, Where) ->
- {ok, Fd} = file:open(File, read_write),
+ {ok, Fd} = file:open(File, [read,write]),
file:position(Fd, Where),
ok = file:truncate(Fd),
ok = file:close(Fd).
diff --git a/lib/kernel/test/erl_prim_loader_SUITE.erl b/lib/kernel/test/erl_prim_loader_SUITE.erl
index f47c4603cf..7599a89779 100644
--- a/lib/kernel/test/erl_prim_loader_SUITE.erl
+++ b/lib/kernel/test/erl_prim_loader_SUITE.erl
@@ -547,8 +547,6 @@ host() ->
stop_node(Node) ->
test_server:stop_node(Node).
-get_loader_flag({ose,_}) ->
- " -loader ose_inet ";
get_loader_flag(_) ->
" -loader inet ".
diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl
index fd4685cdad..cbaec2d6dd 100644
--- a/lib/kernel/test/gen_tcp_api_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_api_SUITE.erl
@@ -158,6 +158,10 @@ t_shutdown_error(Config) when is_list(Config) ->
t_fdopen(Config) when is_list(Config) ->
?line Question = "Aaaa... Long time ago in a small town in Germany,",
+ ?line Question1 = list_to_binary(Question),
+ ?line Question2 = [<<"Aaaa">>, "... ", $L, <<>>, $o, "ng time ago ",
+ ["in ", [], <<"a small town">>, [" in Germany,", <<>>]]],
+ ?line Question1 = iolist_to_binary(Question2),
?line Answer = "there was a shoemaker, Schumacher was his name.",
?line {ok, L} = gen_tcp:listen(0, [{active, false}]),
?line {ok, Port} = inet:port(L),
@@ -167,6 +171,10 @@ t_fdopen(Config) when is_list(Config) ->
?line {ok, Server} = gen_tcp:fdopen(FD, []),
?line ok = gen_tcp:send(Client, Question),
?line {ok, Question} = gen_tcp:recv(Server, length(Question), 2000),
+ ?line ok = gen_tcp:send(Client, Question1),
+ ?line {ok, Question} = gen_tcp:recv(Server, length(Question), 2000),
+ ?line ok = gen_tcp:send(Client, Question2),
+ ?line {ok, Question} = gen_tcp:recv(Server, length(Question), 2000),
?line ok = gen_tcp:send(Server, Answer),
?line {ok, Answer} = gen_tcp:recv(Client, length(Answer), 2000),
?line ok = gen_tcp:close(Client),
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index b734d7fd98..514deaf065 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -201,13 +201,21 @@ binary_passive_recv(suite) ->
binary_passive_recv(doc) ->
["OTP-3823 gen_udp:recv does not return address in binary mode"];
binary_passive_recv(Config) when is_list(Config) ->
- ?line D = "The quick brown fox jumps over a lazy dog",
- ?line B = list_to_binary(D),
+ ?line D1 = "The quick brown fox jumps over a lazy dog",
+ ?line D2 = list_to_binary(D1),
+ ?line D3 = ["The quick", <<" brown ">>, "fox jumps ", <<"over ">>,
+ <<>>, $a, [[], " lazy ", <<"dog">>]],
+ ?line D2 = iolist_to_binary(D3),
+ ?line B = D2,
?line {ok, R} = gen_udp:open(0, [binary, {active, false}]),
?line {ok, RP} = inet:port(R),
?line {ok, S} = gen_udp:open(0),
?line {ok, SP} = inet:port(S),
- ?line ok = gen_udp:send(S, localhost, RP, D),
+ ?line ok = gen_udp:send(S, localhost, RP, D1),
+ ?line {ok, {{127, 0, 0, 1}, SP, B}} = gen_udp:recv(R, byte_size(B)+1),
+ ?line ok = gen_udp:send(S, localhost, RP, D2),
+ ?line {ok, {{127, 0, 0, 1}, SP, B}} = gen_udp:recv(R, byte_size(B)+1),
+ ?line ok = gen_udp:send(S, localhost, RP, D3),
?line {ok, {{127, 0, 0, 1}, SP, B}} = gen_udp:recv(R, byte_size(B)+1),
?line ok = gen_udp:close(S),
?line ok = gen_udp:close(R),
diff --git a/lib/kernel/test/global_group_SUITE.erl b/lib/kernel/test/global_group_SUITE.erl
index 13b2fd07b5..799b0d9d05 100644
--- a/lib/kernel/test/global_group_SUITE.erl
+++ b/lib/kernel/test/global_group_SUITE.erl
@@ -100,7 +100,7 @@ start_gg_proc(Config) when is_list(Config) ->
?line Dir = ?config(priv_dir, Config),
?line File = filename:join(Dir, "global_group.config"),
- ?line {ok, Fd}=file:open(File, write),
+ ?line {ok, Fd}=file:open(File, [write]),
[Ncp1,Ncp2,Ncp3] = node_names([cp1, cp2, cp3], Config),
?line config(Fd, Ncp1, Ncp2, Ncp3, "cpx", "cpy", "cpz", "cpq"),
@@ -135,7 +135,7 @@ no_gg_proc(Config) when is_list(Config) ->
?line Dir = ?config(priv_dir, Config),
?line File = filename:join(Dir, "no_global_group.config"),
- ?line {ok, Fd} = file:open(File, write),
+ ?line {ok, Fd} = file:open(File, [write]),
?line config_no(Fd),
?line NN = node_name(atom_to_list(node())),
@@ -308,7 +308,7 @@ no_gg_proc_sync(Config) when is_list(Config) ->
?line Dir = ?config(priv_dir, Config),
?line File = filename:join(Dir, "no_global_group_sync.config"),
- ?line {ok, Fd} = file:open(File, write),
+ ?line {ok, Fd} = file:open(File, [write]),
[Ncp1,Ncp2,Ncp3,Ncpx,Ncpy,Ncpz] =
node_names([cp1,cp2,cp3,cpx,cpy,cpz], Config),
@@ -482,7 +482,7 @@ compatible(Config) when is_list(Config) ->
?line Dir = ?config(priv_dir, Config),
?line File = filename:join(Dir, "global_group_comp.config"),
- ?line {ok, Fd} = file:open(File, write),
+ ?line {ok, Fd} = file:open(File, [write]),
[Ncp1,Ncp2,Ncp3,Ncpx,Ncpy,Ncpz] =
node_names([cp1,cp2,cp3,cpx,cpy,cpz], Config),
@@ -655,7 +655,7 @@ one_grp(Config) when is_list(Config) ->
?line Dir = ?config(priv_dir, Config),
?line File = filename:join(Dir, "global_group.config"),
- ?line {ok, Fd} = file:open(File, write),
+ ?line {ok, Fd} = file:open(File, [write]),
[Ncp1,Ncp2,Ncp3] = node_names([cp1, cp2, cp3], Config),
?line config(Fd, Ncp1, Ncp2, Ncp3, "cpx", "cpy", "cpz", "cpq"),
@@ -742,7 +742,7 @@ one_grp_x(Config) when is_list(Config) ->
?line Dir = ?config(priv_dir, Config),
?line File = filename:join(Dir, "global_group.config"),
- ?line {ok, Fd} = file:open(File, write),
+ ?line {ok, Fd} = file:open(File, [write]),
[Ncp1,Ncp2,Ncp3] = node_names([cp1, cp2, cp3], Config),
?line config(Fd, Ncp1, Ncp2, Ncp3, "cpx", "cpy", "cpz", "cpq"),
@@ -804,7 +804,7 @@ two_grp(Config) when is_list(Config) ->
?line Dir = ?config(priv_dir, Config),
?line File = filename:join(Dir, "global_group.config"),
- ?line {ok, Fd} = file:open(File, write),
+ ?line {ok, Fd} = file:open(File, [write]),
[Ncp1,Ncp2,Ncp3,Ncpx,Ncpy,Ncpz,Ncpq] =
node_names([cp1,cp2,cp3,cpx,cpy,cpz,cpq], Config),
@@ -1104,7 +1104,7 @@ hidden_groups(Config) when is_list(Config) ->
?line Dir = ?config(priv_dir, Config),
?line File = filename:join(Dir, "global_group.config"),
- ?line {ok, Fd} = file:open(File, write),
+ ?line {ok, Fd} = file:open(File, [write]),
[Ncp1,Ncp2,Ncp3,Ncpx,Ncpy,Ncpz,Ncpq] =
node_names([cp1,cp2,cp3,cpx,cpy,cpz,cpq], Config),
diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl
index 2db0f7dcb8..b39fadd65f 100644
--- a/lib/kernel/test/init_SUITE.erl
+++ b/lib/kernel/test/init_SUITE.erl
@@ -656,7 +656,7 @@ create_script(Config) ->
?line Apps = application_controller:which_applications(),
?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps),
?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps),
- ?line {ok,Fd} = file:open(Name ++ ".rel", write),
+ ?line {ok,Fd} = file:open(Name ++ ".rel", [write]),
?line io:format(Fd,
"{release, {\"Test release 3\", \"P2A\"}, \n"
" {erts, \"4.4\"}, \n"
diff --git a/lib/kernel/test/ram_file_SUITE.erl b/lib/kernel/test/ram_file_SUITE.erl
index 9b3fbb91fc..ab95a3ff5f 100644
--- a/lib/kernel/test/ram_file_SUITE.erl
+++ b/lib/kernel/test/ram_file_SUITE.erl
@@ -552,7 +552,7 @@ large_file_light(Config) when is_list(Config) ->
?line PrivDir = ?config(priv_dir, Config),
%% Marker for next test case that is to heavy to run in a suite.
?line ok = ?FILE_MODULE:write_file(
- filename:join(PrivDir, large_file_light),
+ filename:join(PrivDir, "large_file_light"),
<<"TAG">>),
%%
?line Data = "abcdefghijklmnopqrstuvwzyz",
@@ -582,7 +582,7 @@ large_file_heavy(Config) when is_list(Config) ->
?line PrivDir = ?config(priv_dir, Config),
%% Check previous test case marker.
case ?FILE_MODULE:read_file_info(
- filename:join(PrivDir, large_file_light)) of
+ filename:join(PrivDir, "large_file_light")) of
{ok,_} ->
{skipped,"Too heavy for casual testing!"};
_ ->
diff --git a/lib/kernel/test/zlib_SUITE.erl b/lib/kernel/test/zlib_SUITE.erl
index 9eb84c9167..4ad9c6923d 100644
--- a/lib/kernel/test/zlib_SUITE.erl
+++ b/lib/kernel/test/zlib_SUITE.erl
@@ -412,6 +412,7 @@ api_crc32(Config) when is_list(Config) ->
Compressed = list_to_binary(Compressed1 ++ Compressed2),
CRC1 = ?m( CRC1 when is_integer(CRC1), zlib:crc32(Z1)),
?m(CRC1 when is_integer(CRC1), zlib:crc32(Z1,Bin)),
+ ?m(CRC1 when is_integer(CRC1), zlib:crc32(Z1,binary_to_list(Bin))),
?m(CRC2 when is_integer(CRC2), zlib:crc32(Z1,Compressed)),
CRC2 = ?m(CRC2 when is_integer(CRC2), zlib:crc32(Z1,0,Compressed)),
?m(CRC3 when CRC2 /= CRC3, zlib:crc32(Z1,234,Compressed)),
@@ -437,6 +438,7 @@ api_adler32(Config) when is_list(Config) ->
Compressed2 = ?m(_, zlib:deflate(Z1, <<>>, finish)),
Compressed = list_to_binary(Compressed1 ++ Compressed2),
?m(ADLER1 when is_integer(ADLER1), zlib:adler32(Z1,Bin)),
+ ?m(ADLER1 when is_integer(ADLER1), zlib:adler32(Z1,binary_to_list(Bin))),
ADLER2 = ?m(ADLER2 when is_integer(ADLER2), zlib:adler32(Z1,Compressed)),
?m(ADLER2 when is_integer(ADLER2), zlib:adler32(Z1,1,Compressed)),
?m(ADLER3 when ADLER2 /= ADLER3, zlib:adler32(Z1,234,Compressed)),
@@ -464,6 +466,7 @@ api_un_compress(Config) when is_list(Config) ->
?m({'EXIT',{data_error,_}}, zlib:uncompress(<<120,156,3>>)),
?m({'EXIT',{data_error,_}}, zlib:uncompress(<<120,156,3,0>>)),
?m({'EXIT',{data_error,_}}, zlib:uncompress(<<0,156,3,0,0,0,0,1>>)),
+ ?m(Bin, zlib:uncompress(binary_to_list(Comp))),
?m(Bin, zlib:uncompress(Comp)).
api_un_zip(doc) -> "Test zip";
@@ -472,10 +475,12 @@ api_un_zip(Config) when is_list(Config) ->
?m(?BARG,zlib:zip(not_a_binary)),
Bin = <<1,11,1,23,45>>,
?line Comp = zlib:zip(Bin),
+ ?m(Comp, zlib:zip(binary_to_list(Bin))),
?m(?BARG,zlib:unzip(not_a_binary)),
?m({'EXIT',{data_error,_}}, zlib:unzip(<<171,171,171,171,171>>)),
?m({'EXIT',{data_error,_}}, zlib:unzip(<<>>)),
?m(Bin, zlib:unzip(Comp)),
+ ?m(Bin, zlib:unzip(binary_to_list(Comp))),
%% OTP-6396
B = <<131,104,19,100,0,13,99,95,99,105,100,95,99,115,103,115,110,95,50,97,1,107,0,4,208,161,246,29,107,0,3,237,166,224,107,0,6,66,240,153,0,2,10,1,0,8,97,116,116,97,99,104,101,100,104,2,100,0,22,117,112,100,97,116,101,95,112,100,112,95,99,111,110,116,101,120,116,95,114,101,113,107,0,114,69,3,12,1,11,97,31,113,150,64,104,132,61,64,104,12,3,197,31,113,150,64,104,132,61,64,104,12,1,11,97,31,115,150,64,104,116,73,64,104,0,0,0,0,0,0,65,149,16,61,65,149,16,61,1,241,33,4,5,0,33,4,4,10,6,10,181,4,10,6,10,181,38,15,99,111,109,109,97,110,100,1,114,45,97,112,110,45,49,3,99,111,109,5,109,110,99,57,57,6,109,99,99,50,52,48,4,103,112,114,115,8,0,104,2,104,2,100,0,8,97,99,116,105,118,97,116,101,104,23,100,0,11,112,100,112,95,99,111,110,116,1,120,116,100,0,7,112,114,105,109,97,114,121,97,1,100,0,9,117,110,100,101,102,105,110,101,100,97,1,97,4,97,4,97,7,100,0,9,117,110,100,101,102,105,110,101,100,100,0,9,117,110,100,101,102,105,110,10100,100,0,9,117,110,100,101,102,105,110,101,100,100,0,5,102,97,108,115,101,100,0,9,117,110,100,101,102,105,110,101,100,100,0,9,117,110,100,101,102,105,110,101,100,100,0,9,117,110,100,101,102,105,1,101,100,97,0,100,0,9,117,110,100,101,102,105,110,101,100,107,0,4,16,0,1,144,107,0,4,61,139,186,181,107,0,4,10,8,201,49,100,0,9,117,110,100,101,102,105,110,101,100,100,0,9,117,110,100,101,102,105,0,101,100,100,0,9,117,110,100,101,102,105,110,101,100,104,2,104,3,98,0,0,7,214,97,11,97,20,104,3,97,17,97,16,97,21,106,108,0,0,0,3,104,2,97,1,104,2,104,3,98,0,0,7,214,97,11,97,20,104,3,97,17,97,167,20,104,2,97,4,104,2,104,3,98,0,0,7,214,97,11,97,20,104,3,97,17,97,16,97,21,104,2,97,10,104,2,104,3,98,0,0,7,214,97,11,97,20,104,3,97,17,97,16,97,26,106,100,0,5,118,101,114,57,57,100,0,9,117,110,0,101,102,105,110,101,100,107,0,2,0,244,107,0,4,10,6,102,195,107,0,4,10,6,102,195,100,0,9,117,110,100,101,102,105,110,101,100,100,0,9,117,110,100,101,102,105,110,101,100,107,0,125,248,143,0,203,25115,157,116,65,185,65,172,55,87,164,88,225,50,203,251,115,157,116,65,185,65,172,55,87,164,88,225,50,0,0,82,153,50,0,200,98,87,148,237,193,185,65,149,167,69,144,14,16,153,50,3,81,70,94,13,109,193,1,120,5,181,113,198,118,50,3,81,70,94,13,109,193,185,120,5,181,113,198,118,153,3,81,70,94,13,109,193,185,120,5,181,113,198,118,153,50,16,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,113,92,2,119,128,0,0,108,0,0,1,107,0,114,69,3,12,1,11,97,31,113,150,64,104,132,61,64,104,12,3,11,97,31,113,150,64,104,132,61,64,104,12,1,11,97,31,115,150,64,104,116,73,64,104,0,0,0,0,0,0,65,149,16,61,65,149,16,61,1,241,33,4,0,33,4,4,10,6,10,181,4,10,6,10,181,38,15,99,111,109,109,97,110,100,101,114,45,97,112,110,45,49,3,99,111,109,5,109,110,99,57,57,6,109,99,99,50,52,48,4,103,112,114,115,8,0,106>>,
@@ -504,10 +509,12 @@ api_g_un_zip(Config) when is_list(Config) ->
?m(?BARG,zlib:gzip(not_a_binary)),
Bin = <<1,11,1,23,45>>,
?line Comp = zlib:gzip(Bin),
+ ?m(Comp, zlib:gzip(binary_to_list(Bin))),
?m(?BARG, zlib:gunzip(not_a_binary)),
?m(?DATA_ERROR, zlib:gunzip(<<171,171,171,171,171>>)),
?m(?DATA_ERROR, zlib:gunzip(<<>>)),
?m(Bin, zlib:gunzip(Comp)),
+ ?m(Bin, zlib:gunzip(binary_to_list(Comp))),
%% Bad CRC; bad length.
BadCrc = bad_crc_data(),
@@ -844,6 +851,7 @@ dictionary_usage({run}) ->
?m(ok, zlib:inflateInit(Z2)),
?line {'EXIT',{{need_dictionary,DictID},_}} = (catch zlib:inflate(Z2, Compressed)),
?m(ok, zlib:inflateSetDictionary(Z2, Dict)),
+ ?m(ok, zlib:inflateSetDictionary(Z2, binary_to_list(Dict))),
?line Uncompressed = ?m(B when is_list(B), zlib:inflate(Z2, [])),
?m(ok, zlib:inflateEnd(Z2)),
?m(ok, zlib:close(Z2)),
diff --git a/lib/observer/src/Makefile b/lib/observer/src/Makefile
index 2d06cb6bc4..3875b62101 100644
--- a/lib/observer/src/Makefile
+++ b/lib/observer/src/Makefile
@@ -56,13 +56,16 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET)
PRIVDIR= ../priv
WEBTOOLFILES= $(PRIVDIR)/crashdump_viewer.tool
BINDIR= $(PRIVDIR)/bin
+ifeq ($(findstring win32,$(TARGET)),win32)
+WIN32_EXECUTABLES= $(BINDIR)/etop.bat $(BINDIR)/getop.bat $(BINDIR)/cdv.bat
+else
+WIN32_EXECUTABLES=
+endif
EXECUTABLES= \
$(BINDIR)/etop \
$(BINDIR)/getop \
$(BINDIR)/cdv \
- $(BINDIR)/etop.bat \
- $(BINDIR)/getop.bat \
- $(BINDIR)/cdv.bat
+ $(WIN32_EXECUTABLES)
CDVDIR= $(PRIVDIR)/crashdump_viewer
GIF_FILES= \
$(CDVDIR)/collapsd.gif \
diff --git a/lib/odbc/c_src/odbcserver.c b/lib/odbc/c_src/odbcserver.c
index 11e311d72d..ab2d7fe210 100644
--- a/lib/odbc/c_src/odbcserver.c
+++ b/lib/odbc/c_src/odbcserver.c
@@ -772,6 +772,7 @@ static db_result_msg db_param_query(byte *buffer, db_state *state)
}
associated_result_set(state) = FALSE;
param_query(state) = TRUE;
+ out_params(state) = FALSE;
msg = encode_empty_message();
diff --git a/lib/odbc/test/odbc_data_type_SUITE.erl b/lib/odbc/test/odbc_data_type_SUITE.erl
index 323190dd99..d61a91f973 100644
--- a/lib/odbc/test/odbc_data_type_SUITE.erl
+++ b/lib/odbc/test/odbc_data_type_SUITE.erl
@@ -89,17 +89,15 @@ init_per_group(GroupName, Config) when GroupName == fixed_char;
end;
init_per_group(unicode, Config) ->
- %% Uses parameterized queries
- case {os:type(), erlang:system_info(wordsize)} of
+ case {os:type(), erlang:system_info({wordsize, external})} of
{{unix, _}, 4} ->
Config;
{{unix, _}, _} ->
- {skip, "Not supported by driver"};
+ {skip, "Postgres drivers pre version psqlODBC 08.04.0200 have utf8-problems"};
_ ->
Config
end;
-
init_per_group(_GroupName, Config) ->
Config.
diff --git a/lib/odbc/test/odbc_test_lib.erl b/lib/odbc/test/odbc_test_lib.erl
index 2d6bf5fcac..4d7d1ae2fa 100644
--- a/lib/odbc/test/odbc_test_lib.erl
+++ b/lib/odbc/test/odbc_test_lib.erl
@@ -97,10 +97,13 @@ linux_issue() ->
string:tokens(binary_to_list(Binary), " ").
is_sles11(IssueTokens) ->
- lists:member(11, IssueTokens).
+ lists:member("11", IssueTokens).
is_sles10(IssueTokens) ->
- lists:member(10, IssueTokens).
+ lists:member("10", IssueTokens).
is_sles9(IssueTokens) ->
- lists:member(9, IssueTokens).
+ lists:member("9", IssueTokens).
+
+is_ubuntu(IssueTokens) ->
+ lists:member("Ubuntu", IssueTokens).
diff --git a/lib/parsetools/doc/src/yecc.xml b/lib/parsetools/doc/src/yecc.xml
index c712609cf4..1d2a985d7d 100644
--- a/lib/parsetools/doc/src/yecc.xml
+++ b/lib/parsetools/doc/src/yecc.xml
@@ -425,9 +425,9 @@ myparser:parse_and_scan({Mod, Tokenizer, Args}) </code>
Nonterminals E T F.
Terminals '+' '*' '(' ')' number.
Rootsymbol E.
-E -> E '+' T: ['$1', '$2', '$3'].
+E -> E '+' T: ['$2', '$1', '$3'].
E -> T : '$1'.
-T -> T '*' F: ['$1', '$2', '$3'].
+T -> T '*' F: ['$2', '$1', '$3'].
T -> F : '$1'.
F -> '(' E ')' : '$2'.
F -> number : '$1'. </code>
@@ -438,8 +438,8 @@ Terminals '+' '*' '(' ')' number.
Rootsymbol E.
Left 100 '+'.
Left 200 '*'.
-E -> E '+' E : ['$1', '$2', '$3'].
-E -> E '*' E : ['$1', '$2', '$3'].
+E -> E '+' E : ['$2', '$1', '$3'].
+E -> E '*' E : ['$2', '$1', '$3'].
E -> '(' E ')' : '$2'.
E -> number : '$1'. </code>
<p>3. An overloaded minus operator:</p>
diff --git a/lib/percept/src/percept_db.erl b/lib/percept/src/percept_db.erl
index 52e9afb78f..61b68ce44f 100644
--- a/lib/percept/src/percept_db.erl
+++ b/lib/percept/src/percept_db.erl
@@ -92,7 +92,7 @@ restart(PerceptDB)->
stop_sync(PerceptDB),
do_start().
-%% @spec do_start(pid()) -> pid()
+%% @spec do_start() -> pid()
%% @private
%% @doc starts the percept database.
@@ -131,6 +131,7 @@ stop_sync(Pid)->
{'DOWN', MonitorRef, _Type, Pid, _Info}->
true
after ?STOP_TIMEOUT->
+ erlang:demonitor(MonitorRef, [flush]),
exit(Pid, kill)
end.
@@ -166,14 +167,14 @@ insert(Trace) ->
select(Query) ->
percept_db ! {select, self(), Query},
- receive Match -> Match end.
+ receive {result, Match} -> Match end.
%% @spec select(atom(), list()) -> Result
%% @equiv select({Table,Options})
select(Table, Options) ->
percept_db ! {select, self(), {Table, Options}},
- receive Match -> Match end.
+ receive {result, Match} -> Match end.
%% @spec consolidate() -> Result
%% @doc Checks timestamp and state-flow inconsistencies in the
@@ -213,7 +214,7 @@ loop_percept_db() ->
insert_trace(clean_trace(Trace)),
loop_percept_db();
{select, Pid, Query} ->
- Pid ! select_query(Query),
+ Pid ! {result, select_query(Query)},
loop_percept_db();
{action, stop} ->
stopped;
@@ -222,7 +223,7 @@ loop_percept_db() ->
loop_percept_db();
{operate, Pid, {Table, {Fun, Start}}} ->
Result = ets:foldl(Fun, Start, Table),
- Pid ! Result,
+ Pid ! {result, Result},
loop_percept_db();
Unhandled ->
io:format("loop_percept_db, unhandled query: ~p~n", [Unhandled]),
diff --git a/lib/sasl/doc/src/release_handler.xml b/lib/sasl/doc/src/release_handler.xml
index 4a973bc5ed..5ac0dc1acc 100644
--- a/lib/sasl/doc/src/release_handler.xml
+++ b/lib/sasl/doc/src/release_handler.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2009</year>
+ <year>1996</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -159,9 +159,12 @@ old reboot_old permanent
<funcs>
<func>
<name>check_install_release(Vsn) -> {ok, OtherVsn, Descr} | {error, Reason}</name>
+ <name>check_install_release(Vsn,Opts) -> {ok, OtherVsn, Descr} | {error, Reason}</name>
<fsummary>Check installation of a release in the system.</fsummary>
<type>
<v>Vsn = OtherVsn = string()</v>
+ <v>Opts = [Opt]</v>
+ <v>Opt = purge</v>
<v>Descr = term()</v>
<v>Reason = term()</v>
</type>
@@ -179,6 +182,11 @@ old reboot_old permanent
upgrade script.</p>
<p>Returns the same as <c>install_release/1</c>. <c>Descr</c>
defaults to "" if no <c>relup</c> file is found.</p>
+ <p>If the option <c>purge</c> is given, all old code that can
+ be soft purged will be purged after all other checks are
+ successfully completed. This can be useful in order to
+ reduce the time needed by <seealso
+ marker="#install_release/1">install_release</seealso>.</p>
</desc>
</func>
<func>
@@ -299,6 +307,24 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
<c>{update_paths,true}</c>, afterwards
<c>code:lib_dir(myapp)</c> will return
<c>/home/user/myapp-1.0</c>.</p>
+ <note>
+ <p>Installing a new release might be quite time consuming if
+ there are many processes in the system. The reason is that
+ each process must be checked for references to old code
+ before a module can be purged. This check might lead to
+ garbage collections and copying of data.</p>
+ <p>If you wish to speed up the execution of
+ <c>install_release</c>, then you may call <seealso
+ marker="#check_install_release/1">check_install_release</seealso>
+ first, using the option <c>purge</c>. This will do the same
+ check for old code, and then purge all modules that can be
+ soft purged. The purged modules will then no longer have any
+ old code, and <c>install_release</c> will not need to do the
+ checks.</p>
+ <p>Obviously, this will not reduce the overall time for the
+ upgrade, but it will allow checks and purge to be executed
+ in the background before the real upgrade is started.</p>
+ </note>
</desc>
</func>
<func>
diff --git a/lib/sasl/examples/src/Makefile b/lib/sasl/examples/src/Makefile
index 4a4e04a536..c58f651696 100644
--- a/lib/sasl/examples/src/Makefile
+++ b/lib/sasl/examples/src/Makefile
@@ -66,7 +66,7 @@ release_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)/examples/src
$(INSTALL_DIR) $(RELSYSDIR)/examples/ebin
(cd ..; tar cf - src ebin | (cd $(RELSYSDIR)/examples; tar xf -))
- chmod -f -R ug+w $(RELSYSDIR)/examples
+ chmod -R ug+w $(RELSYSDIR)/examples
release_docs_spec:
diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl
index ab54b1d00b..bc08f94dff 100644
--- a/lib/sasl/src/release_handler.erl
+++ b/lib/sasl/src/release_handler.erl
@@ -25,8 +25,8 @@
-export([start_link/0,
create_RELEASES/1, create_RELEASES/2, create_RELEASES/4,
unpack_release/1,
- check_install_release/1, install_release/1, install_release/2,
- remove_release/1,
+ check_install_release/1, check_install_release/2,
+ install_release/1, install_release/2, remove_release/1,
which_releases/0, make_permanent/1, reboot_old_release/1,
set_unpacked/2, set_removed/1, install_file/2]).
-export([upgrade_app/2, downgrade_app/2, downgrade_app/3,
@@ -149,15 +149,35 @@ unpack_release(ReleaseName) ->
%%-----------------------------------------------------------------
%% Purpose: Checks the relup script for the specified version.
%% The release must be unpacked.
+%% Options = [purge] - all old code that can be soft purged
+%% will be purged if all checks succeeds. This can be usefull
+%% in order to reduce time needed in the following call to
+%% install_release.
%% Returns: {ok, FromVsn, Descr} | {error, Reason}
-%% Reason = {already_installed, Vsn} |
+%% Reason = {illegal_option, IllegalOpt} |
+%% {already_installed, Vsn} |
%% {bad_relup_file, RelFile} |
%% {no_such_release, Vsn} |
%% {no_such_from_vsn, Vsn} |
%% exit_reason()
%%-----------------------------------------------------------------
check_install_release(Vsn) ->
- call({check_install_release, Vsn}).
+ check_install_release(Vsn, []).
+
+check_install_release(Vsn, Opts) ->
+ case check_check_install_options(Opts, false) of
+ {ok,Purge} ->
+ call({check_install_release, Vsn, Purge});
+ Error ->
+ Error
+ end.
+
+check_check_install_options([purge|Opts], _) ->
+ check_check_install_options(Opts, true);
+check_check_install_options([Illegal|_],_Purge) ->
+ {error,{illegal_option,Illegal}};
+check_check_install_options([],Purge) ->
+ {ok,Purge}.
%%-----------------------------------------------------------------
@@ -541,11 +561,12 @@ handle_call({unpack_release, ReleaseName}, _From, S)
handle_call({unpack_release, _ReleaseName}, _From, S) ->
{reply, {error, client_node}, S};
-handle_call({check_install_release, Vsn}, _From, S) ->
+handle_call({check_install_release, Vsn, Purge}, _From, S) ->
case catch do_check_install_release(S#state.rel_dir,
Vsn,
S#state.releases,
- S#state.masters) of
+ S#state.masters,
+ Purge) of
{ok, CurrentVsn, Descr} ->
{reply, {ok, CurrentVsn, Descr}, S};
{error, Reason} ->
@@ -855,7 +876,7 @@ check_path_response(Path, {ok, _Info}) ->
check_path_response(Path, {error, _Reason}) ->
throw({error, {no_such_directory, Path}}).
-do_check_install_release(RelDir, Vsn, Releases, Masters) ->
+do_check_install_release(RelDir, Vsn, Releases, Masters, Purge) ->
case lists:keysearch(Vsn, #release.vsn, Releases) of
{value, #release{status = current}} ->
{error, {already_installed, Vsn}};
@@ -880,7 +901,20 @@ do_check_install_release(RelDir, Vsn, Releases, Masters) ->
case get_rh_script(LatestRelease, Release, RelDir, Masters) of
{ok, {CurrentVsn, Descr, Script}} ->
case catch check_script(Script, Libs) of
- ok ->
+ {ok,SoftPurgeMods} when Purge=:=true ->
+ %% Get modules with brutal_purge
+ %% instructions, but that can be
+ %% soft purged
+ {ok,BrutalPurgeMods} =
+ release_handler_1:check_old_processes(
+ Script,brutal_purge),
+ lists:foreach(
+ fun(Mod) ->
+ catch erlang:purge_module(Mod)
+ end,
+ SoftPurgeMods ++ BrutalPurgeMods),
+ {ok, CurrentVsn, Descr};
+ {ok,_} ->
{ok, CurrentVsn, Descr};
Else ->
Else
@@ -1967,7 +2001,7 @@ safe_write_file_m(File, Data, Masters) ->
%% 'update_paths' option to release_handler:install_release/2 if the
%% code path shall be updated then.
%% -----------------------------------------------------------------
-get_new_libs([{App,Vsn,LibDir}|CurrentLibs], NewLibs) ->
+get_new_libs([{App,Vsn,_LibDir}|CurrentLibs], NewLibs) ->
case lists:keyfind(App,1,NewLibs) of
{App,NewVsn,_} = LibInfo when NewVsn =/= Vsn ->
[LibInfo | get_new_libs(CurrentLibs,NewLibs)];
diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl
index ff62f847ac..ef95606bb5 100644
--- a/lib/sasl/src/release_handler_1.erl
+++ b/lib/sasl/src/release_handler_1.erl
@@ -19,7 +19,8 @@
-module(release_handler_1).
%% External exports
--export([eval_script/1, eval_script/5, check_script/2]).
+-export([eval_script/1, eval_script/5,
+ check_script/2, check_old_processes/2]).
-export([get_current_vsn/1]). %% exported because used in a test case
-record(eval_state, {bins = [], stopped = [], suspended = [], apps = [],
@@ -47,17 +48,20 @@
%%% This is a low-level release handler.
%%%-----------------------------------------------------------------
check_script(Script, LibDirs) ->
- case catch check_old_processes(Script) of
- ok ->
+ case catch check_old_processes(Script,soft_purge) of
+ {ok, PurgeMods} ->
{Before, _After} = split_instructions(Script),
case catch lists:foldl(fun(Instruction, EvalState1) ->
eval(Instruction, EvalState1)
end,
#eval_state{libdirs = LibDirs},
Before) of
- EvalState2 when is_record(EvalState2, eval_state) -> ok;
- {error, Error} -> {error, Error};
- Other -> {error, Other}
+ EvalState2 when is_record(EvalState2, eval_state) ->
+ {ok,PurgeMods};
+ {error, Error} ->
+ {error, Error};
+ Other ->
+ {error, Other}
end;
{error, Mod} ->
{error, {old_processes, Mod}}
@@ -68,8 +72,8 @@ eval_script(Script) ->
eval_script(Script, [], [], [], []).
eval_script(Script, Apps, LibDirs, NewLibs, Opts) ->
- case catch check_old_processes(Script) of
- ok ->
+ case catch check_old_processes(Script,soft_purge) of
+ {ok,_} ->
{Before, After} = split_instructions(Script),
case catch lists:foldl(fun(Instruction, EvalState1) ->
eval(Instruction, EvalState1)
@@ -112,32 +116,63 @@ split_instructions([], Before) ->
{[], lists:reverse(Before)}.
%%-----------------------------------------------------------------
-%% Func: check_old_processes/1
+%% Func: check_old_processes/2
%% Args: Script = [instruction()]
+%% PrePurgeMethod = soft_purge | brutal_purge
%% Purpose: Check if there is any process that runs an old version
-%% of a module that should be soft_purged, (i.e. not purged
-%% at all if there is any such process). Returns {error, Mod}
-%% if so, ok otherwise.
-%% Returns: ok | {error, Mod}
+%% of a module that should be purged according to PrePurgeMethod.
+%% Returns a list of modules that can be soft_purged.
+%%
+%% If PrePurgeMethod == soft_purge, the function will succeed
+%% only if there is no process running old code of any of the
+%% modules. Else it will throw {error,Mod}, where Mod is the
+%% first module found that can not be soft_purged.
+%%
+%% If PrePurgeMethod == brutal_purge, the function will
+%% always succeed and return a list of all modules that are
+%% specified in the script with PrePurgeMethod brutal_purge,
+%% but that can be soft_purged.
+%%
+%% Returns: {ok,PurgeMods} | {error, Mod}
+%% PurgeMods = [Mod]
%% Mod = atom()
%%-----------------------------------------------------------------
-check_old_processes(Script) ->
- lists:foreach(fun({load, {Mod, soft_purge, _PostPurgeMethod}}) ->
- check_old_code(Mod);
- ({remove, {Mod, soft_purge, _PostPurgeMethod}}) ->
- check_old_code(Mod);
- (_) -> ok
- end,
- Script).
+check_old_processes(Script,PrePurgeMethod) ->
+ Procs = erlang:processes(),
+ {ok,lists:flatmap(
+ fun({load, {Mod, PPM, _PostPurgeMethod}}) when PPM==PrePurgeMethod ->
+ check_old_code(Mod,Procs,PrePurgeMethod);
+ ({remove, {Mod, PPM, _PostPurgeMethod}}) when PPM==PrePurgeMethod ->
+ check_old_code(Mod,Procs,PrePurgeMethod);
+ (_) -> []
+ end,
+ Script)}.
+
+check_old_code(Mod,Procs,PrePurgeMethod) ->
+ case erlang:check_old_code(Mod) of
+ true when PrePurgeMethod==soft_purge ->
+ do_check_old_code(Mod,Procs);
+ true when PrePurgeMethod==brutal_purge ->
+ case catch do_check_old_code(Mod,Procs) of
+ {error,Mod} -> [];
+ R -> R
+ end;
+ false ->
+ []
+ end.
+
+
+do_check_old_code(Mod,Procs) ->
+ lists:foreach(
+ fun(Pid) ->
+ case erlang:check_process_code(Pid, Mod) of
+ false -> ok;
+ true -> throw({error, Mod})
+ end
+ end,
+ Procs),
+ [Mod].
-check_old_code(Mod) ->
- lists:foreach(fun(Pid) ->
- case erlang:check_process_code(Pid, Mod) of
- false -> ok;
- true -> throw({error, Mod})
- end
- end,
- erlang:processes()).
%%-----------------------------------------------------------------
%% An unpurged module is a module for which there exist an old
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index 7489ee58d2..5dc83e7b2a 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -1612,9 +1612,9 @@ var_dir(_Dir, _, _, []) ->
false.
appDir(AppDir) ->
- case reverse(filename:split(AppDir)) of
- ["ebin"|Dir] -> filename:join(reverse(Dir));
- _ -> AppDir
+ case filename:basename(AppDir) of
+ "ebin" -> filename:dirname(AppDir);
+ _ -> AppDir
end.
add_modules(Modules, Tar, AppDir, ToDir, Ext) ->
diff --git a/lib/sasl/test/Makefile b/lib/sasl/test/Makefile
index 0bdb79a06a..65be134462 100644
--- a/lib/sasl/test/Makefile
+++ b/lib/sasl/test/Makefile
@@ -86,7 +86,7 @@ release_tests_spec: make_emakefile
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)
$(INSTALL_DATA) sasl.spec sasl.cover $(EMAKEFILE) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cfh - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl
index 9c7733b7ec..b44da72d35 100644
--- a/lib/sasl/test/release_handler_SUITE.erl
+++ b/lib/sasl/test/release_handler_SUITE.erl
@@ -55,7 +55,10 @@ win32_cases() ->
%% Cases that can be run on all platforms
cases() ->
- [otp_2740, otp_2760, otp_5761, otp_9402, otp_9417, instructions, eval_appup].
+ [otp_2740, otp_2760, otp_5761, otp_9402, otp_9417,
+ otp_9395_check_old_code, otp_9395_check_and_purge,
+ otp_9395_update_many_mods, otp_9395_rm_many_mods,
+ instructions, eval_appup].
groups() ->
[{release,[],
@@ -556,7 +559,7 @@ otp_2760(Conf) ->
LibDir = filename:join([DataDir,app1_app2,lib1]),
Rel1 = create_and_install_fake_first_release(Dir,[{app1,"1.0",LibDir}]),
- Rel2 = create_fake_upgrade_release(Dir,"after",[],{Rel1,Rel1,[LibDir]}),
+ Rel2 = create_fake_upgrade_release(Dir,"after",[],{[Rel1],[Rel1],[LibDir]}),
Rel2Dir = filename:dirname(Rel2),
%% Start a node with Rel1.boot and check that the app1 module is loaded
@@ -569,9 +572,12 @@ otp_2760(Conf) ->
{ok, []} = rpc:call(Node, release_handler_1, eval_script, [Script]),
false = rpc:call(Node, code, is_loaded, [app1]),
- true = stop_node(Node),
ok.
+otp_2760(cleanup,_Conf) ->
+ stop_node(node_name(otp_2760)).
+
+
%% Test upgrade using other filesystem than the defined in OTP and
%% option {update_paths, true}
otp_5761(Conf) when is_list(Conf) ->
@@ -597,7 +603,7 @@ otp_5761(Conf) when is_list(Conf) ->
"2",
[{app1,"2.0",LibDir2},
{app2,"1.0",LibDir2}],
- {Rel1,Rel1,[LibDir1]}),
+ {[Rel1],[Rel1],[LibDir1]}),
Rel1Dir = filename:dirname(Rel1),
Rel2Dir = filename:dirname(Rel2),
@@ -653,10 +659,11 @@ otp_5761(Conf) when is_list(Conf) ->
App11Dir = rpc:call(Node, code, lib_dir, [app1]),
App2aDir = rpc:call(Node, code, lib_dir, [app2]),
- %% Stop the slave node
- true = stop_node(Node),
ok.
+otp_5761(cleanup,_Conf) ->
+ stop_node(node_name(otp_5761)).
+
%% When a new version of an application is added, but no module is
%% changed - the path was not updated - i.e. code:priv_dir would point
@@ -673,7 +680,7 @@ otp_9402(Conf) when is_list(Conf) ->
Rel2 = create_fake_upgrade_release(Dir,
"2",
[{a,"1.2",LibDir}],
- {Rel1,Rel1,[LibDir]}),
+ {[Rel1],[Rel1],[LibDir]}),
Rel1Dir = filename:dirname(Rel1),
Rel2Dir = filename:dirname(Rel2),
@@ -722,6 +729,9 @@ otp_9402(Conf) when is_list(Conf) ->
ok.
+otp_9402(cleanup,_Conf) ->
+ stop_node(node_name(otp_9402)).
+
%% When a module is deleted in an appup instruction, the upgrade
%% failed if the module was not loaded.
@@ -737,7 +747,7 @@ otp_9417(Conf) when is_list(Conf) ->
Rel2 = create_fake_upgrade_release(Dir,
"2",
[{b,"2.0",LibDir}],
- {Rel1,Rel1,[LibDir]}),
+ {[Rel1],[Rel1],[LibDir]}),
Rel1Dir = filename:dirname(Rel1),
Rel2Dir = filename:dirname(Rel2),
@@ -777,6 +787,282 @@ otp_9417(Conf) when is_list(Conf) ->
{file,BServerBeam} = rpc:call(Node,code,is_loaded,[b_server]),
ok.
+otp_9417(cleanup,_Conf) ->
+ stop_node(node_name(otp_9417)).
+
+
+%% OTP-9395 - performance problems when there are MANY processes
+%% Test that the procedure of checking for old code before an upgrade
+%% can be started is "very much faster" when there is no old code in
+%% the system.
+otp_9395_check_old_code(Conf) when is_list(Conf) ->
+
+ NProcs = 1000,
+ MPath = filename:join([?config(data_dir,Conf),"lib","many_mods-1.0","ebin"]),
+ code:add_path(MPath),
+
+ %% Start NProc processes, each referencing each module
+ {Modules,Pids} = m:start(NProcs),
+
+ %% Load each module again in order to get old code
+ [code:load_file(Mod) || Mod <- Modules],
+ true = erlang:check_old_code(m10),
+
+ S = [point_of_no_return |
+ [{remove,{M,soft_purge,soft_purge}} || M <- Modules]],
+
+ %% Do the old code check, then purge, and redo
+ {T1,{ok,PurgeMods}} = timer:tc(release_handler_1,check_script,[S,[]]),
+ true = (lists:sort(PurgeMods) == lists:sort(Modules)),
+ [code:purge(M) || M <- PurgeMods],
+ {T2,{ok,[]}} = timer:tc(release_handler_1,check_script,[S,[]]),
+
+ %% Cleanup
+ lists:foreach(fun(Pid) -> Pid ! stop end, Pids),
+ lists:foreach(fun(Mod) -> code:purge(Mod),
+ code:delete(Mod),
+ code:purge(Mod)
+ end, Modules),
+ code:del_path(MPath),
+
+ %% Test that second run was much faster than the first
+ if T2 > 0 ->
+ X = T1/T2,
+ ct:log("~p procs, ~p mods -> ~n"
+ "\tWith old code: ~.2f sec~n"
+ "\tAfter purge: ~.2f sec~n"
+ "\tT1/T2: ~.2f",
+ [NProcs,length(Modules),T1/1000000,T2/1000000,X]),
+ if X < 1000 ->
+ ct:fail({not_enough_improvement_after_purge,round(X)});
+ true ->
+ ok
+ end;
+ T1 > 0 -> %% Means T1/T2 = infinite
+ ok;
+ true ->
+ ct:fail({unexpected_values,T1,T2})
+ end,
+ ok.
+
+
+%% OTP-9395 - performance problems when there are MANY processes
+%% Added option 'purge' to check_install_release
+otp_9395_check_and_purge(Conf) when is_list(Conf) ->
+ %% Set some paths
+ PrivDir = priv_dir(Conf),
+ Dir = filename:join(PrivDir,"otp_9395_check_and_purge"),
+ LibDir = filename:join(?config(data_dir, Conf), "lib"),
+
+ %% Create the releases
+ Rel1 = create_and_install_fake_first_release(Dir,
+ [{b,"1.0",LibDir}]),
+ Rel2 = create_fake_upgrade_release(Dir,
+ "2",
+ [{b,"2.0",LibDir}],
+ {[Rel1],[Rel1],[LibDir]}),
+ Rel1Dir = filename:dirname(Rel1),
+ Rel2Dir = filename:dirname(Rel2),
+
+ %% Start a slave node
+ {ok, Node} = t_start_node(otp_9395_check_and_purge, Rel1,
+ filename:join(Rel1Dir,"sys.config")),
+
+ %% Make sure there is old code for b_lib and b_server
+ rpc:call(Node,code,load_file,[b_lib]),
+ rpc:call(Node,code,load_file,[b_lib]),
+ rpc:call(Node,code,load_file,[b_server]),
+ rpc:call(Node,code,load_file,[b_server]),
+ true = rpc:call(Node,erlang,check_old_code,[b_lib]),
+ true = rpc:call(Node,erlang,check_old_code,[b_server]),
+
+ %% Unpack second release, which removes b_lib module and loads b_server
+ {ok, RelVsn2} =
+ rpc:call(Node, release_handler, set_unpacked,
+ [Rel2++".rel", [{b,"2.0",LibDir}]]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "relup")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "start.boot")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "sys.config")]),
+
+ %% Do check_install_release, and check that old code still exists
+ {ok, _RelVsn1, []} =
+ rpc:call(Node, release_handler, check_install_release, [RelVsn2]),
+ true = rpc:call(Node,erlang,check_old_code,[b_lib]),
+ true = rpc:call(Node,erlang,check_old_code,[b_server]),
+
+ %% Do check_install_release with option 'purge' and check that old
+ %% code is gone
+ {ok, _RelVsn1, []} =
+ rpc:call(Node, release_handler, check_install_release, [RelVsn2,[purge]]),
+ false = rpc:call(Node,erlang,check_old_code,[b_lib]),
+ false = rpc:call(Node,erlang,check_old_code,[b_server]),
+
+ ok.
+
+otp_9395_check_and_purge(cleanup,_Conf) ->
+ stop_node(node_name(otp_9395_check_and_purge)).
+
+
+%% OTP-9395 - performance problems when there are MANY processes
+%% Upgrade which updates many modules (brutal_purge)
+otp_9395_update_many_mods(Conf) when is_list(Conf) ->
+ %% Set some paths
+ PrivDir = priv_dir(Conf),
+ Dir = filename:join(PrivDir,"otp_9395_update_many_mods"),
+ LibDir = filename:join(?config(data_dir, Conf), "lib"),
+
+ %% Create the releases
+ Rel1 = create_and_install_fake_first_release(Dir,
+ [{many_mods,"1.0",LibDir}]),
+ Rel2 = create_fake_upgrade_release(Dir,
+ "2",
+ [{many_mods,"1.1",LibDir}],
+ {[Rel1],[Rel1],[LibDir]}),
+ Rel1Dir = filename:dirname(Rel1),
+ Rel2Dir = filename:dirname(Rel2),
+
+ %% Start a slave node
+ {ok, Node} = t_start_node(otp_9395_update_many_mods, Rel1,
+ filename:join(Rel1Dir,"sys.config")),
+
+ %% Start a lot of processes on the new node, all with refs to each
+ %% module that will be updated
+ NProcs = 1000,
+ {Modules,Pids1} = rpc:call(Node,m,start,[NProcs]),
+
+ %% Then load modules in order to get old code
+ [rpc:call(Node,code,load_file,[Mod]) || Mod <- Modules],
+ true = rpc:call(Node,erlang,check_old_code,[m10]),
+
+ %% Unpack second release, which updates all mX modules
+ {ok, RelVsn2} =
+ rpc:call(Node, release_handler, set_unpacked,
+ [Rel2++".rel", [{many_mods,"1.1",LibDir}]]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "relup")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "start.boot")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "sys.config")]),
+
+ %% First, install release directly and check how much time it takes
+ {TInst0,{ok, _, []}} =
+ timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn2]]),
+ ct:log("install_release: ~.2f",[TInst0/1000000]),
+
+ %% Restore to old release, spawn processes again and load to get old code
+ {_,RelVsn1} = init:script_id(),
+ {_TInst1,{ok, _, []}} =
+ timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn1]]),
+% ct:log("install_release: ~.2f",[_TInst1/1000000]),
+
+ [exit(Pid,kill) || Pid <- Pids1],
+ {Modules,_Pids2} = rpc:call(Node,m,start,[NProcs]),
+ [rpc:call(Node,code,load_file,[Mod]) || Mod <- Modules],
+ true = rpc:call(Node,erlang,check_old_code,[m10]),
+
+ %% Run check_install_release with purge before install this time
+ {TCheck,{ok, _RelVsn1, []}} =
+ timer:tc(rpc,call,[Node, release_handler, check_install_release,
+ [RelVsn2,[purge]]]),
+ ct:log("check_install_release with purge: ~.2f",[TCheck/1000000]),
+
+ %% Finally install release after check and purge, and check that
+ %% this install was faster than the first.
+ {TInst2,{ok, _RelVsn1, []}} =
+ timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn2]]),
+ ct:log("install_release: ~.2f",[TInst2/1000000]),
+
+ true = (TInst2 < TInst0),
+
+ ok.
+
+otp_9395_update_many_mods(cleanup,_Conf) ->
+ stop_node(node_name(otp_9395_update_many_mods)).
+
+
+%% OTP-9395 - performance problems when there are MANY processes
+%% Upgrade which removes many modules (brutal_purge)
+otp_9395_rm_many_mods(Conf) when is_list(Conf) ->
+ %% Set some paths
+ PrivDir = priv_dir(Conf),
+ Dir = filename:join(PrivDir,"otp_9395_rm_many_mods"),
+ LibDir = filename:join(?config(data_dir, Conf), "lib"),
+
+ %% Create the releases
+ Rel1 = create_and_install_fake_first_release(Dir,
+ [{many_mods,"1.0",LibDir}]),
+ Rel2 = create_fake_upgrade_release(Dir,
+ "2",
+ [{many_mods,"2.0",LibDir}],
+ {[Rel1],[Rel1],[LibDir]}),
+ Rel1Dir = filename:dirname(Rel1),
+ Rel2Dir = filename:dirname(Rel2),
+
+ %% Start a slave node
+ {ok, Node} = t_start_node(otp_9395_rm_many_mods, Rel1,
+ filename:join(Rel1Dir,"sys.config")),
+
+ %% Start a lot of processes on the new node, all with refs to each
+ %% module that will be updated
+ NProcs = 1000,
+ {Modules,Pids1} = rpc:call(Node,m,start,[NProcs]),
+
+ %% Then load modules in order to get old code
+ [rpc:call(Node,code,load_file,[Mod]) || Mod <- Modules],
+ true = rpc:call(Node,erlang,check_old_code,[m10]),
+
+ %% Unpack second release, which removes all mX modules
+ {ok, RelVsn2} =
+ rpc:call(Node, release_handler, set_unpacked,
+ [Rel2++".rel", [{many_mods,"2.0",LibDir}]]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "relup")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "start.boot")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "sys.config")]),
+
+ %% First, install release directly and check how much time it takes
+ {TInst0,{ok, _, []}} =
+ timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn2]]),
+ ct:log("install_release: ~.2f",[TInst0/1000000]),
+
+ %% Restore to old release, spawn processes again and load to get old code
+ {_,RelVsn1} = init:script_id(),
+ {_TInst1,{ok, _, []}} =
+ timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn1]]),
+% ct:log("install_release: ~.2f",[_TInst1/1000000]),
+
+ [exit(Pid,kill) || Pid <- Pids1],
+ {Modules,_Pids2} = rpc:call(Node,m,start,[NProcs]),
+ [rpc:call(Node,code,load_file,[Mod]) || Mod <- Modules],
+ true = rpc:call(Node,erlang,check_old_code,[m10]),
+
+ %% Run check_install_release with purge before install this time
+ {TCheck,{ok, _RelVsn1, []}} =
+ timer:tc(rpc,call,[Node, release_handler, check_install_release,
+ [RelVsn2,[purge]]]),
+ ct:log("check_install_release with purge: ~.2f",[TCheck/1000000]),
+
+ %% Finally install release after check and purge, and check that
+ %% this install was faster than the first.
+ {TInst2,{ok, _RelVsn1, []}} =
+ timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn2]]),
+ ct:log("install_release: ~.2f",[TInst2/1000000]),
+
+ true = (TInst2 =< TInst0),
+
+ ok.
+
+otp_9395_rm_many_mods(cleanup,_Conf) ->
+ stop_node(node_name(otp_9395_rm_many_mods)).
+
+
+
%% Test upgrade and downgrade of applications
eval_appup(Conf) when is_list(Conf) ->
@@ -1838,9 +2124,8 @@ create_fake_upgrade_release(Dir,RelVsn,AppDirs,{UpFrom,DownTo,ExtraLibs}) ->
%% And a relup file so it can be upgraded to
RelupPath = Paths ++ [filename:join([Lib,"*","ebin"]) || Lib <- ExtraLibs],
- ok = systools:make_relup(Rel,[UpFrom],[DownTo],
- [{path,RelupPath},
- {outdir,RelDir}]),
+ ok = systools:make_relup(Rel,UpFrom,DownTo,[{path,RelupPath},
+ {outdir,RelDir}]),
Rel.
diff --git a/lib/sasl/test/release_handler_SUITE_data/Makefile.src b/lib/sasl/test/release_handler_SUITE_data/Makefile.src
index a12e526d2e..9b07e7ce0a 100644
--- a/lib/sasl/test/release_handler_SUITE_data/Makefile.src
+++ b/lib/sasl/test/release_handler_SUITE_data/Makefile.src
@@ -13,7 +13,30 @@ LIB= \
lib/a-1.0/ebin/a_sup.@EMULATOR@ \
lib/b-1.0/ebin/b_server.@EMULATOR@ \
lib/b-1.0/ebin/b_lib.@EMULATOR@ \
- lib/b-2.0/ebin/b_server.@EMULATOR@
+ lib/b-2.0/ebin/b_server.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m1.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m2.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m3.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m4.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m5.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m6.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m7.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m8.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m9.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m10.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m1.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m2.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m3.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m4.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m5.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m6.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m7.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m8.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m9.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m10.@EMULATOR@ \
+ lib/many_mods-2.0/ebin/m.@EMULATOR@
APP= \
app1_app2/lib1/app1-1.0/ebin/app1_sup.@EMULATOR@ \
@@ -75,6 +98,52 @@ lib/b-1.0/ebin/b_lib.@EMULATOR@: lib/b-1.0/src/b_lib.erl
lib/b-2.0/ebin/b_server.@EMULATOR@: lib/b-2.0/src/b_server.erl
erlc $(EFLAGS) -olib/b-2.0/ebin lib/b-2.0/src/b_server.erl
+lib/many_mods-1.0/ebin/m.@EMULATOR@: lib/many_mods-1.0/src/m.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m.erl
+lib/many_mods-1.0/ebin/m1.@EMULATOR@: lib/many_mods-1.0/src/m1.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m1.erl
+lib/many_mods-1.0/ebin/m2.@EMULATOR@: lib/many_mods-1.0/src/m2.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m2.erl
+lib/many_mods-1.0/ebin/m3.@EMULATOR@: lib/many_mods-1.0/src/m3.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m3.erl
+lib/many_mods-1.0/ebin/m4.@EMULATOR@: lib/many_mods-1.0/src/m4.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m4.erl
+lib/many_mods-1.0/ebin/m5.@EMULATOR@: lib/many_mods-1.0/src/m5.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m5.erl
+lib/many_mods-1.0/ebin/m6.@EMULATOR@: lib/many_mods-1.0/src/m6.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m6.erl
+lib/many_mods-1.0/ebin/m7.@EMULATOR@: lib/many_mods-1.0/src/m7.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m7.erl
+lib/many_mods-1.0/ebin/m8.@EMULATOR@: lib/many_mods-1.0/src/m8.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m8.erl
+lib/many_mods-1.0/ebin/m9.@EMULATOR@: lib/many_mods-1.0/src/m9.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m9.erl
+lib/many_mods-1.0/ebin/m10.@EMULATOR@: lib/many_mods-1.0/src/m10.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m10.erl
+lib/many_mods-1.1/ebin/m.@EMULATOR@: lib/many_mods-1.1/src/m.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m.erl
+lib/many_mods-1.1/ebin/m1.@EMULATOR@: lib/many_mods-1.1/src/m1.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m1.erl
+lib/many_mods-1.1/ebin/m2.@EMULATOR@: lib/many_mods-1.1/src/m2.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m2.erl
+lib/many_mods-1.1/ebin/m3.@EMULATOR@: lib/many_mods-1.1/src/m3.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m3.erl
+lib/many_mods-1.1/ebin/m4.@EMULATOR@: lib/many_mods-1.1/src/m4.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m4.erl
+lib/many_mods-1.1/ebin/m5.@EMULATOR@: lib/many_mods-1.1/src/m5.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m5.erl
+lib/many_mods-1.1/ebin/m6.@EMULATOR@: lib/many_mods-1.1/src/m6.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m6.erl
+lib/many_mods-1.1/ebin/m7.@EMULATOR@: lib/many_mods-1.1/src/m7.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m7.erl
+lib/many_mods-1.1/ebin/m8.@EMULATOR@: lib/many_mods-1.1/src/m8.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m8.erl
+lib/many_mods-1.1/ebin/m9.@EMULATOR@: lib/many_mods-1.1/src/m9.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m9.erl
+lib/many_mods-1.1/ebin/m10.@EMULATOR@: lib/many_mods-1.1/src/m10.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m10.erl
+lib/many_mods-2.0/ebin/m.@EMULATOR@: lib/many_mods-2.0/src/m.erl
+ erlc $(EFLAGS) -olib/many_mods-2.0/ebin lib/many_mods-2.0/src/m.erl
app1_app2/lib1/app1-1.0/ebin/app1_sup.@EMULATOR@: app1_app2/lib1/app1-1.0/src/app1_sup.erl
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/README b/lib/sasl/test/release_handler_SUITE_data/lib/README
index 667d21d4cf..639a4ca0fb 100644
--- a/lib/sasl/test/release_handler_SUITE_data/lib/README
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/README
@@ -13,4 +13,21 @@ start version, includes b_lib and b_server
b-2.0:
can be upgraded to from b-1.0.
-Removes b_lib and updates b_server
+Removes b_lib (soft_purge) and updates b_server (brutal_purge)
+* The diff in purge method is important for test "check_and_purge", in
+ order to check that the purge option to check_install_release works
+ for both methods.
+
+many_mods-1.0:
+start version.
+m:start/1 starts N procs, each calling Mod:bar() in all other modules (m1-m10).
+m1-m10: implements bar() which returns a big constant.
+The point is to get many processes with references to many modules,
+and then load the modules again so that old code exists. See tests
+otp_9395_update_many_mods and otp_9395_rm_many_mods.
+
+many_mods-1.1:
+can be upgraded to from many_mods-1.0. Updates modules m1-m10.
+
+many_mods-2.0:
+can be upgraded to from many_mods-1.0. Removes modules m1-m10. \ No newline at end of file
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.appup b/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.appup
index d261a37732..001255a88c 100644
--- a/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.appup
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.appup
@@ -1,3 +1,6 @@
+%% -*- erlang -*-
{"2.0",
- [{"1.0",[{delete_module,b_lib}, {update,b_server,{advanced,[]}}]}],
- [{"1.0",[{add_module,b_lib},{update,b_server,{advanced,[]}}]}]}.
+ [{"1.0",[{remove_module,b_lib,soft_purge,soft_purge,[]},
+ {update,b_server,{advanced,[]}}]}],
+ [{"1.0",[{add_module,b_lib},
+ {update,b_server,{advanced,[]}}]}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/ebin/many_mods.app b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/ebin/many_mods.app
new file mode 100644
index 0000000000..aa39adfffa
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/ebin/many_mods.app
@@ -0,0 +1,17 @@
+%% -*- erlang -*-
+{application, many_mods,
+ [{description, "Application with many modules CXC 138 11"},
+ {vsn, "1.0"},
+ {modules, [{m, 1},
+ {m1,1},
+ {m2,1},
+ {m3,1},
+ {m4,1},
+ {m5,1},
+ {m6,1},
+ {m7,1},
+ {m8,1},
+ {m9,1},
+ {m10,1}]},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m.erl
new file mode 100644
index 0000000000..418102bebb
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m.erl
@@ -0,0 +1,11 @@
+-module(m).
+-compile(export_all).
+
+start(NProcs) ->
+ Modules = [m1,m2,m3,m4,m5,m6,m7,m8,m9,m10],
+ Pids = [spawn_link(fun() ->
+ Cs = [M:bar() || M <- Modules],
+ receive stop -> Cs end
+ end) ||
+ _ <- lists:seq(1,NProcs)],
+ {Modules,Pids}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m1.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m1.erl
new file mode 100644
index 0000000000..cacc13f5d7
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m1.erl
@@ -0,0 +1,4 @@
+-module(m1).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m10.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m10.erl
new file mode 100644
index 0000000000..81e120b891
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m10.erl
@@ -0,0 +1,4 @@
+-module(m10).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m2.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m2.erl
new file mode 100644
index 0000000000..481276ba7b
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m2.erl
@@ -0,0 +1,4 @@
+-module(m2).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m3.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m3.erl
new file mode 100644
index 0000000000..9a04ed5fc9
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m3.erl
@@ -0,0 +1,4 @@
+-module(m3).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m4.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m4.erl
new file mode 100644
index 0000000000..90de9a30c9
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m4.erl
@@ -0,0 +1,4 @@
+-module(m4).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m5.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m5.erl
new file mode 100644
index 0000000000..8a9b690dfa
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m5.erl
@@ -0,0 +1,4 @@
+-module(m5).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m6.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m6.erl
new file mode 100644
index 0000000000..cd0d3977ed
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m6.erl
@@ -0,0 +1,4 @@
+-module(m6).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m7.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m7.erl
new file mode 100644
index 0000000000..1f79918d6e
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m7.erl
@@ -0,0 +1,4 @@
+-module(m7).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m8.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m8.erl
new file mode 100644
index 0000000000..2ce03a0b7e
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m8.erl
@@ -0,0 +1,4 @@
+-module(m8).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m9.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m9.erl
new file mode 100644
index 0000000000..1c5f72e628
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m9.erl
@@ -0,0 +1,4 @@
+-module(m9).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.app b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.app
new file mode 100644
index 0000000000..36c50caf2f
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.app
@@ -0,0 +1,17 @@
+%% -*- erlang -*-
+{application, many_mods,
+ [{description, "Application with many modules CXC 138 11"},
+ {vsn, "1.1"},
+ {modules, [{m, 1},
+ {m1,1},
+ {m2,1},
+ {m3,1},
+ {m4,1},
+ {m5,1},
+ {m6,1},
+ {m7,1},
+ {m8,1},
+ {m9,1},
+ {m10,1}]},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.appup b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.appup
new file mode 100644
index 0000000000..696435e06f
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.appup
@@ -0,0 +1,22 @@
+%% -*- erlang -*-
+{"1.1",
+ [{"1.0",[{update,m1},
+ {update,m2},
+ {update,m3},
+ {update,m4},
+ {update,m5},
+ {update,m6},
+ {update,m7},
+ {update,m8},
+ {update,m9},
+ {update,m10}]}],
+ [{"1.0",[{update,m1},
+ {update,m2},
+ {update,m3},
+ {update,m4},
+ {update,m5},
+ {update,m6},
+ {update,m7},
+ {update,m8},
+ {update,m9},
+ {update,m10}]}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m.erl
new file mode 100644
index 0000000000..418102bebb
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m.erl
@@ -0,0 +1,11 @@
+-module(m).
+-compile(export_all).
+
+start(NProcs) ->
+ Modules = [m1,m2,m3,m4,m5,m6,m7,m8,m9,m10],
+ Pids = [spawn_link(fun() ->
+ Cs = [M:bar() || M <- Modules],
+ receive stop -> Cs end
+ end) ||
+ _ <- lists:seq(1,NProcs)],
+ {Modules,Pids}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m1.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m1.erl
new file mode 100644
index 0000000000..cacc13f5d7
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m1.erl
@@ -0,0 +1,4 @@
+-module(m1).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m10.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m10.erl
new file mode 100644
index 0000000000..81e120b891
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m10.erl
@@ -0,0 +1,4 @@
+-module(m10).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m2.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m2.erl
new file mode 100644
index 0000000000..481276ba7b
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m2.erl
@@ -0,0 +1,4 @@
+-module(m2).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m3.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m3.erl
new file mode 100644
index 0000000000..9a04ed5fc9
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m3.erl
@@ -0,0 +1,4 @@
+-module(m3).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m4.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m4.erl
new file mode 100644
index 0000000000..90de9a30c9
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m4.erl
@@ -0,0 +1,4 @@
+-module(m4).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m5.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m5.erl
new file mode 100644
index 0000000000..8a9b690dfa
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m5.erl
@@ -0,0 +1,4 @@
+-module(m5).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m6.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m6.erl
new file mode 100644
index 0000000000..cd0d3977ed
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m6.erl
@@ -0,0 +1,4 @@
+-module(m6).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m7.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m7.erl
new file mode 100644
index 0000000000..1f79918d6e
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m7.erl
@@ -0,0 +1,4 @@
+-module(m7).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m8.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m8.erl
new file mode 100644
index 0000000000..2ce03a0b7e
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m8.erl
@@ -0,0 +1,4 @@
+-module(m8).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m9.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m9.erl
new file mode 100644
index 0000000000..1c5f72e628
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m9.erl
@@ -0,0 +1,4 @@
+-module(m9).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.app b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.app
new file mode 100644
index 0000000000..98f6527750
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.app
@@ -0,0 +1,7 @@
+%% -*- erlang -*-
+{application, many_mods,
+ [{description, "Application with many modules CXC 138 11"},
+ {vsn, "2.0"},
+ {modules, [{m, 1}]},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.appup b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.appup
new file mode 100644
index 0000000000..3a34db78c1
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.appup
@@ -0,0 +1,24 @@
+%% -*- erlang -*-
+{"2.0",
+ [{"1.0",[{update,m},
+ {delete_module,m1},
+ {delete_module,m2},
+ {delete_module,m3},
+ {delete_module,m4},
+ {delete_module,m5},
+ {delete_module,m6},
+ {delete_module,m7},
+ {delete_module,m8},
+ {delete_module,m9},
+ {delete_module,m10}]}],
+ [{"1.0",[{update,m},
+ {add_module,m1},
+ {add_module,m2},
+ {add_module,m3},
+ {add_module,m4},
+ {add_module,m5},
+ {add_module,m6},
+ {add_module,m7},
+ {add_module,m8},
+ {add_module,m9},
+ {add_module,m10}]}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/src/m.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/src/m.erl
new file mode 100644
index 0000000000..2edc1e6be4
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/src/m.erl
@@ -0,0 +1,11 @@
+-module(m).
+-compile(export_all).
+
+start(NProcs) ->
+ Modules = [],
+ Pids = [spawn_link(fun() ->
+ Cs = [M:bar() || M <- Modules],
+ receive stop -> Cs end
+ end) ||
+ _ <- lists:seq(1,NProcs)],
+ {Modules,Pids}.
diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl
index 9190b111ef..539f6de99d 100644
--- a/lib/sasl/test/systools_SUITE.erl
+++ b/lib/sasl/test/systools_SUITE.erl
@@ -48,7 +48,7 @@
included_fail_script/1, included_bug_script/1, exref_script/1]).
-export([ tar_options/1, normal_tar/1, no_mod_vsn_tar/1, variable_tar/1,
src_tests_tar/1, shadow_tar/1, var_tar/1,
- exref_tar/1, link_tar/1]).
+ exref_tar/1, link_tar/1, otp_9507/1]).
-export([ normal_relup/1, abnormal_relup/1, no_appup_relup/1,
bad_appup_relup/1, app_start_type_relup/1, otp_3065/1]).
-export([
@@ -81,7 +81,7 @@ groups() ->
{tar, [],
[tar_options, normal_tar, no_mod_vsn_tar, variable_tar,
src_tests_tar, shadow_tar, var_tar,
- exref_tar, link_tar]},
+ exref_tar, link_tar, otp_9507]},
{relup, [],
[normal_relup, abnormal_relup, no_appup_relup,
bad_appup_relup, app_start_type_relup]},
@@ -1066,6 +1066,48 @@ exref_tar(Config) when is_list(Config) ->
?line ok = file:set_cwd(OldDir),
ok.
+
+
+%% otp_9507
+%%
+otp_9507(suite) -> [];
+otp_9507(doc) ->
+ ["make_tar failed when path given as just 'ebin'."];
+otp_9507(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {LatestDir, LatestName} = create_script(latest_small,Config),
+
+ ?line DataDir = filename:absname(?copydir),
+ ?line LibDir = fname([DataDir, d_normal, lib]),
+ ?line FeDir = fname([LibDir, 'fe-3.1']),
+
+ ?line ok = file:set_cwd(FeDir),
+
+ RelName = fname([LatestDir,LatestName]),
+
+ ?line P1 = ["./ebin",
+ fname([DataDir, lib, kernel, ebin]),
+ fname([DataDir, lib, stdlib, ebin])],
+ ?line {ok, _, _} = systools:make_script(RelName, [silent, {path, P1}]),
+ ?line ok = systools:make_tar(RelName, [{path, P1}]),
+ ?line Content1 = tar_contents(RelName),
+
+ ?line P2 = ["ebin",
+ fname([DataDir, lib, kernel, ebin]),
+ fname([DataDir, lib, stdlib, ebin])],
+
+ %% Tickets solves the following line - it used to fail with
+ %% {function_clause,[{filename,join,[[]]},...}
+ ?line ok = systools:make_tar(RelName, [{path, P2}]),
+ ?line Content2 = tar_contents(RelName),
+ true = (Content1 == Content2),
+
+ ?line ok = file:set_cwd(OldDir),
+
+ ok.
+
+
%% The relup stuff.
%%
%%
diff --git a/lib/snmp/test/test_config/Makefile b/lib/snmp/test/test_config/Makefile
index d7bebbc431..d65bb8abe2 100644
--- a/lib/snmp/test/test_config/Makefile
+++ b/lib/snmp/test/test_config/Makefile
@@ -155,23 +155,23 @@ release_spec:
release_tests_spec: clean opt
$(INSTALL_DIR) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
$(INSTALL_DIR) $(RELSYSDIR)/agent
- chmod -f -R u+w $(RELSYSDIR)/agent
+ chmod -R u+w $(RELSYSDIR)/agent
$(INSTALL_DIR) $(RELSYSDIR)/agent/conf
- chmod -f -R u+w $(RELSYSDIR)/agent/conf
+ chmod -R u+w $(RELSYSDIR)/agent/conf
$(INSTALL_DIR) $(RELSYSDIR)/agent/db
- chmod -f -R u+w $(RELSYSDIR)/agent/db
+ chmod -R u+w $(RELSYSDIR)/agent/db
$(INSTALL_DIR) $(RELSYSDIR)/agent/log
- chmod -f -R u+w $(RELSYSDIR)/agent/log
+ chmod -R u+w $(RELSYSDIR)/agent/log
$(INSTALL_DIR) $(RELSYSDIR)/manager
- chmod -f -R u+w $(RELSYSDIR)/manager
+ chmod -R u+w $(RELSYSDIR)/manager
$(INSTALL_DIR) $(RELSYSDIR)/manager/conf
- chmod -f -R u+w $(RELSYSDIR)/manager/conf
+ chmod -R u+w $(RELSYSDIR)/manager/conf
$(INSTALL_DIR) $(RELSYSDIR)/manager/db
- chmod -f -R u+w $(RELSYSDIR)/manager/db
+ chmod -R u+w $(RELSYSDIR)/manager/db
$(INSTALL_DIR) $(RELSYSDIR)/manager/log
- chmod -f -R u+w $(RELSYSDIR)/manager/log
+ chmod -R u+w $(RELSYSDIR)/manager/log
$(INSTALL_DATA) $(SYS_CONFIG_FILES) $(RELSYSDIR)
$(INSTALL_DATA) $(AGENT_CONFIG_FILES) $(RELSYSDIR)/agent/conf
$(INSTALL_DATA) $(MANAGER_CONFIG_FILES) $(RELSYSDIR)/manager/conf
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 71f3941577..6fc4fdc43d 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -29,6 +29,20 @@
<file>notes.xml</file>
</header>
+<section><title>Ssh 2.0.8</title>
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Calling ssh_sftp:stop_channel/1 resulted in that the trap_exit flag was
+ set to true for the invoking process.</p>
+ <p>
+ Own Id: OTP-9386 Aux Id: seq11865</p>
+ </item>
+ </list>
+ </section>
+</section>
+
<section><title>Ssh 2.0.7</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src
index 974145836c..150b7d86dd 100644
--- a/lib/ssh/src/ssh.appup.src
+++ b/lib/ssh/src/ssh.appup.src
@@ -19,13 +19,19 @@
{"%VSN%",
[
- {"2.0.6", [{load_module, ssh_userreg, soft_purge, soft_purge, []}]},
+ {"2.0.7", [{load_module, ssh_sftp, soft_purge, soft_purge, []}]},
+ {"2.0.6", [{load_module, ssh_userreg, soft_purge, soft_purge, []},
+ {load_module, ssh_sftp, soft_purge, soft_purge, []}]},
{"2.0.5", [{load_module, ssh_userreg, soft_purge, soft_purge, []},
+ {load_module, ssh_sftp, soft_purge, soft_purge, []},
{load_module, ssh_connection_handler, soft_purge, soft_purge, [ssh_userreg]}]}
],
[
- {"2.0.6", [{load_module, ssh_userreg, soft_purge, soft_purge, []}]},
+ {"2.0.7", [{load_module, ssh_sftp, soft_purge, soft_purge, []}]},
+ {"2.0.6", [{load_module, ssh_userreg, soft_purge, soft_purge, []},
+ {load_module, ssh_sftp, soft_purge, soft_purge, []}]},
{"2.0.5", [{load_module, ssh_userreg, soft_purge, soft_purge, []},
+ {load_module, ssh_sftp, soft_purge, soft_purge, []},
{load_module, ssh_connection_handler, soft_purge, soft_purge, [ssh_userreg]}]}
]
}.
diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl
index 59e09fdd0f..f000558100 100755
--- a/lib/ssh/src/ssh_sftp.erl
+++ b/lib/ssh/src/ssh_sftp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2011. 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
@@ -130,9 +130,9 @@ start_channel(Host, Port, Opts) ->
end.
stop_channel(Pid) ->
- case process_info(Pid, [trap_exit]) of
- [{trap_exit, Bool}] ->
- process_flag(trap_exit, true),
+ case is_process_alive(Pid) of
+ true ->
+ OldValue = process_flag(trap_exit, true),
link(Pid),
exit(Pid, ssh_sftp_stop_channel),
receive
@@ -145,9 +145,9 @@ stop_channel(Pid) ->
ok
end
end,
- process_flag(trap_exit, Bool),
+ process_flag(trap_exit, OldValue),
ok;
- undefined ->
+ false ->
ok
end.
diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index 5a2a6de24a..1820924ed6 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -115,7 +115,7 @@ release_tests_spec: opt
$(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)
$(INSTALL_DATA) ssh.spec ssh.cover $(RELSYSDIR)
$(INSTALL_DATA) $(HRL_FILES_NEEDED_IN_TEST) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index d79038df29..fe2b915d17 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 2.0.7
+SSH_VSN = 2.0.8
APP_VSN = "ssh-$(SSH_VSN)"
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 46e4b98c98..59f8479a4c 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -49,9 +49,12 @@
inet_ssl, %% inet options for internal ssl socket
cb %% Callback info
}).
--type option() :: socketoption() | ssloption() | transportoption().
--type socketoption() :: term(). %% See gen_tcp and inet, import spec later when there is one to import
--type ssloption() :: {verify, verify_type()} |
+-type connect_option() :: socket_connect_option() | ssl_option() | transport_option().
+-type socket_connect_option() :: gen_tcp:connect_option().
+-type listen_option() :: socket_listen_option() | ssl_option() | transport_option().
+-type socket_listen_option() :: gen_tcp:listen_option().
+
+-type ssl_option() :: {verify, verify_type()} |
{verify_fun, {fun(), InitialUserState::term()}} |
{fail_if_no_peer_cert, boolean()} | {depth, integer()} |
{cert, Der::binary()} | {certfile, path()} | {key, Der::binary()} |
@@ -66,7 +69,7 @@
string(). % (according to old API)
-type ssl_imp() :: new | old.
--type transportoption() :: {CallbackModule::atom(), DataTag::atom(), ClosedTag::atom()}.
+-type transport_option() :: {cb_info, {CallbackModule::atom(), DataTag::atom(), ClosedTag::atom()}}.
%%--------------------------------------------------------------------
@@ -96,11 +99,11 @@ stop() ->
application:stop(ssl).
%%--------------------------------------------------------------------
--spec connect(host() | port(), [option()]) -> {ok, #sslsocket{}} |
+-spec connect(host() | port(), [connect_option()]) -> {ok, #sslsocket{}} |
{error, reason()}.
--spec connect(host() | port(), [option()] | port_num(), timeout() | list()) ->
+-spec connect(host() | port(), [connect_option()] | inet:port_number(), timeout() | list()) ->
{ok, #sslsocket{}} | {error, reason()}.
--spec connect(host() | port(), port_num(), list(), timeout()) ->
+-spec connect(host() | port(), inet:port_number(), list(), timeout()) ->
{ok, #sslsocket{}} | {error, reason()}.
%%
@@ -148,7 +151,7 @@ connect(Host, Port, Options0, Timeout) ->
end.
%%--------------------------------------------------------------------
--spec listen(port_num(), [option()]) ->{ok, #sslsocket{}} | {error, reason()}.
+-spec listen(inet:port_number(), [listen_option()]) ->{ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Creates an ssl listen socket.
@@ -214,9 +217,9 @@ transport_accept(#sslsocket{} = ListenSocket, Timeout) ->
%%--------------------------------------------------------------------
-spec ssl_accept(#sslsocket{}) -> ok | {error, reason()}.
--spec ssl_accept(#sslsocket{} | port(), timeout()| [option()]) ->
+-spec ssl_accept(#sslsocket{} | port(), timeout()| [ssl_option() | transport_option()]) ->
ok | {ok, #sslsocket{}} | {error, reason()}.
--spec ssl_accept(port(), [option()], timeout()) -> {ok, #sslsocket{}} | {error, reason()}.
+-spec ssl_accept(port(), [ssl_option()| transport_option()], timeout()) -> {ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Performs accept on an ssl listen socket. e.i. performs
%% ssl handshake.
@@ -373,7 +376,7 @@ select_part(plain, Cert, Opts) ->
end.
%%--------------------------------------------------------------------
--spec peername(#sslsocket{}) -> {ok, {tuple(), port_num()}} | {error, reason()}.
+-spec peername(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
%%
%% Description: same as inet:peername/1.
%%--------------------------------------------------------------------
@@ -402,7 +405,8 @@ cipher_suites(openssl) ->
[ssl_cipher:openssl_suite_name(S) || S <- ssl_cipher:suites(Version)].
%%--------------------------------------------------------------------
--spec getopts(#sslsocket{}, [atom()]) -> {ok, [{atom(), term()}]} | {error, reason()}.
+-spec getopts(#sslsocket{}, [gen_tcp:option_name()]) ->
+ {ok, [gen_tcp:option()]} | {error, reason()}.
%%
%% Description: Gets options
%%--------------------------------------------------------------------
@@ -425,7 +429,7 @@ getopts(#sslsocket{} = Socket, OptionTags) ->
ssl_broker:getopts(Socket, OptionTags).
%%--------------------------------------------------------------------
--spec setopts(#sslsocket{}, [proplists:property()]) -> ok | {error, reason()}.
+-spec setopts(#sslsocket{}, [gen_tcp:option()]) -> ok | {error, reason()}.
%%
%% Description: Sets options
%%--------------------------------------------------------------------
@@ -466,7 +470,7 @@ shutdown(#sslsocket{pid = Pid, fd = new_ssl}, How) ->
ssl_connection:shutdown(Pid, How).
%%--------------------------------------------------------------------
--spec sockname(#sslsocket{}) -> {ok, {tuple(), port_num()}} | {error, reason()}.
+-spec sockname(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
%%
%% Description: Same as inet:sockname/1
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 79570c520a..5187d0f78f 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -127,7 +127,7 @@ send(Pid, Data) ->
recv(Pid, Length, Timeout) ->
sync_send_all_state_event(Pid, {recv, Length}, Timeout).
%%--------------------------------------------------------------------
--spec connect(host(), port_num(), port(), {#ssl_options{}, #socket_options{}},
+-spec connect(host(), inet:port_number(), port(), {#ssl_options{}, #socket_options{}},
pid(), tuple(), timeout()) ->
{ok, #sslsocket{}} | {error, reason()}.
%%
@@ -141,7 +141,7 @@ connect(Host, Port, Socket, Options, User, CbInfo, Timeout) ->
{error, ssl_not_started}
end.
%%--------------------------------------------------------------------
--spec ssl_accept(port_num(), port(), {#ssl_options{}, #socket_options{}},
+-spec ssl_accept(inet:port_number(), port(), {#ssl_options{}, #socket_options{}},
pid(), tuple(), timeout()) ->
{ok, #sslsocket{}} | {error, reason()}.
%%
@@ -212,14 +212,14 @@ shutdown(ConnectionPid, How) ->
new_user(ConnectionPid, User) ->
sync_send_all_state_event(ConnectionPid, {new_user, User}).
%%--------------------------------------------------------------------
--spec sockname(pid()) -> {ok, {tuple(), port_num()}} | {error, reason()}.
+-spec sockname(pid()) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
%%
%% Description: Same as inet:sockname/1
%%--------------------------------------------------------------------
sockname(ConnectionPid) ->
sync_send_all_state_event(ConnectionPid, sockname).
%%--------------------------------------------------------------------
--spec peername(pid()) -> {ok, {tuple(), port_num()}} | {error, reason()}.
+-spec peername(pid()) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
%%
%% Description: Same as inet:peername/1
%%--------------------------------------------------------------------
@@ -277,7 +277,7 @@ renegotiation(ConnectionPid) ->
%%====================================================================
%%--------------------------------------------------------------------
--spec start_link(atom(), host(), port_num(), port(), list(), pid(), tuple()) ->
+-spec start_link(atom(), host(), inet:port_number(), port(), list(), pid(), tuple()) ->
{ok, pid()} | ignore | {error, reason()}.
%%
%% Description: Creates a gen_fsm process which calls Module:init/1 to
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 4e74aec4ac..453ea20f99 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -48,7 +48,7 @@
%% Internal application API
%%====================================================================
%%--------------------------------------------------------------------
--spec client_hello(host(), port_num(), #connection_states{},
+-spec client_hello(host(), inet:port_number(), #connection_states{},
#ssl_options{}, boolean(), der_cert()) -> #client_hello{}.
%%
%% Description: Creates a client hello message.
@@ -106,7 +106,7 @@ hello_request() ->
%%--------------------------------------------------------------------
-spec hello(#server_hello{} | #client_hello{}, #ssl_options{},
- #connection_states{} | {port_num(), #session{}, db_handle(),
+ #connection_states{} | {inet:port_number(), #session{}, db_handle(),
atom(), #connection_states{}, binary()},
boolean()) -> {tls_version(), session_id(), #connection_states{}}|
{tls_version(), {resumed | new, #session{}},
@@ -383,8 +383,9 @@ master_secret(Version, #session{master_secret = Mastersecret},
ConnectionStates, Role)
catch
exit:Reason ->
- error_logger:error_report("Key calculation failed due to ~p",
- [Reason]),
+ Report = io_lib:format("Key calculation failed due to ~p",
+ [Reason]),
+ error_logger:error_report(Report),
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)
end;
@@ -400,8 +401,9 @@ master_secret(Version, PremasterSecret, ConnectionStates, Role) ->
SecParams, ConnectionStates, Role)
catch
exit:Reason ->
- error_logger:error_report("Master secret calculation failed"
- " due to ~p", [Reason]),
+ Report = io_lib:format("Master secret calculation failed"
+ " due to ~p", [Reason]),
+ error_logger:error_report(Report),
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)
end.
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index cc66246068..6bf1edc452 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -28,8 +28,7 @@
-type reply() :: term().
-type msg() :: term().
-type from() :: term().
--type host() :: string() | tuple().
--type port_num() :: integer().
+-type host() :: inet:ip_address() | inet:hostname().
-type session_id() :: 0 | binary().
-type tls_version() :: {integer(), integer()}.
-type tls_atom_version() :: sslv3 | tlsv1.
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index b02815bfd8..725a085d1f 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -113,7 +113,7 @@ lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) ->
issuer_candidate(PrevCandidateKey, DbHandle) ->
ssl_certificate_db:issuer_candidate(PrevCandidateKey, DbHandle).
%%--------------------------------------------------------------------
--spec client_session_id(host(), port_num(), #ssl_options{},
+-spec client_session_id(host(), inet:port_number(), #ssl_options{},
der_cert() | undefined) -> session_id().
%%
%% Description: Select a session id for the client.
@@ -122,7 +122,7 @@ client_session_id(Host, Port, SslOpts, OwnCert) ->
call({client_session_id, Host, Port, SslOpts, OwnCert}).
%%--------------------------------------------------------------------
--spec server_session_id(host(), port_num(), #ssl_options{},
+-spec server_session_id(host(), inet:port_number(), #ssl_options{},
der_cert()) -> session_id().
%%
%% Description: Select a session id for the server.
@@ -131,8 +131,8 @@ server_session_id(Port, SuggestedSessionId, SslOpts, OwnCert) ->
call({server_session_id, Port, SuggestedSessionId, SslOpts, OwnCert}).
%%--------------------------------------------------------------------
--spec register_session(port_num(), #session{}) -> ok.
--spec register_session(host(), port_num(), #session{}) -> ok.
+-spec register_session(inet:port_number(), #session{}) -> ok.
+-spec register_session(host(), inet:port_number(), #session{}) -> ok.
%%
%% Description: Make the session available for reuse.
%%--------------------------------------------------------------------
@@ -142,8 +142,8 @@ register_session(Host, Port, Session) ->
register_session(Port, Session) ->
cast({register_session, Port, Session}).
%%--------------------------------------------------------------------
--spec invalidate_session(port_num(), #session{}) -> ok.
--spec invalidate_session(host(), port_num(), #session{}) -> ok.
+-spec invalidate_session(inet:port_number(), #session{}) -> ok.
+-spec invalidate_session(host(), inet:port_number(), #session{}) -> ok.
%%
%% Description: Make the session unavailable for reuse. After
%% a the session has been marked "is_resumable = false" for some while
diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl
index 85c9fcb61c..bf738649f6 100644
--- a/lib/ssl/src/ssl_session.erl
+++ b/lib/ssl/src/ssl_session.erl
@@ -48,7 +48,7 @@ is_new(_ClientSuggestion, _ServerDecision) ->
true.
%%--------------------------------------------------------------------
--spec id({host(), port_num(), #ssl_options{}}, db_handle(), atom(),
+-spec id({host(), inet:port_number(), #ssl_options{}}, db_handle(), atom(),
undefined | binary()) -> binary().
%%
%% Description: Should be called by the client side to get an id
@@ -63,7 +63,7 @@ id(ClientInfo, Cache, CacheCb, OwnCert) ->
end.
%%--------------------------------------------------------------------
--spec id(port_num(), binary(), #ssl_options{}, db_handle(),
+-spec id(inet:port_number(), binary(), #ssl_options{}, db_handle(),
atom(), seconds(), binary()) -> binary().
%%
%% Description: Should be called by the server side to get an id
diff --git a/lib/ssl/src/ssl_session_cache.erl b/lib/ssl/src/ssl_session_cache.erl
index 66610817be..93969f628f 100644
--- a/lib/ssl/src/ssl_session_cache.erl
+++ b/lib/ssl/src/ssl_session_cache.erl
@@ -28,7 +28,7 @@
-export([init/1, terminate/1, lookup/2, update/3, delete/2, foldl/3,
select_session/2]).
--type key() :: {{host(), port_num()}, session_id()} | {port_num(), session_id()}.
+-type key() :: {{host(), inet:port_number()}, session_id()} | {inet:port_number(), session_id()}.
%%--------------------------------------------------------------------
-spec init(list()) -> db_handle(). %% Returns reference to the cache (opaque)
@@ -91,7 +91,7 @@ foldl(Fun, Acc0, Cache) ->
ets:foldl(Fun, Acc0, Cache).
%%--------------------------------------------------------------------
--spec select_session(db_handle(), {host(), port_num()} | port_num()) -> [#session{}].
+-spec select_session(db_handle(), {host(), inet:port_number()} | inet:port_number()) -> [#session{}].
%%
%% Description: Selects a session that could be reused. Should be callable
%% from any process.
diff --git a/lib/stdlib/doc/src/dets.xml b/lib/stdlib/doc/src/dets.xml
index 2512c84e18..54fefbe2b8 100644
--- a/lib/stdlib/doc/src/dets.xml
+++ b/lib/stdlib/doc/src/dets.xml
@@ -1105,7 +1105,7 @@ fun(X) -> {continue, X} end. </pre>
<p>Terminate the traversal and return <c>[<anno>Value</anno> | Acc]</c>.</p>
</item>
</taglist>
- <p>Any other value returned by <c><anno>Fun</anno></c> terminates the
+ <p>Any other value <c><anno>OtherValue</anno></c> returned by <c><anno>Fun</anno></c> terminates the
traversal and is immediately returned.
</p>
</desc>
diff --git a/lib/stdlib/doc/src/gen_fsm.xml b/lib/stdlib/doc/src/gen_fsm.xml
index 4900a8f0ef..e35b5adace 100644
--- a/lib/stdlib/doc/src/gen_fsm.xml
+++ b/lib/stdlib/doc/src/gen_fsm.xml
@@ -639,9 +639,9 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
<v>StateName = atom()</v>
<v>StateData = term()</v>
<v>Result = {next_state,NextStateName,NewStateData}</v>
- <v>&nbsp;>&nbsp;| {next_state,NextStateName,NewStateData,Timeout}</v>
- <v>&nbsp;>&nbsp;| {next_state,NextStateName,NewStateData,hibernate}</v>
- <v>&nbsp;>&nbsp;| {stop,Reason,NewStateData}</v>
+ <v>&nbsp;&nbsp;| {next_state,NextStateName,NewStateData,Timeout}</v>
+ <v>&nbsp;&nbsp;| {next_state,NextStateName,NewStateData,hibernate}</v>
+ <v>&nbsp;&nbsp;| {stop,Reason,NewStateData}</v>
<v>&nbsp;NextStateName = atom()</v>
<v>&nbsp;NewStateData = term()</v>
<v>&nbsp;Timeout = int()>0 | infinity</v>
diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml
index 009aa60faa..edd119d37a 100644
--- a/lib/stdlib/doc/src/supervisor.xml
+++ b/lib/stdlib/doc/src/supervisor.xml
@@ -150,9 +150,12 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules}
<p><c>Restart</c> defines when a terminated child process
should be restarted. A <c>permanent</c> child process should
always be restarted, a <c>temporary</c> child process should
- never be restarted and a <c>transient</c> child process
- should be restarted only if it terminates abnormally, i.e.
- with another exit reason than <c>normal</c>.</p>
+ never be restarted (even when the supervisor's restart strategy
+ is <c>rest_for_one</c> or <c>one_for_all</c> and a sibling's
+ death causes the temporary process to be terminated) and a
+ <c>transient</c> child process should be restarted only if
+ it terminates abnormally, i.e. with another exit reason
+ than <c>normal</c>.</p>
</item>
<item>
<p><c>Shutdown</c> defines how a child process should be
diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl
index 671b5a9dd4..fa0641ffd9 100644
--- a/lib/stdlib/src/dets.erl
+++ b/lib/stdlib/src/dets.erl
@@ -411,7 +411,8 @@ init_table(Tab, InitFun) ->
InitFun :: fun((Arg) -> Res),
Arg :: read | close,
Res :: end_of_input | {[object()], InitFun} | {Data, InitFun} | term(),
- Options :: [{min_no_slots,no_slots()} | {format,term | bchunk}],
+ Options :: Option | [Option],
+ Option :: {min_no_slots,no_slots()} | {format,term | bchunk},
Reason :: term(),
Data :: binary() | tuple().
@@ -871,11 +872,15 @@ to_ets(DTab, ETab) ->
-spec traverse(Name, Fun) -> Return | {'error', Reason} when
Name :: tab_name(),
Fun :: fun((Object) -> FunReturn),
- FunReturn :: 'continue' | {'continue', Val} | {'done', Value},
+ Object :: object(),
+ FunReturn :: 'continue'
+ | {'continue', Val}
+ | {'done', Value}
+ | OtherValue,
+ Return :: [term()] | OtherValue,
Val :: term(),
Value :: term(),
- Object :: object(),
- Return :: [term()],
+ OtherValue :: term(),
Reason :: term().
traverse(Tab, Fun) ->
diff --git a/lib/stdlib/src/erl_internal.erl b/lib/stdlib/src/erl_internal.erl
index 478f05e792..3073fc0fb5 100644
--- a/lib/stdlib/src/erl_internal.erl
+++ b/lib/stdlib/src/erl_internal.erl
@@ -262,6 +262,7 @@ bif(bitsize, 1) -> true;
bif(bit_size, 1) -> true;
bif(bitstring_to_list, 1) -> true;
bif(byte_size, 1) -> true;
+bif(check_old_code, 1) -> true;
bif(check_process_code, 2) -> true;
bif(concat_binary, 1) -> true;
bif(date, 0) -> true;
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index d67617260e..cd1bacd2f5 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -62,10 +62,10 @@
-type zip_create_option() :: term().
-type section() ::
shebang
- | {shebang, shebang()}
+ | {shebang, shebang() | default | undefined}
| comment
- | {comment, comment()}
- | {emu_args, emu_args()}
+ | {comment, comment() | default | undefined}
+ | {emu_args, emu_args() | undefined}
| {source, file:filename() | binary()}
| {beam, file:filename() | binary()}
| {archive, file:filename() | binary()}
diff --git a/lib/stdlib/src/eval_bits.erl b/lib/stdlib/src/eval_bits.erl
index 2cbd6cdae7..2c7192a7e7 100644
--- a/lib/stdlib/src/eval_bits.erl
+++ b/lib/stdlib/src/eval_bits.erl
@@ -34,12 +34,12 @@
%% @type matchfun(). A closure which performs a match given a value, a
%% pattern and an environment
%%
-%% @type field() represents a field in a "bin"
+%% @type field(). Represents a field in a "bin".
%%% Part 1: expression evaluation (binary construction)
%% @spec expr_grp(Fields::[field()], Bindings::bindings(),
-%% EvalFun::evalfun()) ->
+%% EvalFun::evalfun(), term(), term()) ->
%% {value, binary(), bindings()}
%%
%% @doc Returns a tuple with {value,Bin,Bs} where Bin is the binary
@@ -192,9 +192,9 @@ bin_gen_field({bin_element,Line,VE,Size0,Options0},
end.
%%% Part 3: binary pattern matching
-%% @spec match_bits(Fields::[field()], Bin::binary()
+%% @spec match_bits(Fields::[field()], Bin::binary(),
%% GlobalEnv::bindings(), LocalEnv::bindings(),
-%% MatchFun::matchfun(),EvalFun::evalfun()) ->
+%% MatchFun::matchfun(),EvalFun::evalfun(), term()) ->
%% {match, bindings()}
%% @doc Used to perform matching. If the match succeeds a new
%% environment is returned. If the match have some syntactic or
diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl
index 165e03e506..0252cdf742 100644
--- a/lib/stdlib/src/io_lib.erl
+++ b/lib/stdlib/src/io_lib.erl
@@ -109,9 +109,9 @@ fwrite(Format, Args) ->
fread(Chars, Format) ->
io_lib_fread:fread(Chars, Format).
--spec fread(Continuation, String, Format) -> Return when
+-spec fread(Continuation, CharSpec, Format) -> Return when
Continuation :: continuation() | [],
- String :: string(),
+ CharSpec :: string() | eof,
Format :: string(),
Return :: {'more', Continuation1 :: continuation()}
| {'done', Result, LeftOverChars :: string()},
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 39d017d430..5129ba5074 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -461,6 +461,14 @@ obsolete_1(public_key, pem_to_der, 1) ->
obsolete_1(public_key, decode_private_key, A) when A =:= 1; A =:= 2 ->
{deprecated,{public_key,pem_entry_decode,1},"R15A"};
+%% Added in R14B03.
+obsolete_1(docb_gen, _, _) ->
+ {deprecated,"the DocBuilder application is deprecated (will be removed in R15B)"};
+obsolete_1(docb_transform, _, _) ->
+ {deprecated,"the DocBuilder application is deprecated (will be removed in R15B)"};
+obsolete_1(docb_xml_check, _, _) ->
+ {deprecated,"the DocBuilder application is deprecated (will be removed in R15B)"};
+
obsolete_1(_, _, _) ->
no.
diff --git a/lib/stdlib/src/proplists.erl b/lib/stdlib/src/proplists.erl
index 68697d0da2..e3eda5d932 100644
--- a/lib/stdlib/src/proplists.erl
+++ b/lib/stdlib/src/proplists.erl
@@ -49,9 +49,10 @@
%% ---------------------------------------------------------------------
--export_type([property/0]).
+-export_type([property/0, proplist/0]).
-type property() :: atom() | tuple().
+-type proplist() :: [property()].
%% ---------------------------------------------------------------------
diff --git a/lib/stdlib/src/sofs.erl b/lib/stdlib/src/sofs.erl
index d38b8ab37a..34eb224647 100644
--- a/lib/stdlib/src/sofs.erl
+++ b/lib/stdlib/src/sofs.erl
@@ -81,7 +81,8 @@
-define(ORDTAG, 'OrdSet').
-record(?TAG, {data = [] :: list(), type = type :: term()}).
--record(?ORDTAG, {orddata = {} :: tuple(), ordtype = type :: term()}).
+-record(?ORDTAG, {orddata = {} :: tuple() | atom(),
+ ordtype = type :: term()}).
-define(LIST(S), (S)#?TAG.data).
-define(TYPE(S), (S)#?TAG.type).
@@ -375,7 +376,7 @@ to_sets(S) when ?IS_ORDSET(S) ->
-spec(no_elements(ASet) -> NoElements when
ASet :: a_set() | ordset(),
- NoElements :: pos_integer()).
+ NoElements :: non_neg_integer()).
no_elements(S) when ?IS_SET(S) ->
length(?LIST(S));
no_elements(S) when ?IS_ORDSET(S), is_tuple(?ORDTYPE(S)) ->
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index e60706ed05..dc31647eb5 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -735,6 +735,13 @@ restart(one_for_all, Child, State) ->
terminate_children(Children, SupName) ->
terminate_children(Children, SupName, []).
+%% Temporary children should not be restarted and thus should
+%% be skipped when building the list of terminated children, although
+%% we do want them to be shut down as many functions from this module
+%% use this function to just clear everything.
+terminate_children([Child = #child{restart_type=temporary} | Children], SupName, Res) ->
+ do_terminate(Child, SupName),
+ terminate_children(Children, SupName, Res);
terminate_children([Child | Children], SupName, Res) ->
NChild = do_terminate(Child, SupName),
terminate_children(Children, SupName, [NChild | Res]);
diff --git a/lib/stdlib/src/sys.erl b/lib/stdlib/src/sys.erl
index 8ab72c9b50..f34201604c 100644
--- a/lib/stdlib/src/sys.erl
+++ b/lib/stdlib/src/sys.erl
@@ -154,7 +154,7 @@ log_to_file(Name, FileName, Timeout) ->
-spec statistics(Name, Flag) -> 'ok' | {'ok', Statistics} when
Name :: name(),
Flag :: 'true' | 'false' | 'get',
- Statistics :: [StatisticsTuple],
+ Statistics :: [StatisticsTuple] | no_statistics,
StatisticsTuple :: {'start_time', DateTime1}
| {'current_time', DateTime2}
| {'reductions', non_neg_integer()}
@@ -168,7 +168,7 @@ statistics(Name, Flag) ->
-spec statistics(Name, Flag, Timeout) -> 'ok' | {'ok', Statistics} when
Name :: name(),
Flag :: 'true' | 'false' | 'get',
- Statistics :: [StatisticsTuple],
+ Statistics :: [StatisticsTuple] | no_statistics,
StatisticsTuple :: {'start_time', DateTime1}
| {'current_time', DateTime2}
| {'reductions', non_neg_integer()}
diff --git a/lib/stdlib/test/beam_lib_SUITE.erl b/lib/stdlib/test/beam_lib_SUITE.erl
index 4ccc863795..91fff3cee4 100644
--- a/lib/stdlib/test/beam_lib_SUITE.erl
+++ b/lib/stdlib/test/beam_lib_SUITE.erl
@@ -242,8 +242,8 @@ cmp(doc) -> ["Compare contents of BEAM files and directories"];
cmp(Conf) when is_list(Conf) ->
?line PrivDir = ?privdir,
- ?line Dir1 = filename:join(PrivDir, dir1),
- ?line Dir2 = filename:join(PrivDir, dir2),
+ ?line Dir1 = filename:join(PrivDir, "dir1"),
+ ?line Dir2 = filename:join(PrivDir, "dir2"),
ok = file:make_dir(Dir1),
ok = file:make_dir(Dir2),
@@ -292,8 +292,8 @@ cmp_literals(doc) -> ["Compare contents of BEAM files having literals"];
cmp_literals(Conf) when is_list(Conf) ->
?line PrivDir = ?privdir,
- ?line Dir1 = filename:join(PrivDir, dir1),
- ?line Dir2 = filename:join(PrivDir, dir2),
+ ?line Dir1 = filename:join(PrivDir, "dir1"),
+ ?line Dir2 = filename:join(PrivDir, "dir2"),
ok = file:make_dir(Dir1),
ok = file:make_dir(Dir2),
@@ -381,7 +381,7 @@ otp_6711(Conf) when is_list(Conf) ->
(catch {a, beam_lib:strip_files([3])}),
?line PrivDir = ?privdir,
- ?line Dir = filename:join(PrivDir, dir),
+ ?line Dir = filename:join(PrivDir, "dir"),
?line Lib = filename:join(Dir, "lib"),
?line App = filename:join(Lib, "app"),
?line EBin = filename:join(App, "ebin"),
@@ -417,8 +417,8 @@ building(doc) -> "Testing building of BEAM files.";
building(Conf) when is_list(Conf) ->
?line PrivDir = ?privdir,
- ?line Dir1 = filename:join(PrivDir, b_dir1),
- ?line Dir2 = filename:join(PrivDir, b_dir2),
+ ?line Dir1 = filename:join(PrivDir, "b_dir1"),
+ ?line Dir2 = filename:join(PrivDir, "b_dir2"),
ok = file:make_dir(Dir1),
ok = file:make_dir(Dir2),
@@ -688,7 +688,7 @@ chunk_info(File) ->
Chunks.
make_beam(Dir, Module, F) ->
- ?line FileBase = filename:join(Dir, Module),
+ ?line FileBase = filename:join(Dir, atom_to_list(Module)),
?line Source = FileBase ++ ".erl",
?line BeamFile = FileBase ++ ".beam",
?line simple_file(Source, Module, F),
diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl
index 698070368f..22a9d4a7ff 100644
--- a/lib/stdlib/test/dets_SUITE.erl
+++ b/lib/stdlib/test/dets_SUITE.erl
@@ -1516,7 +1516,7 @@ repair(Config, V) ->
if
V =:= 8 ->
%% first estimated number of objects is wrong, repair once more
- ?line {ok, Fd} = file:open(Fname, read_write),
+ ?line {ok, Fd} = file:open(Fname, [read,write]),
NoPos = HeadSize - 8, % no_objects
?line file:pwrite(Fd, NoPos, <<0:32>>), % NoItems
ok = file:close(Fd),
@@ -3247,7 +3247,7 @@ otp_5402(suite) ->
[];
otp_5402(Config) when is_list(Config) ->
Tab = otp_5402,
- ?line File = filename:join([cannot, write, this, file]),
+ ?line File = filename:join(["cannot", "write", "this", "file"]),
%% close
?line{ok, T} = dets:open_file(Tab, [{ram_file,true},
@@ -3887,7 +3887,7 @@ crash(File, Where) ->
crash(File, Where, 10).
crash(File, Where, What) when is_integer(What) ->
- ?line {ok, Fd} = file:open(File, read_write),
+ ?line {ok, Fd} = file:open(File, [read,write]),
?line file:position(Fd, Where),
?line ok = file:write(Fd, [What]),
?line ok = file:close(Fd).
@@ -4031,7 +4031,7 @@ writable(Fname) ->
?line file:write_file_info(Fname, Info#file_info{mode = Mode}).
truncate(File, Where) ->
- ?line {ok, Fd} = file:open(File, read_write),
+ ?line {ok, Fd} = file:open(File, [read,write]),
?line file:position(Fd, Where),
?line ok = file:truncate(Fd),
?line ok = file:close(Fd).
diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl
index 9b024a5b49..57f3f4eddb 100644
--- a/lib/stdlib/test/epp_SUITE.erl
+++ b/lib/stdlib/test/epp_SUITE.erl
@@ -1280,7 +1280,7 @@ eval_tests(Config, Fun, Tests) ->
check_test(Config, Test) ->
- Filename = 'epp_test.erl',
+ Filename = "epp_test.erl",
?line PrivDir = ?config(priv_dir, Config),
?line File = filename:join(PrivDir, Filename),
?line ok = file:write_file(File, Test),
@@ -1293,7 +1293,7 @@ check_test(Config, Test) ->
compile_test(Config, Test0) ->
Test = [<<"-module(epp_test). -compile(export_all). ">>, Test0],
- Filename = 'epp_test.erl',
+ Filename = "epp_test.erl",
?line PrivDir = ?config(priv_dir, Config),
?line File = filename:join(PrivDir, Filename),
?line ok = file:write_file(File, Test),
diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl
index 0bcf3c5b71..784c7cb86e 100644
--- a/lib/stdlib/test/erl_eval_SUITE.erl
+++ b/lib/stdlib/test/erl_eval_SUITE.erl
@@ -1189,7 +1189,7 @@ lfh() ->
{eval, fun(F, As, Bs) -> local_func(F, As, Bs) end}.
local_func(F, As0, Bs0) when is_atom(F) ->
- {As,Bs} = erl_eval:expr_list(As0, Bs0, {eval,lfh()}),
+ {As,Bs} = erl_eval:expr_list(As0, Bs0, lfh()),
case erlang:function_exported(?MODULE, F, length(As)) of
true ->
{value,apply(?MODULE, F, As),Bs};
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index f980d52e4e..9041adbe5c 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -2981,7 +2981,7 @@ run_test(Conf, Test0, Warnings0) ->
run_test2(Conf, Test, Warnings0).
run_test2(Conf, Test, Warnings0) ->
- Filename = 'lint_test.erl',
+ Filename = "lint_test.erl",
DataDir = ?privdir,
File = filename:join(DataDir, Filename),
Opts = case Warnings0 of
diff --git a/lib/stdlib/test/file_sorter_SUITE.erl b/lib/stdlib/test/file_sorter_SUITE.erl
index 80d4ea5fdc..74c08912be 100644
--- a/lib/stdlib/test/file_sorter_SUITE.erl
+++ b/lib/stdlib/test/file_sorter_SUITE.erl
@@ -89,7 +89,7 @@ basic(suite) ->
basic(Config) when is_list(Config) ->
Fmt = binary,
Arg = {format,Fmt},
- Foo = outfile(foo, Config),
+ Foo = outfile("foo", Config),
P0 = pps(),
?line F1s = [F1] = to_files([[]], Fmt, Config),
@@ -455,7 +455,7 @@ inout(suite) ->
[];
inout(Config) when is_list(Config) ->
BTF = {format, binary_term},
- Foo = outfile(foo, Config),
+ Foo = outfile("foo", Config),
%% Input is fun.
End = fun(read) -> end_of_input end,
@@ -522,7 +522,7 @@ many(doc) ->
many(suite) ->
[];
many(Config) when is_list(Config) ->
- Foo = outfile(foo, Config),
+ Foo = outfile("foo", Config),
PrivDir = ?privdir(Config),
P0 = pps(),
@@ -587,7 +587,7 @@ misc(suite) ->
[];
misc(Config) when is_list(Config) ->
BTF = {format, binary_term},
- Foo = outfile(foo, Config),
+ Foo = outfile("foo", Config),
FFoo = filename:absname(Foo),
P0 = pps(),
@@ -704,7 +704,7 @@ misc(Config) when is_list(Config) ->
sort(Fmt, XArgs, Config) ->
Args = make_args(Fmt, [{size,5} | XArgs]),
TmpArgs = [{tmpdir,?privdir(Config)} | Args],
- Foo = outfile(foo, Config),
+ Foo = outfile("foo", Config),
%% Input is a fun. Output is a fun.
?line [] = file_sorter:sort(input([], 2, Fmt), output([], Fmt), Args),
@@ -777,7 +777,7 @@ sort(Fmt, XArgs, Config) ->
keysort(Fmt, XArgs, Config) ->
Args = make_args(Fmt, [{size,50}, {no_files, 2} | XArgs]),
TmpArgs = Args ++ [{tmpdir,?privdir(Config)}],
- Foo = outfile(foo, Config),
+ Foo = outfile("foo", Config),
%% Input is files. Output is a file.
?line ok = file_sorter:keysort(2, [], Foo, Args),
@@ -836,7 +836,7 @@ keysort(Fmt, XArgs, Config) ->
merge(Fmt, XArgs, Config) ->
Args = make_args(Fmt, [{size,5} | XArgs]),
- Foo = outfile(foo, Config),
+ Foo = outfile("foo", Config),
%% Input is a file. Output is a fun.
?line [] = file_sorter:merge([], output([], Fmt), Args),
@@ -873,7 +873,7 @@ merge(Fmt, XArgs, Config) ->
keymerge(Fmt, XArgs, Config) ->
Args = make_args(Fmt, [{size,50}, {no_files, 2} | XArgs]),
- Foo = outfile(foo, Config),
+ Foo = outfile("foo", Config),
%% Input is files. Output is a file.
?line ok = file_sorter:keymerge(2, [], Foo, Args),
diff --git a/lib/stdlib/test/filelib_SUITE.erl b/lib/stdlib/test/filelib_SUITE.erl
index a355097fe2..3010f5e760 100644
--- a/lib/stdlib/test/filelib_SUITE.erl
+++ b/lib/stdlib/test/filelib_SUITE.erl
@@ -243,7 +243,7 @@ otp_5960(doc) ->
["Test that filelib:ensure_dir/1 returns ok or {error,Reason}"];
otp_5960(Config) when is_list(Config) ->
?line PrivDir = ?config(priv_dir, Config),
- ?line Dir = filename:join(PrivDir, otp_5960_dir),
+ ?line Dir = filename:join(PrivDir, "otp_5960_dir"),
?line Name1 = filename:join(Dir, name1),
?line Name2 = filename:join(Dir, name2),
?line ok = filelib:ensure_dir(Name1), % parent is created
@@ -268,7 +268,7 @@ otp_5960(Config) when is_list(Config) ->
ensure_dir_eexist(Config) when is_list(Config) ->
?line PrivDir = ?config(priv_dir, Config),
- ?line Dir = filename:join(PrivDir, ensure_dir_eexist),
+ ?line Dir = filename:join(PrivDir, "ensure_dir_eexist"),
?line Name = filename:join(Dir, "same_name_as_file_and_dir"),
?line ok = filelib:ensure_dir(Name),
?line ok = file:write_file(Name, <<"some string\n">>),
diff --git a/lib/stdlib/test/string_SUITE.erl b/lib/stdlib/test/string_SUITE.erl
index 1dcd4be21e..6969c095a0 100644
--- a/lib/stdlib/test/string_SUITE.erl
+++ b/lib/stdlib/test/string_SUITE.erl
@@ -273,9 +273,9 @@ words(Config) when is_list(Config) ->
?line 2 = string:words("2.35", $.),
?line 100 = string:words(string:copies(". ", 100)),
%% invalid arg type
- ?line {'EXIT',_} = (catch string:chars(hej)),
+ ?line {'EXIT',_} = (catch string:chars(hej, 1)),
%% invalid arg type
- ?line {'EXIT',_} = (catch string:chars("hej", " ")),
+ ?line {'EXIT',_} = (catch string:chars("hej", 1, " ")),
ok.
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index ff5e4c629a..b48450c151 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -42,7 +42,7 @@
-export([ permanent_normal/1, transient_normal/1,
temporary_normal/1,
permanent_abnormal/1, transient_abnormal/1,
- temporary_abnormal/1]).
+ temporary_abnormal/1, temporary_bystander/1]).
%% Restart strategy tests
-export([ one_for_one/1,
@@ -74,7 +74,7 @@ all() ->
{group, abnormal_termination}, child_unlink, tree,
count_children_memory, do_not_save_start_parameters_for_temporary_children,
do_not_save_child_specs_for_temporary_children,
- simple_one_for_one_scale_many_temporary_children].
+ simple_one_for_one_scale_many_temporary_children, temporary_bystander].
groups() ->
[{sup_start, [],
@@ -607,6 +607,37 @@ temporary_abnormal(Config) when is_list(Config) ->
[0,0,0,0] = get_child_counts(sup_test).
%%-------------------------------------------------------------------------
+temporary_bystander(doc) ->
+ ["A temporary process killed as part of a rest_for_one or one_for_all "
+ "restart strategy should not be restarted given its args are not "
+ " saved. Otherwise the supervisor hits its limit and crashes."];
+temporary_bystander(suite) -> [];
+temporary_bystander(_Config) ->
+ Child1 = {child1, {supervisor_1, start_child, []}, permanent, 100,
+ worker, []},
+ Child2 = {child2, {supervisor_1, start_child, []}, temporary, 100,
+ worker, []},
+ {ok, SupPid1} = supervisor:start_link(?MODULE, {ok, {{one_for_all, 2, 300}, []}}),
+ {ok, SupPid2} = supervisor:start_link(?MODULE, {ok, {{rest_for_one, 2, 300}, []}}),
+ unlink(SupPid1), % otherwise we crash with it
+ unlink(SupPid2), % otherwise we crash with it
+ {ok, CPid1} = supervisor:start_child(SupPid1, Child1),
+ {ok, _CPid2} = supervisor:start_child(SupPid1, Child2),
+ {ok, CPid3} = supervisor:start_child(SupPid2, Child1),
+ {ok, _CPid4} = supervisor:start_child(SupPid2, Child2),
+ terminate(SupPid1, CPid1, child1, normal),
+ terminate(SupPid2, CPid3, child1, normal),
+ timer:sleep(350),
+ catch link(SupPid1),
+ catch link(SupPid2),
+ %% The supervisor would die attempting to restart child2
+ true = erlang:is_process_alive(SupPid1),
+ true = erlang:is_process_alive(SupPid2),
+ %% Child2 has not been restarted
+ [{child1, _, _, _}] = supervisor:which_children(SupPid1),
+ [{child1, _, _, _}] = supervisor:which_children(SupPid2).
+
+%%-------------------------------------------------------------------------
one_for_one(doc) ->
["Test the one_for_one base case."];
one_for_one(suite) -> [];
diff --git a/lib/stdlib/test/supervisor_bridge_SUITE.erl b/lib/stdlib/test/supervisor_bridge_SUITE.erl
index f2dbad0b3b..c4d696564d 100644
--- a/lib/stdlib/test/supervisor_bridge_SUITE.erl
+++ b/lib/stdlib/test/supervisor_bridge_SUITE.erl
@@ -158,7 +158,7 @@ internal_loop(State) ->
terminate(Reason,{Parent,Worker}) ->
%% This func knows about supervisor_bridge
io:format("Terminating bridge...\n"),
- exit(kill,Worker),
+ exit(Worker,kill),
Parent ! {dying,Reason},
anything.
diff --git a/lib/stdlib/test/sys_SUITE.erl b/lib/stdlib/test/sys_SUITE.erl
index 72b089aa3f..fe039e8bcc 100644
--- a/lib/stdlib/test/sys_SUITE.erl
+++ b/lib/stdlib/test/sys_SUITE.erl
@@ -71,7 +71,7 @@ log_to_file(Config) when is_list(Config) ->
?line ok = sys:log_to_file(?server,TempName),
?line {ok,-44} = public_call(44),
?line ok = sys:log_to_file(?server,false),
- ?line {ok,Fd} = file:open(TempName,read),
+ ?line {ok,Fd} = file:open(TempName,[read]),
?line Msg1 = io:get_line(Fd,''),
?line Msg2 = io:get_line(Fd,''),
?line file:close(Fd),
diff --git a/lib/stdlib/test/tar_SUITE.erl b/lib/stdlib/test/tar_SUITE.erl
index e32704ca65..48f58cd05d 100644
--- a/lib/stdlib/test/tar_SUITE.erl
+++ b/lib/stdlib/test/tar_SUITE.erl
@@ -65,7 +65,7 @@ borderline(Config) when is_list(Config) ->
?line {ok, Cwd} = file:get_cwd(),
?line RootDir = ?config(priv_dir, Config),
- ?line TempDir = remove_prefix(Cwd++"/", filename:join(RootDir, borderline)),
+ ?line TempDir = remove_prefix(Cwd++"/", filename:join(RootDir, "borderline")),
?line ok = file:make_dir(TempDir),
?line Record = 512,
@@ -323,12 +323,12 @@ create_long_names(doc) ->
create_long_names(Config) when is_list(Config) ->
?line PrivDir = ?config(priv_dir, Config),
?line ok = file:set_cwd(PrivDir),
- Dirs = [aslfjkshjkhliuf,
- asdhjfehnbfsky,
- sahajfskdfhsz,
- asldfkdlfy4y8rchg,
- f7nafhjgffagkhsfkhsjk,
- dfjasldkfjsdkfjashbv],
+ Dirs = ["aslfjkshjkhliuf",
+ "asdhjfehnbfsky",
+ "sahajfskdfhsz",
+ "asldfkdlfy4y8rchg",
+ "f7nafhjgffagkhsfkhsjk",
+ "dfjasldkfjsdkfjashbv"],
?line DeepDir = make_dirs(Dirs, []),
?line AFile = filename:join(DeepDir, "a_file"),
@@ -487,7 +487,7 @@ extract_from_binary_compressed(Config) when is_list(Config) ->
%% Trying extracting from a binary.
?line ok = erl_tar:extract({binary,Bin}, [compressed,{cwd,ExtractDir}]),
- ?line {ok,List} = file:list_dir(filename:join(ExtractDir, ddll_SUITE_data)),
+ ?line {ok,List} = file:list_dir(filename:join(ExtractDir, "ddll_SUITE_data")),
?line io:format("~p\n", [List]),
?line 19 = length(List),
@@ -676,7 +676,7 @@ cooked_compressed(Config) when is_list(Config) ->
end, List),
%% Clean up.
- ?line delete_files([filename:join(PrivDir, ddll_SUITE_data)]),
+ ?line delete_files([filename:join(PrivDir, "ddll_SUITE_data")]),
ok.
memory(doc) ->
diff --git a/lib/test_server/src/ts_install_cth.erl b/lib/test_server/src/ts_install_cth.erl
index c5444a342f..a41916fd0a 100644
--- a/lib/test_server/src/ts_install_cth.erl
+++ b/lib/test_server/src/ts_install_cth.erl
@@ -49,8 +49,7 @@
-include_lib("kernel/include/file.hrl").
--type proplist() :: list({atom(),term()}).
--type config() :: proplist().
+-type config() :: proplists:proplist().
-type reason() :: term().
-type skip_or_fail() :: {skip, reason()} |
{auto_skip, reason()} |
@@ -65,19 +64,19 @@ id(_Opts) ->
?MODULE.
%% @doc Always called before any other callback function.
--spec init(Id :: term(), Opts :: proplist()) ->
- State :: #state{}.
+-spec init(Id :: term(), Opts :: proplists:proplist()) ->
+ {ok, State :: #state{}}.
init(_Id, Opts) ->
Nodenames = proplists:get_value(nodenames, Opts, 0),
Nodes = proplists:get_value(nodes, Opts, 0),
TSConfDir = proplists:get_value(ts_conf_dir, Opts),
TargetSystem = proplists:get_value(target_system, Opts, install_local),
InstallOpts = proplists:get_value(install_opts, Opts, []),
- #state{ nodenames = Nodenames,
- nodes = Nodes,
- ts_conf_dir = TSConfDir,
- target_system = TargetSystem,
- install_opts = InstallOpts }.
+ {ok, #state{ nodenames = Nodenames,
+ nodes = Nodes,
+ ts_conf_dir = TSConfDir,
+ target_system = TargetSystem,
+ install_opts = InstallOpts } }.
%% @doc Called before init_per_suite is called.
-spec pre_init_per_suite(Suite :: atom(),
diff --git a/lib/test_server/test/Makefile b/lib/test_server/test/Makefile
index ab72a9d579..198440bb17 100644
--- a/lib/test_server/test/Makefile
+++ b/lib/test_server/test/Makefile
@@ -85,7 +85,7 @@ release_spec: opt
release_tests_spec: make_emakefile
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) $(COVERFILE) $(RELSYSDIR)
- $(INSTALL_DATA) test_server.spec test_server.cover $(RELSYSDIR)
+ $(INSTALL_DATA) test_server_test_lib.hrl test_server.spec test_server.cover $(RELSYSDIR)
chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index 6728bef2a4..a8dd3ec3ac 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -523,6 +523,32 @@ This is an elisp list of options. Each option can be either:
- a string
Example: '(bin_opt_info (i . \"/path1/include\") (i . \"/path2/include\"))")
+(defvar erlang-compile-command-function-alist
+ '((".erl\\'" . inferior-erlang-compute-erl-compile-command)
+ (".xrl\\'" . inferior-erlang-compute-leex-compile-command)
+ (".yrl\\'" . inferior-erlang-compute-yecc-compile-command)
+ ("." . inferior-erlang-compute-erl-compile-command))
+ "*Alist of filename patterns vs corresponding compilation functions.
+Each element looks like (REGEXP . FUNCTION). Compiling a file whose name
+matches REGEXP specifies FUNCTION to use to compute the compilation
+command. The FUNCTION will be called with two arguments: module name and
+default compilation options, like output directory. The FUNCTION
+is expected to return a string.")
+
+(defvar erlang-leex-compile-opts '()
+ "*Options to pass to leex when compiling xrl files.
+This is an elisp list of options. Each option can be either:
+- an atom
+- a dotted pair
+- a string")
+
+(defvar erlang-yecc-compile-opts '()
+ "*Options to pass to yecc when compiling yrl files.
+This is an elisp list of options. Each option can be either:
+- an atom
+- a dotted pair
+- a string")
+
(eval-and-compile
(defvar erlang-regexp-modern-p
(if (> erlang-emacs-major-version 21) t nil)
@@ -5276,6 +5302,22 @@ unless the optional NO-DISPLAY is non-nil."
(file-name-as-directory buffer-dir))))
(defun inferior-erlang-compute-compile-command (module-name opts)
+ (let ((ccfn erlang-compile-command-function-alist)
+ (res (inferior-erlang-compute-erl-compile-command module-name opts))
+ ccfn-entry
+ done)
+ (if (not (null (buffer-file-name)))
+ (while (and (not done) (not (null ccfn)))
+ (setq ccfn-entry (car ccfn))
+ (setq ccfn (cdr ccfn))
+ (if (string-match (car ccfn-entry) (buffer-file-name))
+ (let ((c-fn (cdr ccfn-entry)))
+ (setq done t)
+ (if (not (null c-fn))
+ (setq result (funcall c-fn module-name opts)))))))
+ result))
+
+(defun inferior-erlang-compute-erl-compile-command (module-name opts)
(let* ((out-dir-opt (assoc 'outdir opts))
(out-dir (cdr out-dir-opt)))
(if erlang-compile-use-outdir
@@ -5299,6 +5341,48 @@ unless the optional NO-DISPLAY is non-nil."
(remq out-dir-opt opts))
tmpvar tmpvar tmpvar2)))))
+(defun inferior-erlang-compute-leex-compile-command (module-name opts)
+ (let ((file-name (buffer-file-name))
+ (erl-compile-expr (inferior-erlang-remove-any-trailing-dot
+ (inferior-erlang-compute-erl-compile-command
+ module-name opts))))
+ (format (concat "f(LErr1__), f(LErr2__), "
+ "case case leex:file(\"%s\", [%s]) of"
+ " ok -> ok;"
+ " {ok,_} -> ok;"
+ " {ok,_,_} -> ok;"
+ " LErr1__ -> LErr1__ "
+ "end of"
+ " ok -> %s;"
+ " LErr2__ -> LErr2__ "
+ "end.")
+ file-name
+ (inferior-erlang-format-comma-opts erlang-leex-compile-opts)
+ erl-compile-expr)))
+
+(defun inferior-erlang-compute-yecc-compile-command (module-name opts)
+ (let ((file-name (buffer-file-name))
+ (erl-compile-expr (inferior-erlang-remove-any-trailing-dot
+ (inferior-erlang-compute-erl-compile-command
+ module-name opts))))
+ (format (concat "f(YErr1__), f(YErr2__), "
+ "case case yecc:file(\"%s\", [%s]) of"
+ " {ok,_} -> ok;"
+ " {ok,_,_} -> ok;"
+ " YErr1__ -> YErr1__ "
+ "end of"
+ " ok -> %s;"
+ " YErr2__ -> YErr2__ "
+ "end.")
+ file-name
+ (inferior-erlang-format-comma-opts erlang-yecc-compile-opts)
+ erl-compile-expr)))
+
+(defun inferior-erlang-remove-any-trailing-dot (str)
+ (if (string= (substring str -1) ".")
+ (substring str 0 (1- (length str)))
+ str))
+
(defun inferior-erlang-format-comma-opts (opts)
(if (null opts)
""
diff --git a/lib/webtool/priv/Makefile b/lib/webtool/priv/Makefile
index 56ab772c45..6e1c6606fe 100644
--- a/lib/webtool/priv/Makefile
+++ b/lib/webtool/priv/Makefile
@@ -39,8 +39,12 @@ HTDOCS_FILES = root/doc/index.html \
root/doc/tool_management.html \
root/doc/start_info.html
-SCRIPTS = bin/start_webtool \
- bin/start_webtool.bat
+ifeq ($(findstring win32,$(TARGET)),win32)
+WIN32_SCRIPTS= bin/start_webtool.bat
+else
+WIN32_SCRIPTS=
+endif
+SCRIPTS = bin/start_webtool $(WIN32_SCRIPTS)
# ----------------------------------------------------
# FLAGS
diff --git a/lib/wx/test/wxt.erl b/lib/wx/test/wxt.erl
index 1f5b1cc3b1..2f52c58f26 100644
--- a/lib/wx/test/wxt.erl
+++ b/lib/wx/test/wxt.erl
@@ -72,7 +72,7 @@ resolve({Suite0, Case}) when is_atom(Suite0), is_atom(Case) ->
{Suite, Case2} ->
{Suite, Case2}
end;
-resolve(List) when list(List) ->
+resolve(List) when is_list(List) ->
[resolve(Case) || Case <- List].
alias(Suite) when is_atom(Suite) ->
@@ -104,7 +104,7 @@ read_config() ->
end.
%% Write new default config file
-write_config(Config) when list(Config) ->
+write_config(Config) when is_list(Config) ->
Fname = config_fname(),
{ok, Fd} = file:open(Fname, write),
write_list(Fd, Config),
diff --git a/lib/xmerl/test/Makefile b/lib/xmerl/test/Makefile
index 9715aa054a..5a2a585841 100644
--- a/lib/xmerl/test/Makefile
+++ b/lib/xmerl/test/Makefile
@@ -124,4 +124,4 @@ release_tests_spec: opt
@tar cfh - xmerl_xsd_MS2002-01-16_SUITE_data | (cd $(RELSYSDIR); tar xf -)
@tar cfh - xmerl_xsd_NIST2002-01-16_SUITE_data | (cd $(RELSYSDIR); tar xf -)
@tar cfh - xmerl_xsd_Sun2002-01-16_SUITE_data | (cd $(RELSYSDIR); tar xf -)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)