aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/src')
-rw-r--r--lib/kernel/src/application.erl174
-rw-r--r--lib/kernel/src/application_controller.erl234
-rw-r--r--lib/kernel/src/application_starter.erl22
-rw-r--r--lib/kernel/src/auth.erl86
-rw-r--r--lib/kernel/src/code.erl274
-rw-r--r--lib/kernel/src/code_server.erl184
-rw-r--r--lib/kernel/src/disk_log.erl252
-rw-r--r--lib/kernel/src/disk_log.hrl42
-rw-r--r--lib/kernel/src/disk_log_1.erl22
-rw-r--r--lib/kernel/src/dist_util.erl15
-rw-r--r--lib/kernel/src/erl_boot_server.erl70
-rw-r--r--lib/kernel/src/erl_ddll.erl68
-rw-r--r--lib/kernel/src/erl_epmd.erl116
-rw-r--r--lib/kernel/src/erl_epmd.hrl17
-rw-r--r--lib/kernel/src/error_handler.erl40
-rw-r--r--lib/kernel/src/error_logger.erl79
-rw-r--r--lib/kernel/src/file.erl435
-rw-r--r--lib/kernel/src/file_io_server.erl65
-rw-r--r--lib/kernel/src/file_server.erl33
-rw-r--r--lib/kernel/src/gen_sctp.erl220
-rw-r--r--lib/kernel/src/gen_tcp.erl190
-rw-r--r--lib/kernel/src/gen_udp.erl133
-rw-r--r--lib/kernel/src/global.erl251
-rw-r--r--lib/kernel/src/global_group.erl58
-rw-r--r--lib/kernel/src/global_search.erl5
-rw-r--r--lib/kernel/src/group.erl48
-rw-r--r--lib/kernel/src/heart.erl27
-rw-r--r--lib/kernel/src/hipe_unified_loader.erl11
-rw-r--r--lib/kernel/src/inet.erl235
-rw-r--r--lib/kernel/src/inet6_sctp.erl23
-rw-r--r--lib/kernel/src/inet6_tcp_dist.erl39
-rw-r--r--lib/kernel/src/inet_config.erl54
-rw-r--r--lib/kernel/src/inet_db.erl67
-rw-r--r--lib/kernel/src/inet_dns.erl44
-rw-r--r--lib/kernel/src/inet_dns_record_adts.pl12
-rw-r--r--lib/kernel/src/inet_gethost_native.erl25
-rw-r--r--lib/kernel/src/inet_int.hrl3
-rw-r--r--lib/kernel/src/inet_parse.erl2
-rw-r--r--lib/kernel/src/inet_res.erl386
-rw-r--r--lib/kernel/src/inet_sctp.erl21
-rw-r--r--lib/kernel/src/inet_udp.erl6
-rw-r--r--lib/kernel/src/kernel.erl9
-rw-r--r--lib/kernel/src/kernel_config.erl27
-rw-r--r--lib/kernel/src/net_adm.erl41
-rw-r--r--lib/kernel/src/net_kernel.erl165
-rw-r--r--lib/kernel/src/os.erl87
-rw-r--r--lib/kernel/src/pg2.erl72
-rw-r--r--lib/kernel/src/ram_file.erl48
-rw-r--r--lib/kernel/src/rpc.erl252
-rw-r--r--lib/kernel/src/seq_trace.erl44
-rw-r--r--lib/kernel/src/standard_error.erl40
-rw-r--r--lib/kernel/src/user.erl21
-rw-r--r--lib/kernel/src/wrap_log_reader.erl45
53 files changed, 3269 insertions, 1670 deletions
diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl
index d9db23d652..fa3a4c3d36 100644
--- a/lib/kernel/src/application.erl
+++ b/lib/kernel/src/application.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-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
@@ -32,20 +32,30 @@
%%%-----------------------------------------------------------------
+-type start_type() :: 'normal'
+ | {'takeover', Node :: node()}
+ | {'failover', Node :: node()}.
-type restart_type() :: 'permanent' | 'transient' | 'temporary'.
--type application_opt() :: {'description', string()}
- | {'vsn', string()}
- | {'id', string()}
- | {'modules', [atom() | {atom(), any()}]}
- | {'registered', [atom()]}
- | {'applications', [atom()]}
- | {'included_applications', [atom()]}
- | {'env', [{atom(), any()}]}
- | {'start_phases', [{atom(), any()}] | 'undefined'}
- | {'maxT', timeout()} % max timeout
- | {'maxP', integer() | 'infinity'} % max processes
- | {'mod', {atom(), any()}}.
--type application_spec() :: {'application', atom(), [application_opt()]}.
+-type application_opt() :: {'description', Description :: string()}
+ | {'vsn', Vsn :: string()}
+ | {'id', Id :: string()}
+ | {'modules', [(Module :: module()) |
+ {Module :: module(), Version :: term()}]}
+ | {'registered', Names :: [Name :: atom()]}
+ | {'applications', [Application :: atom()]}
+ | {'included_applications', [Application :: atom()]}
+ | {'env', [{Par :: atom(), Val :: term()}]}
+ | {'start_phases',
+ [{Phase :: atom(), PhaseArgs :: term()}] | 'undefined'}
+ | {'maxT', MaxT :: timeout()} % max timeout
+ | {'maxP',
+ MaxP :: pos_integer() | 'infinity'} % max processes
+ | {'mod', Start :: {Module :: module(), StartArgs :: term()}}.
+-type application_spec() :: {'application',
+ Application :: atom(),
+ AppSpecKeys :: [application_opt()]}.
+
+-type(tuple_of(_T) :: tuple()).
%%------------------------------------------------------------------
@@ -61,16 +71,29 @@ behaviour_info(_Other) ->
%%% application_master.
%%%-----------------------------------------------------------------
--spec load(Application :: atom() | application_spec()) ->
- 'ok' | {'error', term()}.
+-spec load(AppDescr) -> 'ok' | {'error', Reason} when
+ AppDescr :: Application | (AppSpec :: application_spec()),
+ Application :: atom(),
+ Reason :: term().
load(Application) ->
- load(Application, []).
-
--spec load(Application :: atom() | application_spec(),
- Distributed :: any()) -> 'ok' | {'error', term()}.
+ load1(Application, []).
+
+-spec load(AppDescr, Distributed) -> 'ok' | {'error', Reason} when
+ AppDescr :: Application | (AppSpec :: application_spec()),
+ Application :: atom(),
+ Distributed :: {Application,Nodes}
+ | {Application,Time,Nodes}
+ | 'default',
+ Nodes :: [node() | tuple_of(node())],
+ Time :: pos_integer(),
+ Reason :: term().
load(Application, DistNodes) ->
+ load1(Application, DistNodes).
+
+%% Workaround due to specs.
+load1(Application, DistNodes) ->
case application_controller:load_application(Application) of
ok when DistNodes =/= [] ->
AppName = get_appl_name(Application),
@@ -85,18 +108,24 @@ load(Application, DistNodes) ->
Else
end.
--spec unload(Application :: atom()) -> 'ok' | {'error', term()}.
+-spec unload(Application) -> 'ok' | {'error', Reason} when
+ Application :: atom(),
+ Reason :: term().
unload(Application) ->
application_controller:unload_application(Application).
--spec start(Application :: atom()) -> 'ok' | {'error', term()}.
+-spec start(Application) -> 'ok' | {'error', Reason} when
+ Application :: atom(),
+ Reason :: term().
start(Application) ->
start(Application, temporary).
--spec start(Application :: atom() | application_spec(),
- RestartType :: restart_type()) -> any().
+-spec start(Application, Type) -> 'ok' | {'error', Reason} when
+ Application :: atom(),
+ Type :: restart_type(),
+ Reason :: term().
start(Application, RestartType) ->
case load(Application) of
@@ -120,12 +149,18 @@ start_boot(Application) ->
start_boot(Application, RestartType) ->
application_controller:start_boot_application(Application, RestartType).
--spec takeover(Application :: atom(), RestartType :: restart_type()) -> any().
+-spec takeover(Application, Type) -> 'ok' | {'error', Reason} when
+ Application :: atom(),
+ Type :: restart_type(),
+ Reason :: term().
takeover(Application, RestartType) ->
dist_ac:takeover_application(Application, RestartType).
--spec permit(Application :: atom(), Bool :: boolean()) -> 'ok' | {'error', term()}.
+-spec permit(Application, Permission) -> 'ok' | {'error', Reason} when
+ Application :: atom(),
+ Permission :: boolean(),
+ Reason :: term().
permit(Application, Bool) ->
case Bool of
@@ -142,105 +177,146 @@ permit(Application, Bool) ->
LocalResult
end.
--spec stop(Application :: atom()) -> 'ok' | {'error', term()}.
+-spec stop(Application) -> 'ok' | {'error', Reason} when
+ Application :: atom(),
+ Reason :: term().
stop(Application) ->
application_controller:stop_application(Application).
--spec which_applications() -> [{atom(), string(), string()}].
+-spec which_applications() -> [{Application, Description, Vsn}] when
+ Application :: atom(),
+ Description :: string(),
+ Vsn :: string().
which_applications() ->
application_controller:which_applications().
--spec which_applications(timeout()) -> [{atom(), string(), string()}].
+-spec which_applications(Timeout) -> [{Application, Description, Vsn}] when
+ Timeout :: timeout(),
+ Application :: atom(),
+ Description :: string(),
+ Vsn :: string().
which_applications(infinity) ->
application_controller:which_applications(infinity);
which_applications(Timeout) when is_integer(Timeout), Timeout>=0 ->
application_controller:which_applications(Timeout).
--spec loaded_applications() -> [{atom(), string(), string()}].
+-spec loaded_applications() -> [{Application, Description, Vsn}] when
+ Application :: atom(),
+ Description :: string(),
+ Vsn :: string().
loaded_applications() ->
application_controller:loaded_applications().
--spec info() -> any().
+-spec info() -> term().
info() ->
application_controller:info().
--spec set_env(Application :: atom(), Key :: atom(), Value :: any()) -> 'ok'.
+-spec set_env(Application, Par, Val) -> 'ok' when
+ Application :: atom(),
+ Par :: atom(),
+ Val :: term().
set_env(Application, Key, Val) ->
application_controller:set_env(Application, Key, Val).
--spec set_env(Application :: atom(), Key :: atom(),
- Value :: any(), Timeout :: timeout()) -> 'ok'.
+-spec set_env(Application, Par, Val, Timeout) -> 'ok' when
+ Application :: atom(),
+ Par :: atom(),
+ Val :: term(),
+ Timeout :: timeout().
set_env(Application, Key, Val, infinity) ->
application_controller:set_env(Application, Key, Val, infinity);
set_env(Application, Key, Val, Timeout) when is_integer(Timeout), Timeout>=0 ->
application_controller:set_env(Application, Key, Val, Timeout).
--spec unset_env(atom(), atom()) -> 'ok'.
+-spec unset_env(Application, Par) -> 'ok' when
+ Application :: atom(),
+ Par :: atom().
unset_env(Application, Key) ->
application_controller:unset_env(Application, Key).
--spec unset_env(atom(), atom(), timeout()) -> 'ok'.
+-spec unset_env(Application, Par, Timeout) -> 'ok' when
+ Application :: atom(),
+ Par :: atom(),
+ Timeout :: timeout().
unset_env(Application, Key, infinity) ->
application_controller:unset_env(Application, Key, infinity);
unset_env(Application, Key, Timeout) when is_integer(Timeout), Timeout>=0 ->
application_controller:unset_env(Application, Key, Timeout).
--spec get_env(atom()) -> 'undefined' | {'ok', term()}.
+-spec get_env(Par) -> 'undefined' | {'ok', Val} when
+ Par :: atom(),
+ Val :: term().
get_env(Key) ->
application_controller:get_pid_env(group_leader(), Key).
--spec get_env(atom(), atom()) -> 'undefined' | {'ok', term()}.
+-spec get_env(Application, Par) -> 'undefined' | {'ok', Val} when
+ Application :: atom(),
+ Par :: atom(),
+ Val :: term().
get_env(Application, Key) ->
application_controller:get_env(Application, Key).
--spec get_all_env() -> [] | [{atom(), any()}].
+-spec get_all_env() -> Env when
+ Env :: [{Par :: atom(), Val :: term()}].
get_all_env() ->
application_controller:get_pid_all_env(group_leader()).
--spec get_all_env(atom()) -> [] | [{atom(), any()}].
+-spec get_all_env(Application) -> Env when
+ Application :: atom(),
+ Env :: [{Par :: atom(), Val :: term()}].
get_all_env(Application) ->
application_controller:get_all_env(Application).
--spec get_key(atom()) -> 'undefined' | {'ok', term()}.
+-spec get_key(Key) -> 'undefined' | {'ok', Val} when
+ Key :: atom(),
+ Val :: term().
get_key(Key) ->
application_controller:get_pid_key(group_leader(), Key).
--spec get_key(atom(), atom()) -> 'undefined' | {'ok', term()}.
+-spec get_key(Application, Key) -> 'undefined' | {'ok', Val} when
+ Application :: atom(),
+ Key :: atom(),
+ Val :: term().
get_key(Application, Key) ->
application_controller:get_key(Application, Key).
--spec get_all_key() -> 'undefined' | [] | {'ok', [{atom(),any()},...]}.
+-spec get_all_key() -> [] | {'ok', Keys} when
+ Keys :: [{Key :: atom(),Val :: term()},...].
get_all_key() ->
application_controller:get_pid_all_key(group_leader()).
--spec get_all_key(atom()) -> 'undefined' | {'ok', [{atom(),any()},...]}.
+-spec get_all_key(Application) -> 'undefined' | Keys when
+ Application :: atom(),
+ Keys :: {'ok', [{Key :: atom(),Val :: term()},...]}.
get_all_key(Application) ->
application_controller:get_all_key(Application).
--spec get_application() -> 'undefined' | {'ok', atom()}.
+-spec get_application() -> 'undefined' | {'ok', Application} when
+ Application :: atom().
get_application() ->
application_controller:get_application(group_leader()).
--spec get_application(Pid :: pid()) -> 'undefined' | {'ok', atom()}
- ; (Module :: atom()) -> 'undefined' | {'ok', atom()}.
+-spec get_application(PidOrModule) -> 'undefined' | {'ok', Application} when
+ PidOrModule :: (Pid :: pid()) | (Module :: module()),
+ Application :: atom().
get_application(Pid) when is_pid(Pid) ->
case process_info(Pid, group_leader) of
@@ -252,8 +328,8 @@ get_application(Pid) when is_pid(Pid) ->
get_application(Module) when is_atom(Module) ->
application_controller:get_application_module(Module).
--spec start_type() -> 'undefined' | 'local' | 'normal'
- | {'takeover', node()} | {'failover', node()}.
+-spec start_type() -> StartType | 'undefined' | 'local' when
+ StartType :: start_type().
start_type() ->
application_controller:start_type(group_leader()).
diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl
index 7c1f059875..42f527f400 100644
--- a/lib/kernel/src/application_controller.erl
+++ b/lib/kernel/src/application_controller.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(application_controller).
@@ -40,7 +40,7 @@
-export([test_change_apps/2]).
-import(lists, [zf/2, map/2, foreach/2, foldl/3,
- keysearch/3, keydelete/3, keyreplace/4]).
+ keyfind/3, keydelete/3, keyreplace/4]).
-include("application_master.hrl").
@@ -128,8 +128,13 @@
%% AppName = atom()
%% Application = App | AppName
%%-----------------------------------------------------------------
+
+-type appname() :: atom().
+
-record(state, {loading = [], starting = [], start_p_false = [], running = [],
control = [], started = [], start_req = [], conf_data}).
+-type state() :: #state{}.
+
%%-----------------------------------------------------------------
%% loading = [{AppName, From}] - Load not yet finished
%% starting = [{AppName, RestartType, Type, From}] - Start not
@@ -519,7 +524,9 @@ init(Init, Kernel) ->
end.
-%% Check the syntax of the .config file [{ApplicationName, [{Parameter, Value}]}].
+%% Check the syntax of the .config file
+%% [{ApplicationName, [{Parameter, Value}]}].
+
check_conf_data([]) ->
ok;
check_conf_data(ConfData) when is_list(ConfData) ->
@@ -563,8 +570,8 @@ check_para_kernel([]) ->
ok;
check_para_kernel([{distributed, Apps} | ParaList]) when is_list(Apps) ->
case check_distributed(Apps) of
- {error, ErrorMsg} ->
- {error, ErrorMsg};
+ {error, _ErrorMsg} = Error ->
+ Error;
_ ->
check_para_kernel(ParaList)
end;
@@ -604,6 +611,19 @@ check_para([Else | _ParaList], AppName) ->
lists:flatten(io_lib:format("~p",[Else]))}.
+-type calls() :: 'info' | 'prep_config_change' | 'which_applications'
+ | {'config_change' | 'control_application' |
+ 'load_application' | 'start_type' | 'stop_application' |
+ 'unload_application', term()}
+ | {'change_application_data', _, _}
+ | {'permit_application', atom() | {'application',atom(),_},_}
+ | {'start_application', _, _}
+ | {'unset_env', _, _}
+ | {'set_env', _, _, _}.
+
+-spec handle_call(calls(), {pid(), term()}, state()) ->
+ {'noreply', state()} | {'reply', term(), state()}.
+
handle_call({load_application, Application}, From, S) ->
case catch do_load_application(Application, S) of
{ok, NewS} ->
@@ -615,9 +635,9 @@ handle_call({load_application, Application}, From, S) ->
false ->
{reply, ok, NewS}
end;
- {error, Error} ->
- {reply, {error, Error}, S};
- {'EXIT',R} ->
+ {error, _} = Error ->
+ {reply, Error, S};
+ {'EXIT', R} ->
{reply, {error, R}, S}
end;
@@ -642,7 +662,7 @@ handle_call({start_application, AppName, RestartType}, From, S) ->
%% Incase of erroneous variables do not start the application,
%% if the application is permanent crash the node.
%% Check if the application is already starting.
- case lists:keysearch(AppName, 1, Start_req) of
+ case lists:keyfind(AppName, 1, Start_req) of
false ->
case catch check_start_cond(AppName, RestartType, Started, Running) of
{ok, Appl} ->
@@ -671,13 +691,12 @@ handle_call({start_application, AppName, RestartType}, From, S) ->
{reply, ok, SS}
end
end;
- {error, R} ->
- {reply, {error, R}, S}
+ {error, _R} = Error ->
+ {reply, Error, S}
end;
- {value, {AppName, _FromX}} ->
+ {AppName, _FromX} ->
SS = S#state{start_req = [{AppName, From} | Start_req]},
{noreply, SS}
-
end;
handle_call({permit_application, AppName, Bool}, From, S) ->
@@ -751,11 +770,11 @@ handle_call({permit_application, AppName, Bool}, From, S) ->
{noreply, SS};
%%==========================
- %% unpermit the applicaition
+ %% unpermit the application
%%==========================
%% running
{false, _, _, _, _, {value, {_AppName, Id}}} ->
- {value, {_AppName2, Type}} = keysearch(AppName, 1, Started),
+ {_AppName2, Type} = lists:keyfind(AppName, 1, Started),
stop_appl(AppName, Id, Type),
NRunning = keydelete(AppName, 1, Running),
{reply, ok, S#state{running = NRunning}};
@@ -785,9 +804,9 @@ handle_call({permit_application, AppName, Bool}, From, S) ->
handle_call({stop_application, AppName}, _From, S) ->
#state{running = Running, started = Started} = S,
- case keysearch(AppName, 1, Running) of
- {value, {_AppName, Id}} ->
- {value, {_AppName2, Type}} = keysearch(AppName, 1, Started),
+ case lists:keyfind(AppName, 1, Running) of
+ {_AppName, Id} ->
+ {_AppName2, Type} = lists:keyfind(AppName, 1, Started),
stop_appl(AppName, Id, Type),
NRunning = keydelete(AppName, 1, Running),
NStarted = keydelete(AppName, 1, Started),
@@ -813,8 +832,8 @@ handle_call({change_application_data, Applications, Config}, _From, S) ->
end,
[]),
case catch do_change_apps(Applications, Config, OldAppls) of
- {error, R} ->
- {reply, {error, R}, S};
+ {error, _} = Error ->
+ {reply, Error, S};
{'EXIT', R} ->
{reply, {error, R}, S};
NewAppls ->
@@ -868,10 +887,10 @@ handle_call({control_application, AppName}, {Pid, _Tag}, S) ->
handle_call({start_type, AppName}, _From, S) ->
Starting = S#state.starting,
- StartType = case keysearch(AppName, 1, Starting) of
+ StartType = case lists:keyfind(AppName, 1, Starting) of
false ->
local;
- {value, {_AppName, _RestartType, Type, _F}} ->
+ {_AppName, _RestartType, Type, _F} ->
Type
end,
{reply, StartType, S};
@@ -885,6 +904,9 @@ handle_call(info, _From, S) ->
{starting, S#state.starting}],
{reply, Reply, S}.
+-spec handle_cast({'application_started', appname(), _}, state()) ->
+ {'noreply', state()} | {'stop', string(), state()}.
+
handle_cast({application_started, AppName, Res}, S) ->
handle_application_started(AppName, Res, S).
@@ -892,7 +914,7 @@ handle_application_started(AppName, Res, S) ->
#state{starting = Starting, running = Running, started = Started,
start_req = Start_req} = S,
Start_reqN = reply_to_requester(AppName, Start_req, Res),
- {value, {_AppName, RestartType, _Type, _From}} = keysearch(AppName, 1, Starting),
+ {_AppName, RestartType, _Type, _From} = lists:keyfind(AppName, 1, Starting),
case Res of
{ok, Id} ->
case AppName of
@@ -907,7 +929,6 @@ handle_application_started(AppName, Res, S) ->
running = NRunning,
started = NStarted,
start_req = Start_reqN},
-
%% The permission may have been changed during start
Perm = application:get_env(kernel, permissions),
case {Perm, Id} of
@@ -918,10 +939,10 @@ handle_application_started(AppName, Res, S) ->
case lists:member({AppName, false}, Perms) of
true ->
#state{running = StopRunning, started = StopStarted} = NewS,
- case keysearch(AppName, 1, StopRunning) of
- {value, {_AppName, Id}} ->
- {value, {_AppName2, Type}} =
- keysearch(AppName, 1, StopStarted),
+ case lists:keyfind(AppName, 1, StopRunning) of
+ {_AppName, Id} ->
+ {_AppName2, Type} =
+ lists:keyfind(AppName, 1, StopStarted),
stop_appl(AppName, Id, Type),
NStopRunning = keydelete(AppName, 1, StopRunning),
cntrl(AppName, NewS, {ac_application_stopped, AppName}),
@@ -936,12 +957,8 @@ handle_application_started(AppName, Res, S) ->
_ ->
{noreply, NewS}
end;
-
-
-
-
- {error, R} when RestartType =:= temporary ->
- notify_cntrl_started(AppName, undefined, S, {error, R}),
+ {error, R} = Error when RestartType =:= temporary ->
+ notify_cntrl_started(AppName, undefined, S, Error),
info_exited(AppName, R, RestartType),
{noreply, S#state{starting = keydelete(AppName, 1, Starting),
start_req = Start_reqN}};
@@ -966,8 +983,8 @@ handle_application_started(AppName, Res, S) ->
Reason = {application_start_failure, AppName, R},
{stop, to_string(Reason), S}
end;
- {error, R} -> %% permanent
- notify_cntrl_started(AppName, undefined, S, {error, R}),
+ {error, R} = Error -> %% permanent
+ notify_cntrl_started(AppName, undefined, S, Error),
info_exited(AppName, R, RestartType),
Reason = {application_start_failure, AppName, R},
{stop, to_string(Reason), S};
@@ -977,6 +994,9 @@ handle_application_started(AppName, Res, S) ->
{stop, to_string(Reason), S}
end.
+-spec handle_info(term(), state()) ->
+ {'noreply', state()} | {'stop', string(), state()}.
+
handle_info({ac_load_application_reply, AppName, Res}, S) ->
case keysearchdelete(AppName, 1, S#state.loading) of
{value, {_AppName, From}, Loading} ->
@@ -994,12 +1014,12 @@ handle_info({ac_load_application_reply, AppName, Res}, S) ->
handle_info({ac_start_application_reply, AppName, Res}, S) ->
Start_req = S#state.start_req,
- case keysearch(AppName, 1, Starting = S#state.starting) of
- {value, {_AppName, RestartType, Type, From}} ->
+ case lists:keyfind(AppName, 1, Starting = S#state.starting) of
+ {_AppName, RestartType, Type, From} ->
case Res of
start_it ->
{true, Appl} = get_loaded(AppName),
- spawn_starter(From, Appl, S, Type),
+ spawn_starter(From, Appl, S, Type),
{noreply, S};
{started, Node} ->
handle_application_started(AppName,
@@ -1013,23 +1033,19 @@ handle_info({ac_start_application_reply, AppName, Res}, S) ->
S#state{starting = keydelete(AppName, 1, Starting),
started = [{AppName, RestartType} | Started],
start_req = Start_reqN}};
- {takeover, Node} ->
+ {takeover, _Node} = Takeover ->
{true, Appl} = get_loaded(AppName),
- spawn_starter(From, Appl, S, {takeover, Node}),
+ spawn_starter(From, Appl, S, Takeover),
NewStarting1 = keydelete(AppName, 1, Starting),
- NewStarting = [{AppName, RestartType, {takeover, Node}, From} | NewStarting1],
+ NewStarting = [{AppName, RestartType, Takeover, From} | NewStarting1],
{noreply, S#state{starting = NewStarting}};
- {error, Reason} when RestartType =:= permanent ->
- Start_reqN =
- reply_to_requester(AppName, Start_req,
- {error, Reason}),
+ {error, Reason} = Error when RestartType =:= permanent ->
+ Start_reqN = reply_to_requester(AppName, Start_req, Error),
{stop, to_string(Reason), S#state{start_req = Start_reqN}};
- {error, Reason} ->
- Start_reqN =
- reply_to_requester(AppName, Start_req,
- {error, Reason}),
+ {error, _Reason} = Error ->
+ Start_reqN = reply_to_requester(AppName, Start_req, Error),
{noreply, S#state{starting =
- keydelete(AppName, 1, Starting),
+ keydelete(AppName, 1, Starting),
start_req = Start_reqN}}
end;
false ->
@@ -1040,8 +1056,8 @@ handle_info({ac_change_application_req, AppName, Msg}, S) ->
Running = S#state.running,
Started = S#state.started,
Starting = S#state.starting,
- case {keysearch(AppName, 1, Running), keysearch(AppName, 1, Started)} of
- {{value, {AppName, Id}}, {value, {_AppName2, Type}}} ->
+ case {keyfind(AppName, 1, Running), keyfind(AppName, 1, Started)} of
+ {{AppName, Id}, {_AppName2, Type}} ->
case Msg of
{started, Node} ->
stop_appl(AppName, Id, Type),
@@ -1134,17 +1150,17 @@ handle_info({'EXIT', Pid, Reason}, S) ->
ets:match_delete(ac_tab, {{application_master, '_'}, Pid}),
NRunning = keydelete(Pid, 2, S#state.running),
NewS = S#state{running = NRunning},
- case keysearch(Pid, 2, S#state.running) of
- {value, {AppName, _AmPid}} ->
+ case lists:keyfind(Pid, 2, S#state.running) of
+ {AppName, _AmPid} ->
cntrl(AppName, S, {ac_application_stopped, AppName}),
- case keysearch(AppName, 1, S#state.started) of
- {value, {_AppName, temporary}} ->
+ case lists:keyfind(AppName, 1, S#state.started) of
+ {_AppName, temporary} ->
info_exited(AppName, Reason, temporary),
{noreply, NewS};
- {value, {_AppName, transient}} when Reason =:= normal ->
+ {_AppName, transient} when Reason =:= normal ->
info_exited(AppName, Reason, transient),
{noreply, NewS};
- {value, {_AppName, Type}} ->
+ {_AppName, Type} ->
info_exited(AppName, Reason, Type),
{stop, to_string({application_terminated, AppName, Reason}), NewS}
end;
@@ -1155,6 +1171,8 @@ handle_info({'EXIT', Pid, Reason}, S) ->
handle_info(_, S) ->
{noreply, S}.
+-spec terminate(term(), state()) -> 'ok'.
+
terminate(Reason, S) ->
case application:get_env(kernel, shutdown_func) of
{ok, {M, F}} ->
@@ -1170,8 +1188,10 @@ terminate(Reason, S) ->
(_) -> ok
end,
S#state.running),
- ets:delete(ac_tab).
+ true = ets:delete(ac_tab),
+ ok.
+-spec code_change(term(), state(), term()) -> {'ok', state()}.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
@@ -1181,8 +1201,8 @@ code_change(_OldVsn, State, _Extra) ->
%%% Internal functions
%%%-----------------------------------------------------------------
cntrl(AppName, #state{control = Control}, Msg) ->
- case keysearch(AppName, 1, Control) of
- {value, {_AppName, Pid}} ->
+ case lists:keyfind(AppName, 1, Control) of
+ {_AppName, Pid} ->
Pid ! Msg,
true;
false ->
@@ -1282,8 +1302,8 @@ check_start_cond(AppName, RestartType, Started, Running) ->
end.
do_start(AppName, RT, Type, From, S) ->
- RestartType = case keysearch(AppName, 1, S#state.started) of
- {value, {_AppName2, OldRT}} ->
+ RestartType = case lists:keyfind(AppName, 1, S#state.started) of
+ {_AppName2, OldRT} ->
get_restart_type(RT, OldRT);
false ->
RT
@@ -1295,12 +1315,12 @@ do_start(AppName, RT, Type, From, S) ->
{true, Appl} = get_loaded(AppName),
Start_req = S#state.start_req,
spawn_starter(undefined, Appl, S, Type),
- Starting = case keysearch(AppName, 1, S#state.starting) of
+ Starting = case lists:keymember(AppName, 1, S#state.starting) of
false ->
%% UW: don't know if this is necessary
[{AppName, RestartType, Type, From} |
S#state.starting];
- _ ->
+ true ->
S#state.starting
end,
S#state{starting = Starting,
@@ -1340,10 +1360,10 @@ start_appl(Appl, S, Type) ->
end
end, Appl#appl.apps),
case application_master:start_link(ApplData, Type) of
- {ok, Pid} ->
- {ok, Pid};
- {error, Reason} ->
- throw({error, Reason})
+ {ok, _Pid} = Ok ->
+ Ok;
+ {error, _Reason} = Error ->
+ throw(Error)
end
end.
@@ -1435,15 +1455,15 @@ prim_parse(Tokens, Acc) ->
case erl_parse:parse_term(Tokens2 ++ [Dot]) of
{ok, Term} ->
prim_parse(Rest, [Term | Acc]);
- {error, Reason} ->
- {error, Reason}
+ {error, _R} = Error ->
+ Error
end;
{Tokens2, []} ->
case erl_parse:parse_term(Tokens2) of
{ok, Term} ->
{ok, lists:reverse([Term | Acc])};
- {error, Reason} ->
- {error, Reason}
+ {error, _R} = Error ->
+ Error
end
end.
@@ -1456,7 +1476,7 @@ make_appl_i({application, Name, Opts}) when is_atom(Name), is_list(Opts) ->
Apps = get_opt(applications, Opts, []),
Mod =
case get_opt(mod, Opts, []) of
- {M,A} when is_atom(M) -> {M,A};
+ {M,_A}=MA when is_atom(M) -> MA;
[] -> [];
Other -> throw({error, {badstartspec, Other}})
end,
@@ -1465,8 +1485,8 @@ make_appl_i({application, Name, Opts}) when is_atom(Name), is_list(Opts) ->
MaxP = get_opt(maxP, Opts, infinity),
MaxT = get_opt(maxT, Opts, infinity),
IncApps = get_opt(included_applications, Opts, []),
- {#appl_data{name = Name, regs = Regs, mod = Mod, phases = Phases, mods = Mods,
- inc_apps = IncApps, maxP = MaxP, maxT = MaxT},
+ {#appl_data{name = Name, regs = Regs, mod = Mod, phases = Phases,
+ mods = Mods, inc_apps = IncApps, maxP = MaxP, maxT = MaxT},
Env, IncApps, Descr, Id, Vsn, Apps};
make_appl_i({application, Name, Opts}) when is_list(Opts) ->
throw({error,{invalid_name,Name}});
@@ -1545,12 +1565,12 @@ do_change_appl({ok, {ApplData, Env, IncApps, Descr, Id, Vsn, Apps}},
vsn=Vsn,
inc_apps=IncApps,
apps=Apps};
-do_change_appl({error, R}, _Appl, _ConfData) ->
- throw({error, R}).
+do_change_appl({error, _R} = Error, _Appl, _ConfData) ->
+ throw(Error).
get_opt(Key, List, Default) ->
- case keysearch(Key, 1, List) of
- {value, {_Key, Val}} -> Val;
+ case lists:keyfind(Key, 1, List) of
+ {_Key, Val} -> Val;
_ -> Default
end.
@@ -1584,8 +1604,8 @@ make_term(Str) ->
end.
get_env_i(Name, #state{conf_data = ConfData}) when is_list(ConfData) ->
- case keysearch(Name, 1, ConfData) of
- {value, {_Name, Env}} -> Env;
+ case lists:keyfind(Name, 1, ConfData) of
+ {_Name, Env} -> Env;
_ -> []
end;
get_env_i(_Name, _) -> [].
@@ -1605,9 +1625,6 @@ merge_env([{App, AppEnv1} | T], Env2, Res) ->
merge_env([], Env2, Res) ->
Env2 ++ Res.
-
-
-
%% Merges envs for an application. Env2 overrides Env1
merge_app_env(Env1, Env2) ->
merge_app_env(Env1, Env2, []).
@@ -1671,13 +1688,12 @@ do_config_change([], _EnvBefore, Errors) ->
{error, Errors};
do_config_change([{App, _Id} | Apps], EnvBefore, Errors) ->
AppEnvNow = lists:sort(application:get_all_env(App)),
- AppEnvBefore = case lists:keysearch(App, 1, EnvBefore) of
+ AppEnvBefore = case lists:keyfind(App, 1, EnvBefore) of
false ->
[];
- {value, {App, AppEnvBeforeT}} ->
+ {App, AppEnvBeforeT} ->
lists:sort(AppEnvBeforeT)
end,
-
Res =
case AppEnvNow of
AppEnvBefore ->
@@ -1697,12 +1713,12 @@ do_config_change([{App, _Id} | Apps], EnvBefore, Errors) ->
%% if the cb-function is not defined
{'EXIT', {undef, _}} ->
ok;
- {error, Error} ->
- {error, Error};
+ {error, _} = Error ->
+ Error;
Else ->
{error, Else}
end;
- {ok,[]} ->
+ {ok, []} ->
{error, {module_not_defined, App}};
undefined ->
{error, {application_not_found, App}}
@@ -1716,9 +1732,7 @@ do_config_change([{App, _Id} | Apps], EnvBefore, Errors) ->
{error, NewError} ->
do_config_change(Apps, EnvBefore,[NewError | Errors])
end.
-
-
-
+
%%-----------------------------------------------------------------
%% Check if the configuration is changed in anyway.
@@ -1732,21 +1746,17 @@ do_config_diff([], AppEnvBefore, {Changed, New}) ->
do_config_diff(AppEnvNow, [], {Changed, New}) ->
{Changed, AppEnvNow++New, []};
do_config_diff([{Env, Value} | AppEnvNow], AppEnvBefore, {Changed, New}) ->
- case lists:keysearch(Env, 1, AppEnvBefore) of
- {value, {Env, Value}} ->
+ case lists:keyfind(Env, 1, AppEnvBefore) of
+ {Env, Value} ->
do_config_diff(AppEnvNow, lists:keydelete(Env,1,AppEnvBefore), {Changed, New});
- {value, {Env, _OtherValue}} ->
+ {Env, _OtherValue} ->
do_config_diff(AppEnvNow, lists:keydelete(Env,1,AppEnvBefore),
{[{Env, Value} | Changed], New});
false ->
do_config_diff(AppEnvNow, AppEnvBefore, {Changed, [{Env, Value}|New]})
end.
-
-
-
-
%%-----------------------------------------------------------------
%% Read the .config files.
%%-----------------------------------------------------------------
@@ -1901,14 +1911,13 @@ reply_to_requester(AppName, Start_req, Res) ->
%% Update the environment variable permission for an application.
%%-----------------------------------------------------------------
update_permissions(AppName, Bool) ->
- case ets:lookup(ac_tab, {env, kernel, permissions}) of
+ T = {env, kernel, permissions},
+ case ets:lookup(ac_tab, T) of
[] ->
- ets:insert(ac_tab, {{env, kernel, permissions},
- [{AppName, Bool}]});
+ ets:insert(ac_tab, {T, [{AppName, Bool}]});
[{_, Perm}] ->
Perm2 = lists:keydelete(AppName, 1, Perm),
- ets:insert(ac_tab, {{env, kernel, permissions},
- [{AppName, Bool}| Perm2]})
+ ets:insert(ac_tab, {T, [{AppName, Bool}|Perm2]})
end.
%%-----------------------------------------------------------------
@@ -1937,6 +1946,9 @@ test_make_apps([A|Apps], Res) ->
%% Exit reason needs to be a printable string
%% (and of length <200, but init now does the chopping).
%%-----------------------------------------------------------------
+
+-spec to_string(term()) -> string().
+
to_string(Term) ->
case io_lib:printable_list(Term) of
true ->
diff --git a/lib/kernel/src/application_starter.erl b/lib/kernel/src/application_starter.erl
index 8d839e4662..564366f304 100644
--- a/lib/kernel/src/application_starter.erl
+++ b/lib/kernel/src/application_starter.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1998-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%% ----------------------------------------------------------------------
@@ -42,8 +42,8 @@ start([], _Type, _Apps) ->
ok;
start([{Phase,_PhaseArgs}|Phases], Type, Apps) ->
case start_apps(Phase, Type, Apps) of
- {error, Error} ->
- {error, Error};
+ {error, _} = Error ->
+ Error;
_ ->
start(Phases, Type, Apps)
end.
@@ -56,8 +56,8 @@ start_apps(_Phase, _Type, []) ->
ok;
start_apps(Phase, Type, [App | Apps]) ->
case catch run_start_phase(Phase, Type, App) of
- {error, Error} ->
- {error, Error};
+ {error, _} = Error ->
+ Error;
_ ->
start_apps(Phase, Type, Apps)
end.
@@ -91,10 +91,10 @@ run_the_phase(Phase, Type, App, Mod) ->
{ok, Sp} ->
Sp
end,
- case lists:keysearch(Phase, 1, Start_phases) of
+ case lists:keyfind(Phase, 1, Start_phases) of
false ->
ok;
- {value, {Phase, PhaseArgs}} ->
+ {Phase, PhaseArgs} ->
case catch Mod:start_phase(Phase, Type, PhaseArgs) of
ok ->
ok;
diff --git a/lib/kernel/src/auth.erl b/lib/kernel/src/auth.erl
index 62c0bef0cc..c329a5652a 100644
--- a/lib/kernel/src/auth.erl
+++ b/lib/kernel/src/auth.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-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(auth).
@@ -37,10 +37,12 @@
-define(COOKIE_ETS_PROTECTION, protected).
+-type cookie() :: atom().
-record(state, {
- our_cookie, %% Our own cookie
- other_cookies %% The send-cookies of other nodes
+ our_cookie :: cookie(), %% Our own cookie
+ other_cookies :: ets:tab() %% The send-cookies of other nodes
}).
+-type state() :: #state{}.
-include("../include/file.hrl").
@@ -48,12 +50,15 @@
%% Exported functions
%%----------------------------------------------------------------------
+-spec start_link() -> {'ok',pid()} | {'error', term()} | 'ignore'.
+
start_link() ->
gen_server:start_link({local, auth}, auth, [], []).
%%--Deprecated interface------------------------------------------------
--spec is_auth(Node :: node()) -> 'yes' | 'no'.
+-spec is_auth(Node) -> 'yes' | 'no' when
+ Node :: node().
is_auth(Node) ->
case net_adm:ping(Node) of
@@ -61,24 +66,29 @@ is_auth(Node) ->
pang -> no
end.
--spec cookie() -> atom().
+-spec cookie() -> Cookie when
+ Cookie :: cookie().
cookie() ->
get_cookie().
--spec cookie(Cookies :: [atom(),...] | atom()) -> 'true'.
+-spec cookie(TheCookie) -> 'true' when
+ TheCookie :: Cookie | [Cookie],
+ Cookie :: cookie().
cookie([Cookie]) ->
set_cookie(Cookie);
cookie(Cookie) ->
set_cookie(Cookie).
--spec node_cookie(Cookies :: [atom(),...]) -> 'yes' | 'no'.
+-spec node_cookie(Cookies :: [node() | cookie(),...]) -> 'yes' | 'no'.
node_cookie([Node, Cookie]) ->
node_cookie(Node, Cookie).
--spec node_cookie(Node :: node(), Cookie :: atom()) -> 'yes' | 'no'.
+-spec node_cookie(Node, Cookie) -> 'yes' | 'no' when
+ Node :: node(),
+ Cookie :: cookie().
node_cookie(Node, Cookie) ->
set_cookie(Node, Cookie),
@@ -86,24 +96,24 @@ node_cookie(Node, Cookie) ->
%%--"New" interface-----------------------------------------------------
--spec get_cookie() -> atom().
+-spec get_cookie() -> 'nocookie' | cookie().
get_cookie() ->
get_cookie(node()).
--spec get_cookie(Node :: node()) -> atom().
+-spec get_cookie(Node :: node()) -> 'nocookie' | cookie().
get_cookie(_Node) when node() =:= nonode@nohost ->
nocookie;
get_cookie(Node) ->
gen_server:call(auth, {get_cookie, Node}).
--spec set_cookie(Cookie :: atom()) -> 'true'.
+-spec set_cookie(Cookie :: cookie()) -> 'true'.
set_cookie(Cookie) ->
set_cookie(node(), Cookie).
--spec set_cookie(Node :: node(), Cookie :: atom()) -> 'true'.
+-spec set_cookie(Node :: node(), Cookie :: cookie()) -> 'true'.
set_cookie(_Node, _Cookie) when node() =:= nonode@nohost ->
erlang:error(distribution_not_started);
@@ -117,11 +127,13 @@ sync_cookie() ->
-spec print(Node :: node(), Format :: string(), Args :: [_]) -> 'ok'.
-print(Node,Format,Args) ->
- (catch gen_server:cast({auth,Node},{print,Format,Args})).
+print(Node, Format, Args) ->
+ (catch gen_server:cast({auth, Node}, {print, Format, Args})).
%%--gen_server callbacks------------------------------------------------
+-spec init([]) -> {'ok', state()}.
+
init([]) ->
process_flag(trap_exit, true),
{ok, init_cookie()}.
@@ -130,6 +142,13 @@ init([]) ->
%% The net kernel will let all message to the auth server
%% through as is
+-type calls() :: 'echo' | 'sync_cookie'
+ | {'get_cookie', node()}
+ | {'set_cookie', node(), term()}.
+
+-spec handle_call(calls(), {pid(), term()}, state()) ->
+ {'reply', 'hello' | 'true' | 'nocookie' | cookie(), state()}.
+
handle_call({get_cookie, Node}, {_From,_Tag}, State) when Node =:= node() ->
{reply, State#state.our_cookie, State};
handle_call({get_cookie, Node}, {_From,_Tag}, State) ->
@@ -145,7 +164,7 @@ handle_call({set_cookie, Node, Cookie}, {_From,_Tag}, State)
%%
%% Happens when the distribution is brought up and
-%% Someone wight have set up the cookie for our new nodename.
+%% someone might have set up the cookie for our new node name.
%%
handle_call({set_cookie, Node, Cookie}, {_From,_Tag}, State) ->
@@ -153,9 +172,9 @@ handle_call({set_cookie, Node, Cookie}, {_From,_Tag}, State) ->
{reply, true, State};
handle_call(sync_cookie, _From, State) ->
- case ets:lookup(State#state.other_cookies,node()) of
+ case ets:lookup(State#state.other_cookies, node()) of
[{_N,C}] ->
- ets:delete(State#state.other_cookies,node()),
+ ets:delete(State#state.other_cookies, node()),
{reply, true, State#state{our_cookie = C}};
[] ->
{reply, true, State}
@@ -164,13 +183,22 @@ handle_call(sync_cookie, _From, State) ->
handle_call(echo, _From, O) ->
{reply, hello, O}.
+%%
+%% handle_cast/2
+%%
+
+-spec handle_cast({'print', string(), [term()]}, state()) ->
+ {'noreply', state()}.
+
handle_cast({print,What,Args}, O) ->
%% always allow print outs
- error_logger:error_msg(What,Args),
+ error_logger:error_msg(What, Args),
{noreply, O}.
%% A series of bad messages that may come (from older distribution versions).
+-spec handle_info(term(), state()) -> {'noreply', state()}.
+
handle_info({From,badcookie,net_kernel,{From,spawn,_M,_F,_A,_Gleader}}, O) ->
auth:print(node(From) ,"~n** Unauthorized spawn attempt to ~w **~n",
[node()]),
@@ -184,14 +212,14 @@ handle_info({From,badcookie,net_kernel,{From,spawn_link,_M,_F,_A,_Gleader}}, O)
{noreply, O};
handle_info({_From,badcookie,ddd_server,_Mess}, O) ->
%% Ignore bad messages to the ddd server, they will be resent
- %% If the authentication is succesful
+ %% If the authentication is successful
{noreply, O};
handle_info({From,badcookie,rex,_Msg}, O) ->
auth:print(getnode(From),
- "~n** Unauthorized rpc attempt to ~w **~n",[node()]),
+ "~n** Unauthorized rpc attempt to ~w **~n", [node()]),
disconnect_node(node(From)),
{noreply, O};
-%% These two messages has to do with the old auth:is_auth() call (net_adm:ping)
+%% These two messages have to do with the old auth:is_auth() call (net_adm:ping)
handle_info({From,badcookie,net_kernel,{'$gen_call',{From,Tag},{is_auth,_Node}}}, O) -> %% ho ho
From ! {Tag, no},
{noreply, O};
@@ -215,12 +243,16 @@ handle_info({From,badcookie,Name,Mess}, Opened) ->
end
end,
{noreply, Opened};
-handle_info(_, O)-> % Ignore anything else especially EXIT signals
+handle_info(_, O) -> % Ignore anything else especially EXIT signals
{noreply, O}.
+-spec code_change(term(), state(), term()) -> {'ok', state()}.
+
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
+-spec terminate(term(), state()) -> 'ok'.
+
terminate(_Reason, _State) ->
ok.
@@ -260,7 +292,7 @@ init_cookie() ->
end;
_Other ->
#state{our_cookie = nocookie,
- other_cookies = ets:new(cookies,[?COOKIE_ETS_PROTECTION])}
+ other_cookies = ets:new(cookies, [?COOKIE_ETS_PROTECTION])}
end.
read_cookie() ->
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index ffe58ae7a9..882e9625fe 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-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
@@ -66,111 +66,141 @@
set_primary_archive/3,
clash/0]).
+-export_type([load_error_rsn/0, load_ret/0]).
+
-include_lib("kernel/include/file.hrl").
%% User interface.
%%
-%% objfile_extension() -> ".beam"
-%% set_path(Dir*) -> true
-%% get_path() -> Dir*
-%% add_path(Dir) -> true | {error, What}
-%% add_patha(Dir) -> true | {error, What}
-%% add_pathz(Dir) -> true | {error, What}
-%% add_paths(DirList) -> true | {error, What}
-%% add_pathsa(DirList) -> true | {error, What}
-%% add_pathsz(DirList) -> true | {error, What}
-%% del_path(Dir) -> true | {error, What}
-%% replace_path(Name,Dir) -> true | {error, What}
-%% load_file(File) -> {error,What} | {module, Mod}
-%% load_abs(File) -> {error,What} | {module, Mod}
-%% load_abs(File,Mod) -> {error,What} | {module, Mod}
-%% load_binary(Mod,File,Bin) -> {error,What} | {module,Mod}
-%% ensure_loaded(Module) -> {error,What} | {module, Mod}
-%% delete(Module)
-%% purge(Module) kills all procs running old code
-%% soft_purge(Module) -> true | false
-%% is_loaded(Module) -> {file, File} | false
-%% all_loaded() -> {Module, File}*
-%% get_object_code(Mod) -> error | {Mod, Bin, Filename}
-%% stop() -> true
-%% root_dir()
-%% compiler_dir()
-%% lib_dir()
-%% priv_dir(Name)
-%% stick_dir(Dir) -> ok | error
-%% unstick_dir(Dir) -> ok | error
-%% is_sticky(Module) -> true | false
-%% which(Module) -> Filename
-%% set_primary_archive((FileName, Bin, FileInfo) -> ok | {error, Reason}
-%% clash() -> -> print out
+%% objfile_extension() -> ".beam"
+%% get_path() -> [Dir]
+%% set_path([Dir]) -> true | {error, bad_directory | bad_path}
+%% add_path(Dir) -> true | {error, bad_directory}
+%% add_patha(Dir) -> true | {error, bad_directory}
+%% add_pathz(Dir) -> true | {error, bad_directory}
+%% add_paths([Dir]) -> ok
+%% add_pathsa([Dir]) -> ok
+%% add_pathsz([Dir]) -> ok
+%% del_path(Dir) -> boolean() | {error, bad_name}
+%% replace_path(Name, Dir) -> true | {error, bad_directory | bad_name
+%% | {badarg,_}}
+%% load_file(Module) -> {module, Module} | {error, What :: atom()}
+%% load_abs(File) -> {module, Module} | {error, What :: atom()}
+%% load_abs(File, Module) -> {module, Module} | {error, What :: atom()}
+%% load_binary(Module, File, Bin)-> {module, Module} | {error, What :: atom()}
+%% ensure_loaded(Module) -> {module, Module} | {error, What :: atom()}
+%% delete(Module) -> boolean()
+%% purge(Module) -> boolean() kills all procs running old code
+%% soft_purge(Module) -> boolean()
+%% is_loaded(Module) -> {file, loaded_filename()} | false
+%% all_loaded() -> [{Module, loaded_filename()}]
+%% get_object_code(Module) -> {Module, Bin, Filename} | error
+%% stop() -> no_return()
+%% root_dir() -> Dir
+%% compiler_dir() -> Dir
+%% lib_dir() -> Dir
+%% lib_dir(Application) -> Dir | {error, bad_name}
+%% priv_dir(Application) -> Dir | {error, bad_name}
+%% stick_dir(Dir) -> ok | error
+%% unstick_dir(Dir) -> ok | error
+%% stick_mod(Module) -> true
+%% unstick_mod(Module) -> true
+%% is_sticky(Module) -> boolean()
+%% which(Module) -> Filename | loaded_ret_atoms() | non_existing
+%% set_primary_archive((FileName, Bin, FileInfo) -> ok | {error, Reason}
+%% clash() -> ok prints out number of clashes
%%----------------------------------------------------------------------------
%% Some types for basic exported functions of this module
%%----------------------------------------------------------------------------
--type load_error_rsn() :: 'badfile' | 'native_code' | 'nofile' | 'not_purged'
- | 'sticky_directory'. % for some functions only
--type load_ret() :: {'error', load_error_rsn()} | {'module', atom()}.
+-type load_error_rsn() :: 'badfile'
+ | 'native_code'
+ | 'nofile'
+ | 'not_purged'
+ | 'on_load'
+ | 'sticky_directory'.
+-type load_ret() :: {'error', What :: load_error_rsn()}
+ | {'module', Module :: module()}.
-type loaded_ret_atoms() :: 'cover_compiled' | 'preloaded'.
--type loaded_filename() :: file:filename() | loaded_ret_atoms().
+-type loaded_filename() :: (Filename :: file:filename()) | loaded_ret_atoms().
%%----------------------------------------------------------------------------
%% User interface
%%----------------------------------------------------------------------------
--spec objfile_extension() -> file:filename().
+-spec objfile_extension() -> nonempty_string().
objfile_extension() ->
init:objfile_extension().
--spec load_file(Module :: atom()) -> load_ret().
+-spec load_file(Module) -> load_ret() when
+ Module :: module().
load_file(Mod) when is_atom(Mod) ->
call({load_file,Mod}).
--spec ensure_loaded(Module :: atom()) -> load_ret().
+-spec ensure_loaded(Module) -> {module, Module} | {error, What} when
+ Module :: module(),
+ What :: embedded | badfile | native_code | nofile | on_load.
ensure_loaded(Mod) when is_atom(Mod) ->
call({ensure_loaded,Mod}).
%% XXX File as an atom is allowed only for backwards compatibility.
--spec load_abs(Filename :: file:filename()) -> load_ret().
+-spec load_abs(Filename) -> load_ret() when
+ Filename :: file:filename().
load_abs(File) when is_list(File); is_atom(File) -> call({load_abs,File,[]}).
%% XXX Filename is also an atom(), e.g. 'cover_compiled'
--spec load_abs(Filename :: loaded_filename(), Module :: atom()) -> load_ret().
-load_abs(File,M) when (is_list(File) orelse is_atom(File)), is_atom(M) ->
+-spec load_abs(Filename :: loaded_filename(), Module :: module()) -> load_ret().
+load_abs(File, M) when (is_list(File) orelse is_atom(File)), is_atom(M) ->
call({load_abs,File,M}).
%% XXX Filename is also an atom(), e.g. 'cover_compiled'
--spec load_binary(Module :: atom(), Filename :: loaded_filename(), Binary :: binary()) -> load_ret().
-load_binary(Mod,File,Bin)
+-spec load_binary(Module, Filename, Binary) ->
+ {module, Module} | {error, What} when
+ Module :: module(),
+ Filename :: loaded_filename(),
+ Binary :: binary(),
+ What :: badarg | load_error_rsn().
+load_binary(Mod, File, Bin)
when is_atom(Mod), (is_list(File) orelse is_atom(File)), is_binary(Bin) ->
call({load_binary,Mod,File,Bin}).
--spec load_native_partial(Module :: atom(), Binary :: binary()) -> load_ret().
-load_native_partial(Mod,Bin) when is_atom(Mod), is_binary(Bin) ->
+-spec load_native_partial(Module :: module(), Binary :: binary()) -> load_ret().
+load_native_partial(Mod, Bin) when is_atom(Mod), is_binary(Bin) ->
call({load_native_partial,Mod,Bin}).
--spec load_native_sticky(Module :: atom(), Binary :: binary(), WholeModule :: 'false' | binary()) -> load_ret().
-load_native_sticky(Mod,Bin,WholeModule)
+-spec load_native_sticky(Module :: module(), Binary :: binary(), WholeModule :: 'false' | binary()) -> load_ret().
+load_native_sticky(Mod, Bin, WholeModule)
when is_atom(Mod), is_binary(Bin),
(is_binary(WholeModule) orelse WholeModule =:= false) ->
call({load_native_sticky,Mod,Bin,WholeModule}).
--spec delete(Module :: atom()) -> boolean().
+-spec delete(Module) -> boolean() when
+ Module :: module().
delete(Mod) when is_atom(Mod) -> call({delete,Mod}).
--spec purge/1 :: (Module :: atom()) -> boolean().
+-spec purge(Module) -> boolean() when
+ Module :: module().
purge(Mod) when is_atom(Mod) -> call({purge,Mod}).
--spec soft_purge(Module :: atom()) -> boolean().
+-spec soft_purge(Module) -> boolean() when
+ Module :: module().
soft_purge(Mod) when is_atom(Mod) -> call({soft_purge,Mod}).
--spec is_loaded(Module :: atom()) -> {'file', loaded_filename()} | 'false'.
+-spec is_loaded(Module) -> {'file', Loaded} | false when
+ Module :: module(),
+ Loaded :: loaded_filename().
is_loaded(Mod) when is_atom(Mod) -> call({is_loaded,Mod}).
--spec get_object_code(Module :: atom()) -> {atom(), binary(), file:filename()} | 'error'.
+-spec get_object_code(Module) -> {Module, Binary, Filename} | error when
+ Module :: module(),
+ Binary :: binary(),
+ Filename :: file:filename().
get_object_code(Mod) when is_atom(Mod) -> call({get_object_code, Mod}).
--spec all_loaded() -> [{atom(), loaded_filename()}].
+-spec all_loaded() -> [{Module, Loaded}] when
+ Module :: module(),
+ Loaded :: loaded_filename().
all_loaded() -> call(all_loaded).
-spec stop() -> no_return().
@@ -183,66 +213,88 @@ root_dir() -> call({dir,root_dir}).
lib_dir() -> call({dir,lib_dir}).
%% XXX is_list() is for backwards compatibility -- take out in future version
--spec lib_dir(App :: atom()) -> file:filename() | {'error', 'bad_name'}.
+-spec lib_dir(Name) -> file:filename() | {'error', 'bad_name'} when
+ Name :: atom().
lib_dir(App) when is_atom(App) ; is_list(App) -> call({dir,{lib_dir,App}}).
--spec lib_dir(App :: atom(), SubDir :: atom()) -> file:filename() | {'error', 'bad_name'}.
+-spec lib_dir(Name, SubDir) -> file:filename() | {'error', 'bad_name'} when
+ Name :: atom(),
+ SubDir :: atom().
lib_dir(App, SubDir) when is_atom(App), is_atom(SubDir) -> call({dir,{lib_dir,App,SubDir}}).
-spec compiler_dir() -> file:filename().
compiler_dir() -> call({dir,compiler_dir}).
%% XXX is_list() is for backwards compatibility -- take out in future version
--spec priv_dir(Appl :: atom()) -> file:filename() | {'error', 'bad_name'}.
+-spec priv_dir(Name) -> file:filename() | {'error', 'bad_name'} when
+ Name :: atom().
priv_dir(App) when is_atom(App) ; is_list(App) -> call({dir,{priv_dir,App}}).
--spec stick_dir(Directory :: file:filename()) -> 'ok' | 'error'.
+-spec stick_dir(Dir) -> 'ok' | 'error' when
+ Dir :: file:filename().
stick_dir(Dir) when is_list(Dir) -> call({stick_dir,Dir}).
--spec unstick_dir(Directory :: file:filename()) -> 'ok' | 'error'.
+-spec unstick_dir(Dir) -> 'ok' | 'error' when
+ Dir :: file:filename().
unstick_dir(Dir) when is_list(Dir) -> call({unstick_dir,Dir}).
--spec stick_mod(Module :: atom()) -> 'true'.
+-spec stick_mod(Module :: module()) -> 'true'.
stick_mod(Mod) when is_atom(Mod) -> call({stick_mod,Mod}).
--spec unstick_mod(Module :: atom()) -> 'true'.
+-spec unstick_mod(Module :: module()) -> 'true'.
unstick_mod(Mod) when is_atom(Mod) -> call({unstick_mod,Mod}).
--spec is_sticky(Module :: atom()) -> boolean().
+-spec is_sticky(Module) -> boolean() when
+ Module :: module().
is_sticky(Mod) when is_atom(Mod) -> call({is_sticky,Mod}).
--spec set_path(Directories :: [file:filename()]) -> 'true' | {'error', term()}.
+-spec set_path(Path) -> 'true' | {'error', What} when
+ Path :: [Dir :: file:filename()],
+ What :: 'bad_directory' | 'bad_path'.
set_path(PathList) when is_list(PathList) -> call({set_path,PathList}).
--spec get_path() -> [file:filename()].
+-spec get_path() -> Path when
+ Path :: [Dir :: file:filename()].
get_path() -> call(get_path).
--spec add_path(Directory :: file:filename()) -> 'true' | {'error', term()}.
+-type add_path_ret() :: 'true' | {'error', 'bad_directory'}.
+-spec add_path(Dir) -> add_path_ret() when
+ Dir :: file:filename().
add_path(Dir) when is_list(Dir) -> call({add_path,last,Dir}).
--spec add_pathz(Directory :: file:filename()) -> 'true' | {'error', term()}.
+-spec add_pathz(Dir) -> add_path_ret() when
+ Dir :: file:filename().
add_pathz(Dir) when is_list(Dir) -> call({add_path,last,Dir}).
--spec add_patha(Directory :: file:filename()) -> 'true' | {'error', term()}.
+-spec add_patha(Dir) -> add_path_ret() when
+ Dir :: file:filename().
add_patha(Dir) when is_list(Dir) -> call({add_path,first,Dir}).
--spec add_paths(Directories :: [file:filename()]) -> 'ok'.
+-spec add_paths(Dirs) -> 'ok' when
+ Dirs :: [Dir :: file:filename()].
add_paths(Dirs) when is_list(Dirs) -> call({add_paths,last,Dirs}).
--spec add_pathsz(Directories :: [file:filename()]) -> 'ok'.
+-spec add_pathsz(Dirs) -> 'ok' when
+ Dirs :: [Dir :: file:filename()].
add_pathsz(Dirs) when is_list(Dirs) -> call({add_paths,last,Dirs}).
--spec add_pathsa(Directories :: [file:filename()]) -> 'ok'.
+-spec add_pathsa(Dirs) -> 'ok' when
+ Dirs :: [Dir :: file:filename()].
add_pathsa(Dirs) when is_list(Dirs) -> call({add_paths,first,Dirs}).
-%% XXX Contract's input argument differs from add_path/1 -- why?
--spec del_path(Name :: file:filename() | atom()) -> boolean() | {'error', 'bad_name'}.
+-spec del_path(NameOrDir) -> boolean() | {'error', What} when
+ NameOrDir :: Name | Dir,
+ Name :: atom(),
+ Dir :: file:filename(),
+ What :: 'bad_name'.
del_path(Name) when is_list(Name) ; is_atom(Name) -> call({del_path,Name}).
--type replace_path_error() :: {'error', 'bad_directory' | 'bad_name' | {'badarg',_}}.
--spec replace_path(Name:: atom(), Dir :: file:filename()) -> 'true' | replace_path_error().
-replace_path(Name, Dir) when (is_atom(Name) or is_list(Name)) and
- (is_atom(Dir) or is_list(Dir)) ->
+-spec replace_path(Name, Dir) -> 'true' | {'error', What} when
+ Name:: atom(),
+ Dir :: file:filename(),
+ What :: 'bad_directory' | 'bad_name' | {'badarg',_}.
+replace_path(Name, Dir) when (is_atom(Name) orelse is_list(Name)),
+ (is_atom(Dir) orelse is_list(Dir)) ->
call({replace_path,Name,Dir}).
-spec rehash() -> 'ok'.
@@ -273,19 +325,14 @@ start_link(Flags) ->
do_start(Flags) ->
%% The following module_info/1 calls are here to ensure
- %% that the modules are loaded prior to their use elsewhere in
+ %% that these modules are loaded prior to their use elsewhere in
%% the code_server.
%% Otherwise a deadlock may occur when the code_server is starting.
- code_server:module_info(module),
- packages:module_info(module),
+ code_server = code_server:module_info(module),
+ packages = packages:module_info(module),
catch hipe_unified_loader:load_hipe_modules(),
- gb_sets:module_info(module),
- gb_trees:module_info(module),
-
- ets:module_info(module),
- os:module_info(module),
- filename:module_info(module),
- lists:module_info(module),
+ Modules2 = [gb_sets, gb_trees, ets, os, binary, unicode, filename, lists],
+ lists:foreach(fun (M) -> M = M:module_info(module) end, Modules2),
Mode = get_mode(Flags),
case init:get_argument(root) of
@@ -293,7 +340,7 @@ do_start(Flags) ->
Root = filename:join([Root0]), % Normalize. Use filename
case code_server:start_link([Root,Mode]) of
{ok,_Pid} = Ok2 ->
- if
+ if
Mode =:= interactive ->
case lists:member(stick, Flags) of
true -> do_stick_dirs();
@@ -302,12 +349,14 @@ do_start(Flags) ->
true ->
ok
end,
+ %% Quietly load native code for all modules loaded so far
+ catch load_native_code_for_all_loaded(),
Ok2;
Other ->
Other
end;
Other ->
- error_logger:error_msg("Can not start code server ~w ~n",[Other]),
+ error_logger:error_msg("Can not start code server ~w ~n", [Other]),
{error, crash}
end.
@@ -324,7 +373,7 @@ do_s(Lib) ->
%% The return value is intentionally ignored. Missing
%% directories is not a fatal error. (In embedded systems,
%% there is usually no compiler directory.)
- stick_dir(filename:append(Dir, "ebin")),
+ _ = stick_dir(filename:append(Dir, "ebin")),
ok
end.
@@ -348,10 +397,9 @@ get_mode(Flags) ->
%% In that case return the name of the file which contains
%% the loaded object code
--type which_ret_atoms() :: loaded_ret_atoms() | 'non_existing'.
-
--spec which(Module :: atom()) -> file:filename() | which_ret_atoms().
-
+-spec which(Module) -> Which when
+ Module :: module(),
+ Which :: file:filename() | loaded_ret_atoms() | non_existing.
which(Module) when is_atom(Module) ->
case is_loaded(Module) of
false ->
@@ -391,9 +439,9 @@ which(File, Base, [Directory|Tail]) ->
%% Search the code path for a specific file. Try to locate
%% it in the code path cache if possible.
--spec where_is_file(Filename :: file:filename()) ->
- 'non_existing' | file:filename().
-
+-spec where_is_file(Filename) -> non_existing | Absname when
+ Filename :: file:filename(),
+ Absname :: file:filename().
where_is_file(File) when is_list(File) ->
case call({is_cached,File}) of
no ->
@@ -422,11 +470,11 @@ where_is_file(Path, File) when is_list(Path), is_list(File) ->
-spec set_primary_archive(ArchiveFile :: file:filename(),
ArchiveBin :: binary(),
- FileInfo :: #file_info{})
+ FileInfo :: file:file_info())
-> 'ok' | {'error', atom()}.
-set_primary_archive(ArchiveFile0, ArchiveBin, FileInfo)
- when is_list(ArchiveFile0), is_binary(ArchiveBin), is_record(FileInfo, file_info) ->
+set_primary_archive(ArchiveFile0, ArchiveBin, #file_info{} = FileInfo)
+ when is_list(ArchiveFile0), is_binary(ArchiveBin) ->
ArchiveFile = filename:absname(ArchiveFile0),
case call({set_primary_archive, ArchiveFile, ArchiveBin, FileInfo}) of
{ok, []} ->
@@ -473,19 +521,19 @@ decorate([], _) -> [];
decorate([File|Tail], Dir) ->
[{Dir, File} | decorate(Tail, Dir)].
-filter(_Ext, Dir, {error,_}) ->
+filter(_Ext, Dir, error) ->
io:format("** Bad path can't read ~s~n", [Dir]), [];
filter(Ext, _, {ok,Files}) ->
filter2(Ext, length(Ext), Files).
filter2(_Ext, _Extlen, []) -> [];
-filter2(Ext, Extlen,[File|Tail]) ->
- case has_ext(Ext,Extlen, File) of
+filter2(Ext, Extlen, [File|Tail]) ->
+ case has_ext(Ext, Extlen, File) of
true -> [File | filter2(Ext, Extlen, Tail)];
false -> filter2(Ext, Extlen, Tail)
end.
-has_ext(Ext, Extlen,File) ->
+has_ext(Ext, Extlen, File) ->
L = length(File),
case catch lists:nthtail(L - Extlen, File) of
Ext -> true;
@@ -494,3 +542,19 @@ has_ext(Ext, Extlen,File) ->
to_path(X) ->
filename:join(packages:split(X)).
+
+-spec load_native_code_for_all_loaded() -> ok.
+load_native_code_for_all_loaded() ->
+ Architecture = erlang:system_info(hipe_architecture),
+ ChunkName = hipe_unified_loader:chunk_name(Architecture),
+ lists:foreach(fun({Module, BeamFilename}) ->
+ case code:is_module_native(Module) of
+ false ->
+ case beam_lib:chunks(BeamFilename, [ChunkName]) of
+ {ok,{_,[{_,Bin}]}} when is_binary(Bin) ->
+ load_native_partial(Module, Bin);
+ {error, beam_lib, _} -> ok
+ end;
+ true -> ok
+ end
+ end, all_loaded()).
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index 7aeddb73d1..e3d22e7999 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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
@@ -32,14 +32,15 @@
-import(lists, [foreach/2]).
--record(state,{supervisor,
- root,
- path,
- moddb,
- namedb,
- cache = no_cache,
- mode=interactive,
- on_load = []}).
+-record(state, {supervisor,
+ root,
+ path,
+ moddb,
+ namedb,
+ cache = no_cache,
+ mode = interactive,
+ on_load = []}).
+-type state() :: #state{}.
start_link(Args) ->
Ref = make_ref(),
@@ -65,8 +66,8 @@ init(Ref, Parent, [Root,Mode0]) ->
Mode =
case Mode0 of
- minimal -> interactive;
- _ -> Mode0
+ minimal -> interactive;
+ _ -> Mode0
end,
IPath =
@@ -74,7 +75,7 @@ init(Ref, Parent, [Root,Mode0]) ->
interactive ->
LibDir = filename:append(Root, "lib"),
{ok,Dirs} = erl_prim_loader:list_dir(LibDir),
- {Paths,_Libs} = make_path(LibDir,Dirs),
+ {Paths,_Libs} = make_path(LibDir, Dirs),
UserLibPaths = get_user_lib_dirs(),
["."] ++ UserLibPaths ++ Paths;
_ ->
@@ -97,7 +98,7 @@ init(Ref, Parent, [Root,Mode0]) ->
end,
Parent ! {Ref,{ok,self()}},
- loop(State#state{supervisor=Parent}).
+ loop(State#state{supervisor = Parent}).
get_user_lib_dirs() ->
case os:getenv("ERL_LIBS") of
@@ -169,8 +170,8 @@ loop(#state{supervisor=Supervisor}=State0) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% System upgrade
-handle_system_msg(SysState,Msg,From,Parent,Misc) ->
- case do_sys_cmd(SysState,Msg,Parent, Misc) of
+handle_system_msg(SysState, Msg, From, Parent, Misc) ->
+ case do_sys_cmd(SysState, Msg, Parent, Misc) of
{suspended, Reply, NMisc} ->
gen_reply(From, Reply),
suspend_loop(suspended, Parent, NMisc);
@@ -207,7 +208,7 @@ do_sys_cmd(SysState, {debug, _What}, _Parent, Misc) ->
do_sys_cmd(suspended, {change_code, Module, Vsn, Extra}, _Parent, Misc0) ->
{Res, Misc} =
case catch ?MODULE:system_code_change(Misc0, Module, Vsn, Extra) of
- {ok, Misc1} -> {ok, Misc1};
+ {ok, _} = Ok -> Ok;
Else -> {{error, Else}, Misc0}
end,
{suspended, Res, Misc};
@@ -218,9 +219,10 @@ system_continue(_Parent, _Debug, State) ->
loop(State).
system_terminate(_Reason, _Parent, _Debug, _State) ->
-% error_msg("~p terminating: ~p~n ",[?MODULE,Reason]),
+ %% error_msg("~p terminating: ~p~n ", [?MODULE, Reason]),
exit(shutdown).
+-spec system_code_change(state(), module(), term(), term()) -> {'ok', state()}.
system_code_change(State, _Module, _OldVsn, _Extra) ->
{ok, State}.
@@ -240,7 +242,7 @@ handle_call({stick_mod,Mod}, {_From,_Tag}, S) ->
handle_call({unstick_mod,Mod}, {_From,_Tag}, S) ->
{reply,stick_mod(Mod, false, S),S};
-handle_call({dir,Dir},{_From,_Tag}, S) ->
+handle_call({dir,Dir}, {_From,_Tag}, S) ->
Root = S#state.root,
Resp = do_dir(Root,Dir,S#state.namedb),
{reply,Resp,S};
@@ -253,43 +255,47 @@ handle_call({load_file,Mod}, Caller, St) ->
load_file(Mod, Caller, St)
end;
-handle_call({add_path,Where,Dir0}, {_From,_Tag}, S=#state{cache=Cache0}) ->
+handle_call({add_path,Where,Dir0}, {_From,_Tag},
+ #state{cache=Cache0,namedb=Namedb,path=Path0}=S) ->
case Cache0 of
no_cache ->
- {Resp,Path} = add_path(Where, Dir0, S#state.path, S#state.namedb),
+ {Resp,Path} = add_path(Where, Dir0, Path0, Namedb),
{reply,Resp,S#state{path=Path}};
_ ->
Dir = absname(Dir0), %% Cache always expands the path
- {Resp,Path} = add_path(Where, Dir, S#state.path, S#state.namedb),
- Cache=update_cache([Dir],Where,Cache0),
+ {Resp,Path} = add_path(Where, Dir, Path0, Namedb),
+ Cache = update_cache([Dir], Where, Cache0),
{reply,Resp,S#state{path=Path,cache=Cache}}
end;
-handle_call({add_paths,Where,Dirs0}, {_From,_Tag}, S=#state{cache=Cache0}) ->
+handle_call({add_paths,Where,Dirs0}, {_From,_Tag},
+ #state{cache=Cache0,namedb=Namedb,path=Path0}=S) ->
case Cache0 of
no_cache ->
- {Resp,Path} = add_paths(Where,Dirs0,S#state.path,S#state.namedb),
- {reply,Resp, S#state{path=Path}};
+ {Resp,Path} = add_paths(Where, Dirs0, Path0, Namedb),
+ {reply,Resp,S#state{path=Path}};
_ ->
%% Cache always expands the path
Dirs = [absname(Dir) || Dir <- Dirs0],
- {Resp,Path} = add_paths(Where, Dirs, S#state.path, S#state.namedb),
+ {Resp,Path} = add_paths(Where, Dirs, Path0, Namedb),
Cache=update_cache(Dirs,Where,Cache0),
{reply,Resp,S#state{cache=Cache,path=Path}}
end;
-handle_call({set_path,PathList}, {_From,_Tag}, S) ->
- Path = S#state.path,
- {Resp, NewPath,NewDb} = set_path(PathList, Path, S#state.namedb),
- {reply,Resp,rehash_cache(S#state{path = NewPath, namedb=NewDb})};
+handle_call({set_path,PathList}, {_From,_Tag},
+ #state{path=Path0,namedb=Namedb}=S) ->
+ {Resp,Path,NewDb} = set_path(PathList, Path0, Namedb),
+ {reply,Resp,rehash_cache(S#state{path=Path,namedb=NewDb})};
-handle_call({del_path,Name}, {_From,_Tag}, S) ->
- {Resp,Path} = del_path(Name,S#state.path,S#state.namedb),
- {reply,Resp,rehash_cache(S#state{path = Path})};
+handle_call({del_path,Name}, {_From,_Tag},
+ #state{path=Path0,namedb=Namedb}=S) ->
+ {Resp,Path} = del_path(Name, Path0, Namedb),
+ {reply,Resp,rehash_cache(S#state{path=Path})};
-handle_call({replace_path,Name,Dir}, {_From,_Tag}, S) ->
- {Resp,Path} = replace_path(Name,Dir,S#state.path,S#state.namedb),
- {reply,Resp,rehash_cache(S#state{path = Path})};
+handle_call({replace_path,Name,Dir}, {_From,_Tag},
+ #state{path=Path0,namedb=Namedb}=S) ->
+ {Resp,Path} = replace_path(Name, Dir, Path0, Namedb),
+ {reply,Resp,rehash_cache(S#state{path=Path})};
handle_call(rehash, {_From,_Tag}, S0) ->
S = create_cache(S0),
@@ -311,12 +317,12 @@ handle_call({load_binary,Mod,File,Bin}, Caller, S) ->
do_load_binary(Mod, File, Bin, Caller, S);
handle_call({load_native_partial,Mod,Bin}, {_From,_Tag}, S) ->
- Result = (catch hipe_unified_loader:load(Mod,Bin)),
+ Result = (catch hipe_unified_loader:load(Mod, Bin)),
Status = hipe_result_to_status(Result),
{reply,Status,S};
handle_call({load_native_sticky,Mod,Bin,WholeModule}, {_From,_Tag}, S) ->
- Result = (catch hipe_unified_loader:load_module(Mod,Bin,WholeModule)),
+ Result = (catch hipe_unified_loader:load_module(Mod, Bin, WholeModule)),
Status = hipe_result_to_status(Result),
{reply,Status,S};
@@ -388,8 +394,8 @@ handle_call({set_primary_archive, File, ArchiveBin, FileInfo}, {_From,_Tag}, S=#
case erl_prim_loader:set_primary_archive(File, ArchiveBin, FileInfo) of
{ok, Files} ->
{reply, {ok, Mode, Files}, S};
- {error, Reason} ->
- {reply, {error, Reason}, S}
+ {error, _Reason} = Error ->
+ {reply, Error, S}
end;
handle_call({is_cached,File}, {_From,_Tag}, S=#state{cache=Cache}) ->
@@ -469,8 +475,8 @@ locate_mods([], _, _, Cache, Path) ->
filter_mods([File|Rest], Where, Exts, Dir, Cache) ->
Ext = filename:extension(File),
Root = list_to_atom(filename:rootname(File, Ext)),
- case lists:keysearch(Ext, 2, Exts) of
- {value,{Type,_}} ->
+ case lists:keyfind(Ext, 2, Exts) of
+ {Type, _} ->
Key = {Type,Root},
case Where of
first ->
@@ -487,7 +493,6 @@ filter_mods([File|Rest], Where, Exts, Dir, Cache) ->
ok
end,
filter_mods(Rest, Where, Exts, Dir, Cache);
-
filter_mods([], _, _, _, Cache) ->
Cache.
@@ -498,27 +503,27 @@ filter_mods([], _, _, _, Cache) ->
%%
%% Create the initial path.
%%
-make_path(BundleDir,Bundles0) ->
+make_path(BundleDir, Bundles0) ->
Bundles = choose_bundles(Bundles0),
- make_path(BundleDir,Bundles,[],[]).
+ make_path(BundleDir, Bundles, [], []).
choose_bundles(Bundles) ->
ArchiveExt = archive_extension(),
- Bs = lists:sort([create_bundle(B,ArchiveExt) || B <- Bundles]),
+ Bs = lists:sort([create_bundle(B, ArchiveExt) || B <- Bundles]),
[FullName || {_Name,_NumVsn,FullName} <-
choose(lists:reverse(Bs), [], ArchiveExt)].
-create_bundle(FullName,ArchiveExt) ->
- BaseName = filename:basename(FullName,ArchiveExt),
+create_bundle(FullName, ArchiveExt) ->
+ BaseName = filename:basename(FullName, ArchiveExt),
case split(BaseName, "-") of
- Toks when length(Toks) > 1 ->
+ [_, _|_] = Toks ->
VsnStr = lists:last(Toks),
case vsn_to_num(VsnStr) of
{ok, VsnNum} ->
- Name = join(lists:sublist(Toks,length(Toks)-1),"-"),
+ Name = join(lists:sublist(Toks, length(Toks)-1),"-"),
{Name,VsnNum,FullName};
false ->
- {FullName, [0], FullName}
+ {FullName,[0],FullName}
end;
_ ->
{FullName,[0],FullName}
@@ -569,8 +574,8 @@ join([], _) ->
[].
choose([{Name,NumVsn,NewFullName}=New|Bs], Acc, ArchiveExt) ->
- case lists:keysearch(Name,1,Acc) of
- {value, {_, NV, OldFullName}} when NV =:= NumVsn ->
+ case lists:keyfind(Name, 1, Acc) of
+ {_, NV, OldFullName} when NV =:= NumVsn ->
case filename:extension(OldFullName) =:= ArchiveExt of
false ->
choose(Bs,Acc, ArchiveExt);
@@ -578,7 +583,7 @@ choose([{Name,NumVsn,NewFullName}=New|Bs], Acc, ArchiveExt) ->
Acc2 = lists:keystore(Name, 1, Acc, New),
choose(Bs,Acc2, ArchiveExt)
end;
- {value, {_, _, _}} ->
+ {_, _, _} ->
choose(Bs,Acc, ArchiveExt);
false ->
choose(Bs,[{Name,NumVsn,NewFullName}|Acc], ArchiveExt)
@@ -602,8 +607,8 @@ make_path(BundleDir,[Bundle|Tail],Res,Bs) ->
Ebin2 = filename:join([filename:dirname(Dir), Base ++ Ext, Base, "ebin"]),
Ebins =
case split(Base, "-") of
- Toks when length(Toks) > 1 ->
- AppName = join(lists:sublist(Toks,length(Toks)-1),"-"),
+ [_, _|_] = Toks ->
+ AppName = join(lists:sublist(Toks, length(Toks)-1),"-"),
Ebin3 = filename:join([filename:dirname(Dir), Base ++ Ext, AppName, "ebin"]),
[Ebin3, Ebin2, Dir];
_ ->
@@ -835,30 +840,25 @@ add_path(_,_,Path,_) ->
%% then the table is created :-)
%%
do_add(first,Dir,Path,NameDb) ->
- update(Dir,NameDb),
+ update(Dir, NameDb),
[Dir|lists:delete(Dir,Path)];
do_add(last,Dir,Path,NameDb) ->
case lists:member(Dir,Path) of
true ->
Path;
false ->
- maybe_update(Dir,NameDb),
+ maybe_update(Dir, NameDb),
Path ++ [Dir]
end.
%% Do not update if the same name already exists !
-maybe_update(Dir,NameDb) ->
- case lookup_name(get_name(Dir),NameDb) of
- false -> update(Dir,NameDb);
- _ -> false
- end.
+maybe_update(Dir, NameDb) ->
+ (lookup_name(get_name(Dir), NameDb) =:= false) andalso update(Dir, NameDb).
update(_Dir, false) ->
- ok;
-update(Dir,NameDb) ->
- replace_name(Dir,NameDb).
-
-
+ true;
+update(Dir, NameDb) ->
+ replace_name(Dir, NameDb).
%%
%% Set a completely new path.
@@ -946,8 +946,8 @@ all_archive_subdirs(AppDir) ->
Base = filename:basename(AppDir),
Dirs =
case split(Base, "-") of
- Toks when length(Toks) > 1 ->
- Base2 = join(lists:sublist(Toks,length(Toks)-1),"-"),
+ [_, _|_] = Toks ->
+ Base2 = join(lists:sublist(Toks, length(Toks)-1), "-"),
[Base2, Base];
_ ->
[Base]
@@ -1060,7 +1060,6 @@ check_pars(Name,Dir) ->
{error,bad_name}
end.
-
del_ebin(Dir) ->
case filename:basename(Dir) of
"ebin" ->
@@ -1079,8 +1078,6 @@ del_ebin(Dir) ->
Dir
end.
-
-
replace_name(Dir, Db) ->
case get_name(Dir) of
Dir ->
@@ -1187,15 +1184,7 @@ get_mods([File|Tail], Extension) ->
get_mods([], _) -> [].
is_sticky(Mod, Db) ->
- case erlang:module_loaded(Mod) of
- true ->
- case ets:lookup(Db, {sticky,Mod}) of
- [] -> false;
- _ -> true
- end;
- false ->
- false
- end.
+ erlang:module_loaded(Mod) andalso (ets:lookup(Db, {sticky, Mod}) =/= []).
add_paths(Where,[Dir|Tail],Path,NameDb) ->
{_,NPath} = add_path(Where,Dir,Path,NameDb),
@@ -1203,7 +1192,6 @@ add_paths(Where,[Dir|Tail],Path,NameDb) ->
add_paths(_,_,Path,_) ->
{ok,Path}.
-
do_load_binary(Module, File, Binary, Caller, St) ->
case modp(Module) andalso modp(File) andalso is_binary(Binary) of
true ->
@@ -1220,7 +1208,6 @@ modp(Atom) when is_atom(Atom) -> true;
modp(List) when is_list(List) -> int_list(List);
modp(_) -> false.
-
load_abs(File, Mod0, Caller, St) ->
Ext = objfile_extension(),
FileName0 = lists:concat([File, Ext]),
@@ -1263,20 +1250,20 @@ try_load_module_1(File, Mod, Bin, Caller, #state{moddb=Db}=St) ->
{reply,{error,sticky_directory},St};
false ->
case catch load_native_code(Mod, Bin) of
- {module,Mod} ->
+ {module,Mod} = Module ->
ets:insert(Db, {Mod,File}),
- {reply,{module,Mod},St};
+ {reply,Module,St};
no_native ->
case erlang:load_module(Mod, Bin) of
- {module,Mod} ->
+ {module,Mod} = Module ->
ets:insert(Db, {Mod,File}),
post_beam_load(Mod),
- {reply,{module,Mod},St};
+ {reply,Module,St};
{error,on_load} ->
handle_on_load(Mod, File, Caller, St);
- {error,What} ->
+ {error,What} = Error ->
error_msg("Loading of ~s failed: ~p\n", [File, What]),
- {reply,{error,What},St}
+ {reply,Error,St}
end;
Error ->
error_msg("Native loading of ~s failed: ~p\n",
@@ -1392,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
@@ -1412,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/disk_log.erl b/lib/kernel/src/disk_log.erl
index 7f1b5f9ec6..9b8d2db437 100644
--- a/lib/kernel/src/disk_log.erl
+++ b/lib/kernel/src/disk_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -70,9 +70,10 @@
%%% Contract type specifications
%%%----------------------------------------------------------------------
+-opaque continuation() :: #continuation{}.
+
-type bytes() :: binary() | [byte()].
--type log() :: term(). % XXX: refine
-type file_error() :: term(). % XXX: refine
-type invalid_header() :: term(). % XXX: refine
@@ -87,27 +88,30 @@
-type open_error_rsn() :: 'no_such_log'
| {'badarg', term()}
- | {'size_mismatch', dlog_size(), dlog_size()}
- | {'arg_mismatch', dlog_optattr(), term(), term()}
- | {'name_already_open', log()}
- | {'open_read_write', log()}
- | {'open_read_only', log()}
- | {'need_repair', log()}
- | {'not_a_log_file', string()}
- | {'invalid_index_file', string()}
+ | {'size_mismatch', CurrentSize :: dlog_size(),
+ NewSize :: dlog_size()}
+ | {'arg_mismatch', OptionName :: dlog_optattr(),
+ CurrentValue :: term(), Value :: term()}
+ | {'name_already_open', Log :: log()}
+ | {'open_read_write', Log :: log()}
+ | {'open_read_only', Log :: log()}
+ | {'need_repair', Log :: log()}
+ | {'not_a_log_file', FileName :: file:filename()}
+ | {'invalid_index_file', FileName :: file:filename()}
| {'invalid_header', invalid_header()}
| {'file_error', file:filename(), file_error()}
- | {'node_already_open', log()}.
+ | {'node_already_open', Log :: log()}.
-type dist_error_rsn() :: 'nodedown' | open_error_rsn().
--type ret() :: {'ok', log()}
- | {'repaired', log(), {'recovered', non_neg_integer()},
- {'badbytes', non_neg_integer()}}.
+-type ret() :: {'ok', Log :: log()}
+ | {'repaired', Log :: log(),
+ {'recovered', Rec :: non_neg_integer()},
+ {'badbytes', Bad :: non_neg_integer()}}.
-type open_ret() :: ret() | {'error', open_error_rsn()}.
-type dist_open_ret() :: {[{node(), ret()}],
[{node(), {'error', dist_error_rsn()}}]}.
--type all_open_ret() :: open_ret() | dist_open_ret().
--spec open(Args :: dlog_options()) -> all_open_ret().
+-spec open(ArgL) -> open_ret() | dist_open_ret() when
+ ArgL :: dlog_options().
open(A) ->
disk_log_server:open(check_arg(A, #arg{options = A})).
@@ -116,40 +120,57 @@ open(A) ->
| {'full', log()} | {'invalid_header', invalid_header()}
| {'file_error', file:filename(), file_error()}.
--spec log(Log :: log(), Term :: term()) -> 'ok' | {'error', log_error_rsn()}.
+-spec log(Log, Term) -> ok | {error, Reason :: log_error_rsn()} when
+ Log :: log(),
+ Term :: term().
log(Log, Term) ->
req(Log, {log, term_to_binary(Term)}).
--spec blog(Log :: log(), Bytes :: bytes()) -> 'ok' | {'error', log_error_rsn()}.
+-spec blog(Log, Bytes) -> ok | {error, Reason :: log_error_rsn()} when
+ Log :: log(),
+ Bytes :: bytes().
blog(Log, Bytes) ->
req(Log, {blog, check_bytes(Bytes)}).
--spec log_terms(Log :: log(), Terms :: [term()]) -> 'ok' | {'error', term()}.
+-spec log_terms(Log, TermList) -> ok | {error, Resaon :: log_error_rsn()} when
+ Log :: log(),
+ TermList :: [term()].
log_terms(Log, Terms) ->
Bs = terms2bins(Terms),
req(Log, {log, Bs}).
--spec blog_terms(Log :: log(), Bytes :: [bytes()]) -> 'ok' | {'error', term()}.
+-spec blog_terms(Log, BytesList) ->
+ ok | {error, Reason :: log_error_rsn()} when
+ Log :: log(),
+ BytesList :: [bytes()].
blog_terms(Log, Bytess) ->
Bs = check_bytes_list(Bytess, Bytess),
req(Log, {blog, Bs}).
-type notify_ret() :: 'ok' | {'error', 'no_such_log'}.
--spec alog(Log :: log(), Term :: term()) -> notify_ret().
+-spec alog(Log, Term) -> notify_ret() when
+ Log :: log(),
+ Term :: term().
alog(Log, Term) ->
notify(Log, {alog, term_to_binary(Term)}).
--spec alog_terms(Log :: log(), Terms :: [term()]) -> notify_ret().
+-spec alog_terms(Log, TermList) -> notify_ret() when
+ Log :: log(),
+ TermList :: [term()].
alog_terms(Log, Terms) ->
Bs = terms2bins(Terms),
notify(Log, {alog, Bs}).
--spec balog(Log :: log(), Bytes :: bytes()) -> notify_ret().
+-spec balog(Log, Bytes) -> notify_ret() when
+ Log :: log(),
+ Bytes :: bytes().
balog(Log, Bytes) ->
notify(Log, {balog, check_bytes(Bytes)}).
--spec balog_terms(Log :: log(), Bytes :: [bytes()]) -> notify_ret().
+-spec balog_terms(Log, ByteList) -> notify_ret() when
+ Log :: log(),
+ ByteList :: [bytes()].
balog_terms(Log, Bytess) ->
Bs = check_bytes_list(Bytess, Bytess),
notify(Log, {balog, Bs}).
@@ -157,18 +178,22 @@ balog_terms(Log, Bytess) ->
-type close_error_rsn() ::'no_such_log' | 'nonode'
| {'file_error', file:filename(), file_error()}.
--spec close(Log :: log()) -> 'ok' | {'error', close_error_rsn()}.
+-spec close(Log) -> 'ok' | {'error', close_error_rsn()} when
+ Log :: log().
close(Log) ->
req(Log, close).
-type lclose_error_rsn() :: 'no_such_log'
| {'file_error', file:filename(), file_error()}.
--spec lclose(Log :: log()) -> 'ok' | {'error', lclose_error_rsn()}.
+-spec lclose(Log) -> 'ok' | {'error', lclose_error_rsn()} when
+ Log :: log().
lclose(Log) ->
lclose(Log, node()).
--spec lclose(Log :: log(), Node :: node()) -> 'ok' | {'error', lclose_error_rsn()}.
+-spec lclose(Log, Node) -> 'ok' | {'error', lclose_error_rsn()} when
+ Log :: log(),
+ Node :: node().
lclose(Log, Node) ->
lreq(Log, close, Node).
@@ -178,29 +203,49 @@ lclose(Log, Node) ->
| {'invalid_header', invalid_header()}
| {'file_error', file:filename(), file_error()}.
--spec truncate(Log :: log()) -> 'ok' | {'error', trunc_error_rsn()}.
+-spec truncate(Log) -> 'ok' | {'error', trunc_error_rsn()} when
+ Log :: log().
truncate(Log) ->
req(Log, {truncate, none, truncate, 1}).
--spec truncate(Log :: log(), Head :: term()) -> 'ok' | {'error', trunc_error_rsn()}.
+-spec truncate(Log, Head) -> 'ok' | {'error', trunc_error_rsn()} when
+ Log :: log(),
+ Head :: term().
truncate(Log, Head) ->
req(Log, {truncate, {ok, term_to_binary(Head)}, truncate, 2}).
--spec btruncate(Log :: log(), Head :: bytes()) -> 'ok' | {'error', trunc_error_rsn()}.
+-spec btruncate(Log, BHead) -> 'ok' | {'error', trunc_error_rsn()} when
+ Log :: log(),
+ BHead :: bytes().
btruncate(Log, Head) ->
req(Log, {truncate, {ok, check_bytes(Head)}, btruncate, 2}).
--spec reopen(Log :: log(), Filename :: file:filename()) -> 'ok' | {'error', term()}.
+-type reopen_error_rsn() :: no_such_log
+ | nonode
+ | {read_only_mode, log()}
+ | {blocked_log, log()}
+ | {same_file_name, log()} |
+ {invalid_index_file, file:filename()}
+ | {invalid_header, invalid_header()}
+ | {'file_error', file:filename(), file_error()}.
+
+-spec reopen(Log, File) -> 'ok' | {'error', reopen_error_rsn()} when
+ Log :: log(),
+ File :: file:filename().
reopen(Log, NewFile) ->
req(Log, {reopen, NewFile, none, reopen, 2}).
--spec reopen(Log :: log(), Filename :: file:filename(), Head :: term()) ->
- 'ok' | {'error', term()}.
+-spec reopen(Log, File, Head) -> 'ok' | {'error', reopen_error_rsn()} when
+ Log :: log(),
+ File :: file:filename(),
+ Head :: term().
reopen(Log, NewFile, NewHead) ->
req(Log, {reopen, NewFile, {ok, term_to_binary(NewHead)}, reopen, 3}).
--spec breopen(Log :: log(), Filename :: file:filename(), Head :: bytes()) ->
- 'ok' | {'error', term()}.
+-spec breopen(Log, File, BHead) -> 'ok' | {'error', reopen_error_rsn()} when
+ Log :: log(),
+ File :: file:filename(),
+ BHead :: bytes().
breopen(Log, NewFile, NewHead) ->
req(Log, {reopen, NewFile, {ok, check_bytes(NewHead)}, breopen, 3}).
@@ -210,21 +255,36 @@ breopen(Log, NewFile, NewHead) ->
| {'invalid_header', invalid_header()}
| {'file_error', file:filename(), file_error()}.
--spec inc_wrap_file(Log :: log()) -> 'ok' | {'error', inc_wrap_error_rsn()}.
+-spec inc_wrap_file(Log) -> 'ok' | {'error', inc_wrap_error_rsn()} when
+ Log :: log().
inc_wrap_file(Log) ->
req(Log, inc_wrap_file).
--spec change_size(Log :: log(), Size :: dlog_size()) -> 'ok' | {'error', term()}.
+-spec change_size(Log, Size) -> 'ok' | {'error', Reason} when
+ Log :: log(),
+ Size :: dlog_size(),
+ Reason :: no_such_log | nonode | {read_only_mode, Log}
+ | {blocked_log, Log}
+ | {new_size_too_small, CurrentSize :: pos_integer()}
+ | {badarg, size}
+ | {file_error, file:filename(), file_error()}.
change_size(Log, NewSize) ->
req(Log, {change_size, NewSize}).
--spec change_notify(Log :: log(), Pid :: pid(), Notify :: boolean()) ->
- 'ok' | {'error', term()}.
+-spec change_notify(Log, Owner, Notify) -> 'ok' | {'error', Reason} when
+ Log :: log(),
+ Owner :: pid(),
+ Notify :: boolean(),
+ Reason :: no_such_log | nonode | {blocked_log, Log}
+ | {badarg, notify} | {not_owner, Owner}.
change_notify(Log, Pid, NewNotify) ->
req(Log, {change_notify, Pid, NewNotify}).
--spec change_header(Log :: log(), Head :: {atom(), term()}) ->
- 'ok' | {'error', term()}.
+-spec change_header(Log, Header) -> 'ok' | {'error', Reason} when
+ Log :: log(),
+ Header :: {head, dlog_head_opt()} | {head_func, mfa()},
+ Reason :: no_such_log | nonode | {read_only_mode, Log}
+ | {blocked_log, Log} | {badarg, head}.
change_header(Log, NewHead) ->
req(Log, {change_header, NewHead}).
@@ -232,17 +292,21 @@ change_header(Log, NewHead) ->
| {'blocked_log', log()}
| {'file_error', file:filename(), file_error()}.
--spec sync(Log :: log()) -> 'ok' | {'error', sync_error_rsn()}.
+-spec sync(Log) -> 'ok' | {'error', sync_error_rsn()} when
+ Log :: log().
sync(Log) ->
req(Log, sync).
-type block_error_rsn() :: 'no_such_log' | 'nonode' | {'blocked_log', log()}.
--spec block(Log :: log()) -> 'ok' | {'error', block_error_rsn()}.
+-spec block(Log) -> 'ok' | {'error', block_error_rsn()} when
+ Log :: log().
block(Log) ->
block(Log, true).
--spec block(Log :: log(), QueueLogRecords :: boolean()) -> 'ok' | {'error', term()}.
+-spec block(Log, QueueLogRecords) -> 'ok' | {'error', block_error_rsn()} when
+ Log :: log(),
+ QueueLogRecords :: boolean().
block(Log, QueueLogRecords) ->
req(Log, {block, QueueLogRecords}).
@@ -250,19 +314,46 @@ block(Log, QueueLogRecords) ->
| {'not_blocked', log()}
| {'not_blocked_by_pid', log()}.
--spec unblock(Log :: log()) -> 'ok' | {'error', unblock_error_rsn()}.
+-spec unblock(Log) -> 'ok' | {'error', unblock_error_rsn()} when
+ Log :: log().
unblock(Log) ->
req(Log, unblock).
--spec format_error(Error :: term()) -> string().
+-spec format_error(Error) -> io_lib:chars() when
+ Error :: term().
format_error(Error) ->
do_format_error(Error).
--spec info(Log :: log()) -> [{atom(), any()}] | {'error', term()}.
+-type dlog_info() :: {name, Log :: log()}
+ | {file, File :: file:filename()}
+ | {type, Type :: dlog_type()}
+ | {format, Format :: dlog_format()}
+ | {size, Size :: dlog_size()}
+ | {mode, Mode :: dlog_mode()}
+ | {owners, [{pid(), Notify :: boolean()}]}
+ | {users, Users :: non_neg_integer()}
+ | {status, Status ::
+ ok | {blocked, QueueLogRecords :: boolean()}}
+ | {node, Node :: node()}
+ | {distributed, Dist :: local | [node()]}
+ | {head, Head :: none | {head, term()} | mfa()}
+ | {no_written_items, NoWrittenItems ::non_neg_integer()}
+ | {full, Full :: boolean}
+ | {no_current_bytes, non_neg_integer()}
+ | {no_current_items, non_neg_integer()}
+ | {no_items, non_neg_integer()}
+ | {current_file, pos_integer()}
+ | {no_overflows, {SinceLogWasOpened :: non_neg_integer(),
+ SinceLastInfo :: non_neg_integer()}}.
+-spec info(Log) -> InfoList | {'error', no_such_log} when
+ Log :: log(),
+ InfoList :: [dlog_info()].
info(Log) ->
sreq(Log, info).
--spec pid2name(Pid :: pid()) -> {'ok', log()} | 'undefined'.
+-spec pid2name(Pid) -> {'ok', Log} | 'undefined' when
+ Pid :: pid(),
+ Log :: log().
pid2name(Pid) ->
disk_log_server:start(),
case ets:lookup(?DISK_LOG_PID_TABLE, Pid) of
@@ -274,13 +365,31 @@ pid2name(Pid) ->
%% It retuns a {Cont2, ObjList} | eof | {error, Reason}
%% The initial continuation is the atom 'start'
--spec chunk(Log :: log(), Cont :: any()) ->
- {'error', term()} | 'eof' | {any(), [any()]} | {any(), [any()], integer()}.
+-type chunk_error_rsn() :: no_such_log
+ | {format_external, log()}
+ | {blocked_log, log()}
+ | {badarg, continuation}
+ | {not_internal_wrap, log()}
+ | {corrupt_log_file, FileName :: file:filename()}
+ | {file_error, file:filename(), file_error()}.
+
+-type chunk_ret() :: {Continuation2 :: continuation(), Terms :: [term()]}
+ | {Continuation2 :: continuation(),
+ Terms :: [term()],
+ Badbytes :: non_neg_integer()}
+ | eof
+ | {error, Reason :: chunk_error_rsn()}.
+
+-spec chunk(Log, Continuation) -> chunk_ret() when
+ Log :: log(),
+ Continuation :: start | continuation().
chunk(Log, Cont) ->
chunk(Log, Cont, infinity).
--spec chunk(Log :: log(), Cont :: any(), N :: pos_integer() | 'infinity') ->
- {'error', term()} | 'eof' | {any(), [any()]} | {any(), [any()], integer()}.
+-spec chunk(Log, Continuation, N) -> chunk_ret() when
+ Log :: log(),
+ Continuation :: start | continuation(),
+ N :: pos_integer() | infinity.
chunk(Log, Cont, infinity) ->
%% There cannot be more than ?MAX_CHUNK_SIZE terms in a chunk.
ichunk(Log, Cont, ?MAX_CHUNK_SIZE);
@@ -346,13 +455,24 @@ ichunk_bad_end([B | Bs], Mode, Log, C, Bad, A) ->
ichunk_bad_end(Bs, Mode, Log, C, Bad, [T | A])
end.
--spec bchunk(Log :: log(), Cont :: any()) ->
- {'error', any()} | 'eof' | {any(), [binary()]} | {any(), [binary()], integer()}.
+-type bchunk_ret() :: {Continuation2 :: continuation(),
+ Binaries :: [binary()]}
+ | {Continuation2 :: continuation(),
+ Binaries :: [binary()],
+ Badbytes :: non_neg_integer()}
+ | eof
+ | {error, Reason :: chunk_error_rsn()}.
+
+-spec bchunk(Log, Continuation) -> bchunk_ret() when
+ Log :: log(),
+ Continuation :: start | continuation().
bchunk(Log, Cont) ->
bchunk(Log, Cont, infinity).
--spec bchunk(Log :: log(), Cont :: any(), N :: 'infinity' | pos_integer()) ->
- {'error', any()} | 'eof' | {any(), [binary()]} | {any(), [binary()], integer()}.
+-spec bchunk(Log, Continuation, N) -> bchunk_ret() when
+ Log :: log(),
+ Continuation :: start | continuation(),
+ N :: pos_integer() | infinity.
bchunk(Log, Cont, infinity) ->
%% There cannot be more than ?MAX_CHUNK_SIZE terms in a chunk.
bichunk(Log, Cont, ?MAX_CHUNK_SIZE);
@@ -375,8 +495,14 @@ bichunk_end({C = #continuation{}, R, Bad}) ->
bichunk_end(R) ->
R.
--spec chunk_step(Log :: log(), Cont :: any(), N :: integer()) ->
- {'ok', any()} | {'error', term()}.
+-spec chunk_step(Log, Continuation, Step) ->
+ {'ok', any()} | {'error', Reason} when
+ Log :: log(),
+ Continuation :: start | continuation(),
+ Step :: integer(),
+ Reason :: no_such_log | end_of_log | {format_external, Log}
+ | {blocked_log, Log} | {badarg, continuation}
+ | {file_error, file:filename(), file_error()}.
chunk_step(Log, Cont, N) when is_integer(N) ->
ichunk_step(Log, Cont, N).
@@ -387,14 +513,18 @@ ichunk_step(_Log, More, N) when is_record(More, continuation) ->
ichunk_step(_Log, _, _) ->
{error, {badarg, continuation}}.
--spec chunk_info(More :: any()) ->
- [{'node', node()},...] | {'error', {'no_continuation', any()}}.
+-spec chunk_info(Continuation) -> InfoList | {error, Reason} when
+ Continuation :: continuation(),
+ InfoList :: [{node, Node :: node()}, ...],
+ Reason :: {no_continuation, Continuation}.
chunk_info(More = #continuation{}) ->
[{node, node(More#continuation.pid)}];
chunk_info(BadCont) ->
{error, {no_continuation, BadCont}}.
--spec accessible_logs() -> {[_], [_]}.
+-spec accessible_logs() -> {[LocalLog], [DistributedLog]} when
+ LocalLog :: log(),
+ DistributedLog :: log().
accessible_logs() ->
disk_log_server:accessible_logs().
diff --git a/lib/kernel/src/disk_log.hrl b/lib/kernel/src/disk_log.hrl
index b0849145ca..259967650f 100644
--- a/lib/kernel/src/disk_log.hrl
+++ b/lib/kernel/src/disk_log.hrl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-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%
%%
@@ -44,33 +44,43 @@
-define(OPENED, <<6,7,8,9>>).
-define(CLOSED, <<99,88,77,11>>).
-%% Needed for the definition of fd()
+%% Needed for the definition of #file_info{}
%% Must use include_lib() so that we always can be sure to find
%% file.hrl. A relative path will not work in an installed system.
-include_lib("kernel/include/file.hrl").
-%% Ugly workaround. If we are building the bootstrap compiler,
-%% file.hrl does not define the fd() type.
--ifndef(FILE_HRL_).
--type fd() :: pid() | #file_descriptor{}.
--endif.
-
%%------------------------------------------------------------------------
%% Types -- alphabetically
%%------------------------------------------------------------------------
+-type dlog_byte() :: [dlog_byte()] | byte().
-type dlog_format() :: 'external' | 'internal'.
-type dlog_format_type() :: 'halt_ext' | 'halt_int' | 'wrap_ext' | 'wrap_int'.
-type dlog_head() :: 'none' | {'ok', binary()} | mfa().
+-type dlog_head_opt() :: none | term() | binary() | [dlog_byte()].
+-type log() :: term(). % XXX: refine
-type dlog_mode() :: 'read_only' | 'read_write'.
-type dlog_name() :: atom() | string().
-type dlog_optattr() :: 'name' | 'file' | 'linkto' | 'repair' | 'type'
| 'format' | 'size' | 'distributed' | 'notify'
| 'head' | 'head_func' | 'mode'.
--type dlog_options() :: [{dlog_optattr(), any()}].
+-type dlog_option() :: {name, Log :: log()}
+ | {file, FileName :: file:filename()}
+ | {linkto, LinkTo :: none | pid()}
+ | {repair, Repair :: true | false | truncate}
+ | {type, Type :: dlog_type}
+ | {format, Format :: dlog_format()}
+ | {size, Size :: dlog_size()}
+ | {distributed, Nodes :: [node()]}
+ | {notify, boolean()}
+ | {head, Head :: dlog_head_opt()}
+ | {head_func, mfa()}
+ | {mode, Mode :: dlog_mode()}.
+-type dlog_options() :: [dlog_option()].
-type dlog_repair() :: 'truncate' | boolean().
-type dlog_size() :: 'infinity' | pos_integer()
- | {pos_integer(), pos_integer()}.
+ | {MaxNoBytes :: pos_integer(),
+ MaxNoFiles :: pos_integer()}.
-type dlog_status() :: 'ok' | {'blocked', 'false' | [_]}. %QueueLogRecords
-type dlog_type() :: 'halt' | 'wrap'.
@@ -81,7 +91,7 @@
%% record of args for open
-record(arg, {name = 0,
version = undefined,
- file = none :: 'none' | string(),
+ file = none :: 'none' | file:filename(),
repair = true :: dlog_repair(),
size = infinity :: dlog_size(),
type = halt :: dlog_type(),
@@ -94,7 +104,7 @@
options = [] :: dlog_options()}).
-record(cache, %% Cache for logged terms (per file descriptor).
- {fd :: fd(), %% File descriptor.
+ {fd :: file:fd(), %% File descriptor.
sz = 0 :: non_neg_integer(), %% Number of bytes in the cache.
c = [] :: iodata()} %% The cache.
).
diff --git a/lib/kernel/src/disk_log_1.erl b/lib/kernel/src/disk_log_1.erl
index 7103417149..266df84a03 100644
--- a/lib/kernel/src/disk_log_1.erl
+++ b/lib/kernel/src/disk_log_1.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-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(disk_log_1).
@@ -581,11 +581,13 @@ done_scan(In, Out, OutName, FName, RecoveredTerms, BadChars) ->
file:delete(OutName),
throw(Error)
end.
-
+
+-spec repair_err(file:io_device(), #cache{}, file:filename(),
+ file:filename(), {'error', file:posix()}) -> no_return().
repair_err(In, Out, OutName, ErrFileName, Error) ->
file:close(In),
catch fclose(Out, OutName),
- % OutName is often the culprit, try to remove it anyway...
+ %% OutName is often the culprit, try to remove it anyway...
file:delete(OutName),
file_error(ErrFileName, Error).
@@ -1529,7 +1531,7 @@ write_cache(Fd, FileName, C) ->
Error -> {catch file_error(FileName, Error), #cache{fd = Fd}}
end.
--spec write_cache_close(fd(), file:filename(), iodata()) -> #cache{}. % | throw(Error)
+-spec write_cache_close(file:fd(), file:filename(), iodata()) -> #cache{}. % | throw(Error)
write_cache_close(Fd, _FileName, []) ->
#cache{fd = Fd};
@@ -1539,12 +1541,12 @@ write_cache_close(Fd, FileName, C) ->
Error -> file_error_close(Fd, FileName, Error)
end.
--spec file_error(file:filename(), {'error', atom()}) -> no_return().
+-spec file_error(file:filename(), {'error', file:posix()}) -> no_return().
file_error(FileName, {error, Error}) ->
throw({error, {file_error, FileName, Error}}).
--spec file_error_close(fd(), file:filename(), {'error', atom()}) -> no_return().
+-spec file_error_close(file:fd(), file:filename(), {'error', file:posix()}) -> no_return().
file_error_close(Fd, FileName, {error, Error}) ->
file:close(Fd),
diff --git a/lib/kernel/src/dist_util.erl b/lib/kernel/src/dist_util.erl
index a2937d60b8..f0d54a2f3e 100644
--- a/lib/kernel/src/dist_util.erl
+++ b/lib/kernel/src/dist_util.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%%%----------------------------------------------------------------------
@@ -564,7 +564,7 @@ recv_challenge(#hs_data{socket=Socket,other_node=Node,
case Recv(Socket, 0, infinity) of
{ok,[$n,V1,V0,Fl1,Fl2,Fl3,Fl4,CA3,CA2,CA1,CA0 | Ns]} ->
Flags = ?u32(Fl1,Fl2,Fl3,Fl4),
- case {list_to_existing_atom(Ns),?u16(V1,V0)} of
+ try {list_to_existing_atom(Ns),?u16(V1,V0)} of
{Node,Version} ->
Challenge = ?u32(CA3,CA2,CA1,CA0),
?trace("recv: node=~w, challenge=~w version=~w\n",
@@ -572,6 +572,9 @@ recv_challenge(#hs_data{socket=Socket,other_node=Node,
{Flags,Challenge};
_ ->
?shutdown(no_node)
+ catch
+ error:badarg ->
+ ?shutdown(no_node)
end;
_ ->
?shutdown(no_node)
diff --git a/lib/kernel/src/erl_boot_server.erl b/lib/kernel/src/erl_boot_server.erl
index 702b2feac9..0d68d3e198 100644
--- a/lib/kernel/src/erl_boot_server.erl
+++ b/lib/kernel/src/erl_boot_server.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-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%
%%
%% A simple boot_server at a CP.
@@ -53,12 +53,17 @@
bootp :: pid(), %% boot process
prim_state %% state for efile code loader
}).
+-type state() :: #state{}.
-define(single_addr_mask, {255, 255, 255, 255}).
-type ip4_address() :: {0..255,0..255,0..255,0..255}.
--spec start(Slaves :: [atom()]) -> {'ok', pid()} | {'error', any()}.
+-spec start(Slaves) -> {'ok', Pid} | {'error', What} when
+ Slaves :: [Host],
+ Host :: atom(),
+ Pid :: pid(),
+ What :: any().
start(Slaves) ->
case check_arg(Slaves) of
@@ -68,7 +73,11 @@ start(Slaves) ->
{error, {badarg, Slaves}}
end.
--spec start_link(Slaves :: [atom()]) -> {'ok', pid()} | {'error', any()}.
+-spec start_link(Slaves) -> {'ok', Pid} | {'error', What} when
+ Slaves :: [Host],
+ Host :: atom(),
+ Pid :: pid(),
+ What :: any().
start_link(Slaves) ->
case check_arg(Slaves) of
@@ -94,7 +103,10 @@ check_arg([], Result) ->
check_arg(_, _Result) ->
error.
--spec add_slave(Slave :: atom()) -> 'ok' | {'error', any()}.
+-spec add_slave(Slave) -> 'ok' | {'error', What} when
+ Slave :: Host,
+ Host :: atom(),
+ What :: any().
add_slave(Slave) ->
case inet:getaddr(Slave, inet) of
@@ -104,7 +116,10 @@ add_slave(Slave) ->
{error, {badarg, Slave}}
end.
--spec delete_slave(Slave :: atom()) -> 'ok' | {'error', any()}.
+-spec delete_slave(Slave) -> 'ok' | {'error', What} when
+ Slave :: Host,
+ Host :: atom(),
+ What :: any().
delete_slave(Slave) ->
case inet:getaddr(Slave, inet) of
@@ -130,7 +145,9 @@ add_subnet(Mask, Addr) when is_tuple(Mask), is_tuple(Addr) ->
delete_subnet(Mask, Addr) when is_tuple(Mask), is_tuple(Addr) ->
gen_server:call(boot_server, {delete, {Mask, Addr}}).
--spec which_slaves() -> [atom()].
+-spec which_slaves() -> Slaves when
+ Slaves :: [Host],
+ Host :: atom().
which_slaves() ->
gen_server:call(boot_server, which).
@@ -165,6 +182,8 @@ member_address(_, []) ->
%% call-back functions.
%% ------------------------------------------------------------
+-spec init([atom()]) -> {'ok', state()}.
+
init(Slaves) ->
{ok, U} = gen_udp:open(?EBOOT_PORT, []),
{ok, L} = gen_tcp:listen(0, [binary,{packet,4}]),
@@ -176,15 +195,18 @@ init(Slaves) ->
Pid ! {Ref, L},
%% We trap exit inorder to restart boot_init and udp_port
process_flag(trap_exit, true),
- {ok, #state {priority = 0,
- version = erlang:system_info(version),
- udp_sock = U,
- udp_port = UPort,
- listen_sock = L,
- listen_port = Port,
- slaves = ordsets:from_list(Slaves),
- bootp = Pid
- }}.
+ {ok, #state{priority = 0,
+ version = erlang:system_info(version),
+ udp_sock = U,
+ udp_port = UPort,
+ listen_sock = L,
+ listen_port = Port,
+ slaves = ordsets:from_list(Slaves),
+ bootp = Pid
+ }}.
+
+-spec handle_call('which' | {'add',atom()} | {'delete',atom()}, _, state()) ->
+ {'reply', 'ok' | [atom()], state()}.
handle_call({add,Address}, _, S0) ->
Slaves = ordsets:add_element(Address, S0#state.slaves),
@@ -197,9 +219,13 @@ handle_call({delete,Address}, _, S0) ->
handle_call(which, _, S0) ->
{reply, ordsets:to_list(S0#state.slaves), S0}.
+-spec handle_cast(term(), [atom()]) -> {'noreply', [atom()]}.
+
handle_cast(_, Slaves) ->
{noreply, Slaves}.
+-spec handle_info(term(), state()) -> {'noreply', state()}.
+
handle_info({udp, U, IP, Port, Data}, S0) ->
Token = ?EBOOT_REQUEST ++ S0#state.version,
Valid = member_address(IP, ordsets:to_list(S0#state.slaves)),
@@ -230,9 +256,13 @@ handle_info({udp, U, IP, Port, Data}, S0) ->
handle_info(_Info, S0) ->
{noreply,S0}.
+-spec terminate(term(), state()) -> 'ok'.
+
terminate(_Reason, _S0) ->
ok.
+-spec code_change(term(), state(), term()) -> {'ok', state()}.
+
code_change(_Vsn, State, _Extra) ->
{ok, State}.
@@ -242,6 +272,8 @@ code_change(_Vsn, State, _Extra) ->
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-spec boot_init(reference()) -> no_return().
+
boot_init(Tag) ->
receive
{Tag, Listen} ->
diff --git a/lib/kernel/src/erl_ddll.erl b/lib/kernel/src/erl_ddll.erl
index 88f91de24f..646cac99c5 100644
--- a/lib/kernel/src/erl_ddll.erl
+++ b/lib/kernel/src/erl_ddll.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-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%
%%
%% Dynamic Driver Loader and Linker
@@ -29,6 +29,11 @@
%%----------------------------------------------------------------------------
+-type path() :: string() | atom().
+-type driver() :: string() | atom().
+
+%%----------------------------------------------------------------------------
+
-spec start() -> {'error', {'already_started', 'undefined'}}.
start() ->
@@ -39,14 +44,18 @@ start() ->
stop() ->
ok.
--spec load_driver(Path :: string() | atom(), Driver :: string() | atom()) ->
- 'ok' | {'error', any()}.
+-spec load_driver(Path, Name) -> 'ok' | {'error', ErrorDesc} when
+ Path :: path(),
+ Name :: driver(),
+ ErrorDesc :: term().
load_driver(Path, Driver) ->
do_load_driver(Path, Driver, [{driver_options,[kill_ports]}]).
--spec load(Path :: string() | atom(), Driver :: string() | atom()) ->
- 'ok' | {'error', any()}.
+-spec load(Path, Name) -> 'ok' | {'error', ErrorDesc} when
+ Path :: path(),
+ Name :: driver(),
+ ErrorDesc ::term().
load(Path, Driver) ->
do_load_driver(Path, Driver, []).
@@ -95,42 +104,56 @@ do_unload_driver(Driver,Flags) ->
end
end.
--spec unload_driver(Driver :: string() | atom()) -> 'ok' | {'error', any()}.
+-spec unload_driver(Name) -> 'ok' | {'error', ErrorDesc} when
+ Name :: driver(),
+ ErrorDesc :: term().
unload_driver(Driver) ->
do_unload_driver(Driver,[{monitor,pending_driver},kill_ports]).
--spec unload(Driver :: string() | atom()) -> 'ok' | {'error', any()}.
+-spec unload(Name) -> 'ok' | {'error', ErrorDesc} when
+ Name :: driver(),
+ ErrorDesc :: term().
unload(Driver) ->
do_unload_driver(Driver,[]).
--spec reload(Path :: string() | atom(), Driver :: string() | atom()) ->
- 'ok' | {'error', any()}.
+-spec reload(Path, Name) -> 'ok' | {'error', ErrorDesc} when
+ Path :: path(),
+ Name :: driver(),
+ ErrorDesc :: pending_process | OpaqueError,
+ OpaqueError :: term().
reload(Path,Driver) ->
do_load_driver(Path, Driver, [{reload,pending_driver}]).
--spec reload_driver(Path :: string() | atom(), Driver :: string() | atom()) ->
- 'ok' | {'error', any()}.
+-spec reload_driver(Path, Name) -> 'ok' | {'error', ErrorDesc} when
+ Path :: path(),
+ Name :: driver(),
+ ErrorDesc :: pending_process | OpaqueError,
+ OpaqueError :: term().
reload_driver(Path,Driver) ->
do_load_driver(Path, Driver, [{reload,pending_driver},
{driver_options,[kill_ports]}]).
--spec format_error(Code :: atom()) -> string().
+-spec format_error(ErrorDesc) -> string() when
+ ErrorDesc :: term().
format_error(Code) ->
case Code of
- % This is the only error code returned only from erlang code...
- % 'permanent' has a translation in the emulator, even though the erlang code uses it to...
+ %% This is the only error code returned only from erlang code...
+ %% 'permanent' has a translation in the emulator, even though the erlang code uses it to...
load_cancelled ->
"Loading was cancelled from other process";
_ ->
erl_ddll:format_error_int(Code)
end.
--spec info(Driver :: string() | atom()) -> [{atom(), any()}].
+-spec info(Name) -> InfoList when
+ Name :: driver(),
+ InfoList :: [InfoItem, ...],
+ InfoItem :: {Tag :: atom(), Value :: term()}.
info(Driver) ->
[{processes, erl_ddll:info(Driver,processes)},
@@ -141,7 +164,12 @@ info(Driver) ->
{awaiting_load, erl_ddll:info(Driver,awaiting_load)},
{awaiting_unload, erl_ddll:info(Driver,awaiting_unload)}].
--spec info() -> [{string(), [{atom(), any()}]}].
+-spec info() -> AllInfoList when
+ AllInfoList :: [DriverInfo],
+ DriverInfo :: {DriverName, InfoList},
+ DriverName :: string(),
+ InfoList :: [InfoItem],
+ InfoItem :: {Tag :: atom(), Value :: term()}.
info() ->
{ok,DriverList} = erl_ddll:loaded_drivers(),
diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
index e4b371836b..91af49f303 100644
--- a/lib/kernel/src/erl_epmd.erl
+++ b/lib/kernel/src/erl_epmd.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1998-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(erl_epmd).
@@ -40,6 +40,7 @@
-import(lists, [reverse/1]).
-record(state, {socket, port_no = -1, name = ""}).
+-type state() :: #state{}.
-include("inet_int.hrl").
-include("erl_epmd.hrl").
@@ -111,11 +112,18 @@ register_node(Name, PortNo) ->
%%% Callback functions from gen_server
%%%----------------------------------------------------------------------
+-spec init(_) -> {'ok', state()}.
+
init(_) ->
{ok, #state{socket = -1}}.
%%----------------------------------------------------------------------
+-type calls() :: 'client_info_req' | 'stop' | {'register', term(), term()}.
+
+-spec handle_call(calls(), term(), state()) ->
+ {'reply', term(), state()} | {'stop', 'shutdown', 'ok', state()}.
+
handle_call({register, Name, PortNo}, _From, State) ->
case State#state.socket of
P when P < 0 ->
@@ -133,19 +141,23 @@ handle_call({register, Name, PortNo}, _From, State) ->
end;
handle_call(client_info_req, _From, State) ->
- Reply = {ok,{r4,State#state.name,State#state.port_no}},
- {reply,Reply,State};
+ Reply = {ok,{r4,State#state.name,State#state.port_no}},
+ {reply, Reply, State};
handle_call(stop, _From, State) ->
{stop, shutdown, ok, State}.
%%----------------------------------------------------------------------
+-spec handle_cast(term(), state()) -> {'noreply', state()}.
+
handle_cast(_, State) ->
{noreply, State}.
%%----------------------------------------------------------------------
+-spec handle_info(term(), state()) -> {'noreply', state()}.
+
handle_info({tcp_closed, Socket}, State) when State#state.socket =:= Socket ->
{noreply, State#state{socket = -1}};
handle_info(_, State) ->
@@ -153,6 +165,8 @@ handle_info(_, State) ->
%%----------------------------------------------------------------------
+-spec terminate(term(), state()) -> 'ok'.
+
terminate(_, #state{socket = Socket}) when Socket > 0 ->
close(Socket),
ok;
@@ -161,6 +175,8 @@ terminate(_, _) ->
%%----------------------------------------------------------------------
+-spec code_change(term(), state(), term()) -> {'ok', state()}.
+
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
@@ -194,19 +210,6 @@ open({A,B,C,D,E,F,G,H}=EpmdAddr, Timeout) when ?ip6(A,B,C,D,E,F,G,H) ->
close(Socket) ->
gen_tcp:close(Socket).
-
-do_register_node_v0(NodeName, TcpPort) ->
- case open() of
- {ok, Socket} ->
- Name = cstring(NodeName),
- Len = 1+2+length(Name),
- gen_tcp:send(Socket, [?int16(Len), ?EPMD_ALIVE,
- ?int16(TcpPort), Name]),
- wait_for_reg_reply_v0(Socket, []);
- Error ->
- Error
- end.
-
do_register_node(NodeName, TcpPort) ->
case open() of
{ok, Socket} ->
@@ -224,14 +227,7 @@ do_register_node(NodeName, TcpPort) ->
Name,
?int16(Elen),
Extra]),
- case wait_for_reg_reply(Socket, []) of
- {error, epmd_close} ->
- %% could be old epmd; try old protocol
-% erlang:display('trying old'),
- do_register_node_v0(NodeName, TcpPort);
- Other ->
- Other
- end;
+ wait_for_reg_reply(Socket, []);
Error ->
Error
end.
@@ -289,41 +285,9 @@ wait_for_reg_reply(Socket, SoFar) ->
{error, no_reg_reply_from_epmd}
end.
-wait_for_reg_reply_v0(Socket, SoFar) ->
- receive
- {tcp, Socket, Data0} ->
- case SoFar ++ Data0 of
- [$Y, A, B] ->
- {alive, Socket, ?u16(A, B)};
- Data when length(Data) < 3 ->
- wait_for_reg_reply(Socket, Data);
- Garbage ->
- {error, {garbage_from_epmd, Garbage}}
- end;
- {tcp_closed, Socket} ->
- {error, duplicate_name} % A guess -- the most likely reason.
- after 10000 ->
- gen_tcp:close(Socket),
- {error, no_reg_reply_from_epmd}
- end.
%%
%% Lookup a node "Name" at Host
%%
-get_port_v0(Node, EpmdAddress) ->
- case open(EpmdAddress) of
- {ok, Socket} ->
- Name = cstring(Node),
- Len = 1+length(Name),
- gen_tcp:send(Socket, [?int16(Len),?EPMD_PORT_PLEASE, Name]),
- wait_for_port_reply_v0(Socket, []);
- _Error ->
- ?port_please_failure(),
- noport
- end.
-
-%%% Not used anymore
-%%% get_port(Node, EpmdAddress) ->
-%%% get_port(Node, EpmdAddress, infinity).
get_port(Node, EpmdAddress, Timeout) ->
case open(EpmdAddress, Timeout) of
@@ -331,40 +295,12 @@ get_port(Node, EpmdAddress, Timeout) ->
Name = to_string(Node),
Len = 1+length(Name),
gen_tcp:send(Socket, [?int16(Len),?EPMD_PORT_PLEASE2_REQ, Name]),
- Reply = wait_for_port_reply(Socket, []),
- case Reply of
- closed ->
- get_port_v0(Node, EpmdAddress);
- Other ->
- Other
- end;
+ wait_for_port_reply(Socket, []);
_Error ->
?port_please_failure2(_Error),
noport
end.
-wait_for_port_reply_v0(Socket, SoFar) ->
- receive
- {tcp, Socket, Data0} ->
-% io:format("got ~p~n", [Data0]),
- case SoFar ++ Data0 of
- [A, B] ->
- wait_for_close(Socket, {port, ?u16(A, B), 0});
-% wait_for_close(Socket, {port, ?u16(A, B)});
- Data when length(Data) < 2 ->
- wait_for_port_reply_v0(Socket, Data);
- Garbage ->
- ?port_please_failure(),
- {error, {garbage_from_epmd, Garbage}}
- end;
- {tcp_closed, Socket} ->
- ?port_please_failure(),
- noport
- after 10000 ->
- ?port_please_failure(),
- gen_tcp:close(Socket),
- noport
- end.
wait_for_port_reply(Socket, SoFar) ->
receive
@@ -471,8 +407,6 @@ wait_for_close(Socket, Reply) ->
%%
%% Creates a (flat) null terminated string from atom or list.
%%
-cstring(S) when is_atom(S) -> cstring(atom_to_list(S));
-cstring(S) when is_list(S) -> S ++ [0].
to_string(S) when is_atom(S) -> atom_to_list(S);
to_string(S) when is_list(S) -> S.
diff --git a/lib/kernel/src/erl_epmd.hrl b/lib/kernel/src/erl_epmd.hrl
index 47ab6195d8..5a50fda508 100644
--- a/lib/kernel/src/erl_epmd.hrl
+++ b/lib/kernel/src/erl_epmd.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2010. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -17,16 +17,13 @@
%% %CopyrightEnd%
%%
--define(EPMD_ALIVE, $a).
--define(EPMD_PORT_PLEASE, $p).
--define(EPMD_NAMES, $n).
--define(EPMD_DUMP, $d).
--define(EPMD_KILL, $k).
--define(EPMD_STOP, $s).
-
--define(EPMD_ALIVE_OK, $Y).
-
-define(EPMD_ALIVE2_REQ, $x).
-define(EPMD_PORT_PLEASE2_REQ, $z).
-define(EPMD_ALIVE2_RESP, $y).
-define(EPMD_PORT2_RESP, $w).
+-define(EPMD_NAMES, $n).
+
+%% Commands used only by interactive client
+-define(EPMD_DUMP, $d).
+-define(EPMD_KILL, $k).
+-define(EPMD_STOP, $s).
diff --git a/lib/kernel/src/error_handler.erl b/lib/kernel/src/error_handler.erl
index 5f2507fc08..e1f99bf417 100644
--- a/lib/kernel/src/error_handler.erl
+++ b/lib/kernel/src/error_handler.erl
@@ -1,30 +1,38 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-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(error_handler).
+%% FIXME: remove no_native directive after HiPE has been changed to make
+%% remote calls link to the target's Export* like BEAM does.
+%% For a detailed explanation see the commit titled
+%% "error_handler: add no_native compiler directive"
+-compile(no_native).
%% A simple error handler.
-export([undefined_function/3, undefined_lambda/3, stub_function/3,
breakpoint/3]).
--spec undefined_function(Module :: atom(), Function :: atom(), Args :: [_]) ->
- any().
+-spec undefined_function(Module, Function, Args) ->
+ any() when
+ Module :: atom(),
+ Function :: atom(),
+ Args :: list().
undefined_function(Module, Func, Args) ->
case ensure_loaded(Module) of
@@ -46,8 +54,10 @@ undefined_function(Module, Func, Args) ->
crash(Module, Func, Args)
end.
--spec undefined_lambda(Module :: atom(), Function :: fun(), Args :: [_]) ->
- any().
+-spec undefined_lambda(Module, Fun, Args) -> term() when
+ Module :: atom(),
+ Fun :: fun(),
+ Args :: list().
undefined_lambda(Module, Fun, Args) ->
case ensure_loaded(Module) of
@@ -75,9 +85,13 @@ int() -> int.
%%
%% Crash providing a beautiful stack backtrace.
%%
+-spec crash(atom(), [term()]) -> no_return().
+
crash(Fun, Args) ->
crash({Fun,Args}).
+-spec crash(atom(), atom(), arity()) -> no_return().
+
crash(M, F, A) ->
crash({M,F,A}).
@@ -117,13 +131,13 @@ stub_function(Mod, Func, Args) ->
check_inheritance(Module, Args) ->
Attrs = erlang:get_module_info(Module, attributes),
- case lists:keysearch(extends, 1, Attrs) of
- {value,{extends,[Base]}} when is_atom(Base), Base =/= Module ->
+ case lists:keyfind(extends, 1, Attrs) of
+ {extends, [Base]} when is_atom(Base), Base =/= Module ->
%% This is just a heuristic for detecting abstract modules
%% with inheritance so they can be handled; it would be
%% much better to do it in the emulator runtime
- case lists:keysearch(abstract, 1, Attrs) of
- {value,{abstract,[true]}} ->
+ case lists:keyfind(abstract, 1, Attrs) of
+ {abstract, [true]} ->
case lists:reverse(Args) of
[M|Rs] when tuple_size(M) > 1,
element(1,M) =:= Module,
diff --git a/lib/kernel/src/error_logger.erl b/lib/kernel/src/error_logger.erl
index cafdc52e84..f94cca000f 100644
--- a/lib/kernel/src/error_logger.erl
+++ b/lib/kernel/src/error_logger.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-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
@@ -69,17 +69,22 @@ start_link() ->
%% Used for simple messages; error or information.
%%-----------------------------------------------------------------
--spec error_msg(Format :: string()) -> 'ok'.
+-spec error_msg(Format) -> 'ok' when
+ Format :: string().
error_msg(Format) ->
error_msg(Format,[]).
--spec error_msg(Format :: string(), Args :: list()) -> 'ok'.
+-spec error_msg(Format, Data) -> 'ok' when
+ Format :: string(),
+ Data :: list().
error_msg(Format, Args) ->
notify({error, group_leader(), {self(), Format, Args}}).
--spec format(Format :: string(), Args :: list()) -> 'ok'.
+-spec format(Format, Data) -> 'ok' when
+ Format :: string(),
+ Data :: list().
format(Format, Args) ->
notify({error, group_leader(), {self(), Format, Args}}).
@@ -90,12 +95,18 @@ format(Format, Args) ->
%% The 'std_error' error_report type can always be used.
%%-----------------------------------------------------------------
--spec error_report(Report :: any()) -> 'ok'.
+-type report() ::
+ [{Tag :: term(), Data :: term()} | term()] | string() | term().
+
+-spec error_report(Report) -> 'ok' when
+ Report :: report().
error_report(Report) ->
error_report(std_error, Report).
--spec error_report(Type :: any(), Report :: any()) -> 'ok'.
+-spec error_report(Type, Report) -> 'ok' when
+ Type :: term(),
+ Report :: report().
error_report(Type, Report) ->
notify({error_report, group_leader(), {self(), Type, Report}}).
@@ -109,12 +120,15 @@ error_report(Type, Report) ->
%% mapped to std_info or std_error accordingly.
%%-----------------------------------------------------------------
--spec warning_report(Report :: any()) -> 'ok'.
+-spec warning_report(Report) -> 'ok' when
+ Report :: report().
warning_report(Report) ->
warning_report(std_warning, Report).
--spec warning_report(Type :: any(), Report :: any()) -> 'ok'.
+-spec warning_report(Type, Report) -> 'ok' when
+ Type :: any(),
+ Report :: report().
warning_report(Type, Report) ->
{Tag, NType} = case error_logger:warning_map() of
@@ -143,12 +157,15 @@ warning_report(Type, Report) ->
%% other types of reports.
%%-----------------------------------------------------------------
--spec warning_msg(Format :: string()) -> 'ok'.
+-spec warning_msg(Format) -> 'ok' when
+ Format :: string().
warning_msg(Format) ->
warning_msg(Format,[]).
--spec warning_msg(Format :: string(), Args :: list()) -> 'ok'.
+-spec warning_msg(Format, Data) -> 'ok' when
+ Format :: string(),
+ Data :: list().
warning_msg(Format, Args) ->
Tag = case error_logger:warning_map() of
@@ -167,12 +184,15 @@ warning_msg(Format, Args) ->
%% The 'std_info' info_report type can always be used.
%%-----------------------------------------------------------------
--spec info_report(Report :: any()) -> 'ok'.
+-spec info_report(Report) -> 'ok' when
+ Report :: report().
info_report(Report) ->
info_report(std_info, Report).
--spec info_report(Type :: any(), Report :: any()) -> 'ok'.
+-spec info_report(Type, Report) -> 'ok' when
+ Type :: any(),
+ Report :: report().
info_report(Type, Report) ->
notify({info_report, group_leader(), {self(), Type, Report}}).
@@ -182,12 +202,15 @@ info_report(Type, Report) ->
%% information messages.
%%-----------------------------------------------------------------
--spec info_msg(Format :: string()) -> 'ok'.
+-spec info_msg(Format) -> 'ok' when
+ Format :: string().
info_msg(Format) ->
info_msg(Format,[]).
--spec info_msg(Format :: string(), Args :: list()) -> 'ok'.
+-spec info_msg(Format, Data) -> 'ok' when
+ Format :: string(),
+ Data :: list().
info_msg(Format, Args) ->
notify({info_msg, group_leader(), {self(), Format, Args}}).
@@ -223,17 +246,23 @@ swap_handler(silent) ->
swap_handler(false) ->
ok. % keep primitive event handler as-is
--spec add_report_handler(Module :: atom()) -> any().
+-spec add_report_handler(Handler) -> any() when
+ Handler :: module().
add_report_handler(Module) when is_atom(Module) ->
gen_event:add_handler(error_logger, Module, []).
--spec add_report_handler(atom(), any()) -> any().
+-spec add_report_handler(Handler, Args) -> Result when
+ Handler :: module(),
+ Args :: gen_event:handler_args(),
+ Result :: gen_event:add_handler_ret().
add_report_handler(Module, Args) when is_atom(Module) ->
gen_event:add_handler(error_logger, Module, Args).
--spec delete_report_handler(Module :: atom()) -> any().
+-spec delete_report_handler(Handler) -> Result when
+ Handler :: module(),
+ Result :: gen_event:del_handler_ret().
delete_report_handler(Module) when is_atom(Module) ->
gen_event:delete_handler(error_logger, Module, []).
@@ -250,9 +279,16 @@ simple_logger() ->
%% Log all errors to File for all eternity
--spec logfile(Request :: {'open', string()}) -> 'ok' | {'error',any()}
- ; (Request :: 'close') -> 'ok' | {'error', any()}
- ; (Request :: 'filename') -> atom() | string() | {'error', any()}.
+-type open_error() :: file:posix() | badarg | system_limit.
+
+-spec logfile(Request :: {open, Filename}) -> ok | {error, OpenReason} when
+ Filename ::file:name(),
+ OpenReason :: allready_have_logfile | open_error()
+ ; (Request :: close) -> ok | {error, CloseReason} when
+ CloseReason :: module_not_found
+ ; (Request :: filename) -> Filename | {error, FilenameReason} when
+ Filename :: file:name(),
+ FilenameReason :: no_log_file.
logfile({open, File}) ->
case lists:member(error_logger_file_h,
@@ -280,7 +316,8 @@ logfile(filename) ->
%% Possibly turn off all tty printouts, maybe we only want the errors
%% to go to a file
--spec tty(Flag :: boolean()) -> 'ok'.
+-spec tty(Flag) -> 'ok' when
+ Flag :: boolean().
tty(true) ->
Hs = gen_event:which_handlers(error_logger),
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index a42771dfb6..5e4e1b0ba8 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-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
@@ -36,11 +36,11 @@
%% Specialized
-export([ipread_s32bu_p32bu/3]).
%% Generic file contents.
--export([open/2, close/1,
+-export([open/2, close/1, advise/4,
read/2, write/2,
pread/2, pread/3, pwrite/2, pwrite/3,
read_line/1,
- position/2, truncate/1, sync/1,
+ position/2, truncate/1, datasync/1, sync/1,
copy/2, copy/3]).
%% High level operations
-export([consult/1, path_consult/2]).
@@ -61,6 +61,9 @@
-export([ipread_s32bu_p32bu_int/3]).
+%% Types that can be used from other modules -- alphabetically ordered.
+-export_type([date_time/0, fd/0, file_info/0, filename/0, io_device/0,
+ name/0, posix/0]).
%%% Includes and defines
-include("file.hrl").
@@ -72,22 +75,42 @@
-define(RAM_FILE, ram_file). % Module
%% data types
--type filename() :: string().
+-type filename() :: string() | binary().
-type file_info() :: #file_info{}.
--type io_device() :: pid() | #file_descriptor{}.
--type location() :: integer() | {'bof', integer()} | {'cur', integer()}
- | {'eof', integer()} | 'bof' | 'cur' | 'eof'.
--type mode() :: 'read' | 'write' | 'append' | 'raw' | 'binary' |
- {'delayed_write', non_neg_integer(), non_neg_integer()} |
- 'delayed_write' | {'read_ahead', pos_integer()} |
- 'read_ahead' | 'compressed'.
--type bindings() :: any().
+-type fd() :: #file_descriptor{}.
+-type io_device() :: pid() | fd().
+-type location() :: integer() | {'bof', Offset :: integer()}
+ | {'cur', Offset :: integer()}
+ | {'eof', Offset :: integer()} | 'bof' | 'cur' | 'eof'.
+-type mode() :: 'read' | 'write' | 'append'
+ | 'exclusive' | 'raw' | 'binary'
+ | {'delayed_write',
+ Size :: non_neg_integer(),
+ Delay :: non_neg_integer()}
+ | 'delayed_write' | {'read_ahead', Size :: pos_integer()}
+ | 'read_ahead' | 'compressed'
+ | {'encoding', unicode:encoding()}.
+-type deep_list() :: [char() | atom() | deep_list()].
+-type name() :: string() | atom() | deep_list() | (RawFilename :: binary()).
+-type posix() :: 'eacces' | 'eagain' | 'ebadf' | 'ebusy' | 'edquot'
+ | 'eexist' | 'efault' | 'efbig' | 'eintr' | 'einval'
+ | 'eio' | 'eisdir' | 'eloop' | 'emfile' | 'emlink'
+ | 'enametoolong'
+ | 'enfile' | 'enodev' | 'enoent' | 'enomem' | 'enospc'
+ | 'enotblk' | 'enotdir' | 'enotsup' | 'enxio' | 'eperm'
+ | 'epipe' | 'erofs' | 'espipe' | 'esrch' | 'estale'
+ | 'exdev'.
+-type date_time() :: calendar:datetime().
+-type posix_file_advise() :: 'normal' | 'sequential' | 'random'
+ | 'no_reuse' | 'will_need' | 'dont_need'.
%%%-----------------------------------------------------------------
%%% General functions
--spec format_error(Reason :: posix() | {integer(), atom(), any()}) ->
- string().
+-spec format_error(Reason) -> Chars when
+ Reason :: posix() | badarg | terminated | system_limit
+ | {Line :: integer(), Mod :: module(), Term :: term()},
+ Chars :: string().
format_error({_Line, ?MODULE, undefined_script}) ->
"no value returned from script";
@@ -108,7 +131,9 @@ format_error(terminated) ->
format_error(ErrorId) ->
erl_posix_msg:message(ErrorId).
--spec pid2name(Pid :: pid()) -> {'ok', filename()} | 'undefined'.
+-spec pid2name(Pid) -> {ok, Filename} | undefined when
+ Filename :: filename(),
+ Pid :: pid().
pid2name(Pid) when is_pid(Pid) ->
case whereis(?FILE_SERVER) of
@@ -127,42 +152,61 @@ pid2name(Pid) when is_pid(Pid) ->
%%% File server functions.
%%% Functions that do not operate on a single open file.
%%% Stateless.
--spec get_cwd() -> {'ok', filename()} | {'error', posix()}.
+-spec get_cwd() -> {ok, Dir} | {error, Reason} when
+ Dir :: filename(),
+ Reason :: posix().
get_cwd() ->
call(get_cwd, []).
--spec get_cwd(Drive :: string()) -> {'ok', filename()} | {'error', posix()}.
+-spec get_cwd(Drive) -> {ok, Dir} | {error, Reason} when
+ Drive :: string(),
+ Dir :: filename(),
+ Reason :: posix() | badarg.
get_cwd(Drive) ->
check_and_call(get_cwd, [file_name(Drive)]).
--spec set_cwd(Dirname :: name()) -> 'ok' | {'error', posix()}.
+-spec set_cwd(Dir) -> ok | {error, Reason} when
+ Dir :: name(),
+ Reason :: posix() | badarg.
set_cwd(Dirname) ->
check_and_call(set_cwd, [file_name(Dirname)]).
--spec delete(Name :: name()) -> 'ok' | {'error', posix()}.
+-spec delete(Filename) -> ok | {error, Reason} when
+ Filename :: name(),
+ Reason :: posix() | badarg.
delete(Name) ->
check_and_call(delete, [file_name(Name)]).
--spec rename(From :: name(), To :: name()) -> 'ok' | {'error', posix()}.
+-spec rename(Source, Destination) -> ok | {error, Reason} when
+ Source :: name(),
+ Destination :: name(),
+ Reason :: posix() | badarg.
rename(From, To) ->
check_and_call(rename, [file_name(From), file_name(To)]).
--spec make_dir(Name :: name()) -> 'ok' | {'error', posix()}.
+-spec make_dir(Dir) -> ok | {error, Reason} when
+ Dir :: name(),
+ Reason :: posix() | badarg.
make_dir(Name) ->
check_and_call(make_dir, [file_name(Name)]).
--spec del_dir(Name :: name()) -> 'ok' | {'error', posix()}.
+-spec del_dir(Dir) -> ok | {error, Reason} when
+ Dir :: name(),
+ Reason :: posix() | badarg.
del_dir(Name) ->
check_and_call(del_dir, [file_name(Name)]).
--spec read_file_info(Name :: name()) -> {'ok', #file_info{}} | {'error', posix()}.
+-spec read_file_info(Filename) -> {ok, FileInfo} | {error, Reason} when
+ Filename :: name(),
+ FileInfo :: file_info(),
+ Reason :: posix() | badarg.
read_file_info(Name) ->
check_and_call(read_file_info, [file_name(Name)]).
@@ -172,54 +216,79 @@ read_file_info(Name) ->
altname(Name) ->
check_and_call(altname, [file_name(Name)]).
--spec read_link_info(Name :: name()) -> {'ok', #file_info{}} | {'error', posix()}.
+-spec read_link_info(Name) -> {ok, FileInfo} | {error, Reason} when
+ Name :: name(),
+ FileInfo :: file_info(),
+ Reason :: posix() | badarg.
read_link_info(Name) ->
check_and_call(read_link_info, [file_name(Name)]).
--spec read_link(Name :: name()) -> {'ok', filename()} | {'error', posix()}.
+-spec read_link(Name) -> {ok, Filename} | {error, Reason} when
+ Name :: name(),
+ Filename :: filename(),
+ Reason :: posix() | badarg.
read_link(Name) ->
check_and_call(read_link, [file_name(Name)]).
--spec write_file_info(Name :: name(), Info :: #file_info{}) ->
- 'ok' | {'error', posix()}.
+-spec write_file_info(Filename, FileInfo) -> ok | {error, Reason} when
+ Filename :: name(),
+ FileInfo :: file_info(),
+ Reason :: posix() | badarg.
write_file_info(Name, Info = #file_info{}) ->
check_and_call(write_file_info, [file_name(Name), Info]).
--spec list_dir(Name :: name()) -> {'ok', [filename()]} | {'error', posix()}.
+-spec list_dir(Dir) -> {ok, Filenames} | {error, Reason} when
+ Dir :: name(),
+ Filenames :: [filename()],
+ Reason :: posix() | badarg.
list_dir(Name) ->
check_and_call(list_dir, [file_name(Name)]).
--spec read_file(Name :: name()) -> {'ok', binary()} | {'error', posix()}.
+-spec read_file(Filename) -> {ok, Binary} | {error, Reason} when
+ Filename :: name(),
+ Binary :: binary(),
+ Reason :: posix() | badarg | terminated | system_limit.
read_file(Name) ->
check_and_call(read_file, [file_name(Name)]).
--spec make_link(Old :: name(), New :: name()) -> 'ok' | {'error', posix()}.
+-spec make_link(Existing, New) -> ok | {error, Reason} when
+ Existing :: name(),
+ New :: name(),
+ Reason :: posix() | badarg.
make_link(Old, New) ->
check_and_call(make_link, [file_name(Old), file_name(New)]).
--spec make_symlink(Old :: name(), New :: name()) -> 'ok' | {'error', posix()}.
+-spec make_symlink(Name1, Name2) -> ok | {error, Reason} when
+ Name1 :: name(),
+ Name2 :: name(),
+ Reason :: posix() | badarg.
make_symlink(Old, New) ->
check_and_call(make_symlink, [file_name(Old), file_name(New)]).
--spec write_file(Name :: name(), Bin :: binary()) -> 'ok' | {'error', posix()}.
+-spec write_file(Filename, Bytes) -> ok | {error, Reason} when
+ Filename :: name(),
+ Bytes :: iodata(),
+ Reason :: posix() | badarg | terminated | system_limit.
write_file(Name, Bin) ->
check_and_call(write_file, [file_name(Name), make_binary(Bin)]).
%% This whole operation should be moved to the file_server and prim_file
%% when it is time to change file server protocol again.
-%% Meanwhile, it is implemented here, slihtly less efficient.
-%%
+%% Meanwhile, it is implemented here, slightly less efficient.
--spec write_file(Name :: name(), Bin :: binary(), Modes :: [mode()]) ->
- 'ok' | {'error', posix()}.
+-spec write_file(Filename, Bytes, Modes) -> ok | {error, Reason} when
+ Filename :: name(),
+ Bytes :: iodata(),
+ Modes :: [mode()],
+ Reason :: posix() | badarg | terminated | system_limit.
write_file(Name, Bin, ModeList) when is_list(ModeList) ->
case make_binary(Bin) of
@@ -273,8 +342,11 @@ raw_write_file_info(Name, #file_info{} = Info) ->
%% Contemporary mode specification - list of options
--spec open(Name :: name(), Modes :: [mode()]) ->
- {'ok', io_device()} | {'error', posix()}.
+-spec open(Filename, Modes) -> {ok, IoDevice} | {error, Reason} when
+ Filename :: name(),
+ Modes :: [mode()],
+ IoDevice :: io_device(),
+ Reason :: posix() | badarg | system_limit.
open(Item, ModeList) when is_list(ModeList) ->
case lists:member(raw, ModeList) of
@@ -327,7 +399,9 @@ open(Item, Mode) ->
%%% The File argument must be either a Pid or a handle
%%% returned from ?PRIM_FILE:open.
--spec close(File :: io_device()) -> 'ok' | {'error', posix()}.
+-spec close(IoDevice) -> ok | {error, Reason} when
+ IoDevice :: io_device(),
+ Reason :: posix() | badarg | terminated.
close(File) when is_pid(File) ->
R = file_request(File, close),
@@ -345,10 +419,28 @@ close(#file_descriptor{module = Module} = Handle) ->
close(_) ->
{error, badarg}.
--spec read(File :: io_device(), Size :: non_neg_integer()) ->
- 'eof' | {'ok', [char()] | binary()} | {'error', posix()}.
+-spec advise(IoDevice, Offset, Length, Advise) -> ok | {error, Reason} when
+ IoDevice :: io_device(),
+ Offset :: integer(),
+ Length :: integer(),
+ Advise :: posix_file_advise(),
+ Reason :: posix() | badarg.
+
+advise(File, Offset, Length, Advise) when is_pid(File) ->
+ R = file_request(File, {advise, Offset, Length, Advise}),
+ wait_file_reply(File, R);
+advise(#file_descriptor{module = Module} = Handle, Offset, Length, Advise) ->
+ Module:advise(Handle, Offset, Length, Advise);
+advise(_, _, _, _) ->
+ {error, badarg}.
+
+-spec read(IoDevice, Number) -> {ok, Data} | eof | {error, Reason} when
+ IoDevice :: io_device() | atom(),
+ Number :: non_neg_integer(),
+ Data :: string() | binary(),
+ Reason :: posix() | badarg | terminated.
-read(File, Sz) when is_pid(File), is_integer(Sz), Sz >= 0 ->
+read(File, Sz) when (is_pid(File) orelse is_atom(File)), is_integer(Sz), Sz >= 0 ->
case io:request(File, {get_chars, '', Sz}) of
Data when is_list(Data); is_binary(Data) ->
{ok, Data};
@@ -361,10 +453,12 @@ read(#file_descriptor{module = Module} = Handle, Sz)
read(_, _) ->
{error, badarg}.
--spec read_line(File :: io_device()) ->
- 'eof' | {'ok', [char()] | binary()} | {'error', posix()}.
+-spec read_line(IoDevice) -> {ok, Data} | eof | {error, Reason} when
+ IoDevice :: io_device() | atom(),
+ Data :: string() | binary(),
+ Reason :: posix() | badarg | terminated.
-read_line(File) when is_pid(File) ->
+read_line(File) when (is_pid(File) orelse is_atom(File)) ->
case io:request(File, {get_line, ''}) of
Data when is_list(Data); is_binary(Data) ->
{ok, Data};
@@ -376,9 +470,12 @@ read_line(#file_descriptor{module = Module} = Handle) ->
read_line(_) ->
{error, badarg}.
--spec pread(File :: io_device(),
- LocationNumbers :: [{location(), non_neg_integer()}]) ->
- {'ok', [string() | binary() | 'eof']} | {'error', posix()}.
+-spec pread(IoDevice, LocNums) -> {ok, DataL} | eof | {error, Reason} when
+ IoDevice :: io_device(),
+ LocNums :: [{Location :: location(), Number :: non_neg_integer()}],
+ DataL :: [Data],
+ Data :: string() | binary() | eof,
+ Reason :: posix() | badarg | terminated.
pread(File, L) when is_pid(File), is_list(L) ->
pread_int(File, L, []);
@@ -401,10 +498,13 @@ pread_int(File, [{At, Sz} | T], R) when is_integer(Sz), Sz >= 0 ->
pread_int(_, _, _) ->
{error, badarg}.
--spec pread(File :: io_device(),
- Location :: location(),
- Size :: non_neg_integer()) ->
- 'eof' | {'ok', string() | binary()} | {'error', posix()}.
+-spec pread(IoDevice, Location, Number) ->
+ {ok, Data} | eof | {error, Reason} when
+ IoDevice :: io_device(),
+ Location :: location(),
+ Number :: non_neg_integer(),
+ Data :: string() | binary(),
+ Reason :: posix() | badarg | terminated.
pread(File, At, Sz) when is_pid(File), is_integer(Sz), Sz >= 0 ->
R = file_request(File, {pread, At, Sz}),
@@ -415,10 +515,12 @@ pread(#file_descriptor{module = Module} = Handle, Offs, Sz)
pread(_, _, _) ->
{error, badarg}.
--spec write(File :: io_device(), Byte :: iodata()) ->
- 'ok' | {'error', posix()}.
+-spec write(IoDevice, Bytes) -> ok | {error, Reason} when
+ IoDevice :: io_device() | atom(),
+ Bytes :: iodata(),
+ Reason :: posix() | badarg | terminated.
-write(File, Bytes) when is_pid(File) ->
+write(File, Bytes) when (is_pid(File) orelse is_atom(File)) ->
case make_binary(Bytes) of
Bin when is_binary(Bin) ->
io:request(File, {put_chars,Bin});
@@ -430,8 +532,11 @@ write(#file_descriptor{module = Module} = Handle, Bytes) ->
write(_, _) ->
{error, badarg}.
--spec pwrite(File :: io_device(), L :: [{location(), iodata()}]) ->
- 'ok' | {'error', {non_neg_integer(), posix()}}.
+-spec pwrite(IoDevice, LocBytes) -> ok | {error, {N, Reason}} when
+ IoDevice :: io_device(),
+ LocBytes :: [{Location :: location(), Bytes :: iodata()}],
+ N :: non_neg_integer(),
+ Reason :: posix() | badarg | terminated.
pwrite(File, L) when is_pid(File), is_list(L) ->
pwrite_int(File, L, 0);
@@ -452,10 +557,11 @@ pwrite_int(File, [{At, Bytes} | T], R) ->
pwrite_int(_, _, _) ->
{error, badarg}.
--spec pwrite(File :: io_device(),
- Location :: location(),
- Bytes :: iodata()) ->
- 'ok' | {'error', posix()}.
+-spec pwrite(IoDevice, Location, Bytes) -> ok | {error, Reason} when
+ IoDevice :: io_device(),
+ Location :: location(),
+ Bytes :: iodata(),
+ Reason :: posix() | badarg | terminated.
pwrite(File, At, Bytes) when is_pid(File) ->
R = file_request(File, {pwrite, At, Bytes}),
@@ -465,7 +571,21 @@ pwrite(#file_descriptor{module = Module} = Handle, Offs, Bytes) ->
pwrite(_, _, _) ->
{error, badarg}.
--spec sync(File :: io_device()) -> 'ok' | {'error', posix()}.
+-spec datasync(IoDevice) -> ok | {error, Reason} when
+ IoDevice :: io_device(),
+ Reason :: posix() | badarg | terminated.
+
+datasync(File) when is_pid(File) ->
+ R = file_request(File, datasync),
+ wait_file_reply(File, R);
+datasync(#file_descriptor{module = Module} = Handle) ->
+ Module:datasync(Handle);
+datasync(_) ->
+ {error, badarg}.
+
+-spec sync(IoDevice) -> ok | {error, Reason} when
+ IoDevice :: io_device(),
+ Reason :: posix() | badarg | terminated.
sync(File) when is_pid(File) ->
R = file_request(File, sync),
@@ -475,8 +595,11 @@ sync(#file_descriptor{module = Module} = Handle) ->
sync(_) ->
{error, badarg}.
--spec position(File :: io_device(), Location :: location()) ->
- {'ok',integer()} | {'error', posix()}.
+-spec position(IoDevice, Location) -> {ok, NewPosition} | {error, Reason} when
+ IoDevice :: io_device(),
+ Location :: location(),
+ NewPosition :: integer(),
+ Reason :: posix() | badarg | terminated.
position(File, At) when is_pid(File) ->
R = file_request(File, {position,At}),
@@ -486,7 +609,9 @@ position(#file_descriptor{module = Module} = Handle, At) ->
position(_, _) ->
{error, badarg}.
--spec truncate(File :: io_device()) -> 'ok' | {'error', posix()}.
+-spec truncate(IoDevice) -> ok | {error, Reason} when
+ IoDevice :: io_device(),
+ Reason :: posix() | badarg | terminated.
truncate(File) when is_pid(File) ->
R = file_request(File, truncate),
@@ -496,17 +621,26 @@ truncate(#file_descriptor{module = Module} = Handle) ->
truncate(_) ->
{error, badarg}.
--spec copy(Source :: io_device() | name() | {name(), [mode()]},
- Destination :: io_device() | name() | {name(), [mode()]}) ->
- {'ok', non_neg_integer()} | {'error', posix()}.
+-spec copy(Source, Destination) -> {ok, BytesCopied} | {error, Reason} when
+ Source :: io_device() | Filename | {Filename, Modes},
+ Destination :: io_device() | Filename | {Filename, Modes},
+ Filename :: name(),
+ Modes :: [mode()],
+ BytesCopied :: non_neg_integer(),
+ Reason :: posix() | badarg | terminated.
copy(Source, Dest) ->
copy_int(Source, Dest, infinity).
--spec copy(Source :: io_device() | name() | {name(), [mode()]},
- Destination :: io_device() | name() | {name(), [mode()]},
- Length :: non_neg_integer() | 'infinity') ->
- {'ok', non_neg_integer()} | {'error', posix()}.
+-spec copy(Source, Destination, ByteCount) ->
+ {ok, BytesCopied} | {error, Reason} when
+ Source :: io_device() | Filename | {Filename, Modes},
+ Destination :: io_device() | Filename | {Filename, Modes},
+ Filename :: name(),
+ Modes :: [mode()],
+ ByteCount :: non_neg_integer() | infinity,
+ BytesCopied :: non_neg_integer(),
+ Reason :: posix() | badarg | terminated.
copy(Source, Dest, Length)
when is_integer(Length), Length >= 0;
@@ -728,8 +862,11 @@ ipread_s32bu_p32bu_2(File,
%%% The following functions, built upon the other interface functions,
%%% provide a higher-lever interface to files.
--spec consult(File :: name()) ->
- {'ok', list()} | {'error', posix() | {integer(), atom(), any()}}.
+-spec consult(Filename) -> {ok, Terms} | {error, Reason} when
+ Filename :: name(),
+ Terms :: [term()],
+ Reason :: posix() | badarg | terminated | system_limit
+ | {Line :: integer(), Mod :: module(), Term :: term()}.
consult(File) ->
case open(File, [read]) of
@@ -741,8 +878,14 @@ consult(File) ->
Error
end.
--spec path_consult(Paths :: [name()], File :: name()) ->
- {'ok', list(), filename()} | {'error', posix() | {integer(), atom(), any()}}.
+-spec path_consult(Path, Filename) -> {ok, Terms, FullName} | {error, Reason} when
+ Path :: [Dir],
+ Dir :: name(),
+ Filename :: name(),
+ Terms :: [term()],
+ FullName :: filename(),
+ Reason :: posix() | badarg | terminated | system_limit
+ | {Line :: integer(), Mod :: module(), Term :: term()}.
path_consult(Path, File) ->
case path_open(Path, File, [read]) of
@@ -759,13 +902,19 @@ path_consult(Path, File) ->
E2
end.
--spec eval(File :: name()) -> 'ok' | {'error', posix()}.
+-spec eval(Filename) -> ok | {error, Reason} when
+ Filename :: name(),
+ Reason :: posix() | badarg | terminated | system_limit
+ | {Line :: integer(), Mod :: module(), Term :: term()}.
eval(File) ->
eval(File, erl_eval:new_bindings()).
--spec eval(File :: name(), Bindings :: bindings()) ->
- 'ok' | {'error', posix()}.
+-spec eval(Filename, Bindings) -> ok | {error, Reason} when
+ Filename :: name(),
+ Bindings :: erl_eval:binding_struct(),
+ Reason :: posix() | badarg | terminated | system_limit
+ | {Line :: integer(), Mod :: module(), Term :: term()}.
eval(File, Bs) ->
case open(File, [read]) of
@@ -777,14 +926,24 @@ eval(File, Bs) ->
Error
end.
--spec path_eval(Paths :: [name()], File :: name()) ->
- {'ok', filename()} | {'error', posix() | {integer(), atom(), any()}}.
+-spec path_eval(Path, Filename) -> {ok, FullName} | {error, Reason} when
+ Path :: [Dir :: name()],
+ Filename :: name(),
+ FullName :: filename(),
+ Reason :: posix() | badarg | terminated | system_limit
+ | {Line :: integer(), Mod :: module(), Term :: term()}.
path_eval(Path, File) ->
path_eval(Path, File, erl_eval:new_bindings()).
--spec path_eval(Paths :: [name()], File :: name(), Bindings :: bindings()) ->
- {'ok', filename()} | {'error', posix() | {integer(), atom(), any()}}.
+-spec path_eval(Path, Filename, Bindings) ->
+ {ok, FullName} | {error, Reason} when
+ Path :: [Dir :: name()],
+ Filename :: name(),
+ Bindings :: erl_eval:binding_struct(),
+ FullName :: filename(),
+ Reason :: posix() | badarg | terminated | system_limit
+ | {Line :: integer(), Mod :: module(), Term :: term()}.
path_eval(Path, File, Bs) ->
case path_open(Path, File, [read]) of
@@ -801,14 +960,21 @@ path_eval(Path, File, Bs) ->
E2
end.
--spec script(File :: name()) ->
- {'ok', any()} | {'error', posix() | {integer(), atom(), any()}}.
+-spec script(Filename) -> {ok, Value} | {error, Reason} when
+ Filename :: name(),
+ Value :: term(),
+ Reason :: posix() | badarg | terminated | system_limit
+ | {Line :: integer(), Mod :: module(), Term :: term()}.
script(File) ->
script(File, erl_eval:new_bindings()).
--spec script(File :: name(), Bindings :: bindings()) ->
- {'ok', any()} | {'error', posix() | {integer(), atom(), any()}}.
+-spec script(Filename, Bindings) -> {ok, Value} | {error, Reason} when
+ Filename :: name(),
+ Bindings :: erl_eval:binding_struct(),
+ Value :: term(),
+ Reason :: posix() | badarg | terminated | system_limit
+ | {Line :: integer(), Mod :: module(), Term :: term()}.
script(File, Bs) ->
case open(File, [read]) of
@@ -820,16 +986,27 @@ script(File, Bs) ->
Error
end.
--spec path_script/2 :: (Paths :: [name()], File :: name()) ->
- {'ok', term(), filename()} | {'error', posix() | {integer(), atom(), _}}.
+-spec path_script(Path, Filename) ->
+ {ok, Value, FullName} | {error, Reason} when
+ Path :: [Dir :: name()],
+ Filename :: name(),
+ Value :: term(),
+ FullName :: filename(),
+ Reason :: posix() | badarg | terminated | system_limit
+ | {Line :: integer(), Mod :: module(), Term :: term()}.
path_script(Path, File) ->
path_script(Path, File, erl_eval:new_bindings()).
--spec path_script(Paths :: [name()],
- File :: name(),
- Bindings :: bindings()) ->
- {'ok', term(), filename()} | {'error', posix() | {integer(), atom(), _}}.
+-spec path_script(Path, Filename, Bindings) ->
+ {ok, Value, FullName} | {error, Reason} when
+ Path :: [Dir :: name()],
+ Filename :: name(),
+ Bindings :: erl_eval:binding_struct(),
+ Value :: term(),
+ FullName :: filename(),
+ Reason :: posix() | badarg | terminated | system_limit
+ | {Line :: integer(), Mod :: module(), Term :: term()}.
path_script(Path, File, Bs) ->
case path_open(Path, File, [read]) of
@@ -854,8 +1031,14 @@ path_script(Path, File, Bs) ->
%% Searches the Paths for file Filename which can be opened with Mode.
%% The path list is ignored if Filename contains an absolute path.
--spec path_open(Paths :: [name()], Name :: name(), Modes :: [mode()]) ->
- {'ok', io_device(), filename()} | {'error', posix()}.
+-spec path_open(Path, Filename, Modes) ->
+ {ok, IoDevice, FullName} | {error, Reason} when
+ Path :: [Dir :: name()],
+ Filename :: name(),
+ Modes :: [mode()],
+ IoDevice :: io_device(),
+ FullName :: filename(),
+ Reason :: posix() | badarg | system_limit.
path_open(PathList, Name, Mode) ->
case file_name(Name) of
@@ -875,47 +1058,57 @@ path_open(PathList, Name, Mode) ->
end
end.
--spec change_mode(Name :: name(), Mode :: integer()) ->
- 'ok' | {'error', posix()}.
+-spec change_mode(Filename, Mode) -> ok | {error, Reason} when
+ Filename :: name(),
+ Mode :: integer(),
+ Reason :: posix() | badarg.
change_mode(Name, Mode)
when is_integer(Mode) ->
write_file_info(Name, #file_info{mode=Mode}).
--spec change_owner(Name :: name(), OwnerId :: integer()) ->
- 'ok' | {'error', posix()}.
+-spec change_owner(Filename, Uid) -> ok | {error, Reason} when
+ Filename :: name(),
+ Uid :: integer(),
+ Reason :: posix() | badarg.
change_owner(Name, OwnerId)
when is_integer(OwnerId) ->
write_file_info(Name, #file_info{uid=OwnerId}).
--spec change_owner(Name :: name(),
- OwnerId :: integer(),
- GroupId :: integer()) ->
- 'ok' | {'error', posix()}.
+-spec change_owner(Filename, Uid, Gid) -> ok | {error, Reason} when
+ Filename :: name(),
+ Uid :: integer(),
+ Gid :: integer(),
+ Reason :: posix() | badarg.
change_owner(Name, OwnerId, GroupId)
when is_integer(OwnerId), is_integer(GroupId) ->
write_file_info(Name, #file_info{uid=OwnerId, gid=GroupId}).
--spec change_group(Name :: name(), GroupId :: integer()) ->
- 'ok' | {'error', posix()}.
+-spec change_group(Filename, Gid) -> ok | {error, Reason} when
+ Filename :: name(),
+ Gid :: integer(),
+ Reason :: posix() | badarg.
change_group(Name, GroupId)
when is_integer(GroupId) ->
write_file_info(Name, #file_info{gid=GroupId}).
--spec change_time(Name :: name(), Time :: date_time()) ->
- 'ok' | {'error', posix()}.
+-spec change_time(Filename, Mtime) -> ok | {error, Reason} when
+ Filename :: name(),
+ Mtime :: date_time(),
+ Reason :: posix() | badarg.
change_time(Name, Time)
when is_tuple(Time) ->
write_file_info(Name, #file_info{mtime=Time}).
--spec change_time(Name :: name(),
- ATime :: date_time(),
- MTime :: date_time()) ->
- 'ok' | {'error', posix()}.
+-spec change_time(Filename, Atime, Mtime) -> ok | {error, Reason} when
+ Filename :: name(),
+ Atime :: date_time(),
+ Mtime :: date_time(),
+ Reason :: posix() | badarg.
change_time(Name, Atime, Mtime)
when is_tuple(Atime), is_tuple(Mtime) ->
@@ -990,22 +1183,26 @@ path_open_first([], _Name, _Mode, LastError) ->
%% Generates a flat file name from a deep list of atoms and
%% characters (integers).
+file_name(N) when is_binary(N) ->
+ N;
file_name(N) ->
try
- file_name_1(N)
+ file_name_1(N,file:native_name_encoding())
catch Reason ->
{error, Reason}
end.
-file_name_1([C|T]) when is_integer(C), C > 0, C =< 255 ->
- [C|file_name_1(T)];
-file_name_1([H|T]) ->
- file_name_1(H) ++ file_name_1(T);
-file_name_1([]) ->
+file_name_1([C|T],latin1) when is_integer(C), C < 256->
+ [C|file_name_1(T,latin1)];
+file_name_1([C|T],utf8) when is_integer(C) ->
+ [C|file_name_1(T,utf8)];
+file_name_1([H|T],E) ->
+ file_name_1(H,E) ++ file_name_1(T,E);
+file_name_1([],_) ->
[];
-file_name_1(N) when is_atom(N) ->
+file_name_1(N,_) when is_atom(N) ->
atom_to_list(N);
-file_name_1(_) ->
+file_name_1(_,_) ->
throw(badarg).
make_binary(Bin) when is_binary(Bin) ->
diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl
index 37e803c493..14da9c1a55 100644
--- a/lib/kernel/src/file_io_server.erl
+++ b/lib/kernel/src/file_io_server.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2000-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(file_io_server).
@@ -44,11 +44,11 @@ format_error(ErrorId) ->
erl_posix_msg:message(ErrorId).
start(Owner, FileName, ModeList)
- when is_pid(Owner), is_list(FileName), is_list(ModeList) ->
+ when is_pid(Owner), (is_list(FileName) orelse is_binary(FileName)), is_list(ModeList) ->
do_start(spawn, Owner, FileName, ModeList).
start_link(Owner, FileName, ModeList)
- when is_pid(Owner), is_list(FileName), is_list(ModeList) ->
+ when is_pid(Owner), (is_list(FileName) orelse is_binary(FileName)), is_list(ModeList) ->
do_start(spawn_link, Owner, FileName, ModeList).
%%%-----------------------------------------------------------------
@@ -106,21 +106,21 @@ do_start(Spawn, Owner, FileName, ModeList) ->
parse_options(List) ->
parse_options(expand_encoding(List), list, latin1, []).
-parse_options([],list,Uni,Acc) ->
+parse_options([], list, Uni, Acc) ->
{list,Uni,[binary|lists:reverse(Acc)]};
-parse_options([],binary,Uni,Acc) ->
+parse_options([], binary, Uni, Acc) ->
{binary,Uni,lists:reverse(Acc)};
-parse_options([{encoding, Encoding}|T],RMode,_,Acc) ->
+parse_options([{encoding, Encoding}|T], RMode, _, Acc) ->
case valid_enc(Encoding) of
{ok, ExpandedEnc} ->
- parse_options(T,RMode,ExpandedEnc,Acc);
- {error,Reason} ->
- {error,Reason}
+ parse_options(T, RMode, ExpandedEnc, Acc);
+ {error,_Reason} = Error ->
+ Error
end;
-parse_options([binary|T],_,Uni,Acc) ->
- parse_options(T,binary,Uni,[binary|Acc]);
-parse_options([H|T],R,U,Acc) ->
- parse_options(T,R,U,[H|Acc]).
+parse_options([binary|T], _, Uni, Acc) ->
+ parse_options(T, binary, Uni, [binary|Acc]);
+parse_options([H|T], R, U, Acc) ->
+ parse_options(T, R, U, [H|Acc]).
expand_encoding([]) ->
[];
@@ -153,7 +153,6 @@ valid_enc(_Other) ->
{error,badarg}.
-
server_loop(#state{mref = Mref} = State) ->
receive
{file_request, From, ReplyAs, Request} when is_pid(From) ->
@@ -199,6 +198,14 @@ io_reply(From, ReplyAs, Reply) ->
%%%-----------------------------------------------------------------
%%% file requests
+file_request({advise,Offset,Length,Advise},
+ #state{handle=Handle}=State) ->
+ case ?PRIM_FILE:advise(Handle, Offset, Length, Advise) of
+ {error,_}=Reply ->
+ {stop,normal,Reply,State};
+ Reply ->
+ {reply,Reply,State}
+ end;
file_request({pread,At,Sz},
#state{handle=Handle,buf=Buf,read_mode=ReadMode}=State) ->
case position(Handle, At, Buf) of
@@ -220,6 +227,14 @@ file_request({pwrite,At,Data},
Reply ->
std_reply(Reply, State)
end;
+file_request(datasync,
+ #state{handle=Handle}=State) ->
+ case ?PRIM_FILE:datasync(Handle) of
+ {error,_}=Reply ->
+ {stop,normal,Reply,State};
+ Reply ->
+ {reply,Reply,State}
+ end;
file_request(sync,
#state{handle=Handle}=State) ->
case ?PRIM_FILE:sync(Handle) of
@@ -326,7 +341,6 @@ io_request(Unknown,
{error,{error,Reason},State}.
-
%% Process a list of requests as long as the results are ok.
io_request_loop([], Result) ->
@@ -342,7 +356,6 @@ io_request_loop([Request|Tail],
io_request_loop(Tail, io_request(Request, State)).
-
%% I/O request put_chars
%%
put_chars(Chars, latin1, #state{handle=Handle, unic=latin1}=State) ->
@@ -653,20 +666,14 @@ do_setopts(Opts, State) ->
end.
getopts(#state{read_mode=RM, unic=Unic} = State) ->
- Bin = {binary, case RM of
- binary ->
- true;
- _ ->
- false
- end},
+ Bin = {binary, RM =:= binary},
Uni = {encoding, Unic},
{reply,[Bin,Uni],State}.
-
%% Concatenate two binaries and convert the result to list or binary
-cat(B1, B2, binary,latin1,latin1) ->
+cat(B1, B2, binary, latin1, latin1) ->
list_to_binary([B1,B2]);
-cat(B1, B2, binary,InEncoding,OutEncoding) ->
+cat(B1, B2, binary, InEncoding, OutEncoding) ->
case unicode:characters_to_binary([B1,B2],InEncoding,OutEncoding) of
Good when is_binary(Good) ->
Good;
diff --git a/lib/kernel/src/file_server.erl b/lib/kernel/src/file_server.erl
index 74f2fb94a9..64c61ba3ac 100644
--- a/lib/kernel/src/file_server.erl
+++ b/lib/kernel/src/file_server.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2000-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -62,6 +62,8 @@ stop() ->
%%% Callback functions from gen_server
%%%----------------------------------------------------------------------
+-type state() :: port(). % Internal type
+
%%----------------------------------------------------------------------
%% Func: init/1
%% Returns: {ok, State} |
@@ -69,6 +71,9 @@ stop() ->
%% ignore |
%% {stop, Reason}
%%----------------------------------------------------------------------
+
+-spec init([]) -> {'ok', state()} | {'stop', term()}.
+
init([]) ->
process_flag(trap_exit, true),
case ?PRIM_FILE:start() of
@@ -88,6 +93,12 @@ init([]) ->
%% {stop, Reason, Reply, State} | (terminate/2 is called)
%% {stop, Reason, State} (terminate/2 is called)
%%----------------------------------------------------------------------
+
+-spec handle_call(term(), term(), state()) ->
+ {'noreply', state()} |
+ {'reply', 'eof' | 'ok' | {'error', term()} | {'ok', term()}, state()} |
+ {'stop', 'normal', 'stopped', state()}.
+
handle_call({open, Name, ModeList}, {Pid, _Tag} = _From, Handle)
when is_list(ModeList) ->
Child = ?FILE_IO_SERVER:start_link(Pid, Name, ModeList),
@@ -190,6 +201,9 @@ handle_call(Request, From, Handle) ->
%% {noreply, State, Timeout} |
%% {stop, Reason, State} (terminate/2 is called)
%%----------------------------------------------------------------------
+
+-spec handle_cast(term(), state()) -> {'noreply', state()}.
+
handle_cast(Msg, State) ->
error_logger:error_msg("handle_cast(~p, _)", [Msg]),
{noreply, State}.
@@ -201,6 +215,9 @@ handle_cast(Msg, State) ->
%% {stop, Reason, State} (terminate/2 is called)
%%----------------------------------------------------------------------
+-spec handle_info(term(), state()) ->
+ {'noreply', state()} | {'stop', 'normal', state()}.
+
handle_info({'EXIT', Pid, _Reason}, Handle) when is_pid(Pid) ->
ets:delete(?FILE_IO_SERVER_TABLE, Pid),
{noreply, Handle};
@@ -219,6 +236,9 @@ handle_info(Info, State) ->
%% Purpose: Shutdown the server
%% Returns: any (ignored by gen_server)
%%----------------------------------------------------------------------
+
+-spec terminate(term(), state()) -> 'ok'.
+
terminate(_Reason, Handle) ->
?PRIM_FILE:stop(Handle).
@@ -227,6 +247,9 @@ terminate(_Reason, Handle) ->
%% Purpose: Convert process state when code is changed
%% Returns: {ok, NewState}
%%----------------------------------------------------------------------
+
+-spec code_change(term(), state(), term()) -> {'ok', state()}.
+
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index 5a31e3976f..6cebb7ab97 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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
@@ -33,13 +33,89 @@
-export([error_string/1]).
-export([controlling_process/2]).
-
+-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, inet:posix()} when
+ Port :: inet:port_number(),
+ Socket :: sctp_socket();
+ (Opts) -> {ok, Socket} | {error, inet:posix()} when
+ Opts :: [Opt],
+ 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) ->
- Mod = mod(Opts),
+ Mod = mod(Opts, undefined),
case Mod:open(Opts) of
{error,badarg} ->
erlang:error(badarg, [Opts]);
@@ -52,11 +128,25 @@ open(Port) when is_integer(Port) ->
open(X) ->
erlang:error(badarg, [X]).
+-spec open(Port, Opts) -> {ok, Socket} | {error, inet:posix()} when
+ Opts :: [Opt],
+ 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) ->
open([{port,Port}|Opts]);
open(Port, Opts) ->
erlang:error(badarg, [Port,Opts]).
+-spec close(Socket) -> ok | {error, inet:posix()} when
+ Socket :: sctp_socket().
+
close(S) when is_port(S) ->
case inet_db:lookup_socket(S) of
{ok,Mod} ->
@@ -68,6 +158,11 @@ close(S) ->
+-spec listen(Socket, IsServer) -> ok | {error, Reason} when
+ Socket :: sctp_socket(),
+ IsServer :: boolean(),
+ Reason :: term().
+
listen(S, Flag) when is_port(S), is_boolean(Flag) ->
case inet_db:lookup_socket(S) of
{ok,Mod} ->
@@ -77,9 +172,25 @@ 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, inet:posix()} when
+ Socket :: sctp_socket(),
+ 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, inet:posix()} when
+ Socket :: sctp_socket(),
+ Addr :: inet:ip_address() | inet:hostname(),
+ Port :: inet:port_number(),
+ Opts :: [Opt :: option()],
+ Timeout :: timeout(),
+ Assoc :: #sctp_assoc_change{}.
+
connect(S, Addr, Port, Opts, Timeout) ->
case do_connect(S, Addr, Port, Opts, Timeout, true) of
badarg ->
@@ -88,9 +199,24 @@ connect(S, Addr, Port, Opts, Timeout) ->
Result
end.
+-spec connect_init(Socket, Addr, Port, Opts) ->
+ ok | {error, inet:posix()} when
+ Socket :: sctp_socket(),
+ 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, inet:posix()} when
+ Socket :: sctp_socket(),
+ Addr :: inet:ip_address() | inet:hostname(),
+ Port :: inet:port_number(),
+ Opts :: [option()],
+ Timeout :: timeout().
+
connect_init(S, Addr, Port, Opts, Timeout) ->
case do_connect(S, Addr, Port, Opts, Timeout, false) of
badarg ->
@@ -130,12 +256,20 @@ do_connect(_S, _Addr, _Port, _Opts, _Timeout, _ConnWait) ->
badarg.
+-spec eof(Socket, Assoc) -> ok | {error, Reason} when
+ Socket :: sctp_socket(),
+ Assoc :: #sctp_assoc_change{},
+ Reason :: term().
eof(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) ->
eof_or_abort(S, AssocId, eof);
eof(S, Assoc) ->
erlang:error(badarg, [S,Assoc]).
+-spec abort(Socket, Assoc) -> ok | {error, inet:posix()} when
+ Socket :: sctp_socket(),
+ Assoc :: #sctp_assoc_change{}.
+
abort(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) ->
eof_or_abort(S, AssocId, abort);
abort(S, Assoc) ->
@@ -151,6 +285,11 @@ eof_or_abort(S, AssocId, Action) ->
end.
+-spec send(Socket, SndRcvInfo, Data) -> ok | {error, Reason} when
+ Socket :: sctp_socket(),
+ SndRcvInfo :: #sctp_sndrcvinfo{},
+ Data :: binary | iolist(),
+ Reason :: term().
%% Full-featured send. Rarely needed.
send(S, #sctp_sndrcvinfo{}=SRI, Data) when is_port(S) ->
@@ -162,30 +301,60 @@ send(S, #sctp_sndrcvinfo{}=SRI, Data) when is_port(S) ->
send(S, SRI, Data) ->
erlang:error(badarg, [S,SRI,Data]).
+-spec send(Socket, Assoc, Stream, Data) -> ok | {error, Reason} when
+ Socket :: sctp_socket(),
+ Assoc :: #sctp_assoc_change{} | assoc_id(),
+ Stream :: integer(),
+ Data :: binary | iolist(),
+ Reason :: term().
+
send(S, #sctp_assoc_change{assoc_id=AssocId}, Stream, Data)
when is_port(S), is_integer(Stream) ->
case inet_db:lookup_socket(S) of
{ok,Mod} ->
- Mod:sendmsg(S, #sctp_sndrcvinfo{
- stream = Stream,
- assoc_id = AssocId}, Data);
+ Mod:send(S, AssocId, Stream, Data);
Error -> Error
end;
send(S, AssocId, Stream, Data)
when is_port(S), is_integer(AssocId), is_integer(Stream) ->
case inet_db:lookup_socket(S) of
{ok,Mod} ->
- Mod:sendmsg(S, #sctp_sndrcvinfo{
- stream = Stream,
- assoc_id = AssocId}, Data);
+ Mod:send(S, AssocId, Stream, Data);
Error -> Error
end;
send(S, AssocChange, Stream, Data) ->
erlang:error(badarg, [S,AssocChange,Stream,Data]).
+-spec recv(Socket) -> {ok, {FromIP, FromPort, AncData, Data}}
+ | {error, Reason} when
+ Socket :: sctp_socket(),
+ 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 :: inet:posix() | #sctp_send_failed{} | #sctp_paddr_change{}
+ | #sctp_pdapi_event{} | #sctp_remote_error{}
+ | #sctp_shutdown_event{}.
+
recv(S) ->
recv(S, infinity).
+-spec recv(Socket, Timeout) -> {ok, {FromIP, FromPort, AncData, Data}}
+ | {error, Reason} when
+ Socket :: sctp_socket(),
+ Timeout :: timeout(),
+ 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 :: inet:posix() | #sctp_send_failed{} | #sctp_paddr_change{}
+ | #sctp_pdapi_event{} | #sctp_remote_error{}
+ | #sctp_shutdown_event{}.
+
recv(S, Timeout) when is_port(S) ->
case inet_db:lookup_socket(S) of
{ok,Mod} ->
@@ -196,6 +365,8 @@ recv(S, Timeout) ->
erlang:error(badarg, [S,Timeout]).
+-spec error_string(ErrorNumber) -> ok | string() | unknown_error when
+ ErrorNumber :: integer().
error_string(0) ->
ok;
@@ -228,6 +399,9 @@ error_string(X) ->
erlang:error(badarg, [X]).
+-spec controlling_process(Socket, Pid) -> ok when
+ Socket :: sctp_socket(),
+ Pid :: pid().
controlling_process(S, Pid) when is_port(S), is_pid(Pid) ->
inet:udp_controlling_process(S, Pid);
@@ -238,17 +412,27 @@ controlling_process(S, Pid) ->
%% Utilites
%%
-%% Get the SCTP moudule
-mod() -> inet_db:sctp_module().
+%% Get the SCTP module, but IPv6 address overrides default IPv4
+mod(Address) ->
+ case inet_db:sctp_module() of
+ inet_sctp when tuple_size(Address) =:= 8 ->
+ inet6_sctp;
+ Mod ->
+ Mod
+ end.
%% Get the SCTP module, but option sctp_module|inet|inet6 overrides
-mod([{sctp_module,Mod}|_]) ->
+mod([{sctp_module,Mod}|_], _Address) ->
Mod;
-mod([inet|_]) ->
+mod([inet|_], _Address) ->
inet_sctp;
-mod([inet6|_]) ->
+mod([inet6|_], _Address) ->
inet6_sctp;
-mod([_|Opts]) ->
- mod(Opts);
-mod([]) ->
- mod().
+mod([{ip, Address}|Opts], _) ->
+ mod(Opts, Address);
+mod([{ifaddr, Address}|Opts], _) ->
+ mod(Opts, Address);
+mod([_|Opts], Address) ->
+ mod(Opts, Address);
+mod([], Address) ->
+ mod(Address).
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index 7401b06a64..8ab18c01b4 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -28,12 +28,109 @@
-include("inet_int.hrl").
+-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 :: inet:ip_address() | inet:hostname(),
+ Port :: inet:port_number(),
+ Options :: [connect_option()],
+ Socket :: socket(),
+ Reason :: inet:posix().
+
connect(Address, Port, Opts) ->
connect(Address,Port,Opts,infinity).
+-spec connect(Address, Port, Options, Timeout) ->
+ {ok, Socket} | {error, Reason} when
+ Address :: inet:ip_address() | inet:hostname(),
+ Port :: inet:port_number(),
+ Options :: [connect_option()],
+ Timeout :: timeout(),
+ Socket :: socket(),
+ Reason :: inet:posix().
+
connect(Address, Port, Opts, Time) ->
Timer = inet:start_timer(Time),
Res = (catch connect1(Address,Port,Opts,Timer)),
@@ -46,7 +143,7 @@ connect(Address, Port, Opts, Time) ->
end.
connect1(Address,Port,Opts,Timer) ->
- Mod = mod(Opts),
+ Mod = mod(Opts, Address),
case Mod:getaddrs(Address,Timer) of
{ok,IPs} ->
case Mod:getserv(Port) of
@@ -72,8 +169,15 @@ try_connect([], _Port, _Opts, _Timer, _Mod, Err) ->
%%
%% Listen on a tcp port
%%
+
+-spec listen(Port, Options) -> {ok, ListenSocket} | {error, Reason} when
+ Port :: inet:port_number(),
+ Options :: [listen_option()],
+ ListenSocket :: socket(),
+ Reason :: inet:posix().
+
listen(Port, Opts) ->
- Mod = mod(Opts),
+ Mod = mod(Opts, undefined),
case Mod:getserv(Port) of
{ok,TP} ->
Mod:listen(TP, Opts);
@@ -85,6 +189,12 @@ listen(Port, Opts) ->
%%
%% Generic tcp accept
%%
+
+-spec accept(ListenSocket) -> {ok, Socket} | {error, Reason} when
+ ListenSocket :: socket(),
+ Socket :: socket(),
+ Reason :: closed | timeout | inet:posix().
+
accept(S) ->
case inet_db:lookup_socket(S) of
{ok, Mod} ->
@@ -93,6 +203,12 @@ accept(S) ->
Error
end.
+-spec accept(ListenSocket, Timeout) -> {ok, Socket} | {error, Reason} when
+ ListenSocket :: socket(),
+ Timeout :: timeout(),
+ Socket :: socket(),
+ Reason :: closed | timeout | inet:posix().
+
accept(S, Time) when is_port(S) ->
case inet_db:lookup_socket(S) of
{ok, Mod} ->
@@ -104,6 +220,12 @@ accept(S, Time) when is_port(S) ->
%%
%% Generic tcp shutdown
%%
+
+-spec shutdown(Socket, How) -> ok | {error, Reason} when
+ Socket :: socket(),
+ How :: read | write | read_write,
+ Reason :: inet:posix().
+
shutdown(S, How) when is_port(S) ->
case inet_db:lookup_socket(S) of
{ok, Mod} ->
@@ -115,12 +237,22 @@ shutdown(S, How) when is_port(S) ->
%%
%% Close
%%
+
+-spec close(Socket) -> ok when
+ Socket :: socket().
+
close(S) ->
inet:tcp_close(S).
%%
%% Send
%%
+
+-spec send(Socket, Packet) -> ok | {error, Reason} when
+ Socket :: socket(),
+ Packet :: iodata(),
+ Reason :: inet:posix().
+
send(S, Packet) when is_port(S) ->
case inet_db:lookup_socket(S) of
{ok, Mod} ->
@@ -132,6 +264,14 @@ send(S, Packet) when is_port(S) ->
%%
%% Receive data from a socket (passive mode)
%%
+
+-spec recv(Socket, Length) -> {ok, Packet} | {error, Reason} when
+ Socket :: socket(),
+ Length :: non_neg_integer(),
+ Packet :: string() | binary() | HttpPacket,
+ Reason :: closed | inet:posix(),
+ HttpPacket :: term().
+
recv(S, Length) when is_port(S) ->
case inet_db:lookup_socket(S) of
{ok, Mod} ->
@@ -140,6 +280,14 @@ recv(S, Length) when is_port(S) ->
Error
end.
+-spec recv(Socket, Length, Timeout) -> {ok, Packet} | {error, Reason} when
+ Socket :: socket(),
+ Length :: non_neg_integer(),
+ Timeout :: timeout(),
+ Packet :: string() | binary() | HttpPacket,
+ Reason :: closed | inet:posix(),
+ HttpPacket :: term().
+
recv(S, Length, Time) when is_port(S) ->
case inet_db:lookup_socket(S) of
{ok, Mod} ->
@@ -159,6 +307,12 @@ unrecv(S, Data) when is_port(S) ->
%%
%% Set controlling process
%%
+
+-spec controlling_process(Socket, Pid) -> ok | {error, Reason} when
+ Socket :: socket(),
+ Pid :: pid(),
+ Reason :: closed | not_owner | inet:posix().
+
controlling_process(S, NewOwner) ->
case inet_db:lookup_socket(S) of
{ok, _Mod} -> % Just check that this is an open socket
@@ -173,20 +327,30 @@ controlling_process(S, NewOwner) ->
%% Create a port/socket from a file descriptor
%%
fdopen(Fd, Opts) ->
- Mod = mod(Opts),
+ Mod = mod(Opts, undefined),
Mod:fdopen(Fd, Opts).
-%% Get the tcp_module
-mod() -> inet_db:tcp_module().
+%% Get the tcp_module, but IPv6 address overrides default IPv4
+mod(Address) ->
+ case inet_db:tcp_module() of
+ inet_tcp when tuple_size(Address) =:= 8 ->
+ inet6_tcp;
+ Mod ->
+ Mod
+ end.
%% Get the tcp_module, but option tcp_module|inet|inet6 overrides
-mod([{tcp_module,Mod}|_]) ->
+mod([{tcp_module,Mod}|_], _Address) ->
Mod;
-mod([inet|_]) ->
+mod([inet|_], _Address) ->
inet_tcp;
-mod([inet6|_]) ->
+mod([inet6|_], _Address) ->
inet6_tcp;
-mod([_|Opts]) ->
- mod(Opts);
-mod([]) ->
- mod().
+mod([{ip, Address}|Opts], _) ->
+ mod(Opts, Address);
+mod([{ifaddr, Address}|Opts], _) ->
+ mod(Opts, Address);
+mod([_|Opts], Address) ->
+ mod(Opts, Address);
+mod([], Address) ->
+ mod(Address).
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index 6bded4bda6..8688799ae9 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -25,17 +25,93 @@
-include("inet_int.hrl").
+-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 :: inet:port_number(),
+ Socket :: socket(),
+ Reason :: inet:posix().
+
open(Port) ->
open(Port, []).
+-spec open(Port, Opts) -> {ok, Socket} | {error, Reason} when
+ 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 :: inet:posix().
+
open(Port, Opts) ->
- Mod = mod(Opts),
+ Mod = mod(Opts, undefined),
{ok,UP} = Mod:getserv(Port),
Mod:open(UP, Opts).
+-spec close(Socket) -> ok when
+ Socket :: socket().
+
close(S) ->
inet:udp_close(S).
+-spec send(Socket, Address, Port, Packet) -> ok | {error, Reason} when
+ Socket :: socket(),
+ 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
{ok, Mod} ->
@@ -61,6 +137,15 @@ send(S, Packet) when is_port(S) ->
Error
end.
+-spec recv(Socket, Length) ->
+ {ok, {Address, Port, Packet}} | {error, Reason} when
+ Socket :: socket(),
+ Length :: non_neg_integer(),
+ Address :: inet:ip_address(),
+ Port :: inet:port_number(),
+ Packet :: string() | binary(),
+ Reason :: not_owner | inet:posix().
+
recv(S,Len) when is_port(S), is_integer(Len) ->
case inet_db:lookup_socket(S) of
{ok, Mod} ->
@@ -69,6 +154,16 @@ recv(S,Len) when is_port(S), is_integer(Len) ->
Error
end.
+-spec recv(Socket, Length, Timeout) ->
+ {ok, {Address, Port, Packet}} | {error, Reason} when
+ Socket :: socket(),
+ Length :: non_neg_integer(),
+ Timeout :: timeout(),
+ Address :: inet:ip_address(),
+ Port :: inet:port_number(),
+ Packet :: string() | binary(),
+ Reason :: not_owner | inet:posix().
+
recv(S,Len,Time) when is_port(S) ->
case inet_db:lookup_socket(S) of
{ok, Mod} ->
@@ -90,6 +185,10 @@ connect(S, Address, Port) when is_port(S) ->
Error
end.
+-spec controlling_process(Socket, Pid) -> ok when
+ Socket :: socket(),
+ Pid :: pid().
+
controlling_process(S, NewOwner) ->
inet:udp_controlling_process(S, NewOwner).
@@ -97,21 +196,31 @@ controlling_process(S, NewOwner) ->
%% Create a port/socket from a file descriptor
%%
fdopen(Fd, Opts) ->
- Mod = mod(),
+ Mod = mod(Opts, undefined),
Mod:fdopen(Fd, Opts).
-%% Get the udp_module
-mod() -> inet_db:udp_module().
+%% Get the udp_module, but IPv6 address overrides default IPv4
+mod(Address) ->
+ case inet_db:udp_module() of
+ inet_udp when tuple_size(Address) =:= 8 ->
+ inet6_udp;
+ Mod ->
+ Mod
+ end.
%% Get the udp_module, but option udp_module|inet|inet6 overrides
-mod([{udp_module,Mod}|_]) ->
+mod([{udp_module,Mod}|_], _Address) ->
Mod;
-mod([inet|_]) ->
+mod([inet|_], _Address) ->
inet_udp;
-mod([inet6|_]) ->
+mod([inet6|_], _Address) ->
inet6_udp;
-mod([_|Opts]) ->
- mod(Opts);
-mod([]) ->
- mod().
+mod([{ip, Address}|Opts], _) ->
+ mod(Opts, Address);
+mod([{ifaddr, Address}|Opts], _) ->
+ mod(Opts, Address);
+mod([_|Opts], Address) ->
+ mod(Opts, Address);
+mod([], Address) ->
+ mod(Address).
diff --git a/lib/kernel/src/global.erl b/lib/kernel/src/global.erl
index cc0402da73..7d15f8bf83 100644
--- a/lib/kernel/src/global.erl
+++ b/lib/kernel/src/global.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-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(global).
@@ -112,9 +112,10 @@
resolvers = [],
syncers = [] :: [pid()],
node_name = node() :: node(),
- the_locker, the_deleter, the_registrar, trace,
- global_lock_down = false
+ the_locker, the_registrar, trace,
+ global_lock_down = false :: boolean()
}).
+-type state() :: #state{}.
%%% There are also ETS tables used for bookkeeping of locks and names
%%% (the first position is the key):
@@ -153,6 +154,8 @@
%%% It can be removed later as can the deleter process.
%%% An extra process calling erlang:monitor() is sometimes created.
%%% The new_nodes messages has been augmented with the global lock id.
+%%%
+%%% R14A (OTP-8527): The deleter process has been removed.
start() ->
gen_server:start({local, global_name_server}, ?MODULE, [], []).
@@ -163,7 +166,7 @@ start_link() ->
stop() ->
gen_server:call(global_name_server, stop, infinity).
--spec sync() -> 'ok' | {'error', term()}.
+-spec sync() -> 'ok' | {'error', Reason :: term()}.
sync() ->
case check_sync_nodes() of
{error, _} = Error ->
@@ -172,7 +175,7 @@ sync() ->
gen_server:call(global_name_server, {sync, SyncNodes}, infinity)
end.
--spec sync([node()]) -> 'ok' | {'error', term()}.
+-spec sync([node()]) -> 'ok' | {'error', Reason :: term()}.
sync(Nodes) ->
case check_sync_nodes(Nodes) of
{error, _} = Error ->
@@ -181,7 +184,10 @@ sync(Nodes) ->
gen_server:call(global_name_server, {sync, SyncNodes}, infinity)
end.
--spec send(term(), term()) -> pid().
+-spec send(Name, Msg) -> Pid when
+ Name :: term(),
+ Msg :: term(),
+ Pid :: pid().
send(Name, Msg) ->
case whereis_name(Name) of
Pid when is_pid(Pid) ->
@@ -192,7 +198,8 @@ send(Name, Msg) ->
end.
%% See OTP-3737.
--spec whereis_name(term()) -> pid() | 'undefined'.
+-spec whereis_name(Name) -> pid() | 'undefined' when
+ Name :: term().
whereis_name(Name) ->
where(Name).
@@ -216,13 +223,19 @@ node_disconnected(Node) ->
%% undefined which one of them is used.
%% Method blocks the name registration, but does not affect global locking.
%%-----------------------------------------------------------------
--spec register_name(term(), pid()) -> 'yes' | 'no'.
+-spec register_name(Name, Pid) -> 'yes' | 'no' when
+ Name :: term(),
+ Pid :: pid().
register_name(Name, Pid) when is_pid(Pid) ->
register_name(Name, Pid, fun random_exit_name/3).
--type method() :: fun((term(), pid(), pid()) -> pid() | 'none').
+-type method() :: fun((Name :: term(), Pid :: pid(), Pid2 :: pid()) ->
+ pid() | 'none').
--spec register_name(term(), pid(), method()) -> 'yes' | 'no'.
+-spec register_name(Name, Pid, Resolve) -> 'yes' | 'no' when
+ Name :: term(),
+ Pid :: pid(),
+ Resolve :: method().
register_name(Name, Pid, Method) when is_pid(Pid) ->
Fun = fun(Nodes) ->
case (where(Name) =:= undefined) andalso check_dupname(Name, Pid) of
@@ -254,7 +267,8 @@ check_dupname(Name, Pid) ->
end
end.
--spec unregister_name(term()) -> _.
+-spec unregister_name(Name) -> _ when
+ Name :: term().
unregister_name(Name) ->
case where(Name) of
undefined ->
@@ -270,11 +284,16 @@ unregister_name(Name) ->
gen_server:call(global_name_server, {registrar, Fun}, infinity)
end.
--spec re_register_name(term(), pid()) -> _.
+-spec re_register_name(Name, Pid) -> _ when
+ Name :: term(),
+ Pid :: pid().
re_register_name(Name, Pid) when is_pid(Pid) ->
re_register_name(Name, Pid, fun random_exit_name/3).
--spec re_register_name(term(), pid(), method()) -> _.
+-spec re_register_name(Name, Pid, Resolve) -> _ when
+ Name :: term(),
+ Pid :: pid(),
+ Resolve :: method().
re_register_name(Name, Pid, Method) when is_pid(Pid) ->
Fun = fun(Nodes) ->
gen_server:multi_call(Nodes,
@@ -285,7 +304,8 @@ re_register_name(Name, Pid, Method) when is_pid(Pid) ->
?trace({re_register_name, self(), Name, Pid, Method}),
gen_server:call(global_name_server, {registrar, Fun}, infinity).
--spec registered_names() -> [term()].
+-spec registered_names() -> [Name] when
+ Name :: term().
registered_names() ->
MS = ets:fun2ms(fun({Name,_Pid,_M,_RP,_R}) -> Name end),
ets:select(global_names, MS).
@@ -326,19 +346,25 @@ register_name_external(Name, Pid, Method) when is_pid(Pid) ->
unregister_name_external(Name) ->
unregister_name(Name).
--type id() :: {term(), term()}.
+-type id() :: {ResourceId :: term(), LockRequesterId :: term()}.
--spec set_lock(id()) -> boolean().
+-spec set_lock(Id) -> boolean() when
+ Id :: id().
set_lock(Id) ->
set_lock(Id, [node() | nodes()], infinity, 1).
-type retries() :: non_neg_integer() | 'infinity'.
--spec set_lock(id(), [node()]) -> boolean().
+-spec set_lock(Id, Nodes) -> boolean() when
+ Id :: id(),
+ Nodes :: [node()].
set_lock(Id, Nodes) ->
set_lock(Id, Nodes, infinity, 1).
--spec set_lock(id(), [node()], retries()) -> boolean().
+-spec set_lock(Id, Nodes, Retries) -> boolean() when
+ Id :: id(),
+ Nodes :: [node()],
+ Retries :: retries().
set_lock(Id, Nodes, Retries) when is_integer(Retries), Retries >= 0 ->
set_lock(Id, Nodes, Retries, 1);
set_lock(Id, Nodes, infinity) ->
@@ -360,11 +386,14 @@ set_lock({_ResourceId, _LockRequesterId} = Id, Nodes, Retries, Times) ->
set_lock(Id, Nodes, dec(Retries), Times+1)
end.
--spec del_lock(id()) -> 'true'.
+-spec del_lock(Id) -> 'true' when
+ Id :: id().
del_lock(Id) ->
del_lock(Id, [node() | nodes()]).
--spec del_lock(id(), [node()]) -> 'true'.
+-spec del_lock(Id, Nodes) -> 'true' when
+ Id :: id(),
+ Nodes :: [node()].
del_lock({_ResourceId, _LockRequesterId} = Id, Nodes) ->
?trace({del_lock, {me,self()}, Id, {nodes,Nodes}}),
gen_server:multi_call(Nodes, global_name_server, {del_lock, Id}),
@@ -372,13 +401,25 @@ del_lock({_ResourceId, _LockRequesterId} = Id, Nodes) ->
-type trans_fun() :: function() | {module(), atom()}.
--spec trans(id(), trans_fun()) -> term().
+-spec trans(Id, Fun) -> Res | aborted when
+ Id :: id(),
+ Fun :: trans_fun(),
+ Res :: term().
trans(Id, Fun) -> trans(Id, Fun, [node() | nodes()], infinity).
--spec trans(id(), trans_fun(), [node()]) -> term().
+-spec trans(Id, Fun, Nodes) -> Res | aborted when
+ Id :: id(),
+ Fun :: trans_fun(),
+ Nodes :: [node()],
+ Res :: term().
trans(Id, Fun, Nodes) -> trans(Id, Fun, Nodes, infinity).
--spec trans(id(), trans_fun(), [node()], retries()) -> term().
+-spec trans(Id, Fun, Nodes, Retries) -> Res | aborted when
+ Id :: id(),
+ Fun :: trans_fun(),
+ Nodes :: [node()],
+ Retries :: retries(),
+ Res :: term().
trans(Id, Fun, Nodes, Retries) ->
case set_lock(Id, Nodes, Retries) of
true ->
@@ -397,6 +438,9 @@ info() ->
%%%-----------------------------------------------------------------
%%% Call-back functions from gen_server
%%%-----------------------------------------------------------------
+
+-spec init([]) -> {'ok', state()}.
+
init([]) ->
process_flag(trap_exit, true),
_ = ets:new(global_locks, [set, named_table, protected]),
@@ -418,7 +462,6 @@ init([]) ->
S = #state{the_locker = start_the_locker(DoTrace),
trace = T0,
- the_deleter = start_the_deleter(self()),
the_registrar = start_the_registrar()},
S1 = trace_message(S, {init, node()}, []),
@@ -541,6 +584,11 @@ init([]) ->
%% sent by each node to all new nodes (Node becomes known to them)
%%-----------------------------------------------------------------
+-spec handle_call(term(), {pid(), term()}, state()) ->
+ {'noreply', state()} |
+ {'reply', term(), state()} |
+ {'stop', 'normal', 'stopped', state()}.
+
handle_call({whereis, Name}, From, S) ->
do_whereis(Name, From),
{noreply, S};
@@ -620,6 +668,9 @@ handle_call(Request, From, S) ->
%% init_connect
%%
%%========================================================================
+
+-spec handle_cast(term(), state()) -> {'noreply', state()}.
+
handle_cast({init_connect, Vsn, Node, InitMsg}, S) ->
%% Sent from global_name_server at Node.
?trace({'####', init_connect, {vsn, Vsn}, {node,Node},{initmsg,InitMsg}}),
@@ -763,13 +814,16 @@ handle_cast({in_sync, Node, _IsKnown}, S) ->
%% Called when Pid on other node crashed
handle_cast({async_del_name, _Name, _Pid}, S) ->
- %% Sent from the_deleter at some node in the partition but node().
+ %% Sent from the_deleter at some node in the partition but node() (-R13B)
%% The DOWN message deletes the name.
+ %% R14A nodes and later do not send async_del_name messages.
{noreply, S};
handle_cast({async_del_lock, _ResourceId, _Pid}, S) ->
- %% Sent from global_name_server at some node in the partition but node().
+ %% Sent from global_name_server at some node in the partition but
+ %% node(). (-R13B)
%% The DOWN message deletes the lock.
+ %% R14A nodes and later do not send async_del_lock messages.
{noreply, S};
handle_cast(Request, S) ->
@@ -778,8 +832,11 @@ handle_cast(Request, S) ->
"handle_cast(~p, _)\n", [Request]),
{noreply, S}.
-handle_info({'EXIT', Deleter, _Reason}=Exit, #state{the_deleter=Deleter}=S) ->
- {stop, {deleter_died,Exit}, S#state{the_deleter=undefined}};
+%%========================================================================
+
+-spec handle_info(term(), state()) ->
+ {'noreply', state()} | {'stop', term(), state()}.
+
handle_info({'EXIT', Locker, _Reason}=Exit, #state{the_locker=Locker}=S) ->
{stop, {locker_died,Exit}, S#state{the_locker=undefined}};
handle_info({'EXIT', Registrar, _}=Exit, #state{the_registrar=Registrar}=S) ->
@@ -1120,12 +1177,17 @@ do_whereis(Name, From) ->
send_again({whereis, Name, From})
end.
+-spec terminate(term(), state()) -> 'ok'.
+
terminate(_Reason, _S) ->
true = ets:delete(global_names),
true = ets:delete(global_names_ext),
true = ets:delete(global_locks),
true = ets:delete(global_pid_names),
- true = ets:delete(global_pid_ids).
+ true = ets:delete(global_pid_ids),
+ ok.
+
+-spec code_change(term(), state(), term()) -> {'ok', state()}.
code_change(_OldVsn, S, _Extra) ->
{ok, S}.
@@ -1348,30 +1410,13 @@ lock_still_set(PidOrNode, ExtraInfo, S) ->
[{?GLOBAL_RID, _LockReqId, PidRefs}] when is_pid(PidOrNode) ->
%% Name registration.
lists:keymember(PidOrNode, 1, PidRefs);
- [{?GLOBAL_RID, LockReqId, PidRefs}] when is_atom(PidOrNode) ->
- case extra_info(lock, ExtraInfo) of
- {?GLOBAL_RID, LockId} -> % R11B-4 or later
- LockReqId =:= LockId;
- undefined ->
- lock_still_set_old(PidOrNode, LockReqId, PidRefs)
- end;
+ [{?GLOBAL_RID, LockReqId, _PidRefs}] when is_atom(PidOrNode) ->
+ {?GLOBAL_RID, LockId} = extra_info(lock, ExtraInfo),
+ LockReqId =:= LockId;
[] ->
- %% If the global lock was not removed by a DOWN message
- %% then we have a node that do not monitor locking pids
- %% (pre R11B-3), or an R11B-3 node (which does not ensure
- %% that {new_nodes, ...} arrives before {del_lock, ...}).
not S#state.global_lock_down
end.
-%%% The following is probably overkill. It is possible that this node
-%%% has been locked again, but it is a rare occasion.
-lock_still_set_old(_Node, ReqId, _PidRefs) when is_pid(ReqId) ->
- %% Cannot do better than return true.
- true;
-lock_still_set_old(Node, ReqId, PidRefs) when is_list(ReqId) ->
- %% Connection, version > 4, but before R11B-4.
- [P || {P, _RPid, _Ref} <- PidRefs, node(P) =:= Node] =/= [].
-
extra_info(Tag, ExtraInfo) ->
%% ExtraInfo used to be a list of nodes (vsn 2).
case catch lists:keyfind(Tag, 1, ExtraInfo) of
@@ -1382,36 +1427,18 @@ extra_info(Tag, ExtraInfo) ->
end.
del_name(Ref, S) ->
- NameL = [{Name, Pid} ||
+ NameL = [Name ||
{_, Name} <- ets:lookup(global_pid_names, Ref),
- {_, Pid, _Method, _RPid, Ref1} <-
+ {_, _Pid, _Method, _RPid, Ref1} <-
ets:lookup(global_names, Name),
Ref1 =:= Ref],
- ?trace({async_del_name, self(), NameL, Ref}),
case NameL of
- [{Name, Pid}] ->
- _ = del_names(Name, Pid, S),
+ [Name] ->
delete_global_name2(Name, S);
[] ->
S
end.
-%% Send {async_del_name, ...} to old nodes (pre R11B-3).
-del_names(Name, Pid, S) ->
- Send = case ets:lookup(global_names_ext, Name) of
- [{Name, Pid, RegNode}] ->
- RegNode =:= node();
- [] ->
- node(Pid) =:= node()
- end,
- if
- Send ->
- ?trace({del_names, {pid,Pid}, {name,Name}}),
- S#state.the_deleter ! {delete_name, self(), Name, Pid};
- true ->
- ok
- end.
-
%% Keeps the entry in global_names for whereis_name/1.
delete_global_name_keep_pid(Name, S) ->
case ets:lookup(global_names, Name) of
@@ -1939,7 +1966,10 @@ resolve_it(Method, Name, Pid1, Pid2) ->
minmax(P1,P2) ->
if node(P1) < node(P2) -> {P1, P2}; true -> {P2, P1} end.
--spec random_exit_name(term(), pid(), pid()) -> pid().
+-spec random_exit_name(Name, Pid1, Pid2) -> 'none' when
+ Name :: term(),
+ Pid1 :: pid(),
+ Pid2 :: pid().
random_exit_name(Name, Pid, Pid2) ->
{Min, Max} = minmax(Pid, Pid2),
error_logger:info_msg("global: Name conflict terminating ~w\n",
@@ -1947,12 +1977,19 @@ random_exit_name(Name, Pid, Pid2) ->
exit(Max, kill),
Min.
+-spec random_notify_name(Name, Pid1, Pid2) -> 'none' when
+ Name :: term(),
+ Pid1 :: pid(),
+ Pid2 :: pid().
random_notify_name(Name, Pid, Pid2) ->
{Min, Max} = minmax(Pid, Pid2),
Max ! {global_name_conflict, Name},
Min.
--spec notify_all_name(term(), pid(), pid()) -> 'none'.
+-spec notify_all_name(Name, Pid1, Pid2) -> 'none' when
+ Name :: term(),
+ Pid1 :: pid(),
+ Pid2 :: pid().
notify_all_name(Name, Pid, Pid2) ->
Pid ! {global_name_conflict, Name, Pid2},
Pid2 ! {global_name_conflict, Name, Pid},
@@ -1986,10 +2023,9 @@ pid_is_locking(Pid, PidRefs) ->
delete_lock(Ref, S0) ->
Locks = pid_locks(Ref),
- del_locks(Locks, Ref, S0#state.known),
F = fun({ResourceId, LockRequesterId, PidRefs}, S) ->
{Pid, _RPid, Ref} = lists:keyfind(Ref, 3, PidRefs),
- remove_lock(ResourceId, LockRequesterId, Pid, PidRefs, true,S)
+ remove_lock(ResourceId, LockRequesterId, Pid, PidRefs, true, S)
end,
lists:foldl(F, S0, Locks).
@@ -2003,20 +2039,6 @@ pid_locks(Ref) ->
rpid_is_locking(Ref, PidRefs) ->
lists:keyfind(Ref, 3, PidRefs) =/= false.
-%% Send {async_del_lock, ...} to old nodes (pre R11B-3).
-del_locks([{ResourceId, _LockReqId, PidRefs} | Tail], Ref, KnownNodes) ->
- {Pid, _RPid, Ref} = lists:keyfind(Ref, 3, PidRefs),
- case node(Pid) =:= node() of
- true ->
- gen_server:abcast(KnownNodes, global_name_server,
- {async_del_lock, ResourceId, Pid});
- false ->
- ok
- end,
- del_locks(Tail, Ref, KnownNodes);
-del_locks([], _Ref, _KnownNodes) ->
- ok.
-
handle_nodedown(Node, S) ->
%% DOWN signals from monitors have removed locks and registered names.
#state{known = Known, synced = Syncs} = S,
@@ -2147,51 +2169,6 @@ get_own_nodes() ->
OkTup
end.
-%%-----------------------------------------------------------------
-%% The deleter process is a satellite process to global_name_server
-%% that does background batch deleting of names when a process
-%% that had globally registered names dies. It is started by and
-%% linked to global_name_server.
-%%-----------------------------------------------------------------
-
-start_the_deleter(Global) ->
- spawn_link(fun() -> loop_the_deleter(Global) end).
-
-loop_the_deleter(Global) ->
- Deletions = collect_deletions(Global, []),
- ?trace({loop_the_deleter, self(), {deletions,Deletions},
- {names,get_names()}}),
- %% trans_all_known is called rather than trans/3 with nodes() as
- %% third argument. The reason is that known gets updated by
- %% new_nodes when the lock is still set. nodes() on the other hand
- %% could be updated later (if in_sync is received after the lock
- %% is gone). It is not likely that in_sync would be received after
- %% the lock has been taken here, but using trans_all_known makes it
- %% even less likely.
- trans_all_known(
- fun(Known) ->
- lists:map(
- fun({Name,Pid}) ->
- gen_server:abcast(Known, global_name_server,
- {async_del_name, Name, Pid})
- end, Deletions)
- end),
- loop_the_deleter(Global).
-
-collect_deletions(Global, Deletions) ->
- receive
- {delete_name, Global, Name, Pid} ->
- collect_deletions(Global, [{Name,Pid} | Deletions]);
- Other ->
- unexpected_message(Other, deleter),
- collect_deletions(Global, Deletions)
- after case Deletions of
- [] -> infinity;
- _ -> 0
- end ->
- lists:reverse(Deletions)
- end.
-
%% The registrar is a helper process that registers and unregisters
%% names. Since it never dies it assures that names are registered and
%% unregistered on all known nodes. It is started by and linked to
diff --git a/lib/kernel/src/global_group.erl b/lib/kernel/src/global_group.erl
index 7e141ac5c7..025a9b8a5b 100644
--- a/lib/kernel/src/global_group.erl
+++ b/lib/kernel/src/global_group.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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
@@ -62,9 +62,10 @@
-type sync_state() :: 'no_conf' | 'synced'.
-type group_name() :: atom().
--type group_tuple() :: {group_name(), [node()]}
- | {group_name(), publish_type(), [node()]}.
-
+-type group_tuple() :: {GroupName :: group_name(), [node()]}
+ | {GroupName :: group_name(),
+ PublishType :: publish_type(),
+ [node()]}.
%%%====================================================================================
%%% The state of the global_group process
@@ -97,11 +98,14 @@
%%% External exported
%%%====================================================================================
--spec global_groups() -> {group_name(), [group_name()]} | 'undefined'.
+-spec global_groups() -> {GroupName, GroupNames} | undefined when
+ GroupName :: group_name(),
+ GroupNames :: [GroupName].
global_groups() ->
request(global_groups).
--spec monitor_nodes(boolean()) -> 'ok'.
+-spec monitor_nodes(Flag) -> 'ok' when
+ Flag :: boolean().
monitor_nodes(Flag) ->
case Flag of
true -> request({monitor_nodes, Flag});
@@ -109,30 +113,41 @@ monitor_nodes(Flag) ->
_ -> {error, not_boolean}
end.
--spec own_nodes() -> [node()].
+-spec own_nodes() -> Nodes when
+ Nodes :: [Node :: node()].
own_nodes() ->
request(own_nodes).
-type name() :: atom().
-type where() :: {'node', node()} | {'group', group_name()}.
--spec registered_names(where()) -> [name()].
+-spec registered_names(Where) -> Names when
+ Where :: where(),
+ Names :: [Name :: name()].
registered_names(Arg) ->
request({registered_names, Arg}).
--spec send(name(), term()) -> pid() | {'badarg', {name(), term()}}.
+-spec send(Name, Msg) -> pid() | {'badarg', {Name, Msg}} when
+ Name :: name(),
+ Msg :: term().
send(Name, Msg) ->
request({send, Name, Msg}).
--spec send(where(), name(), term()) -> pid() | {'badarg', {name(), term()}}.
+-spec send(Where, Name, Msg) -> pid() | {'badarg', {Name, Msg}} when
+ Where :: where(),
+ Name :: name(),
+ Msg :: term().
send(Group, Name, Msg) ->
request({send, Group, Name, Msg}).
--spec whereis_name(name()) -> pid() | 'undefined'.
+-spec whereis_name(Name) -> pid() | 'undefined' when
+ Name :: name().
whereis_name(Name) ->
request({whereis_name, Name}).
--spec whereis_name(where(), name()) -> pid() | 'undefined'.
+-spec whereis_name(Where, Name) -> pid() | 'undefined' when
+ Where :: where(),
+ Name :: name().
whereis_name(Group, Name) ->
request({whereis_name, Group, Name}).
@@ -155,14 +170,14 @@ ng_add_check(Node, OthersNG) ->
ng_add_check(Node, PubType, OthersNG) ->
request({ng_add_check, Node, PubType, OthersNG}).
--type info_item() :: {'state', sync_state()}
- | {'own_group_name', group_name()}
- | {'own_group_nodes', [node()]}
- | {'synched_nodes', [node()]}
- | {'sync_error', [node()]}
- | {'no_contact', [node()]}
- | {'other_groups', [group_tuple()]}
- | {'monitoring', [pid()]}.
+-type info_item() :: {'state', State :: sync_state()}
+ | {'own_group_name', GroupName :: group_name()}
+ | {'own_group_nodes', Nodes :: [node()]}
+ | {'synched_nodes', Nodes :: [node()]}
+ | {'sync_error', Nodes :: [node()]}
+ | {'no_contact', Nodes :: [node()]}
+ | {'other_groups', Groups :: [group_tuple()]}
+ | {'monitoring', Pids :: [pid()]}.
-spec info() -> [info_item()].
info() ->
@@ -1012,6 +1027,7 @@ grp_tuple({Name, normal, Nodes}) ->
%%% The special process which checks that all nodes in the own global group
%%% agrees on the configuration.
%%%====================================================================================
+-spec sync_init(_, _, _, _) -> no_return().
sync_init(Type, Cname, PubType, Nodes) ->
{Up, Down} = sync_check_node(lists:delete(node(), Nodes), [], []),
sync_check_init(Type, Up, Cname, Nodes, Down, PubType).
@@ -1032,9 +1048,11 @@ sync_check_node([Node|Nodes], Up, Down) ->
%%% Check that all nodes are in agreement of the global
%%% group configuration.
%%%-------------------------------------------------------------
+-spec sync_check_init(_, _, _, _, _, _) -> no_return().
sync_check_init(Type, Up, Cname, Nodes, Down, PubType) ->
sync_check_init(Type, Up, Cname, Nodes, 3, [], Down, PubType).
+-spec sync_check_init(_, _, _, _, _, _, _, _) -> no_return().
sync_check_init(_Type, NoContact, _Cname, _Nodes, 0, ErrorNodes, Down, _PubType) ->
case ErrorNodes of
[] ->
diff --git a/lib/kernel/src/global_search.erl b/lib/kernel/src/global_search.erl
index b723e18a1b..0bf53e29b8 100644
--- a/lib/kernel/src/global_search.erl
+++ b/lib/kernel/src/global_search.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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
@@ -69,6 +69,7 @@ start(Flag, Arg) ->
%%%====================================================================================
%%%====================================================================================
+-spec init_send(_) -> no_return().
init_send({any, NodesList, Name, Msg, From}) ->
case whereis_any_loop(NodesList, Name) of
undefined ->
@@ -115,6 +116,7 @@ init_send({node, Node, Name, Msg, From}) ->
%%%====================================================================================
%%%====================================================================================
+-spec init_whereis(_) -> no_return().
init_whereis({any, NodesList, Name, From}) ->
R = whereis_any_loop(NodesList, Name),
gen_server:cast(global_group, {find_name_res, R, self(), From}),
@@ -146,6 +148,7 @@ init_whereis({node, Node, Name, From}) ->
%%%====================================================================================
%%%====================================================================================
%%%====================================================================================
+-spec init_names(_) -> no_return().
init_names({group, Nodes, From}) ->
case names_group_loop(Nodes) of
group_down ->
diff --git a/lib/kernel/src/group.erl b/lib/kernel/src/group.erl
index a45ba34eae..f92c6f7208 100644
--- a/lib/kernel/src/group.erl
+++ b/lib/kernel/src/group.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(group).
@@ -477,15 +477,15 @@ get_line(Chars, Pbs, Drv, Encoding) ->
get_line1(edlin:edit_line(Chars, Cont), Drv, new_stack(get(line_buffer)),
Encoding).
-get_line1({done,Line,Rest,Rs}, Drv, _Ls, _Encoding) ->
+get_line1({done,Line,Rest,Rs}, Drv, Ls, _Encoding) ->
send_drv_reqs(Drv, Rs),
- put(line_buffer, [Line|lists:delete(Line, get(line_buffer))]),
+ save_line_buffer(Line, get_lines(Ls)),
{done,Line,Rest};
get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Ls0, Encoding)
when ((Mode =:= none) and (Char =:= $\^P))
or ((Mode =:= meta_left_sq_bracket) and (Char =:= $A)) ->
send_drv_reqs(Drv, Rs),
- case up_stack(Ls0) of
+ case up_stack(save_line(Ls0, edlin:current_line(Cont))) of
{none,_Ls} ->
send_drv(Drv, beep),
get_line1(edlin:edit_line(Cs, Cont), Drv, Ls0, Encoding);
@@ -498,14 +498,14 @@ get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Ls0, Encoding)
Drv,
Ls, Encoding)
end;
-get_line1({undefined,{_A,Mode,Char},_Cs,Cont,Rs}, Drv, Ls0, Encoding)
+get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Ls0, Encoding)
when ((Mode =:= none) and (Char =:= $\^N))
or ((Mode =:= meta_left_sq_bracket) and (Char =:= $B)) ->
send_drv_reqs(Drv, Rs),
- case down_stack(Ls0) of
- {none,Ls} ->
- send_drv_reqs(Drv, edlin:erase_line(Cont)),
- get_line1(edlin:start(edlin:prompt(Cont)), Drv, Ls, Encoding);
+ case down_stack(save_line(Ls0, edlin:current_line(Cont))) of
+ {none,_Ls} ->
+ send_drv(Drv, beep),
+ get_line1(edlin:edit_line(Cs, Cont), Drv, Ls0, Encoding);
{Lcs,Ls} ->
send_drv_reqs(Drv, edlin:erase_line(Cont)),
{more_chars,Ncont,Nrs} = edlin:start(edlin:prompt(Cont)),
@@ -627,6 +627,28 @@ down_stack({stack,U,{},[]}) ->
down_stack({stack,U,C,D}) ->
down_stack({stack,[C|U],{},D}).
+save_line({stack, U, {}, []}, Line) ->
+ {stack, U, {}, [Line]};
+save_line({stack, U, _L, D}, Line) ->
+ {stack, U, Line, D}.
+
+get_lines({stack, U, {}, []}) ->
+ U;
+get_lines({stack, U, {}, D}) ->
+ tl(lists:reverse(D, U));
+get_lines({stack, U, L, D}) ->
+ get_lines({stack, U, {}, [L|D]}).
+
+save_line_buffer("\n", Lines) ->
+ save_line_buffer(Lines);
+save_line_buffer(Line, [Line|_Lines]=Lines) ->
+ save_line_buffer(Lines);
+save_line_buffer(Line, Lines) ->
+ save_line_buffer([Line|Lines]).
+
+save_line_buffer(Lines) ->
+ put(line_buffer, Lines).
+
%% This is get_line without line editing (except for backspace) and
%% without echo.
get_password_line(Chars, Drv) ->
diff --git a/lib/kernel/src/heart.erl b/lib/kernel/src/heart.erl
index bad0950fca..255ae4e51b 100644
--- a/lib/kernel/src/heart.erl
+++ b/lib/kernel/src/heart.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-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(heart).
@@ -61,8 +61,8 @@ start() ->
wait_for_init_ack(From) ->
receive
- {ok, From} ->
- {ok, From};
+ {ok, From} = Ok ->
+ Ok;
{no_heart, From} ->
ignore;
{Error, From} ->
@@ -85,19 +85,21 @@ init(Starter, Parent) ->
Starter ! {start_error, self()}
end.
--spec set_cmd(string()) -> 'ok' | {'error', {'bad_cmd', string()}}.
+-spec set_cmd(Cmd) -> 'ok' | {'error', {'bad_cmd', Cmd}} when
+ Cmd :: string().
set_cmd(Cmd) ->
heart ! {self(), set_cmd, Cmd},
wait().
--spec get_cmd() -> 'ok'.
+-spec get_cmd() -> {ok, Cmd} when
+ Cmd :: string().
get_cmd() ->
heart ! {self(), get_cmd},
wait().
--spec clear_cmd() -> {'ok', string()}.
+-spec clear_cmd() -> ok.
clear_cmd() ->
heart ! {self(), clear_cmd},
@@ -119,8 +121,7 @@ wait() ->
start_portprogram() ->
check_start_heart(),
- HeartCmd = "heart -pid " ++ os:getpid() ++ " " ++
- get_heart_timeouts(),
+ HeartCmd = "heart -pid " ++ os:getpid() ++ " " ++ get_heart_timeouts(),
try open_port({spawn, HeartCmd}, [{packet, 2}]) of
Port when is_port(Port) ->
case wait_ack(Port) of
@@ -175,7 +176,7 @@ wait_ack(Port) ->
loop(Parent, Port, Cmd) ->
send_heart_beat(Port),
receive
- {From, set_cmd, NewCmd} when is_list(NewCmd), length(NewCmd) < 2047 ->
+ {From, set_cmd, NewCmd} when length(NewCmd) < 2047 ->
send_heart_cmd(Port, NewCmd),
wait_ack(Port),
From ! {heart, ok},
diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl
index f289b8110d..1d3eb926ca 100644
--- a/lib/kernel/src/hipe_unified_loader.erl
+++ b/lib/kernel/src/hipe_unified_loader.erl
@@ -258,7 +258,7 @@ find_callee_mfas(Patches) when is_list(Patches) ->
amd64 -> [];
arm -> find_callee_mfas(Patches, gb_sets:empty(), false);
powerpc -> find_callee_mfas(Patches, gb_sets:empty(), true);
- %% ppc64 -> find_callee_mfas(Patches, gb_sets:empty(), true);
+ ppc64 -> find_callee_mfas(Patches, gb_sets:empty(), true);
ultrasparc -> [];
x86 -> []
end.
@@ -301,6 +301,7 @@ mk_trampoline_map(CalleeMFAs, Trampolines) ->
SizeofLong =
case erlang:system_info(hipe_architecture) of
amd64 -> 8;
+ ppc64 -> 8;
_ -> 4
end,
mk_trampoline_map(tuple_size(CalleeMFAs), CalleeMFAs,
@@ -625,15 +626,15 @@ patch_instr(Address, Value, Type) ->
%%
%% XXX: It appears this is used for inserting both code addresses
%% and other data. In HiPE, code addresses are still 32-bit on
-%% 64-bit machines.
+%% some 64-bit machines.
write_word(DataAddress, DataWord) ->
case erlang:system_info(hipe_architecture) of
amd64 ->
hipe_bifs:write_u64(DataAddress, DataWord),
DataAddress+8;
- %% ppc64 ->
- %% hipe_bifs:write_u64(DataAddress, DataWord),
- %% DataAddress+8;
+ ppc64 ->
+ hipe_bifs:write_u64(DataAddress, DataWord),
+ DataAddress+8;
_ ->
hipe_bifs:write_u32(DataAddress, DataWord),
DataAddress+4
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index eb503235d8..48a6f3db65 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -25,6 +25,7 @@
%% socket
-export([peername/1, sockname/1, port/1, send/2,
setopts/2, getopts/2,
+ getifaddrs/0, getifaddrs/1,
getif/1, getif/0, getiflist/0, getiflist/1,
ifget/3, ifget/2, ifset/3, ifset/2,
getstat/1, getstat/2,
@@ -62,6 +63,10 @@
%% timer interface
-export([start_timer/1, timeout/1, timeout/2, stop_timer/1]).
+-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]).
@@ -76,97 +81,22 @@
%%% ---------------------------------
%%% Contract type definitions
+
+-type hostent() :: #hostent{}.
+-type hostname() :: atom() | string().
+-type ip4_address() :: {0..255,0..255,0..255,0..255}.
+-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 port_number() :: 0..65535.
+-type posix() :: exbadport | exbadseq | file:posix().
-type socket() :: port().
--type posix() :: atom().
-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() ::
@@ -184,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' |
@@ -192,12 +122,13 @@
%%% ---------------------------------
--spec get_rc() -> [{any(),any()}].
+-spec get_rc() -> [{Par :: any(), Val :: any()}].
get_rc() ->
inet_db:get_rc().
--spec close(Socket :: socket()) -> 'ok'.
+-spec close(Socket) -> 'ok' when
+ Socket :: socket().
close(Socket) ->
prim_inet:close(Socket),
@@ -208,13 +139,15 @@ close(Socket) ->
ok
end.
--spec peername(Socket :: socket()) ->
- {'ok', {ip_address(), non_neg_integer()}} | {'error', posix()}.
+-spec peername(Socket) -> {ok, {Address, Port}} | {error, posix()} when
+ Socket :: socket(),
+ Address :: ip_address(),
+ Port :: non_neg_integer().
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}) ->
@@ -223,13 +156,15 @@ setpeername(Socket, undefined) ->
prim_inet:setpeername(Socket, undefined).
--spec sockname(Socket :: socket()) ->
- {'ok', {ip_address(), non_neg_integer()}} | {'error', posix()}.
+-spec sockname(Socket) -> {ok, {Address, Port}} | {error, posix()} when
+ Socket :: socket(),
+ Address :: ip_address(),
+ Port :: non_neg_integer().
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}) ->
@@ -237,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
@@ -251,18 +188,45 @@ 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 :: socket(), Opts :: [socket_getopt()]) ->
- {'ok', [socket_setopt()]} | {'error', posix()}.
+-spec getopts(Socket, Options) ->
+ {'ok', OptionValues} | {'error', posix()} when
+ Socket :: socket(),
+ Options :: [socket_getopt()],
+ OptionValues :: [socket_setopt()].
getopts(Socket, Opts) ->
prim_inet:getopts(Socket, Opts).
+-spec getifaddrs(Socket :: socket()) ->
+ {'ok', [string()]} | {'error', posix()}.
+
+getifaddrs(Socket) ->
+ prim_inet:getifaddrs(Socket).
+
+-spec getifaddrs() -> {ok, Iflist} | {error, posix()} when
+ Iflist :: [{Ifname,[Ifopt]}],
+ Ifname :: string(),
+ Ifopt :: {flag,[Flag]} | {addr,Addr} | {netmask,Netmask}
+ | {broadaddr,Broadaddr} | {dstaddr,Dstaddr}
+ | {hwaddr,Hwaddr},
+ Flag :: up | broadcast | loopback | pointtopoint
+ | running | multicast,
+ Addr :: ip_address(),
+ Netmask :: ip_address(),
+ Broadaddr :: ip_address(),
+ Dstaddr :: ip_address(),
+ Hwaddr :: [byte()].
+
+getifaddrs() ->
+ withsocket(fun(S) -> prim_inet:getifaddrs(S) end).
+
-spec getiflist(Socket :: socket()) ->
{'ok', [string()]} | {'error', posix()}.
@@ -357,7 +321,8 @@ popf(_Socket) ->
% use of the DHCP-protocol
% should never fail
--spec gethostname() -> {'ok', string()}.
+-spec gethostname() -> {'ok', Hostname} when
+ Hostname :: string().
gethostname() ->
case inet_udp:open(0,[]) of
@@ -376,32 +341,41 @@ 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).
--spec gethostbyname(Name :: string() | atom()) ->
- {'ok', #hostent{}} | {'error', posix()}.
+-spec gethostbyname(Hostname) -> {ok, Hostent} | {error, posix()} when
+ Hostname :: hostname(),
+ Hostent :: hostent().
gethostbyname(Name) ->
gethostbyname_tm(Name, inet, false).
--spec gethostbyname(Name :: string() | atom(), Family :: family_option()) ->
- {'ok', #hostent{}} | {'error', posix()}.
+-spec gethostbyname(Hostname, Family) ->
+ {ok, Hostent} | {error, posix()} when
+ Hostname :: hostname(),
+ Family :: address_family(),
+ Hostent :: hostent().
gethostbyname(Name,Family) ->
gethostbyname_tm(Name, Family, false).
--spec gethostbyname(Name :: string() | atom(),
- Family :: family_option(),
+-spec gethostbyname(Name :: hostname(),
+ Family :: address_family(),
Timeout :: non_neg_integer() | 'infinity') ->
{'ok', #hostent{}} | {'error', posix()}.
@@ -425,8 +399,9 @@ gethostbyname_tm(Name,Family,Timer) ->
gethostbyname_tm(Name, Family, Timer, Opts).
--spec gethostbyaddr(Address :: string() | ip_address()) ->
- {'ok', #hostent{}} | {'error', posix()}.
+-spec gethostbyaddr(Address) -> {ok, Hostent} | {error, posix()} when
+ Address :: string() | ip_address(),
+ Hostent :: hostent().
gethostbyaddr(Address) ->
gethostbyaddr_tm(Address, false).
@@ -477,15 +452,16 @@ getfd(Socket) ->
%% Lookup an ip address
%%
--spec getaddr(Host :: ip_address() | string() | atom(),
- Family :: family_option()) ->
- {'ok', ip_address()} | {'error', posix()}.
+-spec getaddr(Host, Family) -> {ok, Address} | {error, posix()} when
+ Host :: ip_address() | hostname(),
+ Family :: address_family(),
+ Address :: ip_address().
getaddr(Address, Family) ->
getaddr(Address, Family, infinity).
--spec getaddr(Host :: ip_address() | string() | atom(),
- Family :: family_option(),
+-spec getaddr(Host :: ip_address() | hostname(),
+ Family :: address_family(),
Timeout :: non_neg_integer() | 'infinity') ->
{'ok', ip_address()} | {'error', posix()}.
@@ -501,15 +477,17 @@ getaddr_tm(Address, Family, Timer) ->
Error -> Error
end.
--spec getaddrs(Host :: ip_address() | string() | atom(),
- Family :: family_option()) ->
- {'ok', [ip_address()]} | {'error', posix()}.
+-spec getaddrs(Host, Family) ->
+ {ok, Addresses} | {error, posix()} when
+ Host :: ip_address() | hostname(),
+ 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()}.
@@ -519,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) ->
@@ -533,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
@@ -1016,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',
@@ -1057,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()}.
@@ -1223,7 +1201,8 @@ port_list(Name) ->
%% utils
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec format_error(posix()) -> string().
+-spec format_error(Posix) -> string() when
+ Posix :: posix().
format_error(exbadport) -> "invalid port state";
format_error(exbadseq) -> "bad command sequence";
diff --git a/lib/kernel/src/inet6_sctp.erl b/lib/kernel/src/inet6_sctp.erl
index 5c49c4fec3..5bf3fca647 100644
--- a/lib/kernel/src/inet6_sctp.erl
+++ b/lib/kernel/src/inet6_sctp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2010. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -32,7 +32,7 @@
-define(FAMILY, inet6).
-export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]).
--export([open/1,close/1,listen/2,connect/5,sendmsg/3,recv/2]).
+-export([open/1,close/1,listen/2,connect/5,sendmsg/3,send/4,recv/2]).
@@ -71,5 +71,24 @@ connect(S, Addr, Port, Opts, Timer) ->
sendmsg(S, SRI, Data) ->
prim_inet:sendmsg(S, SRI, Data).
+send(S, AssocId, Stream, Data) ->
+ case prim_inet:getopts(
+ S,
+ [{sctp_default_send_param,#sctp_sndrcvinfo{assoc_id=AssocId}}]) of
+ {ok,
+ [{sctp_default_send_param,
+ #sctp_sndrcvinfo{
+ flags=Flags, context=Context, ppid=PPID, timetolive=TTL}}]} ->
+ prim_inet:sendmsg(
+ S,
+ #sctp_sndrcvinfo{
+ flags=Flags, context=Context, ppid=PPID, timetolive=TTL,
+ assoc_id=AssocId, stream=Stream},
+ Data);
+ _ ->
+ prim_inet:sendmsg(
+ S, #sctp_sndrcvinfo{assoc_id=AssocId, stream=Stream}, Data)
+ end.
+
recv(S, Timeout) ->
prim_inet:recvfrom(S, 0, Timeout).
diff --git a/lib/kernel/src/inet6_tcp_dist.erl b/lib/kernel/src/inet6_tcp_dist.erl
index 34cf582af7..b9c4fa607c 100644
--- a/lib/kernel/src/inet6_tcp_dist.erl
+++ b/lib/kernel/src/inet6_tcp_dist.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-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(inet6_tcp_dist).
@@ -87,7 +87,7 @@ accept(Listen) ->
accept_loop(Kernel, Listen) ->
case inet6_tcp:accept(Listen) of
{ok, Socket} ->
- Kernel ! {accept,self(),Socket,inet,tcp},
+ Kernel ! {accept,self(),Socket,inet6,tcp},
controller(Kernel, Socket),
accept_loop(Kernel, Listen);
Error ->
@@ -162,8 +162,8 @@ do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
inet:getll(S)
end,
f_address = fun get_remote_id/2,
- mf_tick = {?MODULE, tick},
- mf_getstat = {?MODULE,getstat}
+ mf_tick = fun ?MODULE:tick/1,
+ mf_getstat = fun ?MODULE:getstat/1
},
dist_util:handshake_other_started(HSData);
{false,IP} ->
@@ -236,8 +236,8 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
timer = Timer,
this_flags = 0,
other_version = Version,
- f_send = fun inet_tcp:send/2,
- f_recv = fun inet_tcp:recv/3,
+ f_send = fun inet6_tcp:send/2,
+ f_recv = fun inet6_tcp:recv/3,
f_setopts_pre_nodeup =
fun(S) ->
inet:setopts
@@ -262,7 +262,7 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
address = {Ip,TcpPort},
host = Address,
protocol = tcp,
- family = inet}
+ family = inet6}
end,
mf_tick = fun ?MODULE:tick/1,
mf_getstat = fun ?MODULE:getstat/1,
@@ -302,12 +302,17 @@ splitnode(Node, LongOrShortNames) ->
Host = lists:append(Tail),
case split_node(Host, $., []) of
[_] when LongOrShortNames =:= longnames ->
- error_msg("** System running to use "
- "fully qualified "
- "hostnames **~n"
- "** Hostname ~s is illegal **~n",
- [Host]),
- ?shutdown(Node);
+ case inet_parse:ipv6strict_address(Host) of
+ {ok, _} ->
+ [Name, Host];
+ _ ->
+ error_msg("** System running to use "
+ "fully qualified "
+ "hostnames **~n"
+ "** Hostname ~s is illegal **~n",
+ [Host]),
+ ?shutdown(Node)
+ end;
L when length(L) > 1, LongOrShortNames =:= shortnames ->
error_msg("** System NOT running to use fully qualified "
"hostnames **~n"
diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl
index 311e6bc9f9..1ddbdcec25 100644
--- a/lib/kernel/src/inet_config.erl
+++ b/lib/kernel/src/inet_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -23,6 +23,8 @@
-import(lists, [foreach/2, member/2, reverse/1]).
+%% Avoid warning for local function error/2 clashing with autoimported BIF.
+-compile({no_auto_import,[error/2]}).
-export([init/0]).
-export([do_load_resolv/2]).
@@ -42,26 +44,6 @@
%%
-spec init() -> 'ok'.
init() ->
- OsType = os:type(),
- case OsType of
- {ose,_} ->
- case init:get_argument(loader) of
- {ok,[["ose_inet"]]} ->
- %% port already started by prim_loader
- ok;
- _Other ->
- %% Setup reserved port for ose_inet driver (only OSE)
- case catch erlang:open_port({spawn,"ose_inet"}, [binary]) of
- {'EXIT',Why} ->
- error("can't open port for ose_inet: ~p", [Why]);
- OseInetPort ->
- erlang:display({ose_inet_port,OseInetPort})
- end
- end;
- _ ->
- ok
- end,
-
set_hostname(),
%% Note: In shortnames (or non-distributed) mode we don't need to know
@@ -69,6 +51,7 @@ init() ->
%% the user to provide it (by means of inetrc), so we need to look
%% for it ourselves.
+ OsType = os:type(),
do_load_resolv(OsType, erl_dist_mode()),
case OsType of
@@ -224,35 +207,6 @@ do_load_resolv(vxworks, _) ->
load_resolv(Resolv, resolv)
end;
-do_load_resolv({ose,_Type}, _) ->
- inet_db:set_lookup([file, dns]),
- case os:getenv("NAMESERVER") of
- false ->
- case os:getenv("RESOLVFILE") of
- false ->
- erlang:display('Warning: No NAMESERVER or RESOLVFILE specified!'),
- no_resolv;
- Resolv ->
- load_resolv(Resolv, resolv)
- end;
- Ns ->
- {ok,IP} = inet_parse:address(Ns),
- inet_db:add_rc_list([{nameserver,IP}])
- end,
- case os:getenv("DOMAIN") of
- false ->
- no_domain;
- D ->
- ok = inet_db:add_rc_list([{domain,D}])
- end,
- case os:getenv("HOSTSFILE") of
- false ->
- erlang:display('Warning: No HOSTSFILE specified!'),
- no_hosts_file;
- File ->
- load_hosts(File, ose)
- end;
-
do_load_resolv(_, _) ->
inet_db:set_lookup([native]).
diff --git a/lib/kernel/src/inet_db.erl b/lib/kernel/src/inet_db.erl
index a05b380855..d4749b9756 100644
--- a/lib/kernel/src/inet_db.erl
+++ b/lib/kernel/src/inet_db.erl
@@ -88,6 +88,7 @@
hosts_file_byaddr, %% hosts table from system file
cache_timer %% timer reference for refresh
}).
+-type state() :: #state{}.
-include("inet.hrl").
-include("inet_int.hrl").
@@ -101,14 +102,14 @@
start() ->
case gen_server:start({local, inet_db}, inet_db, [], []) of
- {ok,Pid} -> inet_config:init(), {ok,Pid};
+ {ok, _Pid}=Ok -> inet_config:init(), Ok;
Error -> Error
end.
start_link() ->
case gen_server:start_link({local, inet_db}, inet_db, [], []) of
- {ok,Pid} -> inet_config:init(), {ok,Pid};
+ {ok, _Pid}=Ok -> inet_config:init(), Ok;
Error -> Error
end.
@@ -139,7 +140,6 @@ add_hosts(File) ->
Error -> Error
end.
-
add_host(IP, Names) -> call({add_host, IP, Names}).
del_host(IP) -> call({del_host, IP}).
@@ -481,10 +481,7 @@ res_check_option_absfile(F) ->
res_check_list([], _Fun) -> true;
res_check_list([H|T], Fun) ->
- case Fun(H) of
- true -> res_check_list(T, Fun);
- false -> false
- end;
+ Fun(H) andalso res_check_list(T, Fun);
res_check_list(_, _Fun) -> false.
res_check_ns({{A,B,C,D,E,F,G,H}, Port})
@@ -496,12 +493,12 @@ res_check_ns(_) -> false.
res_check_search("") -> true;
res_check_search(Dom) -> inet_parse:visible_string(Dom).
-socks_option(server) -> db_get(socks5_server);
-socks_option(port) -> db_get(socks5_port);
-socks_option(methods) -> db_get(socks5_methods);
-socks_option(noproxy) -> db_get(socks5_noproxy).
+socks_option(server) -> db_get(socks5_server);
+socks_option(port) -> db_get(socks5_port);
+socks_option(methods) -> db_get(socks5_methods);
+socks_option(noproxy) -> db_get(socks5_noproxy).
-gethostname() -> db_get(hostname).
+gethostname() -> db_get(hostname).
res_update_conf() ->
res_update(res_resolv_conf, res_resolv_conf_tm, res_resolv_conf_info,
@@ -590,15 +587,13 @@ getbyname(Name, Type) ->
getbysearch(Name, Dot, [Dom | Ds], Type, _) ->
case hostent_by_domain(Name ++ Dot ++ Dom, Type) of
- {ok, HEnt} -> {ok, HEnt};
- Error ->
- getbysearch(Name, Dot, Ds, Type, Error)
+ {ok, _HEnt}=Ok -> Ok;
+ Error -> getbysearch(Name, Dot, Ds, Type, Error)
end;
getbysearch(_Name, _Dot, [], _Type, Error) ->
Error.
-
%%
%% get_searchlist
%%
@@ -609,7 +604,6 @@ get_searchlist() ->
end.
-
make_hostent(Name, Addrs, Aliases, ?S_A) ->
#hostent {
h_name = Name,
@@ -844,6 +838,9 @@ lookup_socket(Socket) when is_port(Socket) ->
%% node_auth Ls - Default authenication
%% node_crypt Ls - Default encryption
%%
+
+-spec init([]) -> {'ok', state()}.
+
init([]) ->
process_flag(trap_exit, true),
Db = ets:new(inet_db, [public, named_table]),
@@ -897,6 +894,10 @@ reset_db(Db) ->
%% {stop, Reason, Reply, State} | (terminate/2 is called)
%% {stop, Reason, Reply, State} (terminate/2 is called)
%%----------------------------------------------------------------------
+
+-spec handle_call(term(), {pid(), term()}, state()) ->
+ {'reply', term(), state()} | {'stop', 'normal', 'ok', state()}.
+
handle_call(Request, From, #state{db=Db}=State) ->
case Request of
{load_hosts_file,IPNmAs} when is_list(IPNmAs) ->
@@ -1138,13 +1139,15 @@ handle_call(Request, From, #state{db=Db}=State) ->
{reply, error, State}
end.
-
%%----------------------------------------------------------------------
%% Func: handle_cast/2
%% Returns: {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State} (terminate/2 is called)
%%----------------------------------------------------------------------
+
+-spec handle_cast(term(), state()) -> {'noreply', state()}.
+
handle_cast(_Msg, State) ->
{noreply, State}.
@@ -1154,6 +1157,9 @@ handle_cast(_Msg, State) ->
%% {noreply, State, Timeout} |
%% {stop, Reason, State} (terminate/2 is called)
%%----------------------------------------------------------------------
+
+-spec handle_info(term(), state()) -> {'noreply', state()}.
+
handle_info(refresh_timeout, State) ->
do_refresh_cache(State#state.cache),
{noreply, State#state{cache_timer = init_timer()}};
@@ -1166,6 +1172,9 @@ handle_info(_Info, State) ->
%% Purpose: Shutdown the server
%% Returns: any (ignored by gen_server)
%%----------------------------------------------------------------------
+
+-spec terminate(term(), state()) -> 'ok'.
+
terminate(_Reason, State) ->
stop_timer(State#state.cache_timer),
ok.
@@ -1342,16 +1351,15 @@ do_add_rr(RR, Db, State) ->
TM = times(),
case alloc_entry(Db, CacheDb, TM) of
true ->
- cache_rr(Db, CacheDb, RR#dns_rr { tm = TM,
- cnt = TM });
+ cache_rr(Db, CacheDb, RR#dns_rr{tm = TM, cnt = TM});
_ ->
false
end.
cache_rr(_Db, Cache, RR) ->
%% delete possible old entry
- ets:match_delete(Cache, RR#dns_rr { cnt = '_', tm = '_', ttl = '_',
- bm = '_', func = '_'}),
+ ets:match_delete(Cache, RR#dns_rr{cnt = '_', tm = '_', ttl = '_',
+ bm = '_', func = '_'}),
ets:insert(Cache, RR).
times() ->
@@ -1361,9 +1369,9 @@ times() ->
%% lookup and remove old entries
do_lookup_rr(Domain, Class, Type) ->
- match_rr(#dns_rr { domain = tolower(Domain), class = Class,type = Type,
- cnt = '_', tm = '_', ttl = '_',
- bm = '_', func = '_', data = '_'}).
+ match_rr(#dns_rr{domain = tolower(Domain), class = Class,type = Type,
+ cnt = '_', tm = '_', ttl = '_',
+ bm = '_', func = '_', data = '_'}).
match_rr(RR) ->
filter_rr(ets:match_object(inet_cache, RR), times()).
@@ -1414,7 +1422,7 @@ dn_in_addr_arpa(A,B,C,D) ->
integer_to_list(A) ++ ".in-addr.arpa".
dnib(X) ->
- [ hex(X), $., hex(X bsr 4), $., hex(X bsr 8), $., hex(X bsr 12), $.].
+ [hex(X), $., hex(X bsr 4), $., hex(X bsr 8), $., hex(X bsr 12), $.].
hex(X) ->
X4 = (X band 16#f),
@@ -1509,12 +1517,7 @@ alloc_entry(CacheDb, OldSize, TM, N) ->
delete_n_oldest(CacheDb, TM, OldestTM, N) ->
DelTM = trunc((TM - OldestTM) * 0.3) + OldestTM,
- case delete_older(CacheDb, DelTM, N) of
- 0 ->
- false;
- _ ->
- true
- end.
+ delete_older(CacheDb, DelTM, N) =/= 0.
%% Delete entries with latest access time older than TM.
%% Delete max N number of entries.
diff --git a/lib/kernel/src/inet_dns.erl b/lib/kernel/src/inet_dns.erl
index 669a361c9d..1289e176c7 100644
--- a/lib/kernel/src/inet_dns.erl
+++ b/lib/kernel/src/inet_dns.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(inet_dns).
@@ -129,27 +129,33 @@ do_decode(<<Id:16,
RA:1,PR:1,_:2,Rcode:4,
QdCount:16,AnCount:16,NsCount:16,ArCount:16,
QdBuf/binary>>=Buffer) ->
- {AnBuf,QdList} = decode_query_section(QdBuf,QdCount,Buffer),
- {NsBuf,AnList} = decode_rr_section(AnBuf,AnCount,Buffer),
- {ArBuf,NsList} = decode_rr_section(NsBuf,NsCount,Buffer),
- {Rest,ArList} = decode_rr_section(ArBuf,ArCount,Buffer),
+ {AnBuf,QdList,QdTC} = decode_query_section(QdBuf,QdCount,Buffer),
+ {NsBuf,AnList,AnTC} = decode_rr_section(AnBuf,AnCount,Buffer),
+ {ArBuf,NsList,NsTC} = decode_rr_section(NsBuf,NsCount,Buffer),
+ {Rest,ArList,ArTC} = decode_rr_section(ArBuf,ArCount,Buffer),
case Rest of
<<>> ->
+ HdrTC = decode_boolean(TC),
DnsHdr =
#dns_header{id=Id,
qr=decode_boolean(QR),
opcode=decode_opcode(Opcode),
aa=decode_boolean(AA),
- tc=decode_boolean(TC),
+ tc=HdrTC,
rd=decode_boolean(RD),
ra=decode_boolean(RA),
pr=decode_boolean(PR),
rcode=Rcode},
- #dns_rec{header=DnsHdr,
- qdlist=QdList,
- anlist=AnList,
- nslist=NsList,
- arlist=ArList};
+ case QdTC or AnTC or NsTC or ArTC of
+ true when not HdrTC ->
+ throw(?DECODE_ERROR);
+ _ ->
+ #dns_rec{header=DnsHdr,
+ qdlist=QdList,
+ anlist=AnList,
+ nslist=NsList,
+ arlist=ArList}
+ end;
_ ->
%% Garbage data after DNS message
throw(?DECODE_ERROR)
@@ -161,8 +167,10 @@ do_decode(_) ->
decode_query_section(Bin, N, Buffer) ->
decode_query_section(Bin, N, Buffer, []).
+decode_query_section(<<>>=Rest, N, _Buffer, Qs) ->
+ {Rest,reverse(Qs),N =/= 0};
decode_query_section(Rest, 0, _Buffer, Qs) ->
- {Rest,reverse(Qs)};
+ {Rest,reverse(Qs),false};
decode_query_section(Bin, N, Buffer, Qs) ->
case decode_name(Bin, Buffer) of
{<<Type:16,Class:16,Rest/binary>>,Name} ->
@@ -179,8 +187,10 @@ decode_query_section(Bin, N, Buffer, Qs) ->
decode_rr_section(Bin, N, Buffer) ->
decode_rr_section(Bin, N, Buffer, []).
+decode_rr_section(<<>>=Rest, N, _Buffer, RRs) ->
+ {Rest,reverse(RRs),N =/= 0};
decode_rr_section(Rest, 0, _Buffer, RRs) ->
- {Rest,reverse(RRs)};
+ {Rest,reverse(RRs),false};
decode_rr_section(Bin, N, Buffer, RRs) ->
case decode_name(Bin, Buffer) of
{<<T:16/unsigned,C:16/unsigned,TTL:4/binary,
diff --git a/lib/kernel/src/inet_dns_record_adts.pl b/lib/kernel/src/inet_dns_record_adts.pl
index b1d8fab939..da50c7114f 100644
--- a/lib/kernel/src/inet_dns_record_adts.pl
+++ b/lib/kernel/src/inet_dns_record_adts.pl
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009. All Rights Reserved.
+# Copyright Ericsson AB 2009-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
@@ -73,6 +73,10 @@ while( my ($Name, $r) = each(%Names)) {
# "@Values" = "V1,V2"...",VN"
my @D = @DATA;
foreach my $line (@D) {
+ # Ignore !name lines
+ if ($line =~ s/^\!(\S+)\s+//) {
+ next if $1 eq $Name;
+ }
my $m = 1;
# For leading * iterate $n times, otherwise once
$line =~ s/^\s*[*]// and $m = $n;
@@ -155,9 +159,9 @@ make_Name() -> \
make_Name(L) when is_list(L) -> \
make_Name(#Record{}, L).
-%% Generate #Record{} with one updated field
-%%
-*make_Name(Field, Value) -> \
+!dns_rr_opt %% Generate #Record{} with one updated field
+!dns_rr_opt %%
+!dns_rr_opt *make_Name(Field, Value) -> \
#Record{Field=Value};
%%
%% Update #Record{} from property list
diff --git a/lib/kernel/src/inet_gethost_native.erl b/lib/kernel/src/inet_gethost_native.erl
index fabe9bf8b3..db3e44ce6f 100644
--- a/lib/kernel/src/inet_gethost_native.erl
+++ b/lib/kernel/src/inet_gethost_native.erl
@@ -106,8 +106,11 @@
pool_size = 4, % Number of C processes in pool.
statistics % Statistics record (records error causes).
}).
+-type state() :: #state{}.
%% The supervisor bridge code
+-spec init([]) -> {'ok', pid(), pid()} | {'error', term()}.
+
init([]) -> % Called by supervisor_bridge:start_link
Ref = make_ref(),
SaveTE = process_flag(trap_exit,true),
@@ -151,11 +154,13 @@ run_once() ->
{Port, {data, <<1:32, BinReply/binary>>}} ->
Pid ! {R, {ok, BinReply}}
after Timeout ->
- Pid ! {R,{error,timeout}}
+ Pid ! {R, {error, timeout}}
end.
-terminate(_Reason,Pid) ->
- (catch exit(Pid,kill)),
+-spec terminate(term(), pid()) -> 'ok'.
+
+terminate(_Reason, Pid) ->
+ (catch exit(Pid, kill)),
ok.
%%-----------------------------------------------------------------------
@@ -337,14 +342,14 @@ pick_client(State,RID,Clid) ->
{last, SoleClient}; % Note, not removed, the caller
% should cleanup request data
CList ->
- case lists:keysearch(Clid,1,CList) of
- {value, Client} ->
+ case lists:keyfind(Clid,1,CList) of
+ false ->
+ false;
+ Client ->
NCList = lists:keydelete(Clid,1,CList),
ets:insert(State#state.requests,
R#request{clients = NCList}),
- {more, Client};
- false ->
- false
+ {more, Client}
end
end
end.
@@ -382,8 +387,7 @@ restart_port(#state{port = Port, requests = Requests}) ->
end,
Requests),
NewPort.
-
-
+
do_open_port(Poolsize, ExtraArgs) ->
try
@@ -431,6 +435,7 @@ system_continue(_Parent, _, State) ->
system_terminate(Reason, _Parent, _, _State) ->
exit(Reason).
+-spec system_code_change(state(), module(), term(), term()) -> {'ok', state()}.
system_code_change(State, _Module, _OldVsn, _Extra) ->
{ok, State}. %% Nothing to do in this version.
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index cf357b7fba..6f1688c6a2 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -82,6 +82,7 @@
-define(INET_REQ_IFGET, 22).
-define(INET_REQ_IFSET, 23).
-define(INET_REQ_SUBSCRIBE, 24).
+-define(INET_REQ_GETIFADDRS, 25).
%% TCP requests
-define(TCP_REQ_ACCEPT, 40).
-define(TCP_REQ_LISTEN, 41).
diff --git a/lib/kernel/src/inet_parse.erl b/lib/kernel/src/inet_parse.erl
index 3bd5fa0958..65edddcb46 100644
--- a/lib/kernel/src/inet_parse.erl
+++ b/lib/kernel/src/inet_parse.erl
@@ -20,6 +20,8 @@
%% Parser for all kinds of ineternet configuration files
+%% Avoid warning for local function error/2 clashing with autoimported BIF.
+-compile({no_auto_import,[error/2]}).
-export([hosts/1, hosts/2]).
-export([hosts_vxworks/1]).
-export([protocols/1, protocols/2]).
diff --git a/lib/kernel/src/inet_res.erl b/lib/kernel/src/inet_res.erl
index 9b9e078898..59ba408d7a 100644
--- a/lib/kernel/src/inet_res.erl
+++ b/lib/kernel/src/inet_res.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-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%
%%
%% RFC 1035, 2671, 2782, 2915.
@@ -47,18 +47,93 @@
false -> ok
end).
+-type res_option() ::
+ {alt_nameservers, [nameserver()]}
+ | {edns, 0 | false}
+ | {inet6, boolean()}
+ | {nameservers, [nameserver()]}
+ | {recurse, boolean()}
+ | {retry, integer()}
+ | {timeout, integer()}
+ | {udp_payload_size, integer()}
+ | {usevc, boolean()}.
+
+-type nameserver() :: {inet:ip_address(), Port :: 1..65535}.
+
+-type res_error() :: formerr | qfmterror | servfail | nxdomain |
+ notimp | refused | badvers | timeout.
+
+-type dns_name() :: string().
+
+-type rr_type() :: a | aaaa | cname | gid | hinfo | ns | mb | md | mg | mf
+ | minfo | mx | naptr | null | ptr | soa | spf | srv | txt
+ | uid | uinfo | unspec | wks.
+
+-type dns_class() :: in | chaos | hs | any.
+
+-type dns_msg() :: term().
+
+-type dns_data() ::
+ dns_name()
+ | inet:ip4_address()
+ | inet:ip6_address()
+ | {MName :: dns_name(),
+ RName :: dns_name(),
+ Serial :: integer(),
+ Refresh :: integer(),
+ Retry :: integer(),
+ Expiry :: integer(),
+ Minimum :: integer()}
+ | {inet:ip4_address(), Proto :: integer(), BitMap :: binary()}
+ | {CpuString :: string(), OsString :: string()}
+ | {RM :: dns_name(), EM :: dns_name()}
+ | {Prio :: integer(), dns_name()}
+ | {Prio :: integer(),Weight :: integer(),Port :: integer(),dns_name()}
+ | {Order :: integer(),Preference :: integer(),Flags :: string(),
+ Services :: string(),Regexp :: string(), dns_name()}
+ | [string()]
+ | binary().
+
%% --------------------------------------------------------------------------
%% resolve:
%%
%% Nameserver query
%%
+-spec resolve(Name, Class, Type) -> {ok, dns_msg()} | Error when
+ Name :: dns_name() | inet:ip_address(),
+ Class :: dns_class(),
+ Type :: rr_type(),
+ Error :: {error, Reason} | {error,{Reason,dns_msg()}},
+ Reason :: inet:posix() | res_error().
+
resolve(Name, Class, Type) ->
resolve(Name, Class, Type, [], infinity).
+-spec resolve(Name, Class, Type, Opts) ->
+ {ok, dns_msg()} | Error when
+ Name :: dns_name() | inet:ip_address(),
+ Class :: dns_class(),
+ Type :: rr_type(),
+ Opts :: [Opt],
+ Opt :: res_option() | verbose | atom(),
+ Error :: {error, Reason} | {error,{Reason,dns_msg()}},
+ Reason :: inet:posix() | res_error().
+
resolve(Name, Class, Type, Opts) ->
resolve(Name, Class, Type, Opts, infinity).
+-spec resolve(Name, Class, Type, Opts, Timeout) ->
+ {ok, dns_msg()} | Error when
+ Name :: dns_name() | inet:ip_address(),
+ Class :: dns_class(),
+ Type :: rr_type(),
+ Opts :: [Opt],
+ Opt :: res_option() | verbose | atom(),
+ Timeout :: timeout(),
+ Error :: {error, Reason} | {error,{Reason,dns_msg()}},
+ Reason :: inet:posix() | res_error().
+
resolve(Name, Class, Type, Opts, Timeout) ->
case nsdname(Name) of
{ok, Nm} ->
@@ -76,12 +151,30 @@ resolve(Name, Class, Type, Opts, Timeout) ->
%% Convenience wrapper to resolve/3,4,5 that filters out all answer data
%% fields of the class and type asked for.
+-spec lookup(Name, Class, Type) -> [dns_data()] when
+ Name :: dns_name() | inet:ip_address(),
+ Class :: dns_class(),
+ Type :: rr_type().
+
lookup(Name, Class, Type) ->
lookup(Name, Class, Type, []).
+-spec lookup(Name, Class, Type, Opts) -> [dns_data()] when
+ Name :: dns_name() | inet:ip_address(),
+ Class :: dns_class(),
+ Type :: rr_type(),
+ Opts :: [res_option() | verbose].
+
lookup(Name, Class, Type, Opts) ->
lookup(Name, Class, Type, Opts, infinity).
+-spec lookup(Name, Class, Type, Opts, Timeout) -> [dns_data()] when
+ Name :: dns_name() | inet:ip_address(),
+ Class :: dns_class(),
+ Type :: rr_type(),
+ Opts :: [res_option() | verbose],
+ Timeout :: timeout().
+
lookup(Name, Class, Type, Opts, Timeout) ->
lookup_filter(resolve(Name, Class, Type, Opts, Timeout),
Class, Type).
@@ -101,17 +194,55 @@ lookup_filter({error,_}, _, _) -> [].
%%
%% To be deprecated
+-spec nslookup(Name, Class, Type) -> {ok, dns_msg()} | {error, Reason} when
+ Name :: dns_name() | inet:ip_address(),
+ Class :: dns_class(),
+ Type :: rr_type(),
+ Reason :: inet:posix() | res_error().
+
nslookup(Name, Class, Type) ->
do_nslookup(Name, Class, Type, [], infinity).
+-spec nslookup(Name, Class, Type, Timeout) ->
+ {ok, dns_msg()} | {error, Reason} when
+ Name :: dns_name() | inet:ip_address(),
+ Class :: dns_class(),
+ Type :: rr_type(),
+ Timeout :: timeout(),
+ Reason :: inet:posix() | res_error();
+ (Name, Class, Type, Nameservers) ->
+ {ok, dns_msg()} | {error, Reason} when
+ Name :: dns_name() | inet:ip_address(),
+ Class :: dns_class(),
+ Type :: rr_type(),
+ Nameservers :: [nameserver()],
+ Reason :: inet:posix() | res_error().
+
nslookup(Name, Class, Type, Timeout) when is_integer(Timeout), Timeout >= 0 ->
do_nslookup(Name, Class, Type, [], Timeout);
nslookup(Name, Class, Type, NSs) -> % For backwards compatibility
nnslookup(Name, Class, Type, NSs). % with OTP R6B only
+-spec nnslookup(Name, Class, Type, Nameservers) ->
+ {ok, dns_msg()} | {error, Reason} when
+ Name :: dns_name() | inet:ip_address(),
+ Class :: dns_class(),
+ Type :: rr_type(),
+ Nameservers :: [nameserver()],
+ Reason :: inet:posix().
+
nnslookup(Name, Class, Type, NSs) ->
nnslookup(Name, Class, Type, NSs, infinity).
+-spec nnslookup(Name, Class, Type, Nameservers, Timeout) ->
+ {ok, dns_msg()} | {error, Reason} when
+ Name :: dns_name() | inet:ip_address(),
+ Class :: dns_class(),
+ Type :: rr_type(),
+ Timeout :: timeout(),
+ Nameservers :: [nameserver()],
+ Reason :: inet:posix().
+
nnslookup(Name, Class, Type, NSs, Timeout) ->
do_nslookup(Name, Class, Type, [{nameservers,NSs}], Timeout).
@@ -192,8 +323,19 @@ make_options(Opts, [Name|Names]) ->
%%
%% --------------------------------------------------------------------------
+-spec gethostbyaddr(Address) -> {ok, Hostent} | {error, Reason} when
+ Address :: inet:ip_address(),
+ Hostent :: inet:hostent(),
+ Reason :: inet:posix() | res_error().
+
gethostbyaddr(IP) -> gethostbyaddr_tm(IP,false).
+-spec gethostbyaddr(Address, Timeout) -> {ok, Hostent} | {error, Reason} when
+ Address :: inet:ip_address(),
+ Timeout :: timeout(),
+ Hostent :: inet:hostent(),
+ Reason :: inet:posix() | res_error().
+
gethostbyaddr(IP,Timeout) ->
Timer = inet:start_timer(Timeout),
Res = gethostbyaddr_tm(IP,Timer),
@@ -249,6 +391,11 @@ res_gethostbyaddr(Addr, IP, Timer) ->
%% Caches the answer.
%% --------------------------------------------------------------------------
+-spec gethostbyname(Name) -> {ok, Hostent} | {error, Reason} when
+ Name :: dns_name(),
+ Hostent :: inet:hostent(),
+ Reason :: inet:posix() | res_error().
+
gethostbyname(Name) ->
case inet_db:res_option(inet6) of
true ->
@@ -257,9 +404,23 @@ gethostbyname(Name) ->
gethostbyname_tm(Name, inet, false)
end.
+-spec gethostbyname(Name, Family) -> {ok, Hostent} | {error, Reason} when
+ Name :: dns_name(),
+ Hostent :: inet:hostent(),
+ Family :: inet:address_family(),
+ Reason :: inet:posix() | res_error().
+
gethostbyname(Name,Family) ->
gethostbyname_tm(Name,Family,false).
+-spec gethostbyname(Name, Family, Timeout) ->
+ {ok, Hostent} | {error, Reason} when
+ Name :: dns_name(),
+ Hostent :: inet:hostent(),
+ Timeout :: timeout(),
+ Family :: inet:address_family(),
+ Reason :: inet:posix() | res_error().
+
gethostbyname(Name,Family,Timeout) ->
Timer = inet:start_timer(Timeout),
Res = gethostbyname_tm(Name,Family,Timer),
@@ -298,14 +459,27 @@ gethostbyname_tm(_Name, _Family, _Timer) ->
%%
%% getbyname(domain_name(), Type) => {ok, hostent()} | {error, Reason}
%%
-%% where domain_name() is domain string or atom and Type is ?S_A, ?S_MX ...
+%% where domain_name() is domain string and Type is ?S_A, ?S_MX ...
%%
%% Caches the answer.
%% --------------------------------------------------------------------------
+-spec getbyname(Name, Type) -> {ok, Hostent} | {error, Reason} when
+ Name :: dns_name(),
+ Type :: rr_type(),
+ Hostent :: inet:hostent(),
+ Reason :: inet:posix() | res_error().
+
getbyname(Name, Type) ->
getbyname_tm(Name,Type,false).
+-spec getbyname(Name, Type, Timeout) -> {ok, Hostent} | {error, Reason} when
+ Name :: dns_name(),
+ Type :: rr_type(),
+ Timeout :: timeout(),
+ Hostent :: inet:hostent(),
+ Reason :: inet:posix() | res_error().
+
getbyname(Name, Type, Timeout) ->
Timer = inet:start_timer(Timeout),
Res = getbyname_tm(Name, Type, Timer),
@@ -539,27 +713,41 @@ udp_send(#sock{inet=I}, {A,B,C,D}=IP, Port, Buffer)
when ?ip(A,B,C,D), ?port(Port) ->
gen_udp:send(I, IP, Port, Buffer).
-udp_recv(#sock{inet6=I}, {A,B,C,D,E,F,G,H}=IP, Port, Timeout)
+udp_recv(#sock{inet6=I}, {A,B,C,D,E,F,G,H}=IP, Port, Timeout, Decode)
when ?ip6(A,B,C,D,E,F,G,H), ?port(Port) ->
- do_udp_recv(fun(T) -> gen_udp:recv(I, 0, T) end, IP, Port, Timeout);
-udp_recv(#sock{inet=I}, {A,B,C,D}=IP, Port, Timeout)
+ do_udp_recv(I, IP, Port, Timeout, Decode, erlang:now(), Timeout);
+udp_recv(#sock{inet=I}, {A,B,C,D}=IP, Port, Timeout, Decode)
when ?ip(A,B,C,D), ?port(Port) ->
- do_udp_recv(fun(T) -> gen_udp:recv(I, 0, T) end, IP, Port, Timeout).
-
-do_udp_recv(Recv, IP, Port, Timeout) ->
- do_udp_recv(Recv, IP, Port, Timeout,
- if Timeout =/= 0 -> erlang:now(); true -> undefined end).
-
-do_udp_recv(Recv, IP, Port, Timeout, Then) ->
- case Recv(Timeout) of
- {ok,{IP,Port,Answer}} ->
- {ok,Answer,erlang:max(0, Timeout - now_ms(erlang:now(), Then))};
- {ok,_} when Timeout =:= 0 ->
- {error,timeout};
- {ok,_} ->
- Now = erlang:now(),
- T = erlang:max(0, Timeout - now_ms(Now, Then)),
- do_udp_recv(Recv, IP, Port, T, Now);
+ do_udp_recv(I, IP, Port, Timeout, Decode, erlang:now(), Timeout).
+
+do_udp_recv(_I, _IP, _Port, 0, _Decode, _Start, _T) ->
+ timeout;
+do_udp_recv(I, IP, Port, Timeout, Decode, Start, T) ->
+ case gen_udp:recv(I, 0, T) of
+ {ok,Reply} ->
+ case Decode(Reply) of
+ false when T =:= 0 ->
+ %% This is a compromize between the hard way i.e
+ %% in the clause below if NewT becomes 0 bailout
+ %% immediately and risk that the right reply lies
+ %% ahead after some bad id replies, and the
+ %% forgiving way i.e go on with Timeout 0 until
+ %% the right reply comes or no reply (timeout)
+ %% which opens for a DOS attack by a malicious
+ %% DNS server flooding with bad id replies causing
+ %% an infinite loop here.
+ %%
+ %% Timeout is used as a sanity limit counter
+ %% just to put an end to the loop.
+ NewTimeout = erlang:max(0, Timeout - 50),
+ do_udp_recv(I, IP, Port, NewTimeout, Decode, Start, T);
+ false ->
+ Now = erlang:now(),
+ NewT = erlang:max(0, Timeout - now_ms(Now, Start)),
+ do_udp_recv(I, IP, Port, Timeout, Decode, Start, NewT);
+ Result ->
+ Result
+ end;
Error -> Error
end.
@@ -580,6 +768,17 @@ udp_close(#sock{inet=I,inet6=I6}) ->
%% end
%% end
%%
+%% But that man page also says dig always use num_servers = 1.
+%%
+%% Our man page says: timeout/retry, then double for next retry, i.e
+%% for i = 0 to retry - 1
+%% foreach nameserver
+%% send query
+%% wait((time * (2**i)) / retry)
+%% end
+%% end
+%%
+%% And that is what the code seems to do, now fixed, hopefully...
do_query(_Q, [], _Timer) ->
{error,nxdomain};
@@ -589,18 +788,16 @@ do_query(#q{options=#options{retry=Retry}}=Q, NSs, Timer) ->
query_retries(_Q, _NSs, _Timer, Retry, Retry, S) ->
udp_close(S),
{error,timeout};
+query_retries(_Q, [], _Timer, _Retry, _I, S) ->
+ udp_close(S),
+ {error,timeout};
query_retries(Q, NSs, Timer, Retry, I, S0) ->
- Num = length(NSs),
- if Num =:= 0 ->
- {error,timeout};
- true ->
- case query_nss(Q, NSs, Timer, Retry, I, S0, []) of
- {S,{noanswer,ErrNSs}} -> %% remove unreachable nameservers
- query_retries(Q, NSs--ErrNSs, Timer, Retry, I+1, S);
- {S,Result} ->
- udp_close(S),
- Result
- end
+ case query_nss(Q, NSs, Timer, Retry, I, S0, []) of
+ {S,{noanswer,ErrNSs}} -> %% remove unreachable nameservers
+ query_retries(Q, NSs--ErrNSs, Timer, Retry, I+1, S);
+ {S,Result} ->
+ udp_close(S),
+ Result
end.
query_nss(_Q, [], _Timer, _Retry, _I, S, ErrNSs) ->
@@ -610,13 +807,13 @@ query_nss(#q{edns=undefined}=Q, NSs, Timer, Retry, I, S, ErrNSs) ->
query_nss(Q, NSs, Timer, Retry, I, S, ErrNSs) ->
query_nss_edns(Q, NSs, Timer, Retry, I, S, ErrNSs).
-query_nss_edns(#q{options=#options{udp_payload_size=PSz}=Options,
- edns={Id,Buffer}}=Q,
- [{IP,Port}=NS|NSs]=NSs0, Timer, Retry, I, S0, ErrNSs) ->
- {S,Res}=Reply = query_ns(S0, Id, Buffer, IP, Port, Timer,
- Retry, I, Options, PSz),
+query_nss_edns(
+ #q{options=#options{udp_payload_size=PSz}=Options,edns={Id,Buffer}}=Q,
+ [{IP,Port}=NS|NSs]=NSs0, Timer, Retry, I, S0, ErrNSs) ->
+ {S,Res}=Reply =
+ query_ns(S0, Id, Buffer, IP, Port, Timer, Retry, I, Options, PSz),
case Res of
- timeout -> {S,{error,timeout}};
+ timeout -> {S,{error,timeout}}; % Bailout timeout
{ok,_} -> Reply;
{error,{nxdomain,_}} -> Reply;
{error,{E,_}} when E =:= qfmterror; E =:= notimp; E =:= servfail;
@@ -628,17 +825,19 @@ query_nss_edns(#q{options=#options{udp_payload_size=PSz}=Options,
query_nss(Q, NSs, Timer, Retry, I, S, ErrNSs)
end.
-query_nss_dns(#q{dns=Qdns}=Q0, [{IP,Port}=NS|NSs],
- Timer, Retry, I, S0, ErrNSs) ->
+query_nss_dns(
+ #q{dns=Qdns}=Q0,
+ [{IP,Port}=NS|NSs], Timer, Retry, I, S0, ErrNSs) ->
#q{options=Options,dns={Id,Buffer}}=Q =
if
is_function(Qdns, 0) -> Q0#q{dns=Qdns()};
true -> Q0
end,
- {S,Res}=Reply = query_ns(S0, Id, Buffer, IP, Port, Timer,
- Retry, I, Options, ?PACKETSZ),
+ {S,Res}=Reply =
+ query_ns(
+ S0, Id, Buffer, IP, Port, Timer, Retry, I, Options, ?PACKETSZ),
case Res of
- timeout -> {S,{error,timeout}};
+ timeout -> {S,{error,timeout}}; % Bailout timeout
{ok,_} -> Reply;
{error,{E,_}} when E =:= nxdomain; E =:= qfmterror -> Reply;
{error,E} when E =:= fmt; E =:= enetunreach; E =:= econnrefused ->
@@ -652,48 +851,66 @@ query_ns(S0, Id, Buffer, IP, Port, Timer, Retry, I,
PSz) ->
case UseVC orelse iolist_size(Buffer) > PSz of
true ->
- {S0,query_tcp(Tm, Id, Buffer, IP, Port, Timer, Verbose)};
+ TcpTimeout = inet:timeout(Tm*5, Timer),
+ {S0,query_tcp(TcpTimeout, Id, Buffer, IP, Port, Verbose)};
false ->
case udp_open(S0, IP) of
{ok,S} ->
- {S,case query_udp(S, Id, Buffer, IP, Port, Timer,
- Retry, I, Tm, Verbose) of
- {ok,#dns_rec{header=H}} when H#dns_header.tc ->
- query_tcp(Tm, Id, Buffer,
- IP, Port, Timer, Verbose);
- Reply -> Reply
- end};
+ Timeout =
+ inet:timeout( (Tm * (1 bsl I)) div Retry, Timer),
+ {S,
+ case query_udp(
+ S, Id, Buffer, IP, Port, Timeout, Verbose) of
+ {ok,#dns_rec{header=H}} when H#dns_header.tc ->
+ TcpTimeout = inet:timeout(Tm*5, Timer),
+ query_tcp(
+ TcpTimeout, Id, Buffer, IP, Port, Verbose);
+ Reply -> Reply
+ end};
Error ->
{S0,Error}
end
end.
-query_udp(S, Id, Buffer, IP, Port, Timer, Retry, I, Tm, Verbose) ->
- Timeout = inet:timeout( (Tm * (1 bsl I)) div Retry, Timer),
+query_udp(_S, _Id, _Buffer, _IP, _Port, 0, _Verbose) ->
+ timeout;
+query_udp(S, Id, Buffer, IP, Port, Timeout, Verbose) ->
?verbose(Verbose, "Try UDP server : ~p:~p (timeout=~w)\n",
- [IP, Port, Timeout]),
- udp_connect(S, IP, Port),
- udp_send(S, IP, Port, Buffer),
- query_udp_recv(S, IP, Port, Id, Timeout, Verbose).
-
-query_udp_recv(S, IP, Port, Id, Timeout, Verbose) ->
- case udp_recv(S, IP, Port, Timeout) of
- {ok,Answer,T} ->
- case decode_answer(Answer, Id, Verbose) of
- {error, badid} ->
- query_udp_recv(S, IP, Port, Id, T, Verbose);
- Reply -> Reply
+ [IP,Port,Timeout]),
+ case
+ case udp_connect(S, IP, Port) of
+ ok ->
+ udp_send(S, IP, Port, Buffer);
+ E1 ->
+ E1 end of
+ ok ->
+ Decode =
+ fun ({RecIP,RecPort,Answer})
+ when RecIP =:= IP, RecPort =:= Port ->
+ case decode_answer(Answer, Id, Verbose) of
+ {error,badid} ->
+ false;
+ Reply ->
+ Reply
+ end;
+ ({_,_,_}) ->
+ false
+ end,
+ case udp_recv(S, IP, Port, Timeout, Decode) of
+ {ok,_}=Result ->
+ Result;
+ E2 ->
+ ?verbose(Verbose, "UDP server error: ~p\n", [E2]),
+ E2
end;
- {error, timeout} when Timeout =:= 0 ->
- ?verbose(Verbose, "UDP server timeout\n", []),
- timeout;
- Error ->
- ?verbose(Verbose, "UDP server error: ~p\n", [Error]),
- Error
+ E3 ->
+ ?verbose(Verbose, "UDP send failed: ~p\n", [E3]),
+ {error,econnrefused}
end.
-query_tcp(Tm, Id, Buffer, IP, Port, Timer, Verbose) ->
- Timeout = inet:timeout(Tm*5, Timer),
+query_tcp(0, _Id, _Buffer, _IP, _Port, _Verbose) ->
+ timeout;
+query_tcp(Timeout, Id, Buffer, IP, Port, Verbose) ->
?verbose(Verbose, "Try TCP server : ~p:~p (timeout=~w)\n",
[IP, Port, Timeout]),
Family = case IP of
@@ -715,19 +932,10 @@ query_tcp(Tm, Id, Buffer, IP, Port, Timer, Verbose) ->
end;
Error ->
gen_tcp:close(S),
- case Error of
- {error, timeout} when Timeout =:= 0 ->
- ?verbose(Verbose, "TCP server recv timeout\n", []),
- timeout;
- _ ->
- ?verbose(Verbose, "TCP server recv error: ~p\n",
- [Error]),
- Error
- end
+ ?verbose(Verbose, "TCP server recv error: ~p\n",
+ [Error]),
+ Error
end;
- {error, timeout} when Timeout =:= 0 ->
- ?verbose(Verbose, "TCP server connect timeout\n", []),
- timeout;
Error ->
?verbose(Verbose, "TCP server error: ~p\n", [Error]),
Error
diff --git a/lib/kernel/src/inet_sctp.erl b/lib/kernel/src/inet_sctp.erl
index 795bf83807..de74b573bd 100644
--- a/lib/kernel/src/inet_sctp.erl
+++ b/lib/kernel/src/inet_sctp.erl
@@ -31,7 +31,7 @@
-define(FAMILY, inet).
-export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]).
--export([open/1,close/1,listen/2,connect/5,sendmsg/3,recv/2]).
+-export([open/1,close/1,listen/2,connect/5,sendmsg/3,send/4,recv/2]).
@@ -141,5 +141,24 @@ connect_get_assoc(S, Addr, Port, Active, Timer) ->
sendmsg(S, SRI, Data) ->
prim_inet:sendmsg(S, SRI, Data).
+send(S, AssocId, Stream, Data) ->
+ case prim_inet:getopts(
+ S,
+ [{sctp_default_send_param,#sctp_sndrcvinfo{assoc_id=AssocId}}]) of
+ {ok,
+ [{sctp_default_send_param,
+ #sctp_sndrcvinfo{
+ flags=Flags, context=Context, ppid=PPID, timetolive=TTL}}]} ->
+ prim_inet:sendmsg(
+ S,
+ #sctp_sndrcvinfo{
+ flags=Flags, context=Context, ppid=PPID, timetolive=TTL,
+ assoc_id=AssocId, stream=Stream},
+ Data);
+ _ ->
+ prim_inet:sendmsg(
+ S, #sctp_sndrcvinfo{assoc_id=AssocId, stream=Stream}, Data)
+ end.
+
recv(S, Timeout) ->
prim_inet:recvfrom(S, 0, Timeout).
diff --git a/lib/kernel/src/inet_udp.erl b/lib/kernel/src/inet_udp.erl
index 9a4089ab19..60bd96f332 100644
--- a/lib/kernel/src/inet_udp.erl
+++ b/lib/kernel/src/inet_udp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -39,8 +39,10 @@ getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,udp).
getaddr(Address) -> inet:getaddr(Address, inet).
getaddr(Address,Timer) -> inet:getaddr_tm(Address, inet, Timer).
+-spec open(_) -> {ok, inet:socket()} | {error, atom()}.
open(Port) -> open(Port, []).
+-spec open(_, _) -> {ok, inet:socket()} | {error, atom()}.
open(Port, Opts) ->
case inet:udp_options(
[{port,Port}, {recbuf, ?RECBUF} | Opts],
@@ -69,6 +71,8 @@ recv(S,Len) ->
recv(S,Len,Time) ->
prim_inet:recvfrom(S, Len, Time).
+-spec close(inet:socket()) -> ok.
+
close(S) ->
inet:udp_close(S).
diff --git a/lib/kernel/src/kernel.erl b/lib/kernel/src/kernel.erl
index 92ee7b441a..1e07620a3e 100644
--- a/lib/kernel/src/kernel.erl
+++ b/lib/kernel/src/kernel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -143,6 +143,13 @@ init(safe) ->
Boot = start_boot_server(),
DiskLog = start_disk_log(),
Pg2 = start_pg2(),
+
+ %% Run the on_load handlers for all modules that have been
+ %% loaded so far. Running them at this point means that
+ %% on_load handlers can safely call kernel processes
+ %% (and in particular call code:priv_dir/1 or code:lib_dir/1).
+ init:run_on_load_handlers(),
+
{ok, {SupFlags, Boot ++ DiskLog ++ Pg2}}.
get_code_args() ->
diff --git a/lib/kernel/src/kernel_config.erl b/lib/kernel/src/kernel_config.erl
index e5e9a0498d..b1daf655c9 100644
--- a/lib/kernel/src/kernel_config.erl
+++ b/lib/kernel/src/kernel_config.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(kernel_config).
@@ -40,6 +40,9 @@ start_link() -> gen_server:start_link(kernel_config, [], []).
%%-----------------------------------------------------------------
%% Callback functions from gen_server
%%-----------------------------------------------------------------
+
+-spec init([]) -> {'ok', []} | {'stop', term()}.
+
init([]) ->
process_flag(trap_exit, true),
case sync_nodes() of
@@ -59,18 +62,28 @@ init([]) ->
{stop, Error}
end.
+-spec handle_info(term(), State) -> {'noreply', State}.
+
handle_info(_, State) ->
{noreply, State}.
+-spec terminate(term(), term()) -> 'ok'.
+
terminate(_Reason, _State) ->
ok.
+-spec handle_call(term(), term(), State) -> {'reply', 'ok', State}.
+
handle_call('__not_used', _From, State) ->
{reply, ok, State}.
+-spec handle_cast(term(), State) -> {'noreply', State}.
+
handle_cast('__not_used', State) ->
{noreply, State}.
+-spec code_change(term(), State, term()) -> {'ok', State}.
+
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
@@ -79,9 +92,9 @@ code_change(_OldVsn, State, _Extra) ->
%%-----------------------------------------------------------------
sync_nodes() ->
case catch get_sync_data() of
- {error, Reason} ->
+ {error, Reason} = Error ->
error_logger:format("~p", [Reason]),
- {error, Reason};
+ Error;
{infinity, MandatoryNodes, OptionalNodes} ->
case wait_nodes(MandatoryNodes, OptionalNodes) of
ok ->
diff --git a/lib/kernel/src/net_adm.erl b/lib/kernel/src/net_adm.erl
index 737b1ecee9..9b2dac9544 100644
--- a/lib/kernel/src/net_adm.erl
+++ b/lib/kernel/src/net_adm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-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
@@ -35,7 +35,11 @@
%% Try to read .hosts.erlang file in
%% 1. cwd , 2. $HOME 3. init:root_dir()
--spec host_file() -> [atom()] | {'error',atom() | {integer(),atom(),_}}.
+-spec host_file() -> Hosts | {error, Reason} when
+ Hosts :: [Host :: atom()],
+ %% Copied from file:path_consult/2:
+ Reason :: file:posix() | badarg | terminated | system_limit
+ | {Line :: integer(), Mod :: module(), Term :: term()}.
host_file() ->
Home = case init:get_argument(home) of
@@ -50,7 +54,8 @@ host_file() ->
%% Check whether a node is up or down
%% side effect: set up a connection to Node if there not yet is one.
--spec ping(atom()) -> 'pang' | 'pong'.
+-spec ping(Node) -> pong | pang when
+ Node :: atom().
ping(Node) when is_atom(Node) ->
case catch gen:call({net_kernel, Node},
@@ -63,7 +68,8 @@ ping(Node) when is_atom(Node) ->
pang
end.
--spec localhost() -> string().
+-spec localhost() -> Name when
+ Name :: string().
localhost() ->
{ok, Host} = inet:gethostname(),
@@ -73,12 +79,20 @@ localhost() ->
end.
--spec names() -> {'ok', [{string(), integer()}]} | {'error', _}.
+-spec names() -> {ok, [{Name, Port}]} | {error, Reason} when
+ Name :: string(),
+ Port :: non_neg_integer(),
+ Reason :: address | file:posix().
names() ->
names(localhost()).
--spec names(atom() | string()) -> {'ok', [{string(), integer()}]} | {'error', _}.
+
+-spec names(Host) -> {ok, [{Name, Port}]} | {error, Reason} when
+ Host :: atom() | string(),
+ Name :: string(),
+ Port :: non_neg_integer(),
+ Reason :: address | file:posix().
names(Hostname) ->
case inet:gethostbyname(Hostname) of
@@ -88,8 +102,9 @@ names(Hostname) ->
Else
end.
--spec dns_hostname(atom() | string()) ->
- {'ok', string()} | {'error', atom() | string()}.
+-spec dns_hostname(Host) -> {ok, Name} | {error, Host} when
+ Host :: atom() | string(),
+ Name :: string().
dns_hostname(Hostname) ->
case inet:gethostbyname(Hostname) of
@@ -164,7 +179,8 @@ collect_new(Sofar, Nodelist) ->
world() ->
world(silent).
--spec world(verbosity()) -> [node()].
+-spec world(Arg) -> [node()] when
+ Arg :: verbosity().
world(Verbose) ->
case net_adm:host_file() of
@@ -172,12 +188,15 @@ world(Verbose) ->
Hosts -> expand_hosts(Hosts, Verbose)
end.
--spec world_list([atom()]) -> [node()].
+-spec world_list(Hosts) -> [node()] when
+ Hosts :: [atom()].
world_list(Hosts) when is_list(Hosts) ->
expand_hosts(Hosts, silent).
--spec world_list([atom()], verbosity()) -> [node()].
+-spec world_list(Hosts, Arg) -> [node()] when
+ Hosts :: [atom()],
+ Arg :: verbosity().
world_list(Hosts, Verbose) when is_list(Hosts) ->
expand_hosts(Hosts, Verbose).
diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl
index 9875044844..9e3d730cee 100644
--- a/lib/kernel/src/net_kernel.erl
+++ b/lib/kernel/src/net_kernel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-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
@@ -72,7 +72,7 @@
-export([publish_on_node/1, update_publish_nodes/1]).
-%% Internal Exports
+%% Internal Exports
-export([do_spawn/3,
spawn_func/6,
ticker/2,
@@ -94,7 +94,7 @@
connecttime, %% the connection setuptime.
connections, %% table of connections
conn_owners = [], %% List of connection owner pids,
- pend_owners = [], %% List of potential owners
+ pend_owners = [], %% List of potential owners
listen, %% list of #listen
allowed, %% list of allowed nodes in a restricted system
verbose = 0, %% level of verboseness
@@ -145,8 +145,15 @@
%% Interface functions
kernel_apply(M,F,A) -> request({apply,M,F,A}).
+
+-spec allow(Nodes) -> ok | error when
+ Nodes :: [node()].
allow(Nodes) -> request({allow, Nodes}).
+
longnames() -> request(longnames).
+
+-spec stop() -> ok | {error, Reason} when
+ Reason :: not_allowed | not_found.
stop() -> erl_distribution:stop().
node_info(Node) -> get_node_info(Node).
@@ -158,10 +165,28 @@ i(Node) -> print_info(Node).
verbose(Level) when is_integer(Level) ->
request({verbose, Level}).
+-spec set_net_ticktime(NetTicktime, TransitionPeriod) -> Res when
+ NetTicktime :: pos_integer(),
+ TransitionPeriod :: non_neg_integer(),
+ Res :: unchanged
+ | change_initiated
+ | {ongoing_change_to, NewNetTicktime},
+ NewNetTicktime :: pos_integer().
set_net_ticktime(T, TP) when is_integer(T), T > 0, is_integer(TP), TP >= 0 ->
ticktime_res(request({new_ticktime, T*250, TP*1000})).
+
+-spec set_net_ticktime(NetTicktime) -> Res when
+ NetTicktime :: pos_integer(),
+ Res :: unchanged
+ | change_initiated
+ | {ongoing_change_to, NewNetTicktime},
+ NewNetTicktime :: pos_integer().
set_net_ticktime(T) when is_integer(T) ->
set_net_ticktime(T, ?DEFAULT_TRANSITION_PERIOD).
+
+-spec get_net_ticktime() -> Res when
+ Res :: NetTicktime | {ongoing_change_to, NetTicktime} | ignored,
+ NetTicktime :: pos_integer().
get_net_ticktime() ->
ticktime_res(request(ticktime)).
@@ -171,6 +196,9 @@ get_net_ticktime() ->
%% flags (we may want to move it elsewhere later). In order to easily
%% be backward compatible, errors are created here when process_flag()
%% fails.
+-spec monitor_nodes(Flag) -> ok | Error when
+ Flag :: boolean(),
+ Error :: error | {error, term()}.
monitor_nodes(Flag) ->
case catch process_flag(monitor_nodes, Flag) of
true -> ok;
@@ -178,6 +206,13 @@ monitor_nodes(Flag) ->
_ -> mk_monitor_nodes_error(Flag, [])
end.
+-spec monitor_nodes(Flag, Options) -> ok | Error when
+ Flag :: boolean(),
+ Options :: [Option],
+ Option :: {node_type, NodeType}
+ | nodedown_reason,
+ NodeType :: visible | hidden | all,
+ Error :: error | {error, term()}.
monitor_nodes(Flag, Opts) ->
case catch process_flag({monitor_nodes, Opts}, Flag) of
true -> ok;
@@ -209,6 +244,8 @@ publish_on_node(Node) when is_atom(Node) ->
update_publish_nodes(Ns) ->
request({update_publish_nodes, Ns}).
+-spec connect_node(Node) -> boolean() | ignored when
+ Node :: node().
%% explicit connects
connect_node(Node) when is_atom(Node) ->
request({connect, normal, Node}).
@@ -232,7 +269,7 @@ do_connect(Node, Type, WaitForBarred) -> %% Type = normal | hidden
%% "connected from other end.~n",[Node]),
true;
{Pid, false} ->
- ?connect_failure(Node,{barred_connection,
+ ?connect_failure(Node,{barred_connection,
ets:lookup(sys_dist, Node)}),
%%io:format("Net Kernel: barred connection (~p) "
%% "- failure.~n",[Node]),
@@ -244,12 +281,12 @@ do_connect(Node, Type, WaitForBarred) -> %% Type = normal | hidden
{ok, never} ->
?connect_failure(Node,{dist_auto_connect,never}),
false;
- % This might happen due to connection close
+ % This might happen due to connection close
% not beeing propagated to user space yet.
- % Save the day by just not connecting...
+ % Save the day by just not connecting...
{ok, once} when Else =/= [],
(hd(Else))#connection.state =:= up ->
- ?connect_failure(Node,{barred_connection,
+ ?connect_failure(Node,{barred_connection,
ets:lookup(sys_dist, Node)}),
false;
_ ->
@@ -276,8 +313,8 @@ passive_connect_monitor(Parent, Node) ->
Parent ! {self(),true}
end
end.
-
-%% If the net_kernel isn't running we ignore all requests to the
+
+%% If the net_kernel isn't running we ignore all requests to the
%% kernel, thus basically accepting them :-)
request(Req) ->
case whereis(net_kernel) of
@@ -302,7 +339,7 @@ start_link([Name, LongOrShortNames]) ->
start_link([Name, LongOrShortNames, 15000]);
start_link([Name, LongOrShortNames, Ticktime]) ->
- case gen_server:start_link({local, net_kernel}, net_kernel,
+ case gen_server:start_link({local, net_kernel}, net_kernel,
{Name, LongOrShortNames, Ticktime}, []) of
{ok, Pid} ->
{ok, Pid};
@@ -313,7 +350,7 @@ start_link([Name, LongOrShortNames, Ticktime]) ->
end.
%% auth:get_cookie should only be able to return an atom
-%% tuple cookies are unknowns
+%% tuple cookies are unknowns
init({Name, LongOrShortNames, TickT}) ->
process_flag(trap_exit,true),
@@ -322,24 +359,19 @@ init({Name, LongOrShortNames, TickT}) ->
process_flag(priority, max),
Ticktime = to_integer(TickT),
Ticker = spawn_link(net_kernel, ticker, [self(), Ticktime]),
- case auth:get_cookie(Node) of
- Cookie when is_atom(Cookie) ->
- {ok, #state{name = Name,
- node = Node,
- type = LongOrShortNames,
- tick = #tick{ticker = Ticker, time = Ticktime},
- connecttime = connecttime(),
- connections =
- ets:new(sys_dist,[named_table,
- protected,
- {keypos, 2}]),
- listen = Listeners,
- allowed = [],
- verbose = 0
- }};
- _ELSE ->
- {stop, {error,{bad_cookie, Node}}}
- end;
+ {ok, #state{name = Name,
+ node = Node,
+ type = LongOrShortNames,
+ tick = #tick{ticker = Ticker, time = Ticktime},
+ connecttime = connecttime(),
+ connections =
+ ets:new(sys_dist,[named_table,
+ protected,
+ {keypos, 2}]),
+ listen = Listeners,
+ allowed = [],
+ verbose = 0
+ }};
Error ->
{stop, Error}
end.
@@ -390,27 +422,27 @@ handle_call({disconnect, Node}, From, State) ->
{Reply, State1} = do_disconnect(Node, State),
async_reply({reply, Reply, State1}, From);
-%%
+%%
%% The spawn/4 BIF ends up here.
-%%
+%%
handle_call({spawn,M,F,A,Gleader},{From,Tag},State) when is_pid(From) ->
do_spawn([no_link,{From,Tag},M,F,A,Gleader],[],State);
-%%
+%%
%% The spawn_link/4 BIF ends up here.
-%%
+%%
handle_call({spawn_link,M,F,A,Gleader},{From,Tag},State) when is_pid(From) ->
do_spawn([link,{From,Tag},M,F,A,Gleader],[],State);
-%%
+%%
%% The spawn_opt/5 BIF ends up here.
-%%
+%%
handle_call({spawn_opt,M,F,A,O,L,Gleader},{From,Tag},State) when is_pid(From) ->
do_spawn([L,{From,Tag},M,F,A,Gleader],O,State);
-%%
+%%
%% Only allow certain nodes.
-%%
+%%
handle_call({allow, Nodes}, From, State) ->
case all_atoms(Nodes) of
true ->
@@ -421,17 +453,17 @@ handle_call({allow, Nodes}, From, State) ->
async_reply({reply,error,State}, From)
end;
-%%
+%%
%% authentication, used by auth. Simply works as this:
%% if the message comes through, the other node IS authorized.
-%%
+%%
handle_call({is_auth, _Node}, From, State) ->
async_reply({reply,yes,State}, From);
-%%
+%%
%% Not applicable any longer !?
-%%
-handle_call({apply,_Mod,_Fun,_Args}, {From,Tag}, State)
+%%
+handle_call({apply,_Mod,_Fun,_Args}, {From,Tag}, State)
when is_pid(From), node(From) =:= node() ->
async_gen_server_reply({From,Tag}, not_implemented),
% Port = State#state.port,
@@ -503,7 +535,10 @@ handle_call({new_ticktime,T,TP}, From, #state{tick = #tick{ticker = Tckr,
handle_call({new_ticktime,_T,_TP},
From,
#state{tick = #tick_change{time = T}} = State) ->
- async_reply({reply, {ongoing_change_to, T}, State}, From).
+ async_reply({reply, {ongoing_change_to, T}, State}, From);
+
+handle_call(_Msg, _From, State) ->
+ {noreply, State}.
%% ------------------------------------------------------------
%% handle_cast.
@@ -571,7 +606,7 @@ handle_info({accept,AcceptPid,Socket,Family,Proto}, State) ->
%%
%% A node has successfully been connected.
%%
-handle_info({SetupPid, {nodeup,Node,Address,Type,Immediate}},
+handle_info({SetupPid, {nodeup,Node,Address,Type,Immediate}},
State) ->
case {Immediate, ets:lookup(sys_dist, Node)} of
{true, [Conn]} when Conn#connection.state =:= pending,
@@ -659,7 +694,7 @@ handle_info({From,registered_send,To,Mess},State) ->
send(From,To,Mess),
{noreply,State};
-%% badcookies SHOULD not be sent
+%% badcookies SHOULD not be sent
%% (if someone does erlang:set_cookie(node(),foo) this may be)
handle_info({From,badcookie,_To,_Mess}, State) ->
error_logger:error_msg("~n** Got OLD cookie from ~w~n",
@@ -707,7 +742,7 @@ handle_info(X, State) ->
%% 4. The ticker process.
%% (5. Garbage pid.)
%%
-%% The process type function that handled the process throws
+%% The process type function that handled the process throws
%% the handle_info return value !
%% -----------------------------------------------------------
@@ -997,9 +1032,9 @@ ticker(Kernel, Tick) when is_integer(Tick) ->
ticker_loop(Kernel, Tick).
to_integer(T) when is_integer(T) -> T;
-to_integer(T) when is_atom(T) ->
+to_integer(T) when is_atom(T) ->
list_to_integer(atom_to_list(T));
-to_integer(T) when is_list(T) ->
+to_integer(T) when is_list(T) ->
list_to_integer(T).
ticker_loop(Kernel, Tick) ->
@@ -1007,7 +1042,7 @@ ticker_loop(Kernel, Tick) ->
{new_ticktime, NewTick} ->
?tckr_dbg({ticker_changed_time, Tick, NewTick}),
?MODULE:ticker_loop(Kernel, NewTick)
- after Tick ->
+ after Tick ->
Kernel ! tick,
?MODULE:ticker_loop(Kernel, Tick)
end.
@@ -1055,7 +1090,7 @@ send(_From,To,Mess) ->
-ifdef(UNUSED).
safesend(Name,Mess) when is_atom(Name) ->
- case whereis(Name) of
+ case whereis(Name) of
undefined ->
Mess;
P when is_pid(P) ->
@@ -1149,7 +1184,7 @@ get_proto_mod(Family,Protocol,[L|Ls]) ->
true ->
get_proto_mod(Family,Protocol,Ls)
end;
-get_proto_mod(_Family, _Protocol, []) ->
+get_proto_mod(_Family, _Protocol, []) ->
error.
%% -------- Initialisation functions ------------------------
@@ -1160,9 +1195,9 @@ init_node(Name, LongOrShortNames) ->
case create_name(Name, LongOrShortNames, 1) of
{ok,Node} ->
case start_protos(list_to_atom(NameWithoutHost),Node) of
- {ok, Ls} ->
+ {ok, Ls} ->
{ok, Node, Ls};
- Error ->
+ Error ->
Error
end;
Error ->
@@ -1171,9 +1206,9 @@ init_node(Name, LongOrShortNames) ->
%% Create the node name
create_name(Name, LongOrShortNames, Try) ->
- put(longnames, case LongOrShortNames of
- shortnames -> false;
- longnames -> true
+ put(longnames, case LongOrShortNames of
+ shortnames -> false;
+ longnames -> true
end),
{Head,Host1} = create_hostpart(Name, LongOrShortNames),
case Host1 of
@@ -1222,7 +1257,7 @@ create_hostpart(Name, LongOrShortNames) ->
{Head,Host1}.
%%
-%%
+%%
%%
protocol_childspecs() ->
case init:get_argument(proto_dist) of
@@ -1232,7 +1267,7 @@ protocol_childspecs() ->
protocol_childspecs(["inet_tcp"])
end.
-protocol_childspecs([]) ->
+protocol_childspecs([]) ->
[];
protocol_childspecs([H|T]) ->
Mod = list_to_atom(H ++ "_dist"),
@@ -1242,16 +1277,16 @@ protocol_childspecs([H|T]) ->
_ ->
protocol_childspecs(T)
end.
-
-
+
+
%%
%% epmd_module() -> module_name of erl_epmd or similar gen_server_module.
%%
epmd_module() ->
case init:get_argument(epmd_module) of
- {ok,[[Module]]} ->
- Module;
+ {ok,[[Module]]} ->
+ list_to_atom(Module);
_ ->
erl_epmd
end.
@@ -1297,7 +1332,7 @@ start_protos(Name, [Proto | Ps], Node, Ls) ->
error_logger:info_msg("Protocol: ~p: not supported~n", [Proto]),
start_protos(Name,Ps, Node, Ls);
{'EXIT', Reason} ->
- error_logger:info_msg("Protocol: ~p: register error: ~p~n",
+ error_logger:info_msg("Protocol: ~p: register error: ~p~n",
[Proto, Reason]),
start_protos(Name,Ps, Node, Ls);
{error, duplicate_name} ->
@@ -1307,7 +1342,7 @@ start_protos(Name, [Proto | Ps], Node, Ls) ->
[Proto]),
start_protos(Name,Ps, Node, Ls);
{error, Reason} ->
- error_logger:info_msg("Protocol: ~p: register/listen error: ~p~n",
+ error_logger:info_msg("Protocol: ~p: register/listen error: ~p~n",
[Proto, Reason]),
start_protos(Name,Ps, Node, Ls)
end;
@@ -1459,7 +1494,7 @@ display_info({Node, Info}, {I,O}) ->
integer_to_list(In), integer_to_list(Out), Address),
{I+In,O+Out}.
-fmt_address(undefined) ->
+fmt_address(undefined) ->
"-";
fmt_address(A) ->
case A#net_address.family of
diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl
index d0b498edc9..f6769df585 100644
--- a/lib/kernel/src/os.erl
+++ b/lib/kernel/src/os.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -24,7 +24,10 @@
-include("file.hrl").
--spec type() -> 'vxworks' | {'unix',atom()} | {'win32',atom()} | {'ose',atom()}.
+-spec type() -> vxworks | {Osfamily, Osname} when
+ Osfamily :: unix | win32,
+ Osname :: atom().
+
type() ->
case erlang:system_info(os_type) of
{vxworks, _} ->
@@ -32,25 +35,34 @@ type() ->
Else -> Else
end.
--spec version() -> string() | {non_neg_integer(),non_neg_integer(),non_neg_integer()}.
+-spec version() -> VersionString | {Major, Minor, Release} when
+ VersionString :: string(),
+ Major :: non_neg_integer(),
+ Minor :: non_neg_integer(),
+ Release :: non_neg_integer().
version() ->
erlang:system_info(os_version).
--spec find_executable(string()) -> string() | 'false'.
+-spec find_executable(Name) -> Filename | 'false' when
+ Name :: string(),
+ Filename :: string().
find_executable(Name) ->
case os:getenv("PATH") of
false -> find_executable(Name, []);
Path -> find_executable(Name, Path)
end.
--spec find_executable(string(), string()) -> string() | 'false'.
+-spec find_executable(Name, Path) -> Filename | 'false' when
+ Name :: string(),
+ Path :: string(),
+ Filename :: string().
find_executable(Name, Path) ->
Extensions = extensions(),
case filename:pathtype(Name) of
relative ->
find_executable1(Name, split_path(Path), Extensions);
_ ->
- case verify_executable(Name, Extensions) of
+ case verify_executable(Name, Extensions, Extensions) of
{ok, Complete} ->
Complete;
error ->
@@ -60,7 +72,7 @@ find_executable(Name, Path) ->
find_executable1(Name, [Base|Rest], Extensions) ->
Complete0 = filename:join(Base, Name),
- case verify_executable(Complete0, Extensions) of
+ case verify_executable(Complete0, Extensions, Extensions) of
{ok, Complete} ->
Complete;
error ->
@@ -69,7 +81,7 @@ find_executable1(Name, [Base|Rest], Extensions) ->
find_executable1(_Name, [], _Extensions) ->
false.
-verify_executable(Name0, [Ext|Rest]) ->
+verify_executable(Name0, [Ext|Rest], OrigExtensions) ->
Name1 = Name0 ++ Ext,
case os:type() of
vxworks ->
@@ -78,21 +90,40 @@ verify_executable(Name0, [Ext|Rest]) ->
{ok, _} ->
{ok, Name1};
_ ->
- verify_executable(Name0, Rest)
+ verify_executable(Name0, Rest, OrigExtensions)
end;
_ ->
case file:read_file_info(Name1) of
- {ok, #file_info{mode=Mode}} when Mode band 8#111 =/= 0 ->
- %% XXX This test for execution permission is not full-proof
+ {ok, #file_info{type=regular,mode=Mode}}
+ when Mode band 8#111 =/= 0 ->
+ %% XXX This test for execution permission is not fool-proof
%% on Unix, since we test if any execution bit is set.
{ok, Name1};
_ ->
- verify_executable(Name0, Rest)
+ verify_executable(Name0, Rest, OrigExtensions)
end
end;
-verify_executable(_, []) ->
+verify_executable(Name, [], OrigExtensions) when OrigExtensions =/= [""] -> %% Windows
+ %% Will only happen on windows, hence case insensitivity
+ case can_be_full_name(string:to_lower(Name),OrigExtensions) of
+ true ->
+ verify_executable(Name,[""],[""]);
+ _ ->
+ error
+ end;
+verify_executable(_, [], _) ->
error.
+can_be_full_name(_Name,[]) ->
+ false;
+can_be_full_name(Name,[H|T]) ->
+ case lists:suffix(H,Name) of %% Name is in lowercase, cause this is a windows thing
+ true ->
+ true;
+ _ ->
+ can_be_full_name(Name,T)
+ end.
+
split_path(Path) ->
case type() of
{win32, _} ->
@@ -118,7 +149,8 @@ reverse_element([$"|T]) -> %"
reverse_element(List) ->
lists:reverse(List).
--spec extensions() -> [string()].
+-spec extensions() -> [string(),...].
+%% Extensions in lower case
extensions() ->
case type() of
{win32, _} -> [".exe",".com",".cmd",".bat"];
@@ -127,7 +159,8 @@ extensions() ->
end.
%% Executes the given command in the default shell for the operating system.
--spec cmd(atom() | string() | [string()]) -> string().
+-spec cmd(Command) -> string() when
+ Command :: atom() | io_lib:chars().
cmd(Cmd) ->
validate(Cmd),
case type() of
@@ -211,9 +244,13 @@ start_port_srv(Request) ->
catch
error:_ -> false
end,
- start_port_srv_loop(Request, StayAlive).
+ start_port_srv_handle(Request),
+ case StayAlive of
+ true -> start_port_srv_loop();
+ false -> exiting
+ end.
-start_port_srv_loop({Ref,Client}, StayAlive) ->
+start_port_srv_handle({Ref,Client}) ->
Reply = try open_port({spawn, ?SHELL},[stream]) of
Port when is_port(Port) ->
(catch port_connect(Port, Client)),
@@ -223,20 +260,18 @@ start_port_srv_loop({Ref,Client}, StayAlive) ->
error:Reason ->
{Reason,erlang:get_stacktrace()}
end,
- Client ! {Ref,Reply},
- case StayAlive of
- true -> start_port_srv_loop(get_open_port_request(), true);
- false -> exiting
- end.
+ Client ! {Ref,Reply}.
+
-get_open_port_request() ->
+start_port_srv_loop() ->
receive
{Ref, Client} = Request when is_reference(Ref),
is_pid(Client) ->
- Request;
+ start_port_srv_handle(Request);
_Junk ->
- get_open_port_request()
- end.
+ ignore
+ end,
+ start_port_srv_loop().
%%
%% unix_get_data(Port) -> Result
diff --git a/lib/kernel/src/pg2.erl b/lib/kernel/src/pg2.erl
index cb9fec2ffe..0d5838716e 100644
--- a/lib/kernel/src/pg2.erl
+++ b/lib/kernel/src/pg2.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -30,17 +30,19 @@
%%% Exported functions
%%%
--spec start_link() -> {'ok', pid()} | {'error', term()}.
+-spec start_link() -> {'ok', pid()} | {'error', any()}.
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
--spec start() -> {'ok', pid()} | {'error', term()}.
+-spec start() -> {'ok', pid()} | {'error', any()}.
start() ->
ensure_started().
--spec create(term()) -> 'ok'.
+-type name() :: any().
+
+-spec create(Name :: name()) -> 'ok'.
create(Name) ->
ensure_started(),
@@ -55,9 +57,7 @@ create(Name) ->
ok
end.
--type name() :: term().
-
--spec delete(name()) -> 'ok'.
+-spec delete(Name :: name()) -> 'ok'.
delete(Name) ->
ensure_started(),
@@ -67,7 +67,8 @@ delete(Name) ->
end),
ok.
--spec join(name(), pid()) -> 'ok' | {'error', {'no_such_group', term()}}.
+-spec join(Name, Pid :: pid()) -> 'ok' | {'error', {'no_such_group', Name}}
+ when Name :: name().
join(Name, Pid) when is_pid(Pid) ->
ensure_started(),
@@ -83,7 +84,8 @@ join(Name, Pid) when is_pid(Pid) ->
ok
end.
--spec leave(name(), pid()) -> 'ok' | {'error', {'no_such_group', name()}}.
+-spec leave(Name, Pid :: pid()) -> 'ok' | {'error', {'no_such_group', Name}}
+ when Name :: name().
leave(Name, Pid) when is_pid(Pid) ->
ensure_started(),
@@ -99,10 +101,9 @@ leave(Name, Pid) when is_pid(Pid) ->
ok
end.
--type get_members_ret() :: [pid()] | {'error', {'no_such_group', name()}}.
+-spec get_members(Name) -> [pid()] | {'error', {'no_such_group', Name}}
+ when Name :: name().
--spec get_members(name()) -> get_members_ret().
-
get_members(Name) ->
ensure_started(),
case ets:member(pg2_table, {group, Name}) of
@@ -112,7 +113,8 @@ get_members(Name) ->
{error, {no_such_group, Name}}
end.
--spec get_local_members(name()) -> get_members_ret().
+-spec get_local_members(Name) -> [pid()] | {'error', {'no_such_group', Name}}
+ when Name :: name().
get_local_members(Name) ->
ensure_started(),
@@ -123,15 +125,15 @@ get_local_members(Name) ->
{error, {no_such_group, Name}}
end.
--spec which_groups() -> [name()].
+-spec which_groups() -> [Name :: name()].
which_groups() ->
ensure_started(),
all_groups().
--type gcp_error_reason() :: {'no_process', term()} | {'no_such_group', term()}.
-
--spec get_closest_pid(term()) -> pid() | {'error', gcp_error_reason()}.
+-spec get_closest_pid(Name) -> pid() | {'error', Reason} when
+ Name :: name(),
+ Reason :: {'no_process', Name} | {'no_such_group', Name}.
get_closest_pid(Name) ->
case get_local_members(Name) of
@@ -157,7 +159,9 @@ get_closest_pid(Name) ->
-record(state, {}).
--spec init([]) -> {'ok', #state{}}.
+-opaque state() :: #state{}.
+
+-spec init(Arg :: []) -> {'ok', state()}.
init([]) ->
Ns = nodes(),
@@ -169,13 +173,13 @@ init([]) ->
pg2_table = ets:new(pg2_table, [ordered_set, protected, named_table]),
{ok, #state{}}.
--type call() :: {'create', name()}
- | {'delete', name()}
- | {'join', name(), pid()}
- | {'leave', name(), pid()}.
-
--spec handle_call(call(), _, #state{}) ->
- {'reply', 'ok', #state{}}.
+-spec handle_call(Call :: {'create', Name}
+ | {'delete', Name}
+ | {'join', Name, Pid :: pid()}
+ | {'leave', Name, Pid :: pid()},
+ From :: {pid(),Tag :: any()},
+ State :: state()) -> {'reply', 'ok', state()}
+ when Name :: name().
handle_call({create, Name}, _From, S) ->
assure_group(Name),
@@ -195,11 +199,10 @@ handle_call(Request, From, S) ->
[Request, From]),
{noreply, S}.
--type all_members() :: [[name(),...]].
--type cast() :: {'exchange', node(), all_members()}
- | {'del_member', name(), pid()}.
-
--spec handle_cast(cast(), #state{}) -> {'noreply', #state{}}.
+-spec handle_cast(Cast :: {'exchange', node(), Names :: [[Name,...]]}
+ | {'del_member', Name, Pid :: pid()},
+ State :: state()) -> {'noreply', state()}
+ when Name :: name().
handle_cast({exchange, _Node, List}, S) ->
store(List),
@@ -208,7 +211,8 @@ handle_cast(_, S) ->
%% Ignore {del_member, Name, Pid}.
{noreply, S}.
--spec handle_info(tuple(), #state{}) -> {'noreply', #state{}}.
+-spec handle_info(Tuple :: tuple(), State :: state()) ->
+ {'noreply', state()}.
handle_info({'DOWN', MonitorRef, process, _Pid, _Info}, S) ->
member_died(MonitorRef),
@@ -222,7 +226,7 @@ handle_info({new_pg2, Node}, S) ->
handle_info(_, S) ->
{noreply, S}.
--spec terminate(term(), #state{}) -> 'ok'.
+-spec terminate(Reason :: any(), State :: state()) -> 'ok'.
terminate(_Reason, _S) ->
true = ets:delete(pg2_table),
@@ -251,7 +255,9 @@ terminate(_Reason, _S) ->
%%% Pid is a member of group Name.
store(List) ->
- _ = [assure_group(Name) andalso [join_group(Name, P) || P <- Members] ||
+ _ = [(assure_group(Name)
+ andalso
+ [join_group(Name, P) || P <- Members -- group_members(Name)]) ||
[Name, Members] <- List],
ok.
diff --git a/lib/kernel/src/ram_file.erl b/lib/kernel/src/ram_file.erl
index d996650948..48ea871433 100644
--- a/lib/kernel/src/ram_file.erl
+++ b/lib/kernel/src/ram_file.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(ram_file).
@@ -24,11 +24,11 @@
-export([open/2, close/1]).
-export([write/2, read/2, copy/3,
pread/2, pread/3, pwrite/2, pwrite/3,
- position/2, truncate/1, sync/1]).
+ position/2, truncate/1, datasync/1, sync/1]).
%% Specialized file operations
-export([get_size/1, get_file/1, set_file/2, get_file_close/1]).
--export([compress/1, uncompress/1, uuencode/1, uudecode/1]).
+-export([compress/1, uncompress/1, uuencode/1, uudecode/1, advise/4]).
-export([open_mode/1]). %% used by ftp-file
@@ -60,6 +60,7 @@
-define(RAM_FILE_TRUNCATE, 14).
-define(RAM_FILE_PREAD, 17).
-define(RAM_FILE_PWRITE, 18).
+-define(RAM_FILE_FDATASYNC, 19).
%% Other operations
-define(RAM_FILE_GET, 30).
@@ -70,6 +71,7 @@
-define(RAM_FILE_UUENCODE, 35).
-define(RAM_FILE_UUDECODE, 36).
-define(RAM_FILE_SIZE, 37).
+-define(RAM_FILE_ADVISE, 38).
%% Open modes for RAM_FILE_OPEN
-define(RAM_FILE_MODE_READ, 1).
@@ -90,6 +92,14 @@
-define(RAM_FILE_RESP_NUMBER, 3).
-define(RAM_FILE_RESP_INFO, 4).
+%% POSIX file advises
+-define(POSIX_FADV_NORMAL, 0).
+-define(POSIX_FADV_RANDOM, 1).
+-define(POSIX_FADV_SEQUENTIAL, 2).
+-define(POSIX_FADV_WILLNEED, 3).
+-define(POSIX_FADV_DONTNEED, 4).
+-define(POSIX_FADV_NOREUSE, 5).
+
%% --------------------------------------------------------------------------
%% Generic file contents operations.
%%
@@ -167,6 +177,8 @@ copy(#file_descriptor{module = ?MODULE} = Source,
%% XXX Should be moved down to the driver for optimization.
file:copy_opened(Source, Dest, Length).
+datasync(#file_descriptor{module = ?MODULE, data = Port}) ->
+ call_port(Port, <<?RAM_FILE_FDATASYNC>>).
sync(#file_descriptor{module = ?MODULE, data = Port}) ->
call_port(Port, <<?RAM_FILE_FSYNC>>).
@@ -349,6 +361,28 @@ uudecode(#file_descriptor{module = ?MODULE, data = Port}) ->
uudecode(#file_descriptor{}) ->
{error, enotsup}.
+advise(#file_descriptor{module = ?MODULE, data = Port}, Offset,
+ Length, Advise) ->
+ Cmd0 = <<?RAM_FILE_ADVISE, Offset:64/signed, Length:64/signed>>,
+ case Advise of
+ normal ->
+ call_port(Port, <<Cmd0/binary, ?POSIX_FADV_NORMAL:32/signed>>);
+ random ->
+ call_port(Port, <<Cmd0/binary, ?POSIX_FADV_RANDOM:32/signed>>);
+ sequential ->
+ call_port(Port, <<Cmd0/binary, ?POSIX_FADV_SEQUENTIAL:32/signed>>);
+ will_need ->
+ call_port(Port, <<Cmd0/binary, ?POSIX_FADV_WILLNEED:32/signed>>);
+ dont_need ->
+ call_port(Port, <<Cmd0/binary, ?POSIX_FADV_DONTNEED:32/signed>>);
+ no_reuse ->
+ call_port(Port, <<Cmd0/binary, ?POSIX_FADV_NOREUSE:32/signed>>);
+ _ ->
+ {error, einval}
+ end;
+advise(#file_descriptor{}, _Offset, _Length, _Advise) ->
+ {error, enotsup}.
+
%%%-----------------------------------------------------------------
diff --git a/lib/kernel/src/rpc.erl b/lib/kernel/src/rpc.erl
index d69f2a12ad..e214ffa404 100644
--- a/lib/kernel/src/rpc.erl
+++ b/lib/kernel/src/rpc.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-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(rpc).
@@ -56,7 +56,7 @@
-export([safe_multi_server_call/2,safe_multi_server_call/3]).
%% gen_server exports
--export([init/1,handle_call/3,handle_cast/2,handle_info/2,
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
%% Internals
@@ -64,13 +64,23 @@
%%------------------------------------------------------------------------
+-type state() :: gb_tree().
+
+%%------------------------------------------------------------------------
+
%% Remote execution and broadcasting facility
+-spec start() -> {'ok', pid()} | 'ignore' | {'error', term()}.
+
start() ->
- gen_server:start({local,?NAME},?MODULE,[],[]).
+ gen_server:start({local,?NAME}, ?MODULE, [], []).
+
+-spec start_link() -> {'ok', pid()} | 'ignore' | {'error', term()}.
start_link() ->
- gen_server:start_link({local,?NAME},?MODULE,[],[]).
+ gen_server:start_link({local,?NAME}, ?MODULE, [], []).
+
+-spec stop() -> term().
stop() ->
stop(?NAME).
@@ -78,11 +88,17 @@ stop() ->
stop(Rpc) ->
gen_server:call(Rpc, stop, infinity).
--spec init([]) -> {'ok', gb_tree()}.
+-spec init([]) -> {'ok', state()}.
+
init([]) ->
process_flag(trap_exit, true),
{ok, gb_trees:empty()}.
+-spec handle_call(term(), term(), state()) ->
+ {'noreply', state()} |
+ {'reply', term(), state()} |
+ {'stop', 'normal', 'stopped', state()}.
+
handle_call({call, Mod, Fun, Args, Gleader}, To, S) ->
handle_call_call(Mod, Fun, Args, Gleader, To, S);
handle_call({block_call, Mod, Fun, Args, Gleader}, _To, S) ->
@@ -102,17 +118,18 @@ handle_call(stop, _To, S) ->
handle_call(_, _To, S) ->
{noreply, S}. % Ignore !
+-spec handle_cast(term(), state()) -> {'noreply', state()}.
handle_cast({cast, Mod, Fun, Args, Gleader}, S) ->
- spawn(
- fun() ->
- set_group_leader(Gleader),
- apply(Mod, Fun, Args)
- end),
- {noreply, S};
+ spawn(fun() ->
+ set_group_leader(Gleader),
+ apply(Mod, Fun, Args)
+ end),
+ {noreply, S};
handle_cast(_, S) ->
{noreply, S}. % Ignore !
+-spec handle_info(term(), state()) -> {'noreply', state()}.
handle_info({'DOWN', _, process, Caller, Reason}, S) ->
case gb_trees:lookup(Caller, S) of
@@ -145,7 +162,7 @@ handle_info({From, {sbcast, Name, Msg}}, S) ->
_ ->
From ! {?NAME, node(), node()}
end,
- {noreply,S};
+ {noreply, S};
handle_info({From, {send, Name, Msg}}, S) ->
case catch Name ! {From, Msg} of %% use catch to get the printout
{'EXIT', _} ->
@@ -153,16 +170,20 @@ handle_info({From, {send, Name, Msg}}, S) ->
_ ->
ok %% It's up to Name to respond !!!!!
end,
- {noreply,S};
+ {noreply, S};
handle_info({From, {call,Mod,Fun,Args,Gleader}}, S) ->
%% Special for hidden C node's, uugh ...
handle_call_call(Mod, Fun, Args, Gleader, {From,?NAME}, S);
handle_info(_, S) ->
- {noreply,S}.
+ {noreply, S}.
+
+-spec terminate(term(), state()) -> 'ok'.
terminate(_, _S) ->
ok.
+-spec code_change(term(), state(), term()) -> {'ok', state()}.
+
code_change(_, S, _) ->
{ok, S}.
@@ -209,7 +230,7 @@ proxy_user() ->
case whereis(rex_proxy_user) of
Pid when is_pid(Pid) -> Pid;
undefined ->
- Pid = spawn(fun()-> proxy_user_loop() end),
+ Pid = spawn(fun() -> proxy_user_loop() end),
try register(rex_proxy_user,Pid) of
true -> Pid
catch error:_ -> % spawn race, kill and try again
@@ -226,6 +247,8 @@ proxy_user_loop() ->
undefined -> proxy_user_loop()
end.
+-spec proxy_user_flush() -> no_return().
+
proxy_user_flush() ->
%% Forward all received messages to 'user'
receive Msg ->
@@ -240,14 +263,28 @@ proxy_user_flush() ->
%% THE rpc client interface
--spec call(node(), atom(), atom(), [term()]) -> term().
+-spec call(Node, Module, Function, Args) -> Res | {badrpc, Reason} when
+ Node :: node(),
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ Res :: term(),
+ Reason :: term().
call(N,M,F,A) when node() =:= N -> %% Optimize local call
local_call(M, F, A);
call(N,M,F,A) ->
do_call(N, {call,M,F,A,group_leader()}, infinity).
--spec call(node(), atom(), atom(), [term()], timeout()) -> term().
+-spec call(Node, Module, Function, Args, Timeout) ->
+ Res | {badrpc, Reason} when
+ Node :: node(),
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ Res :: term(),
+ Reason :: term(),
+ Timeout :: timeout().
call(N,M,F,A,_Timeout) when node() =:= N -> %% Optimize local call
local_call(M,F,A);
@@ -256,14 +293,28 @@ call(N,M,F,A,infinity) ->
call(N,M,F,A,Timeout) when is_integer(Timeout), Timeout >= 0 ->
do_call(N, {call,M,F,A,group_leader()}, Timeout).
--spec block_call(node(), atom(), atom(), [term()]) -> term().
+-spec block_call(Node, Module, Function, Args) -> Res | {badrpc, Reason} when
+ Node :: node(),
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ Res :: term(),
+ Reason :: term().
block_call(N,M,F,A) when node() =:= N -> %% Optimize local call
local_call(M,F,A);
block_call(N,M,F,A) ->
do_call(N, {block_call,M,F,A,group_leader()}, infinity).
--spec block_call(node(), atom(), atom(), [term()], timeout()) -> term().
+-spec block_call(Node, Module, Function, Args, Timeout) ->
+ Res | {badrpc, Reason} when
+ Node :: node(),
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ Res :: term(),
+ Reason :: term(),
+ Timeout :: timeout().
block_call(N,M,F,A,_Timeout) when node() =:= N -> %% Optimize local call
local_call(M, F, A);
@@ -316,7 +367,13 @@ rpc_check(X) -> X.
%% The entire call is packed into an atomic transaction which
%% either succeeds or fails, i.e. never hangs (unless the server itself hangs).
--spec server_call(node(), atom(), term(), term()) -> term() | {'error', 'nodedown'}.
+-spec server_call(Node, Name, ReplyWrapper, Msg) -> Reply | {error, Reason} when
+ Node :: node(),
+ Name :: atom(),
+ ReplyWrapper :: term(),
+ Msg :: term(),
+ Reply :: term(),
+ Reason :: nodedown.
server_call(Node, Name, ReplyWrapper, Msg)
when is_atom(Node), is_atom(Name) ->
@@ -339,7 +396,11 @@ server_call(Node, Name, ReplyWrapper, Msg)
end
end.
--spec cast(node(), atom(), atom(), [term()]) -> 'true'.
+-spec cast(Node, Module, Function, Args) -> true when
+ Node :: node(),
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()].
cast(Node, Mod, Fun, Args) when Node =:= node() ->
catch spawn(Mod, Fun, Args),
@@ -350,12 +411,17 @@ cast(Node, Mod, Fun, Args) ->
%% Asynchronous broadcast, returns nothing, it's just send'n prey
--spec abcast(atom(), term()) -> 'abcast'.
+-spec abcast(Name, Msg) -> abcast when
+ Name :: atom(),
+ Msg :: term().
abcast(Name, Mess) ->
abcast([node() | nodes()], Name, Mess).
--spec abcast([node()], atom(), term()) -> 'abcast'.
+-spec abcast(Nodes, Name, Msg) -> abcast when
+ Nodes :: [node()],
+ Name :: atom(),
+ Msg :: term().
abcast([Node|Tail], Name, Mess) ->
Dest = {Name,Node},
@@ -373,23 +439,39 @@ abcast([], _,_) -> abcast.
%% message when we return from the call, we can't know that they have
%% processed the message though.
--spec sbcast(atom(), term()) -> {[node()], [node()]}.
+-spec sbcast(Name, Msg) -> {GoodNodes, BadNodes} when
+ Name :: atom(),
+ Msg :: term(),
+ GoodNodes :: [node()],
+ BadNodes :: [node()].
sbcast(Name, Mess) ->
sbcast([node() | nodes()], Name, Mess).
--spec sbcast([node()], atom(), term()) -> {[node()], [node()]}.
+-spec sbcast(Nodes, Name, Msg) -> {GoodNodes, BadNodes} when
+ Name :: atom(),
+ Msg :: term(),
+ Nodes :: [node()],
+ GoodNodes :: [node()],
+ BadNodes :: [node()].
sbcast(Nodes, Name, Mess) ->
Monitors = send_nodes(Nodes, ?NAME, {sbcast, Name, Mess}, []),
rec_nodes(?NAME, Monitors).
--spec eval_everywhere(atom(), atom(), [term()]) -> 'abcast'.
+-spec eval_everywhere(Module, Function, Args) -> abcast when
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()].
eval_everywhere(Mod, Fun, Args) ->
eval_everywhere([node() | nodes()] , Mod, Fun, Args).
--spec eval_everywhere([node()], atom(), atom(), [term()]) -> 'abcast'.
+-spec eval_everywhere(Nodes, Module, Function, Args) -> abcast when
+ Nodes :: [node()],
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()].
eval_everywhere(Nodes, Mod, Fun, Args) ->
gen_server:abcast(Nodes, ?NAME, {cast,Mod,Fun,Args,group_leader()}).
@@ -430,20 +512,45 @@ unmonitor(Ref) when is_reference(Ref) ->
%% Call apply(M,F,A) on all nodes in parallel
--spec multicall(atom(), atom(), [term()]) -> {[_], [node()]}.
+-spec multicall(Module, Function, Args) -> {ResL, BadNodes} when
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ ResL :: [term()],
+ BadNodes :: [node()].
multicall(M, F, A) ->
multicall(M, F, A, infinity).
--spec multicall([node()], atom(), atom(), [term()]) -> {[_], [node()]}
- ; (atom(), atom(), [term()], timeout()) -> {[_], [node()]}.
+-spec multicall(Nodes, Module, Function, Args) -> {ResL, BadNodes} when
+ Nodes :: [node()],
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ ResL :: [term()],
+ BadNodes :: [node()];
+ (Module, Function, Args, Timeout) -> {ResL, BadNodes} when
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ Timeout :: timeout(),
+ ResL :: [term()],
+ BadNodes :: [node()].
multicall(Nodes, M, F, A) when is_list(Nodes) ->
multicall(Nodes, M, F, A, infinity);
multicall(M, F, A, Timeout) ->
multicall([node() | nodes()], M, F, A, Timeout).
--spec multicall([node()], atom(), atom(), [term()], timeout()) -> {[_], [node()]}.
+-spec multicall(Nodes, Module, Function, Args, Timeout) ->
+ {ResL, BadNodes} when
+ Nodes :: [node()],
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ Timeout :: timeout(),
+ ResL :: [term()],
+ BadNodes :: [node()].
multicall(Nodes, M, F, A, infinity)
when is_list(Nodes), is_atom(M), is_atom(F), is_list(A) ->
@@ -472,12 +579,21 @@ do_multicall(Nodes, M, F, A, Timeout) ->
%%
%% There is no apparent order among the replies.
--spec multi_server_call(atom(), term()) -> {[_], [node()]}.
+-spec multi_server_call(Name, Msg) -> {Replies, BadNodes} when
+ Name :: atom(),
+ Msg :: term(),
+ Replies :: [Reply :: term()],
+ BadNodes :: [node()].
multi_server_call(Name, Msg) ->
multi_server_call([node() | nodes()], Name, Msg).
--spec multi_server_call([node()], atom(), term()) -> {[_], [node()]}.
+-spec multi_server_call(Nodes, Name, Msg) -> {Replies, BadNodes} when
+ Nodes :: [node()],
+ Name :: atom(),
+ Msg :: term(),
+ Replies :: [Reply :: term()],
+ BadNodes :: [node()].
multi_server_call(Nodes, Name, Msg)
when is_list(Nodes), is_atom(Name) ->
@@ -486,9 +602,22 @@ multi_server_call(Nodes, Name, Msg)
%% Deprecated functions. Were only needed when communicating with R6 nodes.
+-spec safe_multi_server_call(Name, Msg) -> {Replies, BadNodes} when
+ Name :: atom(),
+ Msg :: term(),
+ Replies :: [Reply :: term()],
+ BadNodes :: [node()].
+
safe_multi_server_call(Name, Msg) ->
multi_server_call(Name, Msg).
+-spec safe_multi_server_call(Nodes, Name, Msg) -> {Replies, BadNodes} when
+ Nodes :: [node()],
+ Name :: atom(),
+ Msg :: term(),
+ Replies :: [Reply :: term()],
+ BadNodes :: [node()].
+
safe_multi_server_call(Nodes, Name, Msg) ->
multi_server_call(Nodes, Name, Msg).
@@ -516,7 +645,14 @@ rec_nodes(Name, [{N,R} | Tail], Badnodes, Replies) ->
%% rpc's towards the same node. I.e. it returns immediately and
%% it returns a Key that can be used in a subsequent yield(Key).
--spec async_call(node(), atom(), atom(), [term()]) -> pid().
+-opaque key() :: pid().
+
+-spec async_call(Node, Module, Function, Args) -> Key when
+ Node :: node(),
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ Key :: key().
async_call(Node, Mod, Fun, Args) ->
ReplyTo = self(),
@@ -526,20 +662,28 @@ async_call(Node, Mod, Fun, Args) ->
ReplyTo ! {self(), {promise_reply, R}} %% self() is key
end).
--spec yield(pid()) -> term().
+-spec yield(Key) -> Res | {badrpc, Reason} when
+ Key :: key(),
+ Res :: term(),
+ Reason :: term().
yield(Key) when is_pid(Key) ->
{value,R} = do_yield(Key, infinity),
R.
--spec nb_yield(pid(), timeout()) -> {'value', _} | 'timeout'.
+-spec nb_yield(Key, Timeout) -> {value, Val} | timeout when
+ Key :: key(),
+ Timeout :: timeout(),
+ Val :: (Res :: term()) | {badrpc, Reason :: term()}.
nb_yield(Key, infinity=Inf) when is_pid(Key) ->
do_yield(Key, Inf);
nb_yield(Key, Timeout) when is_pid(Key), is_integer(Timeout), Timeout >= 0 ->
do_yield(Key, Timeout).
--spec nb_yield(pid()) -> {'value', _} | 'timeout'.
+-spec nb_yield(Key) -> {value, Val} | timeout when
+ Key :: key(),
+ Val :: (Res :: term()) | {badrpc, Reason :: term()}.
nb_yield(Key) when is_pid(Key) ->
do_yield(Key, 0).
@@ -559,7 +703,12 @@ do_yield(Key, Timeout) ->
%% ArgL === [{M,F,Args},........]
%% Returns a lists of the evaluations in the same order as
%% given to ArgL
--spec parallel_eval([{atom(), atom(), [_]}]) -> [_].
+-spec parallel_eval(FuncCalls) -> ResL when
+ FuncCalls :: [{Module, Function, Args}],
+ Module :: module(),
+ Function :: atom(),
+ Args :: [term()],
+ ResL :: [term()].
parallel_eval(ArgL) ->
Nodes = [node() | nodes()],
@@ -576,7 +725,13 @@ map_nodes([{M,F,A}|Tail],[Node|MoreNodes], Original) ->
%% Parallel version of lists:map/3 with exactly the same
%% arguments and return value as lists:map/3,
%% except that it calls exit/1 if a network error occurs.
--spec pmap({atom(),atom()}, [term()], [term()]) -> [term()].
+-spec pmap(FuncSpec, ExtraArgs, List1) -> List2 when
+ FuncSpec :: {Module,Function},
+ Module :: module(),
+ Function :: atom(),
+ ExtraArgs :: [term()],
+ List1 :: [Elem :: term()],
+ List2 :: [term()].
pmap({M,F}, As, List) ->
check(parallel_eval(build_args(M,F,As, List, [])), []).
@@ -593,15 +748,20 @@ check([], Ack) -> Ack.
%% location transparent version of process_info
--spec pinfo(pid()) -> [{atom(), _}] | 'undefined'.
+-spec pinfo(Pid) -> [{Item, Info}] | undefined when
+ Pid :: pid(),
+ Item :: atom(),
+ Info :: term().
pinfo(Pid) when node(Pid) =:= node() ->
process_info(Pid);
pinfo(Pid) ->
call(node(Pid), erlang, process_info, [Pid]).
--spec pinfo(pid(), Item) -> {Item, _} | 'undefined' | []
- when is_subtype(Item, atom()).
+-spec pinfo(Pid, Item) -> {Item, Info} | undefined | [] when
+ Pid :: pid(),
+ Item :: atom(),
+ Info :: term().
pinfo(Pid, Item) when node(Pid) =:= node() ->
process_info(Pid, Item);
diff --git a/lib/kernel/src/seq_trace.erl b/lib/kernel/src/seq_trace.erl
index 78c3040f21..a90b7b07c8 100644
--- a/lib/kernel/src/seq_trace.erl
+++ b/lib/kernel/src/seq_trace.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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
@@ -38,15 +38,17 @@
-type flag() :: 'send' | 'receive' | 'print' | 'timestamp'.
-type component() :: 'label' | 'serial' | flag().
--type value() :: non_neg_integer()
- | {non_neg_integer(), non_neg_integer()}
- | boolean().
--type token_pair() :: {component(), value()}.
+-type value() :: (Integer :: non_neg_integer())
+ | {Previous :: non_neg_integer(),
+ Current :: non_neg_integer()}
+ | (Bool :: boolean()).
%%---------------------------------------------------------------------------
--type token() :: [] | {integer(), boolean(), _, _, _}.
--spec set_token(token()) -> token() | 'ok'.
+-type token() :: {integer(), boolean(), _, _, _}.
+-spec set_token(Token) -> PreviousToken | 'ok' when
+ Token :: [] | token(),
+ PreviousToken :: [] | token().
set_token([]) ->
erlang:seq_trace(sequential_trace_token,[]);
@@ -58,28 +60,35 @@ set_token({Flags,Label,Serial,_From,Lastcnt}) ->
%% expects that, the BIF can however "unofficially" handle atoms as well, and
%% atoms can be used if only Erlang nodes are involved
--spec set_token(component(), value()) -> token_pair().
+-spec set_token(Component, Val) -> {Component, OldVal} when
+ Component :: component(),
+ Val :: value(),
+ OldVal :: value().
set_token(Type, Val) ->
erlang:seq_trace(Type, Val).
--spec get_token() -> term().
+-spec get_token() -> [] | token().
get_token() ->
element(2,process_info(self(),sequential_trace_token)).
--spec get_token(component()) -> token_pair().
-
+-spec get_token(Component) -> {Component, Val} when
+ Component :: component(),
+ Val :: value().
get_token(Type) ->
erlang:seq_trace_info(Type).
--spec print(term()) -> 'ok'.
+-spec print(TraceInfo) -> 'ok' when
+ TraceInfo :: term().
print(Term) ->
erlang:seq_trace_print(Term),
ok.
--spec print(integer(), term()) -> 'ok'.
+-spec print(Label, TraceInfo) -> 'ok' when
+ Label :: integer(),
+ TraceInfo :: term().
print(Label, Term) when is_atom(Label) ->
erlang:error(badarg, [Label, Term]);
@@ -94,14 +103,17 @@ reset_trace() ->
%% reset_trace(Pid) -> % this might be a useful function too
--type tracer() :: pid() | port() | 'false'.
+-type tracer() :: (Pid :: pid()) | port() | 'false'.
--spec set_system_tracer(tracer()) -> tracer().
+-spec set_system_tracer(Tracer) -> OldTracer when
+ Tracer :: tracer(),
+ OldTracer :: tracer().
set_system_tracer(Pid) ->
erlang:system_flag(sequential_tracer, Pid).
--spec get_system_tracer() -> tracer().
+-spec get_system_tracer() -> Tracer when
+ Tracer :: tracer().
get_system_tracer() ->
element(2, erlang:system_info(sequential_tracer)).
diff --git a/lib/kernel/src/standard_error.erl b/lib/kernel/src/standard_error.erl
index 73901d9896..e41dcd01fc 100644
--- a/lib/kernel/src/standard_error.erl
+++ b/lib/kernel/src/standard_error.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(standard_error).
@@ -24,8 +24,6 @@
-define(NAME, standard_error).
-define(PROCNAME_SUP, standard_error_sup).
-%% Internal exports
--export([server/1, server/2]).
%% Defines for control ops
-define(CTRL_OP_GET_WINSIZE,100).
@@ -33,13 +31,19 @@
%%
%% The basic server and start-up.
%%
+-spec start_link() -> 'ignore' | {'error',term()} | {'ok',pid()}.
+
start_link() ->
supervisor_bridge:start_link({local, ?PROCNAME_SUP}, ?MODULE, []).
+-spec terminate(term(), pid()) -> 'ok'.
+
terminate(_Reason,Pid) ->
(catch exit(Pid,kill)),
ok.
+-spec init([]) -> {'error','no_stderror'} | {'ok',pid(),pid()}.
+
init([]) ->
case (catch start_port([out,binary])) of
Pid when is_pid(Pid) ->
@@ -48,18 +52,11 @@ init([]) ->
{error,no_stderror}
end.
-
start_port(PortSettings) ->
- Id = spawn(?MODULE,server,[{fd,2,2},PortSettings]),
- register(?NAME,Id),
+ Id = spawn(fun () -> server({fd,2,2}, PortSettings) end),
+ register(?NAME, Id),
Id.
-
-server(Pid) when is_pid(Pid) ->
- process_flag(trap_exit, true),
- link(Pid),
- run(Pid).
-
server(PortName,PortSettings) ->
process_flag(trap_exit, true),
Port = open_port(PortName,PortSettings),
@@ -82,17 +79,15 @@ server_loop(Port) ->
server_loop(Port)
end.
-
get_fd_geometry(Port) ->
case (catch port_control(Port,?CTRL_OP_GET_WINSIZE,[])) of
- List when is_list(List), length(List) =:= 8 ->
+ List when length(List) =:= 8 ->
<<W:32/native,H:32/native>> = list_to_binary(List),
{W,H};
_ ->
error
end.
-
%% NewSaveBuffer = io_request(Request, FromPid, ReplyAs, Port, SaveBuffer)
do_io_request(Req, From, ReplyAs, Port) ->
@@ -221,12 +216,7 @@ do_setopts(Opts, _Port) ->
{ok,ok}.
getopts(_Port) ->
- Uni = {unicode, case get(unicode) of
- true ->
- true;
- _ ->
- false
- end},
+ Uni = {unicode, get(unicode) =:= true},
{ok,[Uni]}.
wrap_characters_to_binary(Chars,From,To) ->
diff --git a/lib/kernel/src/user.erl b/lib/kernel/src/user.erl
index 17dc5a56a2..88f32df20b 100644
--- a/lib/kernel/src/user.erl
+++ b/lib/kernel/src/user.erl
@@ -26,9 +26,6 @@
-define(NAME, user).
-%% Internal exports
--export([server/1, server/2]).
-
%% Defines for control ops
-define(CTRL_OP_GET_WINSIZE,100).
@@ -43,7 +40,7 @@ start([Mod,Fun|Args]) ->
%% Mod,Fun,Args should return a pid. That process is supposed to act
%% as the io port.
Pid = apply(Mod, Fun, Args), % This better work!
- Id = spawn(?MODULE, server, [Pid]),
+ Id = spawn(fun() -> server(Pid) end),
register(?NAME, Id),
Id.
@@ -52,8 +49,8 @@ start_out() ->
start_port([out,binary]).
start_port(PortSettings) ->
- Id = spawn(?MODULE,server,[{fd,0,1},PortSettings]),
- register(?NAME,Id),
+ Id = spawn(fun() -> server({fd,0,1}, PortSettings) end),
+ register(?NAME, Id),
Id.
%% Return the pid of the shell process.
@@ -72,7 +69,6 @@ interfaces(User) ->
[]
end.
-
server(Pid) when is_pid(Pid) ->
process_flag(trap_exit, true),
link(Pid),
@@ -104,7 +100,7 @@ catch_loop(Port, Shell, Q) ->
new_shell ->
exit(Shell, kill),
catch_loop(Port, start_new_shell());
- {unknown_exit,{Shell,Reason},_} -> % shell has exited
+ {unknown_exit,{Shell,Reason},_} -> % shell has exited
case Reason of
normal ->
put_chars("*** ", Port, []);
@@ -172,7 +168,7 @@ server_loop(Port, Q) ->
get_fd_geometry(Port) ->
case (catch port_control(Port,?CTRL_OP_GET_WINSIZE,[])) of
- List when is_list(List), length(List) =:= 8 ->
+ List when length(List) =:= 8 ->
<<W:32/native,H:32/native>> = list_to_binary(List),
{W,H};
_ ->
@@ -373,12 +369,7 @@ do_setopts(Opts, _Port, Q) ->
end.
getopts(_Port,Q) ->
- Bin = {binary, case get(read_mode) of
- binary ->
- true;
- _ ->
- false
- end},
+ Bin = {binary, get(read_mode) =:= binary},
Uni = {encoding, case get(unicode) of
true ->
unicode;
diff --git a/lib/kernel/src/wrap_log_reader.erl b/lib/kernel/src/wrap_log_reader.erl
index 5030d3aed5..c41e0091e4 100644
--- a/lib/kernel/src/wrap_log_reader.erl
+++ b/lib/kernel/src/wrap_log_reader.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1998-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%
%%
@@ -37,10 +37,12 @@
cont :: dlog_cont(), % disk_log's continuation record
file :: file:filename(), % file name without extension
file_no :: non_neg_integer(), % current file number
- mod_time :: date_time(), % modification time of current file
+ mod_time :: file:date_time(), % modification time of current file
first_no :: non_neg_integer() | 'one' % first read file number
}).
+-opaque continuation() :: #wrap_reader{}.
+
%%
%% Exported functions
%%
@@ -50,9 +52,11 @@
%% is not yet reached, we are on the first 'round' of filling the wrap
%% files.
--type open_ret() :: {'ok', #wrap_reader{}} | {'error', tuple()}.
+-type open_ret() :: {'ok', Continuation :: continuation()}
+ | {'error', Reason :: tuple()}.
--spec open(atom() | string()) -> open_ret().
+-spec open(Filename) -> open_ret() when
+ Filename :: string() | atom().
open(File) when is_atom(File) ->
open(atom_to_list(File));
@@ -77,7 +81,9 @@ open(File) when is_list(File) ->
Error
end.
--spec open(atom() | string(), integer()) -> open_ret().
+-spec open(Filename, N) -> open_ret() when
+ Filename :: string() | atom(),
+ N :: integer().
open(File, FileNo) when is_atom(File), is_integer(FileNo) ->
open(atom_to_list(File), FileNo);
@@ -100,22 +106,29 @@ open(File, FileNo) when is_list(File), is_integer(FileNo) ->
Error
end.
--spec close(#wrap_reader{}) -> 'ok' | {'error', atom()}.
+-spec close(Continuation) -> 'ok' | {'error', Reason} when
+ Continuation :: continuation(),
+ Reason :: file:posix().
close(#wrap_reader{fd = FD}) ->
file:close(FD).
--type chunk_ret() :: {#wrap_reader{}, [term()]}
- | {#wrap_reader{}, [term()], non_neg_integer()}
- | {#wrap_reader{}, 'eof'}
- | {'error', term()}.
+-type chunk_ret() :: {Continuation2, Terms :: [term()]}
+ | {Continuation2,
+ Terms :: [term()],
+ Badbytes :: non_neg_integer()}
+ | {Continuation2, 'eof'}
+ | {'error', Reason :: term()}.
--spec chunk(#wrap_reader{}) -> chunk_ret().
+-spec chunk(Continuation) -> chunk_ret() when
+ Continuation :: continuation().
chunk(WR = #wrap_reader{}) ->
chunk(WR, ?MAX_CHUNK_SIZE, 0).
--spec chunk(#wrap_reader{}, 'infinity' | pos_integer()) -> chunk_ret().
+-spec chunk(Continuation, N) -> chunk_ret() when
+ Continuation :: continuation(),
+ N :: infinity | pos_integer().
chunk(WR = #wrap_reader{}, infinity) ->
chunk(WR, ?MAX_CHUNK_SIZE, 0);