aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib/src/supervisor_bridge.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib/src/supervisor_bridge.erl')
-rw-r--r--lib/stdlib/src/supervisor_bridge.erl116
1 files changed, 116 insertions, 0 deletions
diff --git a/lib/stdlib/src/supervisor_bridge.erl b/lib/stdlib/src/supervisor_bridge.erl
new file mode 100644
index 0000000000..3d2bd2c9a5
--- /dev/null
+++ b/lib/stdlib/src/supervisor_bridge.erl
@@ -0,0 +1,116 @@
+%%
+%% %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(supervisor_bridge).
+
+-behaviour(gen_server).
+
+%% External exports
+-export([start_link/2, start_link/3]).
+-export([behaviour_info/1]).
+%% Internal exports
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2]).
+-export([code_change/3]).
+
+behaviour_info(callbacks) ->
+ [{init,1},{terminate,2}];
+behaviour_info(_Other) ->
+ undefined.
+
+%%%-----------------------------------------------------------------
+%%% This is a rewrite of supervisor_bridge from BS.3.
+%%%
+%%% This module is built to function as process code
+%%% for a process sitting inbetween a real supervisor
+%%% and a not start&recovery complient server/system
+%%% The process inbetween simulates start&recovery
+%%% behaviour of the server/system below.
+%%%
+%%% The supervisor_bridge behaviour must export the following
+%%% functions:
+%%% init(Args) -> {ok, Pid, State} | {error, Reason} | ignore
+%%% where Pid is the child process
+%%% terminate(Reason, State) -> ok
+%%%-----------------------------------------------------------------
+-record(state, {mod, pid, child_state, name}).
+
+start_link(Mod, StartArgs) ->
+ gen_server:start_link(supervisor_bridge, [Mod, StartArgs, self], []).
+
+start_link(Name, Mod, StartArgs) ->
+ gen_server:start_link(Name, supervisor_bridge, [Mod, StartArgs, Name], []).
+
+%%-----------------------------------------------------------------
+%% Callback functions from gen_server
+%%-----------------------------------------------------------------
+init([Mod, StartArgs, Name0]) ->
+ process_flag(trap_exit, true),
+ Name = supname(Name0, Mod),
+ case Mod:init(StartArgs) of
+ {ok, Pid, ChildState} when is_pid(Pid) ->
+ link(Pid),
+ report_progress(Pid, Mod, StartArgs, Name),
+ {ok, #state{mod = Mod, pid = Pid,
+ child_state = ChildState, name = Name}};
+ ignore ->
+ ignore;
+ {error, Reason} ->
+ {stop, Reason}
+ end.
+
+supname(self, Mod) -> {self(),Mod};
+supname(N, _) -> N.
+
+%% A supervisor *must* answer the supervisor:which_children call.
+handle_call(which_children, _From, State) ->
+ {reply, [], State};
+handle_call(_Req, _From, State) ->
+ {reply, {error, badcall}, State}.
+
+handle_cast(_, State) ->
+ {noreply, State}.
+
+handle_info({'EXIT', Pid, Reason}, State) when State#state.pid =:= Pid ->
+ report_error(child_terminated, Reason, State),
+ {stop, Reason, State#state{pid = undefined}};
+handle_info(_, State) ->
+ {noreply, State}.
+
+terminate(_Reason, #state{pid = undefined}) ->
+ ok;
+terminate(Reason, State) ->
+ terminate_pid(Reason, State).
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%% This function is supposed to terminate the 'real' server.
+terminate_pid(Reason, #state{mod = Mod, child_state = ChildState}) ->
+ Mod:terminate(Reason, ChildState).
+
+report_progress(Pid, Mod, StartArgs, SupName) ->
+ Progress = [{supervisor, SupName},
+ {started, [{pid, Pid}, {mfa, {Mod, init, [StartArgs]}}]}],
+ error_logger:info_report(progress, Progress).
+
+report_error(Error, Reason, #state{name = Name, pid = Pid, mod = Mod}) ->
+ ErrorMsg = [{supervisor, Name},
+ {errorContext, Error},
+ {reason, Reason},
+ {offender, [{pid, Pid}, {mod, Mod}]}],
+ error_logger:error_report(supervisor_report, ErrorMsg).