diff options
Diffstat (limited to 'lib/kernel/src')
40 files changed, 971 insertions, 821 deletions
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..5c7fe2421d 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-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(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,6 +50,8 @@ %% Exported functions %%---------------------------------------------------------------------- +-spec start_link() -> {'ok',pid()} | {'error', term()} | 'ignore'. + start_link() -> gen_server:start_link({local, auth}, auth, [], []). @@ -61,24 +65,24 @@ is_auth(Node) -> pang -> no end. --spec cookie() -> atom(). +-spec cookie() -> cookie(). cookie() -> get_cookie(). --spec cookie(Cookies :: [atom(),...] | atom()) -> 'true'. +-spec cookie(Cookies :: [cookie(),...] | cookie()) -> 'true'. 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 :: node(), Cookie :: cookie()) -> 'yes' | 'no'. node_cookie(Node, Cookie) -> set_cookie(Node, Cookie), @@ -86,24 +90,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 +121,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 +136,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 +158,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 +166,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 +177,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()]), @@ -188,10 +210,10 @@ handle_info({_From,badcookie,ddd_server,_Mess}, O) -> {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 +237,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 +286,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..ec256d5806 100644 --- a/lib/kernel/src/code.erl +++ b/lib/kernel/src/code.erl @@ -66,6 +66,8 @@ set_primary_archive/3, clash/0]). +-export_type([load_error_rsn/0, load_ret/0]). + -include_lib("kernel/include/file.hrl"). %% User interface. @@ -302,6 +304,8 @@ do_start(Flags) -> true -> ok end, + % Quietly load the native code for all modules loaded so far. + catch load_native_code_for_all_loaded(), Ok2; Other -> Other @@ -425,8 +429,8 @@ where_is_file(Path, File) when is_list(Path), is_list(File) -> FileInfo :: #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,7 +477,7 @@ 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). @@ -494,3 +498,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..4a1fc7df34 100644 --- a/lib/kernel/src/code_server.erl +++ b/lib/kernel/src/code_server.erl @@ -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", diff --git a/lib/kernel/src/disk_log.hrl b/lib/kernel/src/disk_log.hrl index b0849145ca..9a94d4d3b9 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-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% %% @@ -44,17 +44,11 @@ -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 %%------------------------------------------------------------------------ @@ -94,7 +88,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..8ccdb88d12 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-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(disk_log_1). @@ -1529,7 +1529,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 +1539,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..b4c5f5e27c 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-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% %% %% A simple boot_server at a CP. @@ -53,6 +53,7 @@ bootp :: pid(), %% boot process prim_state %% state for efile code loader }). +-type state() :: #state{}. -define(single_addr_mask, {255, 255, 255, 255}). @@ -165,6 +166,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 +179,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 +203,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 +240,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 +256,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_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..17dd02acd4 100644 --- a/lib/kernel/src/error_handler.erl +++ b/lib/kernel/src/error_handler.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(error_handler). @@ -117,13 +117,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/file.erl b/lib/kernel/src/file.erl index a42771dfb6..cffe4e3db5 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -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"). @@ -74,15 +77,24 @@ %% data types -type filename() :: string(). -type file_info() :: #file_info{}. --type io_device() :: pid() | #file_descriptor{}. +-type fd() :: #file_descriptor{}. +-type io_device() :: pid() | fd(). -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'. + 'read_ahead' | 'compressed' | 'exclusive'. +-type name() :: string() | atom() | [name()]. +-type posix() :: atom(). -type bindings() :: any(). +-type date() :: {pos_integer(), pos_integer(), pos_integer()}. +-type time() :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}. +-type date_time() :: {date(), time()}. +-type posix_file_advise() :: 'normal' | 'sequential' | 'random' | 'no_reuse' | + 'will_need' | 'dont_need'. + %%%----------------------------------------------------------------- %%% General functions @@ -345,10 +357,22 @@ close(#file_descriptor{module = Module} = Handle) -> close(_) -> {error, badarg}. --spec read(File :: io_device(), Size :: non_neg_integer()) -> +-spec advise(File :: io_device(), Offset :: integer(), + Length :: integer(), Advise :: posix_file_advise()) -> + 'ok' | {'error', posix()}. + +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(File :: io_device() | atom(), Size :: non_neg_integer()) -> 'eof' | {'ok', [char()] | binary()} | {'error', posix()}. -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 +385,10 @@ read(#file_descriptor{module = Module} = Handle, Sz) read(_, _) -> {error, badarg}. --spec read_line(File :: io_device()) -> +-spec read_line(File :: io_device() | atom()) -> 'eof' | {'ok', [char()] | binary()} | {'error', posix()}. -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}; @@ -415,10 +439,10 @@ pread(#file_descriptor{module = Module} = Handle, Offs, Sz) pread(_, _, _) -> {error, badarg}. --spec write(File :: io_device(), Byte :: iodata()) -> +-spec write(File :: io_device() | atom(), Byte :: iodata()) -> 'ok' | {'error', posix()}. -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}); @@ -465,6 +489,16 @@ pwrite(#file_descriptor{module = Module} = Handle, Offs, Bytes) -> pwrite(_, _, _) -> {error, badarg}. +-spec datasync(File :: io_device()) -> 'ok' | {'error', posix()}. + +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(File :: io_device()) -> 'ok' | {'error', posix()}. sync(File) when is_pid(File) -> diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl index 37e803c493..39dc32bb79 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). @@ -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..cccfa75005 100644 --- a/lib/kernel/src/gen_sctp.erl +++ b/lib/kernel/src/gen_sctp.erl @@ -39,7 +39,7 @@ open() -> open([]). open(Opts) when is_list(Opts) -> - Mod = mod(Opts), + Mod = mod(Opts, undefined), case Mod:open(Opts) of {error,badarg} -> erlang:error(badarg, [Opts]); @@ -166,18 +166,14 @@ 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) -> @@ -238,17 +234,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..16a87d71b6 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-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 @@ -46,7 +46,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 @@ -73,7 +73,7 @@ try_connect([], _Port, _Opts, _Timer, _Mod, Err) -> %% Listen on a tcp port %% listen(Port, Opts) -> - Mod = mod(Opts), + Mod = mod(Opts, undefined), case Mod:getserv(Port) of {ok,TP} -> Mod:listen(TP, Opts); @@ -173,20 +173,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..99020c7b6c 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-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 @@ -29,7 +29,7 @@ open(Port) -> open(Port, []). open(Port, Opts) -> - Mod = mod(Opts), + Mod = mod(Opts, undefined), {ok,UP} = Mod:getserv(Port), Mod:open(UP, Opts). @@ -97,21 +97,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..081e7e2f93 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-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(global). @@ -112,7 +112,7 @@ resolvers = [], syncers = [] :: [pid()], node_name = node() :: node(), - the_locker, the_deleter, the_registrar, trace, + the_locker, the_registrar, trace, global_lock_down = false }). @@ -153,6 +153,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, [], []). @@ -418,7 +420,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()}, []), @@ -763,13 +764,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 +782,6 @@ 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}}; 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) -> @@ -1348,30 +1350,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 +1367,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 @@ -1986,7 +1953,6 @@ 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) @@ -2003,20 +1969,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 +2099,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/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..e78acfc7a6 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-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(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} -> @@ -119,8 +119,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 +174,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/inet.erl b/lib/kernel/src/inet.erl index eb503235d8..93d75321ba 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -62,6 +62,8 @@ %% timer interface -export([start_timer/1, timeout/1, timeout/2, stop_timer/1]). +-export_type([ip_address/0, socket/0]). + %% imports -import(lists, [append/1, duplicate/2, filter/2, foldl/3]). 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..fab00bbb9f 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-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(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 -> @@ -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..2458876326 100644 --- a/lib/kernel/src/inet_config.erl +++ b/lib/kernel/src/inet_config.erl @@ -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]). 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_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_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..de0f23bf24 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-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% %% %% RFC 1035, 2671, 2782, 2915. @@ -592,6 +592,7 @@ query_retries(_Q, _NSs, _Timer, Retry, Retry, S) -> query_retries(Q, NSs, Timer, Retry, I, S0) -> Num = length(NSs), if Num =:= 0 -> + udp_close(S0), {error,timeout}; true -> case query_nss(Q, NSs, Timer, Retry, I, S0, []) of 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/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_kernel.erl b/lib/kernel/src/net_kernel.erl index 9875044844..f5e2820bbe 100644 --- a/lib/kernel/src/net_kernel.erl +++ b/lib/kernel/src/net_kernel.erl @@ -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 @@ -232,7 +232,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 +244,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 +276,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 +302,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 +313,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), @@ -390,27 +390,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 +421,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 +503,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 +574,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 +662,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 +710,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 +1000,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 +1010,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 +1058,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 +1152,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 +1163,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 +1174,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 +1225,7 @@ create_hostpart(Name, LongOrShortNames) -> {Head,Host1}. %% -%% +%% %% protocol_childspecs() -> case init:get_argument(proto_dist) of @@ -1232,7 +1235,7 @@ protocol_childspecs() -> protocol_childspecs(["inet_tcp"]) end. -protocol_childspecs([]) -> +protocol_childspecs([]) -> []; protocol_childspecs([H|T]) -> Mod = list_to_atom(H ++ "_dist"), @@ -1242,15 +1245,15 @@ 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]]} -> + {ok,[[Module]]} -> Module; _ -> erl_epmd @@ -1297,7 +1300,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 +1310,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 +1462,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..75a11a8afd 100644 --- a/lib/kernel/src/os.erl +++ b/lib/kernel/src/os.erl @@ -50,7 +50,7 @@ find_executable(Name, Path) -> 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 +60,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 +69,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,7 +78,7 @@ 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 @@ -87,12 +87,30 @@ verify_executable(Name0, [Ext|Rest]) -> %% 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, _} -> @@ -119,6 +137,7 @@ reverse_element(List) -> lists:reverse(List). -spec extensions() -> [string()]. +%% Extensions in lower case extensions() -> case type() of {win32, _} -> [".exe",".com",".cmd",".bat"]; diff --git a/lib/kernel/src/pg2.erl b/lib/kernel/src/pg2.erl index cb9fec2ffe..956a900adc 100644 --- a/lib/kernel/src/pg2.erl +++ b/lib/kernel/src/pg2.erl @@ -251,7 +251,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..e09acb5024 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-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(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 -> 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..fabaa07752 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-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% %% @@ -37,7 +37,7 @@ 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 }). |