diff options
Diffstat (limited to 'lib/kernel/src/user_sup.erl')
-rw-r--r-- | lib/kernel/src/user_sup.erl | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/lib/kernel/src/user_sup.erl b/lib/kernel/src/user_sup.erl new file mode 100644 index 0000000000..35b7ff0cfe --- /dev/null +++ b/lib/kernel/src/user_sup.erl @@ -0,0 +1,129 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2009. 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(user_sup). + +%% --------------------------------------------- +%% This is a supervisor bridge hiding the process +%% details of the user/group implementation. +%% --------------------------------------------- + +-behaviour(supervisor_bridge). + +-export([start/0]). + +%% Internal exports. +-export([init/1, terminate/2, relay/1]). + +-spec start() -> {'error', {'already_started', pid()}} | {'ok', pid()}. + +start() -> + supervisor_bridge:start_link(user_sup, []). + +-spec init([]) -> 'ignore' | {'error', 'nouser'} | {'ok', pid(), pid()}. + +init([]) -> + case get_user() of + nouser -> + ignore; + {master, Master} -> + Pid = start_slave(Master), + {ok, Pid, Pid}; + {M, F, A} -> + case start_user({M, F}, A) of + {ok, Pid} -> + {ok, Pid, Pid}; + Error -> + Error + end + end. + +start_slave(Master) -> + case rpc:call(Master, erlang, whereis, [user]) of + User when is_pid(User) -> + spawn(?MODULE, relay, [User]); + _ -> + error_logger:error_msg("Cannot get remote user", []), + receive after 1000 -> true end, + halt() + end. + +-spec relay(pid()) -> no_return(). + +relay(Pid) -> + register(user, self()), + relay1(Pid). + +relay1(Pid) -> + receive + X -> + Pid ! X, + relay1(Pid) + end. + + +%%----------------------------------------------------------------- +%% Sleep a while in order to let user write all (some) buffered +%% information before termination. +%%----------------------------------------------------------------- + +-spec terminate(term(), pid()) -> 'ok'. + +terminate(_Reason, UserPid) -> + receive after 1000 -> ok end, + exit(UserPid, kill), + ok. + +%%----------------------------------------------------------------- +%% If there is a user, wait for it to register itself. (But wait +%% no more than 10 seconds). This is so the application_controller +%% is guaranteed that the user is started. +%%----------------------------------------------------------------- + +start_user(Func,A) -> + apply(Func, A), + wait_for_user_p(100). + +wait_for_user_p(0) -> + {error, nouser}; +wait_for_user_p(N) -> + case whereis(user) of + Pid when is_pid(Pid) -> + link(Pid), + {ok, Pid}; + _ -> + receive after 100 -> ok end, + wait_for_user_p(N-1) + end. + +get_user() -> + Flags = init:get_arguments(), + check_flags(Flags, {user_drv, start, []}). + +%% These flags depend upon what arguments the erl script passes on +%% to erl91. +check_flags([{nouser, []} |T], _) -> check_flags(T, nouser); +check_flags([{user, [User]} | T], _) -> + check_flags(T, {list_to_atom(User), start, []}); +check_flags([{noshell, []} | T], _) -> check_flags(T, {user, start, []}); +check_flags([{oldshell, []} | T], _) -> check_flags(T, {user, start, []}); +check_flags([{noinput, []} | T], _) -> check_flags(T, {user, start_out, []}); +check_flags([{master, [Node]} | T], _) -> + check_flags(T, {master, list_to_atom(Node)}); +check_flags([_H | T], User) -> check_flags(T, User); +check_flags([], User) -> User. |