From 3159fa506c2ddf4cbca9887be798c67e32a981cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 8 Mar 2016 06:47:43 +0100 Subject: Clean up splitting of node names --- lib/kernel/src/net_kernel.erl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl index 35a54f591e..45a0e26933 100644 --- a/lib/kernel/src/net_kernel.erl +++ b/lib/kernel/src/net_kernel.erl @@ -1202,8 +1202,7 @@ get_proto_mod(_Family, _Protocol, []) -> %% -------- Initialisation functions ------------------------ init_node(Name, LongOrShortNames) -> - {NameWithoutHost,_Host} = lists:splitwith(fun($@)->false;(_)->true end, - atom_to_list(Name)), + {NameWithoutHost,_Host} = split_node(Name), case create_name(Name, LongOrShortNames, 1) of {ok,Node} -> case start_protos(list_to_atom(NameWithoutHost),Node) of @@ -1240,8 +1239,7 @@ create_name(Name, LongOrShortNames, Try) -> end. create_hostpart(Name, LongOrShortNames) -> - {Head,Host} = lists:splitwith(fun($@)->false;(_)->true end, - atom_to_list(Name)), + {Head,Host} = split_node(Name), Host1 = case {Host,LongOrShortNames} of {[$@,_|_],longnames} -> {ok,Host}; @@ -1268,6 +1266,9 @@ create_hostpart(Name, LongOrShortNames) -> end, {Head,Host1}. +split_node(Name) -> + lists:splitwith(fun(C) -> C =/= $@ end, atom_to_list(Name)). + %% %% %% -- cgit v1.2.3 From b5e35d8da2c83f176071730b0e7ce7daa7866f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 8 Mar 2016 07:15:34 +0100 Subject: Reorder and comment API functions Move all functions meant to be called from other modules before the internal functions. Comment them to make it clearer what their purpose are. --- lib/kernel/src/erl_distribution.erl | 54 ++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/lib/kernel/src/erl_distribution.erl b/lib/kernel/src/erl_distribution.erl index 99db7a8bf0..e97c9db81f 100644 --- a/lib/kernel/src/erl_distribution.erl +++ b/lib/kernel/src/erl_distribution.erl @@ -25,6 +25,8 @@ -define(DBG,erlang:display([?MODULE,?LINE])). +%% Called during system start-up. + start_link() -> case catch start_p() of {ok,Args} -> @@ -33,8 +35,38 @@ start_link() -> ignore end. +%% Called from net_kernel:start/1 to start distribution after the +%% system has already started. + +start(Args) -> + C = {net_sup_dynamic, {?MODULE,start_link,[Args]}, permanent, + 1000, supervisor, [erl_distribution]}, + supervisor:start_child(kernel_sup, C). + +%% Stop distribution. + +stop() -> + case supervisor:terminate_child(kernel_sup, net_sup_dynamic) of + ok -> + supervisor:delete_child(kernel_sup, net_sup_dynamic); + Error -> + case whereis(net_sup) of + Pid when is_pid(Pid) -> + %% Dist. started through -sname | -name flags + {error, not_allowed}; + _ -> + Error + end + end. + +%%% +%%% Internal helper functions. +%%% + +%% Helper start function. + start_link(Args) -> - supervisor:start_link({local,net_sup},erl_distribution,Args). + supervisor:start_link({local,net_sup}, ?MODULE, Args). init(NetArgs) -> Epmd = @@ -84,23 +116,3 @@ ticktime() -> _ -> [] end. - -start(Args) -> - C = {net_sup_dynamic, {erl_distribution, start_link, [Args]}, permanent, - 1000, supervisor, [erl_distribution]}, - supervisor:start_child(kernel_sup, C). - -stop() -> - case supervisor:terminate_child(kernel_sup, net_sup_dynamic) of - ok -> - supervisor:delete_child(kernel_sup, net_sup_dynamic); - Error -> - case whereis(net_sup) of - Pid when is_pid(Pid) -> - %% Dist. started through -sname | -name flags - {error, not_allowed}; - _ -> - Error - end - end. - -- cgit v1.2.3 From 20e4f4fd8eefc85d8101d7b40a5c5e3cb90c8f8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 8 Mar 2016 07:20:13 +0100 Subject: erl_distribution: Simplify start_link/0 and friends start_link/0 and friends are too convoluted for me. --- lib/kernel/src/erl_distribution.erl | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/lib/kernel/src/erl_distribution.erl b/lib/kernel/src/erl_distribution.erl index e97c9db81f..142807d6a0 100644 --- a/lib/kernel/src/erl_distribution.erl +++ b/lib/kernel/src/erl_distribution.erl @@ -28,12 +28,7 @@ %% Called during system start-up. start_link() -> - case catch start_p() of - {ok,Args} -> - start_link(Args); - _ -> - ignore - end. + do_start_link([{sname,shortnames},{name,longnames}]). %% Called from net_kernel:start/1 to start distribution after the %% system has already started. @@ -84,26 +79,15 @@ init(NetArgs) -> EarlySpecs = net_kernel:protocol_childspecs(), {ok,{{one_for_all,0,1}, EarlySpecs ++ Epmd ++ [Auth,Kernel]}}. -start_p() -> - sname(), - lname(), - false. - -sname() -> - case init:get_argument(sname) of - {ok,[[Name]]} -> - throw({ok,[list_to_atom(Name),shortnames|ticktime()]}); - _ -> - false - end. - -lname() -> - case init:get_argument(name) of +do_start_link([{Arg,Flag}|T]) -> + case init:get_argument(Arg) of {ok,[[Name]]} -> - throw({ok,[list_to_atom(Name),longnames|ticktime()]}); + start_link([list_to_atom(Name),Flag|ticktime()]); _ -> - false - end. + do_start_link(T) + end; +do_start_link([]) -> + ignore. ticktime() -> %% catch, in case the system was started with boot file start_old, -- cgit v1.2.3 From 51628bfae821e184878f97d1e81d8c0c7f8e433e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 8 Mar 2016 10:02:32 +0100 Subject: net_kernel: Separate exports into documented and non-documented groups --- lib/kernel/src/net_kernel.erl | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl index 45a0e26933..d457a20287 100644 --- a/lib/kernel/src/net_kernel.erl +++ b/lib/kernel/src/net_kernel.erl @@ -53,18 +53,25 @@ -define(tckr_dbg(X), ok). -endif. -%% User Interface Exports --export([start/1, start_link/1, stop/0, - kernel_apply/3, +%% Documented API functions. + +-export([allow/1, + connect_node/1, monitor_nodes/1, monitor_nodes/2, + start/1, + stop/0]). + +%% Exports for internal use. + +-export([start_link/1, + kernel_apply/3, longnames/0, - allow/1, protocol_childspecs/0, epmd_module/0]). -export([connect/1, disconnect/1, hidden_connect/1, passive_cnct/1]). --export([connect_node/1, hidden_connect_node/1]). %% explicit connect +-export([hidden_connect_node/1]). %% explicit connect -export([set_net_ticktime/1, set_net_ticktime/2, get_net_ticktime/0]). -export([node_info/1, node_info/2, nodes_info/0, @@ -73,7 +80,8 @@ -export([publish_on_node/1, update_publish_nodes/1]). -%% Internal Exports +%% Internal exports for spawning processes. + -export([do_spawn/3, spawn_func/6, ticker/2, -- cgit v1.2.3 From bb2f9e3ebecf5101c142887c41d3db4e3e88118f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 8 Mar 2016 10:12:34 +0100 Subject: Make distribution failures during start-up easier to read When an attempt is made to start a distributed Erlang node with the same name as an existing node, the crash reports for several supervisors would be displayed. Only the first line contains useful information. The verbiage is annoying for old hands and could easily scare newcomers away for good. For all the common distribution failures during start-up, write a simple message and terminate the emulator using halt/1. Here is an example of what will be printed: Protocol 'inet_tcp': the name somename@somehost seems to be in use by another Erlang node --- lib/kernel/src/erl_distribution.erl | 12 ++-- lib/kernel/src/net_kernel.erl | 106 +++++++++++++++++++++--------------- 2 files changed, 68 insertions(+), 50 deletions(-) diff --git a/lib/kernel/src/erl_distribution.erl b/lib/kernel/src/erl_distribution.erl index 142807d6a0..559e2a853b 100644 --- a/lib/kernel/src/erl_distribution.erl +++ b/lib/kernel/src/erl_distribution.erl @@ -21,7 +21,7 @@ -behaviour(supervisor). --export([start_link/0,start_link/1,init/1,start/1,stop/0]). +-export([start_link/0,start_link/2,init/1,start/1,stop/0]). -define(DBG,erlang:display([?MODULE,?LINE])). @@ -34,7 +34,7 @@ start_link() -> %% system has already started. start(Args) -> - C = {net_sup_dynamic, {?MODULE,start_link,[Args]}, permanent, + C = {net_sup_dynamic, {?MODULE,start_link,[Args,false]}, permanent, 1000, supervisor, [erl_distribution]}, supervisor:start_child(kernel_sup, C). @@ -60,8 +60,8 @@ stop() -> %% Helper start function. -start_link(Args) -> - supervisor:start_link({local,net_sup}, ?MODULE, Args). +start_link(Args, CleanHalt) -> + supervisor:start_link({local,net_sup}, ?MODULE, [Args,CleanHalt]). init(NetArgs) -> Epmd = @@ -74,7 +74,7 @@ init(NetArgs) -> permanent,2000,worker,[EpmdMod]}] end, Auth = {auth,{auth,start_link,[]},permanent,2000,worker,[auth]}, - Kernel = {net_kernel,{net_kernel,start_link,[NetArgs]}, + Kernel = {net_kernel,{net_kernel,start_link,NetArgs}, permanent,2000,worker,[net_kernel]}, EarlySpecs = net_kernel:protocol_childspecs(), {ok,{{one_for_all,0,1}, EarlySpecs ++ Epmd ++ [Auth,Kernel]}}. @@ -82,7 +82,7 @@ init(NetArgs) -> do_start_link([{Arg,Flag}|T]) -> case init:get_argument(Arg) of {ok,[[Name]]} -> - start_link([list_to_atom(Name),Flag|ticktime()]); + start_link([list_to_atom(Name),Flag|ticktime()], true); _ -> do_start_link(T) end; diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl index d457a20287..a19c116388 100644 --- a/lib/kernel/src/net_kernel.erl +++ b/lib/kernel/src/net_kernel.erl @@ -64,7 +64,7 @@ %% Exports for internal use. --export([start_link/1, +-export([start_link/2, kernel_apply/3, longnames/0, protocol_childspecs/0, @@ -349,18 +349,18 @@ request(Req) -> start(Args) -> erl_distribution:start(Args). -%% This is the main startup routine for net_kernel -%% The defaults are longnames and a ticktime of 15 secs to the tcp_drv. +%% This is the main startup routine for net_kernel (only for internal +%% use by the Kernel application. -start_link([Name]) -> - start_link([Name, longnames]); +start_link([Name], CleanHalt) -> + start_link([Name, longnames], CleanHalt); +start_link([Name, LongOrShortNames], CleanHalt) -> + start_link([Name, LongOrShortNames, 15000], CleanHalt); -start_link([Name, LongOrShortNames]) -> - start_link([Name, LongOrShortNames, 15000]); - -start_link([Name, LongOrShortNames, Ticktime]) -> - case gen_server:start_link({local, net_kernel}, net_kernel, - {Name, LongOrShortNames, Ticktime}, []) of +start_link([Name, LongOrShortNames, Ticktime], CleanHalt) -> + Args = {Name, LongOrShortNames, Ticktime, CleanHalt}, + case gen_server:start_link({local, net_kernel}, ?MODULE, + Args, []) of {ok, Pid} -> {ok, Pid}; {error, {already_started, Pid}} -> @@ -369,12 +369,9 @@ start_link([Name, LongOrShortNames, Ticktime]) -> exit(nodistribution) end. -%% auth:get_cookie should only be able to return an atom -%% tuple cookies are unknowns - -init({Name, LongOrShortNames, TickT}) -> +init({Name, LongOrShortNames, TickT, CleanHalt}) -> process_flag(trap_exit,true), - case init_node(Name, LongOrShortNames) of + case init_node(Name, LongOrShortNames, CleanHalt) of {ok, Node, Listeners} -> process_flag(priority, max), Ticktime = to_integer(TickT), @@ -1209,11 +1206,12 @@ get_proto_mod(_Family, _Protocol, []) -> %% -------- Initialisation functions ------------------------ -init_node(Name, LongOrShortNames) -> - {NameWithoutHost,_Host} = split_node(Name), +init_node(Name, LongOrShortNames, CleanHalt) -> + {NameWithoutHost0,_Host} = split_node(Name), case create_name(Name, LongOrShortNames, 1) of {ok,Node} -> - case start_protos(list_to_atom(NameWithoutHost),Node) of + NameWithoutHost = list_to_atom(NameWithoutHost0), + case start_protos(NameWithoutHost, Node, CleanHalt) of {ok, Ls} -> {ok, Node, Ls}; Error -> @@ -1316,21 +1314,26 @@ epmd_module() -> %% Start all protocols %% -start_protos(Name,Node) -> +start_protos(Name, Node, CleanHalt) -> case init:get_argument(proto_dist) of {ok, [Protos]} -> - start_protos(Name,Protos, Node); + start_protos(Name, Protos, Node, CleanHalt); _ -> - start_protos(Name,["inet_tcp"], Node) + start_protos(Name, ["inet_tcp"], Node, CleanHalt) end. -start_protos(Name,Ps, Node) -> - case start_protos(Name, Ps, Node, []) of - [] -> {error, badarg}; - Ls -> {ok, Ls} +start_protos(Name, Ps, Node, CleanHalt) -> + case start_protos(Name, Ps, Node, [], CleanHalt) of + [] -> + case CleanHalt of + true -> halt(1); + false -> {error, badarg} + end; + Ls -> + {ok, Ls} end. -start_protos(Name, [Proto | Ps], Node, Ls) -> +start_protos(Name, [Proto | Ps], Node, Ls, CleanHalt) -> Mod = list_to_atom(Proto ++ "_dist"), case catch Mod:listen(Name) of {ok, {Socket, Address, Creation}} -> @@ -1343,33 +1346,48 @@ start_protos(Name, [Proto | Ps], Node, Ls) -> address = Address, accept = AcceptPid, module = Mod }, - start_protos(Name,Ps, Node, [L|Ls]); + start_protos(Name,Ps, Node, [L|Ls], CleanHalt); _ -> Mod:close(Socket), - error_logger:info_msg("Invalid node name: ~p~n", [Node]), - start_protos(Name, Ps, Node, Ls) + S = "invalid node name: " ++ atom_to_list(Node), + proto_error(CleanHalt, Proto, S), + start_protos(Name, Ps, Node, Ls, CleanHalt) end; {'EXIT', {undef,_}} -> - error_logger:info_msg("Protocol: ~tp: not supported~n", [Proto]), - start_protos(Name,Ps, Node, Ls); + proto_error(CleanHalt, Proto, "not supported"), + start_protos(Name, Ps, Node, Ls, CleanHalt); {'EXIT', Reason} -> - error_logger:info_msg("Protocol: ~tp: register error: ~tp~n", - [Proto, Reason]), - start_protos(Name,Ps, Node, Ls); + register_error(CleanHalt, Proto, Reason), + start_protos(Name, Ps, Node, Ls, CleanHalt); {error, duplicate_name} -> - error_logger:info_msg("Protocol: ~tp: the name " ++ - atom_to_list(Node) ++ - " seems to be in use by another Erlang node", - [Proto]), - start_protos(Name,Ps, Node, Ls); + S = "the name " ++ atom_to_list(Node) ++ + " seems to be in use by another Erlang node", + proto_error(CleanHalt, Proto, S), + start_protos(Name, Ps, Node, Ls, CleanHalt); {error, Reason} -> - error_logger:info_msg("Protocol: ~tp: register/listen error: ~tp~n", - [Proto, Reason]), - start_protos(Name,Ps, Node, Ls) + register_error(CleanHalt, Proto, Reason), + start_protos(Name, Ps, Node, Ls, CleanHalt) end; -start_protos(_,[], _Node, Ls) -> +start_protos(_, [], _Node, Ls, _CleanHalt) -> Ls. +register_error(false, Proto, Reason) -> + S = io_lib:format("register/listen error: ~p", [Reason]), + proto_error(false, Proto, lists:flatten(S)); +register_error(true, Proto, Reason) -> + S = "Protocol '" ++ Proto ++ "': register/listen error: ", + erlang:display_string(S), + erlang:display(Reason). + +proto_error(CleanHalt, Proto, String) -> + S = "Protocol '" ++ Proto ++ "': " ++ String ++ "\n", + case CleanHalt of + false -> + error_logger:info_msg(S); + true -> + erlang:display_string(S) + end. + set_node(Node, Creation) when node() =:= nonode@nohost -> case catch erlang:setnode(Node, Creation) of true -> -- cgit v1.2.3