diff options
Diffstat (limited to 'lib/stdlib/src/supervisor_bridge.erl')
-rw-r--r-- | lib/stdlib/src/supervisor_bridge.erl | 116 |
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). |