src/supervisor2.erl
author Matthias Radestock <matthias@rabbitmq.com>
Wed Apr 23 20:22:01 2014 +0100 (13 hours ago)
changeset 13368 f9dbe64874cf
parent 12128 a7cca270c93d
permissions -rw-r--r--
merge stable into default
     1 %% This file is a copy of supervisor.erl from the R16B Erlang/OTP
     2 %% distribution, with the following modifications:
     3 %%
     4 %% 1) the module name is supervisor2
     5 %%
     6 %% 2) a find_child/2 utility function has been added
     7 %%
     8 %% 3) Added an 'intrinsic' restart type. Like the transient type, this
     9 %%    type means the child should only be restarted if the child exits
    10 %%    abnormally. Unlike the transient type, if the child exits
    11 %%    normally, the supervisor itself also exits normally. If the
    12 %%    child is a supervisor and it exits normally (i.e. with reason of
    13 %%    'shutdown') then the child's parent also exits normally.
    14 %%
    15 %% 4) child specifications can contain, as the restart type, a tuple
    16 %%    {permanent, Delay} | {transient, Delay} | {intrinsic, Delay}
    17 %%    where Delay >= 0 (see point (4) below for intrinsic). The delay,
    18 %%    in seconds, indicates what should happen if a child, upon being
    19 %%    restarted, exceeds the MaxT and MaxR parameters. Thus, if a
    20 %%    child exits, it is restarted as normal. If it exits sufficiently
    21 %%    quickly and often to exceed the boundaries set by the MaxT and
    22 %%    MaxR parameters, and a Delay is specified, then rather than
    23 %%    stopping the supervisor, the supervisor instead continues and
    24 %%    tries to start up the child again, Delay seconds later.
    25 %%
    26 %%    Note that you can never restart more frequently than the MaxT
    27 %%    and MaxR parameters allow: i.e. you must wait until *both* the
    28 %%    Delay has passed *and* the MaxT and MaxR parameters allow the
    29 %%    child to be restarted.
    30 %%
    31 %%    Also note that the Delay is a *minimum*. There is no guarantee
    32 %%    that the child will be restarted within that time, especially if
    33 %%    other processes are dying and being restarted at the same time -
    34 %%    essentially we have to wait for the delay to have passed and for
    35 %%    the MaxT and MaxR parameters to permit the child to be
    36 %%    restarted. This may require waiting for longer than Delay.
    37 %%
    38 %%    Sometimes, you may wish for a transient or intrinsic child to
    39 %%    exit abnormally so that it gets restarted, but still log
    40 %%    nothing. gen_server will log any exit reason other than
    41 %%    'normal', 'shutdown' or {'shutdown', _}. Thus the exit reason of
    42 %%    {'shutdown', 'restart'} is interpreted to mean you wish the
    43 %%    child to be restarted according to the delay parameters, but
    44 %%    gen_server will not log the error. Thus from gen_server's
    45 %%    perspective it's a normal exit, whilst from supervisor's
    46 %%    perspective, it's an abnormal exit.
    47 %%
    48 %% 5) normal, and {shutdown, _} exit reasons are all treated the same
    49 %%    (i.e. are regarded as normal exits)
    50 %%
    51 %% All modifications are (C) 2010-2013 GoPivotal, Inc.
    52 %%
    53 %% %CopyrightBegin%
    54 %%
    55 %% Copyright Ericsson AB 1996-2012. All Rights Reserved.
    56 %%
    57 %% The contents of this file are subject to the Erlang Public License,
    58 %% Version 1.1, (the "License"); you may not use this file except in
    59 %% compliance with the License. You should have received a copy of the
    60 %% Erlang Public License along with this software. If not, it can be
    61 %% retrieved online at http://www.erlang.org/.
    62 %%
    63 %% Software distributed under the License is distributed on an "AS IS"
    64 %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
    65 %% the License for the specific language governing rights and limitations
    66 %% under the License.
    67 %%
    68 %% %CopyrightEnd%
    69 %%
    70 -module(supervisor2).
    71 
    72 -behaviour(gen_server).
    73 
    74 %% External exports
    75 -export([start_link/2, start_link/3,
    76 	 start_child/2, restart_child/2,
    77 	 delete_child/2, terminate_child/2,
    78 	 which_children/1, count_children/1,
    79 	 find_child/2, check_childspecs/1]).
    80 
    81 %% Internal exports
    82 -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
    83 	 terminate/2, code_change/3]).
    84 -export([try_again_restart/3]).
    85 
    86 %%--------------------------------------------------------------------------
    87 -ifdef(use_specs).
    88 -export_type([child_spec/0, startchild_ret/0, strategy/0, sup_name/0]).
    89 -endif.
    90 %%--------------------------------------------------------------------------
    91 
    92 -ifdef(use_specs).
    93 -type child()    :: 'undefined' | pid().
    94 -type child_id() :: term().
    95 -type mfargs()   :: {M :: module(), F :: atom(), A :: [term()] | undefined}.
    96 -type modules()  :: [module()] | 'dynamic'.
    97 -type delay()    :: non_neg_integer().
    98 -type restart()  :: 'permanent' | 'transient' | 'temporary' | 'intrinsic' | {'permanent', delay()} | {'transient', delay()} | {'intrinsic', delay()}.
    99 -type shutdown() :: 'brutal_kill' | timeout().
   100 -type worker()   :: 'worker' | 'supervisor'.
   101 -type sup_name() :: {'local', Name :: atom()} | {'global', Name :: atom()}.
   102 -type sup_ref()  :: (Name :: atom())
   103                   | {Name :: atom(), Node :: node()}
   104                   | {'global', Name :: atom()}
   105                   | pid().
   106 -type child_spec() :: {Id :: child_id(),
   107                        StartFunc :: mfargs(),
   108                        Restart :: restart(),
   109                        Shutdown :: shutdown(),
   110                        Type :: worker(),
   111                        Modules :: modules()}.
   112 
   113 -type strategy() :: 'one_for_all' | 'one_for_one'
   114                   | 'rest_for_one' | 'simple_one_for_one'.
   115 -endif.
   116 
   117 %%--------------------------------------------------------------------------
   118 
   119 -ifdef(use_specs).
   120 -record(child, {% pid is undefined when child is not running
   121 	        pid = undefined :: child() | {restarting,pid()} | [pid()],
   122 		name            :: child_id(),
   123 		mfargs          :: mfargs(),
   124 		restart_type    :: restart(),
   125 		shutdown        :: shutdown(),
   126 		child_type      :: worker(),
   127 		modules = []    :: modules()}).
   128 -type child_rec() :: #child{}.
   129 -else.
   130 -record(child, {
   131 	        pid = undefined,
   132 		name,
   133 		mfargs,
   134 		restart_type,
   135 		shutdown,
   136 		child_type,
   137 		modules = []}).
   138 -endif.
   139 
   140 -define(DICT, dict).
   141 -define(SETS, sets).
   142 -define(SET, set).
   143 
   144 -ifdef(use_specs).
   145 -record(state, {name,
   146 		strategy               :: strategy(),
   147 		children = []          :: [child_rec()],
   148 		dynamics               :: ?DICT() | ?SET(),
   149 		intensity              :: non_neg_integer(),
   150 		period                 :: pos_integer(),
   151 		restarts = [],
   152 	        module,
   153 	        args}).
   154 -type state() :: #state{}.
   155 -else.
   156 -record(state, {name,
   157 		strategy,
   158 		children = [],
   159 		dynamics,
   160 		intensity,
   161 		period,
   162 		restarts = [],
   163 	        module,
   164 	        args}).
   165 -endif.
   166 
   167 -define(is_simple(State), State#state.strategy =:= simple_one_for_one).
   168 -define(is_permanent(R), ((R =:= permanent) orelse
   169                           (is_tuple(R) andalso
   170                            tuple_size(R) == 2 andalso
   171                            element(1, R) =:= permanent))).
   172 -define(is_explicit_restart(R),
   173         R == {shutdown, restart}).
   174 
   175 -ifdef(use_specs).
   176 -callback init(Args :: term()) ->
   177     {ok, {{RestartStrategy :: strategy(),
   178            MaxR            :: non_neg_integer(),
   179            MaxT            :: non_neg_integer()},
   180            [ChildSpec :: child_spec()]}}
   181     | ignore.
   182 -endif.
   183 -define(restarting(_Pid_), {restarting,_Pid_}).
   184 
   185 %%% ---------------------------------------------------
   186 %%% This is a general process supervisor built upon gen_server.erl.
   187 %%% Servers/processes should/could also be built using gen_server.erl.
   188 %%% SupName = {local, atom()} | {global, atom()}.
   189 %%% ---------------------------------------------------
   190 -ifdef(use_specs).
   191 -type startlink_err() :: {'already_started', pid()}
   192                          | {'shutdown', term()}
   193                          | term().
   194 -type startlink_ret() :: {'ok', pid()} | 'ignore' | {'error', startlink_err()}.
   195 
   196 -spec start_link(Module, Args) -> startlink_ret() when
   197       Module :: module(),
   198       Args :: term().
   199 
   200 -endif.
   201 start_link(Mod, Args) ->
   202     gen_server:start_link(?MODULE, {self, Mod, Args}, []).
   203  
   204 -ifdef(use_specs).
   205 -spec start_link(SupName, Module, Args) -> startlink_ret() when
   206       SupName :: sup_name(),
   207       Module :: module(),
   208       Args :: term().
   209 -endif.
   210 start_link(SupName, Mod, Args) ->
   211     gen_server:start_link(SupName, ?MODULE, {SupName, Mod, Args}, []).
   212  
   213 %%% ---------------------------------------------------
   214 %%% Interface functions.
   215 %%% ---------------------------------------------------
   216 -ifdef(use_specs).
   217 -type startchild_err() :: 'already_present'
   218 			| {'already_started', Child :: child()} | term().
   219 -type startchild_ret() :: {'ok', Child :: child()}
   220                         | {'ok', Child :: child(), Info :: term()}
   221 			| {'error', startchild_err()}.
   222 
   223 -spec start_child(SupRef, ChildSpec) -> startchild_ret() when
   224       SupRef :: sup_ref(),
   225       ChildSpec :: child_spec() | (List :: [term()]).
   226 -endif.
   227 start_child(Supervisor, ChildSpec) ->
   228     call(Supervisor, {start_child, ChildSpec}).
   229 
   230 -ifdef(use_specs).
   231 -spec restart_child(SupRef, Id) -> Result when
   232       SupRef :: sup_ref(),
   233       Id :: child_id(),
   234       Result :: {'ok', Child :: child()}
   235               | {'ok', Child :: child(), Info :: term()}
   236               | {'error', Error},
   237       Error :: 'running' | 'restarting' | 'not_found' | 'simple_one_for_one' |
   238 	       term().
   239 -endif.
   240 restart_child(Supervisor, Name) ->
   241     call(Supervisor, {restart_child, Name}).
   242 
   243 -ifdef(use_specs).
   244 -spec delete_child(SupRef, Id) -> Result when
   245       SupRef :: sup_ref(),
   246       Id :: child_id(),
   247       Result :: 'ok' | {'error', Error},
   248       Error :: 'running' | 'restarting' | 'not_found' | 'simple_one_for_one'.
   249 -endif.
   250 delete_child(Supervisor, Name) ->
   251     call(Supervisor, {delete_child, Name}).
   252 
   253 %%-----------------------------------------------------------------
   254 %% Func: terminate_child/2
   255 %% Returns: ok | {error, Reason}
   256 %%          Note that the child is *always* terminated in some
   257 %%          way (maybe killed).
   258 %%-----------------------------------------------------------------
   259 -ifdef(use_specs).
   260 -spec terminate_child(SupRef, Id) -> Result when
   261       SupRef :: sup_ref(),
   262       Id :: pid() | child_id(),
   263       Result :: 'ok' | {'error', Error},
   264       Error :: 'not_found' | 'simple_one_for_one'.
   265 -endif.
   266 terminate_child(Supervisor, Name) ->
   267     call(Supervisor, {terminate_child, Name}).
   268 
   269 -ifdef(use_specs).
   270 -spec which_children(SupRef) -> [{Id,Child,Type,Modules}] when
   271       SupRef :: sup_ref(),
   272       Id :: child_id() | undefined,
   273       Child :: child() | 'restarting',
   274       Type :: worker(),
   275       Modules :: modules().
   276 -endif.
   277 which_children(Supervisor) ->
   278     call(Supervisor, which_children).
   279 
   280 -ifdef(use_specs).
   281 -spec count_children(SupRef) -> PropListOfCounts when
   282       SupRef :: sup_ref(),
   283       PropListOfCounts :: [Count],
   284       Count :: {specs, ChildSpecCount :: non_neg_integer()}
   285              | {active, ActiveProcessCount :: non_neg_integer()}
   286              | {supervisors, ChildSupervisorCount :: non_neg_integer()}
   287              |{workers, ChildWorkerCount :: non_neg_integer()}.
   288 -endif.
   289 count_children(Supervisor) ->
   290     call(Supervisor, count_children).
   291 
   292 -ifdef(use_specs).
   293 -spec find_child(Supervisor, Name) -> [pid()] when
   294       Supervisor :: sup_ref(),
   295       Name :: child_id().
   296 -endif.
   297 find_child(Supervisor, Name) ->
   298     [Pid || {Name1, Pid, _Type, _Modules} <- which_children(Supervisor),
   299             Name1 =:= Name].
   300 
   301 call(Supervisor, Req) ->
   302     gen_server:call(Supervisor, Req, infinity).
   303 
   304 -ifdef(use_specs).
   305 -spec check_childspecs(ChildSpecs) -> Result when
   306       ChildSpecs :: [child_spec()],
   307       Result :: 'ok' | {'error', Error :: term()}.
   308 -endif.
   309 check_childspecs(ChildSpecs) when is_list(ChildSpecs) ->
   310     case check_startspec(ChildSpecs) of
   311 	{ok, _} -> ok;
   312 	Error -> {error, Error}
   313     end;
   314 check_childspecs(X) -> {error, {badarg, X}}.
   315 
   316 %%%-----------------------------------------------------------------
   317 %%% Called by timer:apply_after from restart/2
   318 -ifdef(use_specs).
   319 -spec try_again_restart(SupRef, Child, Reason) -> ok when
   320       SupRef :: sup_ref(),
   321       Child :: child_id() | pid(),
   322       Reason :: term().
   323 -endif.
   324 try_again_restart(Supervisor, Child, Reason) ->
   325     cast(Supervisor, {try_again_restart, Child, Reason}).
   326 
   327 cast(Supervisor, Req) ->
   328     gen_server:cast(Supervisor, Req).
   329 
   330 %%% ---------------------------------------------------
   331 %%% 
   332 %%% Initialize the supervisor.
   333 %%% 
   334 %%% ---------------------------------------------------
   335 -ifdef(use_specs).
   336 -type init_sup_name() :: sup_name() | 'self'.
   337 
   338 -type stop_rsn() :: {'shutdown', term()}
   339                   | {'bad_return', {module(),'init', term()}}
   340                   | {'bad_start_spec', term()}
   341                   | {'start_spec', term()}
   342                   | {'supervisor_data', term()}.
   343 
   344 -spec init({init_sup_name(), module(), [term()]}) ->
   345         {'ok', state()} | 'ignore' | {'stop', stop_rsn()}.
   346 -endif.
   347 init({SupName, Mod, Args}) ->
   348     process_flag(trap_exit, true),
   349     case Mod:init(Args) of
   350 	{ok, {SupFlags, StartSpec}} ->
   351 	    case init_state(SupName, SupFlags, Mod, Args) of
   352 		{ok, State} when ?is_simple(State) ->
   353 		    init_dynamic(State, StartSpec);
   354 		{ok, State} ->
   355 		    init_children(State, StartSpec);
   356 		Error ->
   357 		    {stop, {supervisor_data, Error}}
   358 	    end;
   359 	ignore ->
   360 	    ignore;
   361 	Error ->
   362 	    {stop, {bad_return, {Mod, init, Error}}}
   363     end.
   364 
   365 init_children(State, StartSpec) ->
   366     SupName = State#state.name,
   367     case check_startspec(StartSpec) of
   368         {ok, Children} ->
   369             case start_children(Children, SupName) of
   370                 {ok, NChildren} ->
   371                     {ok, State#state{children = NChildren}};
   372                 {error, NChildren, Reason} ->
   373                     terminate_children(NChildren, SupName),
   374                     {stop, {shutdown, Reason}}
   375             end;
   376         Error ->
   377             {stop, {start_spec, Error}}
   378     end.
   379 
   380 init_dynamic(State, [StartSpec]) ->
   381     case check_startspec([StartSpec]) of
   382         {ok, Children} ->
   383 	    {ok, State#state{children = Children}};
   384         Error ->
   385             {stop, {start_spec, Error}}
   386     end;
   387 init_dynamic(_State, StartSpec) ->
   388     {stop, {bad_start_spec, StartSpec}}.
   389 
   390 %%-----------------------------------------------------------------
   391 %% Func: start_children/2
   392 %% Args: Children = [child_rec()] in start order
   393 %%       SupName = {local, atom()} | {global, atom()} | {pid(), Mod}
   394 %% Purpose: Start all children.  The new list contains #child's
   395 %%          with pids.
   396 %% Returns: {ok, NChildren} | {error, NChildren, Reason}
   397 %%          NChildren = [child_rec()] in termination order (reversed
   398 %%                        start order)
   399 %%-----------------------------------------------------------------
   400 start_children(Children, SupName) -> start_children(Children, [], SupName).
   401 
   402 start_children([Child|Chs], NChildren, SupName) ->
   403     case do_start_child(SupName, Child) of
   404 	{ok, undefined} when Child#child.restart_type =:= temporary ->
   405 	    start_children(Chs, NChildren, SupName);
   406 	{ok, Pid} ->
   407 	    start_children(Chs, [Child#child{pid = Pid}|NChildren], SupName);
   408 	{ok, Pid, _Extra} ->
   409 	    start_children(Chs, [Child#child{pid = Pid}|NChildren], SupName);
   410 	{error, Reason} ->
   411 	    report_error(start_error, Reason, Child, SupName),
   412 	    {error, lists:reverse(Chs) ++ [Child | NChildren],
   413 	     {failed_to_start_child,Child#child.name,Reason}}
   414     end;
   415 start_children([], NChildren, _SupName) ->
   416     {ok, NChildren}.
   417 
   418 do_start_child(SupName, Child) ->
   419     #child{mfargs = {M, F, Args}} = Child,
   420     case catch apply(M, F, Args) of
   421 	{ok, Pid} when is_pid(Pid) ->
   422 	    NChild = Child#child{pid = Pid},
   423 	    report_progress(NChild, SupName),
   424 	    {ok, Pid};
   425 	{ok, Pid, Extra} when is_pid(Pid) ->
   426 	    NChild = Child#child{pid = Pid},
   427 	    report_progress(NChild, SupName),
   428 	    {ok, Pid, Extra};
   429 	ignore ->
   430 	    {ok, undefined};
   431 	{error, What} -> {error, What};
   432 	What -> {error, What}
   433     end.
   434 
   435 do_start_child_i(M, F, A) ->
   436     case catch apply(M, F, A) of
   437 	{ok, Pid} when is_pid(Pid) ->
   438 	    {ok, Pid};
   439 	{ok, Pid, Extra} when is_pid(Pid) ->
   440 	    {ok, Pid, Extra};
   441 	ignore ->
   442 	    {ok, undefined};
   443 	{error, Error} ->
   444 	    {error, Error};
   445 	What ->
   446 	    {error, What}
   447     end.
   448 
   449 %%% ---------------------------------------------------
   450 %%% 
   451 %%% Callback functions.
   452 %%% 
   453 %%% ---------------------------------------------------
   454 -ifdef(use_specs).
   455 -type call() :: 'which_children' | 'count_children' | {_, _}.	% XXX: refine
   456 -spec handle_call(call(), term(), state()) -> {'reply', term(), state()}.
   457 -endif.
   458 handle_call({start_child, EArgs}, _From, State) when ?is_simple(State) ->
   459     Child = hd(State#state.children),
   460     #child{mfargs = {M, F, A}} = Child,
   461     Args = A ++ EArgs,
   462     case do_start_child_i(M, F, Args) of
   463 	{ok, undefined} when Child#child.restart_type =:= temporary ->
   464 	    {reply, {ok, undefined}, State};
   465 	{ok, Pid} ->
   466 	    NState = save_dynamic_child(Child#child.restart_type, Pid, Args, State),
   467 	    {reply, {ok, Pid}, NState};
   468 	{ok, Pid, Extra} ->
   469 	    NState = save_dynamic_child(Child#child.restart_type, Pid, Args, State),
   470 	    {reply, {ok, Pid, Extra}, NState};
   471 	What ->
   472 	    {reply, What, State}
   473     end;
   474 
   475 %% terminate_child for simple_one_for_one can only be done with pid
   476 handle_call({terminate_child, Name}, _From, State) when not is_pid(Name),
   477 							?is_simple(State) ->
   478     {reply, {error, simple_one_for_one}, State};
   479 
   480 handle_call({terminate_child, Name}, _From, State) ->
   481     case get_child(Name, State, ?is_simple(State)) of
   482 	{value, Child} ->
   483 	    case do_terminate(Child, State#state.name) of
   484 		#child{restart_type=RT} when RT=:=temporary; ?is_simple(State) ->
   485 		    {reply, ok, state_del_child(Child, State)};
   486 		NChild ->
   487 		    {reply, ok, replace_child(NChild, State)}
   488 		end;
   489 	false ->
   490 	    {reply, {error, not_found}, State}
   491     end;
   492 
   493 %%% The requests delete_child and restart_child are invalid for
   494 %%% simple_one_for_one supervisors.
   495 handle_call({_Req, _Data}, _From, State) when ?is_simple(State) ->
   496     {reply, {error, simple_one_for_one}, State};
   497 
   498 handle_call({start_child, ChildSpec}, _From, State) ->
   499     case check_childspec(ChildSpec) of
   500 	{ok, Child} ->
   501 	    {Resp, NState} = handle_start_child(Child, State),
   502 	    {reply, Resp, NState};
   503 	What ->
   504 	    {reply, {error, What}, State}
   505     end;
   506 
   507 handle_call({restart_child, Name}, _From, State) ->
   508     case get_child(Name, State) of
   509 	{value, Child} when Child#child.pid =:= undefined ->
   510 	    case do_start_child(State#state.name, Child) of
   511 		{ok, Pid} ->
   512 		    NState = replace_child(Child#child{pid = Pid}, State),
   513 		    {reply, {ok, Pid}, NState};
   514 		{ok, Pid, Extra} ->
   515 		    NState = replace_child(Child#child{pid = Pid}, State),
   516 		    {reply, {ok, Pid, Extra}, NState};
   517 		Error ->
   518 		    {reply, Error, State}
   519 	    end;
   520 	{value, #child{pid=?restarting(_)}} ->
   521 	    {reply, {error, restarting}, State};
   522 	{value, _} ->
   523 	    {reply, {error, running}, State};
   524 	_ ->
   525 	    {reply, {error, not_found}, State}
   526     end;
   527 
   528 handle_call({delete_child, Name}, _From, State) ->
   529     case get_child(Name, State) of
   530 	{value, Child} when Child#child.pid =:= undefined ->
   531 	    NState = remove_child(Child, State),
   532 	    {reply, ok, NState};
   533 	{value, #child{pid=?restarting(_)}} ->
   534 	    {reply, {error, restarting}, State};
   535 	{value, _} ->
   536 	    {reply, {error, running}, State};
   537 	_ ->
   538 	    {reply, {error, not_found}, State}
   539     end;
   540 
   541 handle_call(which_children, _From, #state{children = [#child{restart_type = temporary,
   542 							     child_type = CT,
   543 							     modules = Mods}]} =
   544 		State) when ?is_simple(State) ->
   545     Reply = lists:map(fun(Pid) -> {undefined, Pid, CT, Mods} end,
   546                       ?SETS:to_list(dynamics_db(temporary, State#state.dynamics))),
   547     {reply, Reply, State};
   548 
   549 handle_call(which_children, _From, #state{children = [#child{restart_type = RType,
   550 							 child_type = CT,
   551 							 modules = Mods}]} =
   552 		State) when ?is_simple(State) ->
   553     Reply = lists:map(fun({?restarting(_),_}) -> {undefined,restarting,CT,Mods};
   554 			 ({Pid, _}) -> {undefined, Pid, CT, Mods} end,
   555 		      ?DICT:to_list(dynamics_db(RType, State#state.dynamics))),
   556     {reply, Reply, State};
   557 
   558 handle_call(which_children, _From, State) ->
   559     Resp =
   560 	lists:map(fun(#child{pid = ?restarting(_), name = Name,
   561 			     child_type = ChildType, modules = Mods}) ->
   562 			  {Name, restarting, ChildType, Mods};
   563 		     (#child{pid = Pid, name = Name,
   564 			     child_type = ChildType, modules = Mods}) ->
   565 			  {Name, Pid, ChildType, Mods}
   566 		  end,
   567 		  State#state.children),
   568     {reply, Resp, State};
   569 
   570 
   571 handle_call(count_children, _From, #state{children = [#child{restart_type = temporary,
   572 							     child_type = CT}]} = State)
   573   when ?is_simple(State) ->
   574     {Active, Count} =
   575 	?SETS:fold(fun(Pid, {Alive, Tot}) ->
   576 			   case is_pid(Pid) andalso is_process_alive(Pid) of
   577 			       true ->{Alive+1, Tot +1};
   578 			       false ->
   579 				   {Alive, Tot + 1}
   580 			   end
   581 		   end, {0, 0}, dynamics_db(temporary, State#state.dynamics)),
   582     Reply = case CT of
   583 		supervisor -> [{specs, 1}, {active, Active},
   584 			       {supervisors, Count}, {workers, 0}];
   585 		worker -> [{specs, 1}, {active, Active},
   586 			   {supervisors, 0}, {workers, Count}]
   587 	    end,
   588     {reply, Reply, State};
   589 
   590 handle_call(count_children, _From,  #state{children = [#child{restart_type = RType,
   591 							      child_type = CT}]} = State)
   592   when ?is_simple(State) ->
   593     {Active, Count} =
   594 	?DICT:fold(fun(Pid, _Val, {Alive, Tot}) ->
   595 			   case is_pid(Pid) andalso is_process_alive(Pid) of
   596 			       true ->
   597 				   {Alive+1, Tot +1};
   598 			       false ->
   599 				   {Alive, Tot + 1}
   600 			   end
   601 		   end, {0, 0}, dynamics_db(RType, State#state.dynamics)),
   602     Reply = case CT of
   603 		supervisor -> [{specs, 1}, {active, Active},
   604 			       {supervisors, Count}, {workers, 0}];
   605 		worker -> [{specs, 1}, {active, Active},
   606 			   {supervisors, 0}, {workers, Count}]
   607 	    end,
   608     {reply, Reply, State};
   609 
   610 handle_call(count_children, _From, State) ->
   611     %% Specs and children are together on the children list...
   612     {Specs, Active, Supers, Workers} =
   613 	lists:foldl(fun(Child, Counts) ->
   614 			   count_child(Child, Counts)
   615 		   end, {0,0,0,0}, State#state.children),
   616 
   617     %% Reformat counts to a property list.
   618     Reply = [{specs, Specs}, {active, Active},
   619 	     {supervisors, Supers}, {workers, Workers}],
   620     {reply, Reply, State}.
   621 
   622 
   623 count_child(#child{pid = Pid, child_type = worker},
   624 	    {Specs, Active, Supers, Workers}) ->
   625     case is_pid(Pid) andalso is_process_alive(Pid) of
   626 	true ->  {Specs+1, Active+1, Supers, Workers+1};
   627 	false -> {Specs+1, Active, Supers, Workers+1}
   628     end;
   629 count_child(#child{pid = Pid, child_type = supervisor},
   630 	    {Specs, Active, Supers, Workers}) ->
   631     case is_pid(Pid) andalso is_process_alive(Pid) of
   632 	true ->  {Specs+1, Active+1, Supers+1, Workers};
   633 	false -> {Specs+1, Active, Supers+1, Workers}
   634     end.
   635 
   636 
   637 %%% If a restart attempt failed, this message is sent via
   638 %%% timer:apply_after(0,...) in order to give gen_server the chance to
   639 %%% check it's inbox before trying again.
   640 -ifdef(use_specs).
   641 -spec handle_cast({try_again_restart, child_id() | pid(), term()}, state()) ->
   642 			 {'noreply', state()} | {stop, shutdown, state()}.
   643 -endif.
   644 handle_cast({try_again_restart,Pid,Reason}, #state{children=[Child]}=State)
   645   when ?is_simple(State) ->
   646     RT = Child#child.restart_type,
   647     RPid = restarting(Pid),
   648     case dynamic_child_args(RPid, dynamics_db(RT, State#state.dynamics)) of
   649 	{ok, Args} ->
   650 	    {M, F, _} = Child#child.mfargs,
   651 	    NChild = Child#child{pid = RPid, mfargs = {M, F, Args}},
   652             try_restart(Child#child.restart_type, Reason, NChild, State);
   653 	error ->
   654             {noreply, State}
   655     end;
   656 
   657 handle_cast({try_again_restart,Name,Reason}, State) ->
   658     %% we still support >= R12-B3 in which lists:keyfind/3 doesn't exist
   659     case lists:keysearch(Name,#child.name,State#state.children) of
   660 	{value, Child = #child{pid=?restarting(_), restart_type=RestartType}} ->
   661             try_restart(RestartType, Reason, Child, State);
   662 	_ ->
   663 	    {noreply,State}
   664     end.
   665 
   666 %%
   667 %% Take care of terminated children.
   668 %%
   669 -ifdef(use_specs).
   670 -spec handle_info(term(), state()) ->
   671         {'noreply', state()} | {'stop', 'shutdown', state()}.
   672 -endif.
   673 handle_info({'EXIT', Pid, Reason}, State) ->
   674     case restart_child(Pid, Reason, State) of
   675 	{ok, State1} ->
   676 	    {noreply, State1};
   677 	{shutdown, State1} ->
   678 	    {stop, shutdown, State1}
   679     end;
   680 
   681 handle_info({delayed_restart, {RestartType, Reason, Child}}, State)
   682   when ?is_simple(State) ->
   683     try_restart(RestartType, Reason, Child, State);
   684 handle_info({delayed_restart, {RestartType, Reason, Child}}, State) ->
   685     case get_child(Child#child.name, State) of
   686         {value, Child1} ->
   687             try_restart(RestartType, Reason, Child1, State);
   688         _What ->
   689             {noreply, State}
   690     end;
   691 
   692 handle_info(Msg, State) ->
   693     error_logger:error_msg("Supervisor received unexpected message: ~p~n", 
   694 			   [Msg]),
   695     {noreply, State}.
   696 
   697 %%
   698 %% Terminate this server.
   699 %%
   700 -ifdef(use_specs).
   701 -spec terminate(term(), state()) -> 'ok'.
   702 -endif.
   703 terminate(_Reason, #state{children=[Child]} = State) when ?is_simple(State) ->
   704     terminate_dynamic_children(Child, dynamics_db(Child#child.restart_type,
   705                                                   State#state.dynamics),
   706                                State#state.name);
   707 terminate(_Reason, State) ->
   708     terminate_children(State#state.children, State#state.name).
   709 
   710 %%
   711 %% Change code for the supervisor.
   712 %% Call the new call-back module and fetch the new start specification.
   713 %% Combine the new spec. with the old. If the new start spec. is
   714 %% not valid the code change will not succeed.
   715 %% Use the old Args as argument to Module:init/1.
   716 %% NOTE: This requires that the init function of the call-back module
   717 %%       does not have any side effects.
   718 %%
   719 -ifdef(use_specs).
   720 -spec code_change(term(), state(), term()) ->
   721         {'ok', state()} | {'error', term()}.
   722 -endif.
   723 code_change(_, State, _) ->
   724     case (State#state.module):init(State#state.args) of
   725 	{ok, {SupFlags, StartSpec}} ->
   726 	    case catch check_flags(SupFlags) of
   727 		ok ->
   728 		    {Strategy, MaxIntensity, Period} = SupFlags,
   729                     update_childspec(State#state{strategy = Strategy,
   730                                                  intensity = MaxIntensity,
   731                                                  period = Period},
   732                                      StartSpec);
   733 		Error ->
   734 		    {error, Error}
   735 	    end;
   736 	ignore ->
   737 	    {ok, State};
   738 	Error ->
   739 	    Error
   740     end.
   741 
   742 check_flags({Strategy, MaxIntensity, Period}) ->
   743     validStrategy(Strategy),
   744     validIntensity(MaxIntensity),
   745     validPeriod(Period),
   746     ok;
   747 check_flags(What) ->
   748     {bad_flags, What}.
   749 
   750 update_childspec(State, StartSpec) when ?is_simple(State) ->
   751     case check_startspec(StartSpec) of
   752         {ok, [Child]} ->
   753             {ok, State#state{children = [Child]}};
   754         Error ->
   755             {error, Error}
   756     end;
   757 update_childspec(State, StartSpec) ->
   758     case check_startspec(StartSpec) of
   759 	{ok, Children} ->
   760 	    OldC = State#state.children, % In reverse start order !
   761 	    NewC = update_childspec1(OldC, Children, []),
   762 	    {ok, State#state{children = NewC}};
   763         Error ->
   764 	    {error, Error}
   765     end.
   766 
   767 update_childspec1([Child|OldC], Children, KeepOld) ->
   768     case update_chsp(Child, Children) of
   769 	{ok,NewChildren} ->
   770 	    update_childspec1(OldC, NewChildren, KeepOld);
   771 	false ->
   772 	    update_childspec1(OldC, Children, [Child|KeepOld])
   773     end;
   774 update_childspec1([], Children, KeepOld) ->
   775     %% Return them in (kept) reverse start order.
   776     lists:reverse(Children ++ KeepOld).
   777 
   778 update_chsp(OldCh, Children) ->
   779     case lists:map(fun(Ch) when OldCh#child.name =:= Ch#child.name ->
   780 			   Ch#child{pid = OldCh#child.pid};
   781 		      (Ch) ->
   782 			   Ch
   783 		   end,
   784 		   Children) of
   785 	Children ->
   786 	    false;  % OldCh not found in new spec.
   787 	NewC ->
   788 	    {ok, NewC}
   789     end.
   790     
   791 %%% ---------------------------------------------------
   792 %%% Start a new child.
   793 %%% ---------------------------------------------------
   794 
   795 handle_start_child(Child, State) ->
   796     case get_child(Child#child.name, State) of
   797 	false ->
   798 	    case do_start_child(State#state.name, Child) of
   799 		{ok, undefined} when Child#child.restart_type =:= temporary ->
   800 		    {{ok, undefined}, State};
   801 		{ok, Pid} ->
   802 		    {{ok, Pid}, save_child(Child#child{pid = Pid}, State)};
   803 		{ok, Pid, Extra} ->
   804 		    {{ok, Pid, Extra}, save_child(Child#child{pid = Pid}, State)};
   805 		{error, What} ->
   806 		    {{error, {What, Child}}, State}
   807 	    end;
   808 	{value, OldChild} when is_pid(OldChild#child.pid) ->
   809 	    {{error, {already_started, OldChild#child.pid}}, State};
   810 	{value, _OldChild} ->
   811 	    {{error, already_present}, State}
   812     end.
   813 
   814 %%% ---------------------------------------------------
   815 %%% Restart. A process has terminated.
   816 %%% Returns: {ok, state()} | {shutdown, state()}
   817 %%% ---------------------------------------------------
   818 
   819 restart_child(Pid, Reason, #state{children = [Child]} = State) when ?is_simple(State) ->
   820     RestartType = Child#child.restart_type,
   821     case dynamic_child_args(Pid, dynamics_db(RestartType, State#state.dynamics)) of
   822 	{ok, Args} ->
   823 	    {M, F, _} = Child#child.mfargs,
   824 	    NChild = Child#child{pid = Pid, mfargs = {M, F, Args}},
   825 	    do_restart(RestartType, Reason, NChild, State);
   826 	error ->
   827             {ok, State}
   828     end;
   829 
   830 restart_child(Pid, Reason, State) ->
   831     Children = State#state.children,
   832     %% we still support >= R12-B3 in which lists:keyfind/3 doesn't exist
   833     case lists:keysearch(Pid, #child.pid, Children) of
   834 	{value, #child{restart_type = RestartType} = Child} ->
   835 	    do_restart(RestartType, Reason, Child, State);
   836 	false ->
   837 	    {ok, State}
   838     end.
   839 
   840 try_restart(RestartType, Reason, Child, State) ->
   841     case handle_restart(RestartType, Reason, Child, State) of
   842         {ok, NState}       -> {noreply, NState};
   843         {shutdown, State2} -> {stop, shutdown, State2}
   844     end.
   845 
   846 do_restart(RestartType, Reason, Child, State) ->
   847     maybe_report_error(RestartType, Reason, Child, State),
   848     handle_restart(RestartType, Reason, Child, State).
   849 
   850 maybe_report_error(permanent, Reason, Child, State) ->
   851     report_child_termination(Reason, Child, State);
   852 maybe_report_error({permanent, _}, Reason, Child, State) ->
   853     report_child_termination(Reason, Child, State);
   854 maybe_report_error(_Type, Reason, Child, State) ->
   855     case is_abnormal_termination(Reason) of
   856         true  -> report_child_termination(Reason, Child, State);
   857         false -> ok
   858     end.
   859 
   860 report_child_termination(Reason, Child, State) ->
   861     report_error(child_terminated, Reason, Child, State#state.name).
   862 
   863 handle_restart(permanent, _Reason, Child, State) ->
   864     restart(Child, State);
   865 handle_restart(transient, Reason, Child, State) ->
   866     restart_if_explicit_or_abnormal(fun restart/2,
   867                                     fun delete_child_and_continue/2,
   868                                     Reason, Child, State);
   869 handle_restart(intrinsic, Reason, Child, State) ->
   870     restart_if_explicit_or_abnormal(fun restart/2,
   871                                     fun delete_child_and_stop/2,
   872                                     Reason, Child, State);
   873 handle_restart(temporary, _Reason, Child, State) ->
   874     delete_child_and_continue(Child, State);
   875 handle_restart({permanent, _Delay}=Restart, Reason, Child, State) ->
   876     do_restart_delay(Restart, Reason, Child, State);
   877 handle_restart({transient, _Delay}=Restart, Reason, Child, State) ->
   878     restart_if_explicit_or_abnormal(defer_to_restart_delay(Restart, Reason),
   879                                     fun delete_child_and_continue/2,
   880                                     Reason, Child, State);
   881 handle_restart({intrinsic, _Delay}=Restart, Reason, Child, State) ->
   882     restart_if_explicit_or_abnormal(defer_to_restart_delay(Restart, Reason),
   883                                     fun delete_child_and_stop/2,
   884                                     Reason, Child, State).
   885 
   886 restart_if_explicit_or_abnormal(RestartHow, Otherwise, Reason, Child, State) ->
   887     case ?is_explicit_restart(Reason) orelse is_abnormal_termination(Reason) of
   888         true  -> RestartHow(Child, State);
   889         false -> Otherwise(Child, State)
   890     end.
   891 
   892 defer_to_restart_delay(Restart, Reason) ->
   893     fun(Child, State) -> do_restart_delay(Restart, Reason, Child, State) end.
   894 
   895 delete_child_and_continue(Child, State) ->
   896     {ok, state_del_child(Child, State)}.
   897 
   898 delete_child_and_stop(Child, State) ->
   899     {shutdown, state_del_child(Child, State)}.
   900 
   901 is_abnormal_termination(normal)        -> false;
   902 is_abnormal_termination(shutdown)      -> false;
   903 is_abnormal_termination({shutdown, _}) -> false;
   904 is_abnormal_termination(_Other)        -> true.
   905 
   906 do_restart_delay({RestartType, Delay}, Reason, Child, State) ->
   907     case add_restart(State) of
   908         {ok, NState} ->
   909             maybe_restart(NState#state.strategy, Child, NState);
   910         {terminate, _NState} ->
   911             %% we've reached the max restart intensity, but the
   912             %% add_restart will have added to the restarts
   913             %% field. Given we don't want to die here, we need to go
   914             %% back to the old restarts field otherwise we'll never
   915             %% attempt to restart later, which is why we ignore
   916             %% NState for this clause.
   917             _TRef = erlang:send_after(trunc(Delay*1000), self(),
   918                                       {delayed_restart,
   919                                        {{RestartType, Delay}, Reason, Child}}),
   920             {ok, state_del_child(Child, State)}
   921     end.
   922 
   923 restart(Child, State) ->
   924     case add_restart(State) of
   925 	{ok, NState} ->
   926 	    maybe_restart(NState#state.strategy, Child, NState);
   927 	{terminate, NState} ->
   928 	    report_error(shutdown, reached_max_restart_intensity,
   929 			 Child, State#state.name),
   930 	    {shutdown, remove_child(Child, NState)}
   931     end.
   932 
   933 maybe_restart(Strategy, Child, State) ->
   934     case restart(Strategy, Child, State) of
   935         {try_again, Reason, NState2} ->
   936             %% Leaving control back to gen_server before
   937             %% trying again. This way other incoming requsts
   938             %% for the supervisor can be handled - e.g. a
   939             %% shutdown request for the supervisor or the
   940             %% child.
   941             Id = if ?is_simple(State) -> Child#child.pid;
   942                     true -> Child#child.name
   943                  end,
   944             timer:apply_after(0,?MODULE,try_again_restart,[self(),Id,Reason]),
   945             {ok,NState2};
   946         Other ->
   947             Other
   948     end.
   949 
   950 restart(simple_one_for_one, Child, State) ->
   951     #child{pid = OldPid, mfargs = {M, F, A}} = Child,
   952     Dynamics = ?DICT:erase(OldPid, dynamics_db(Child#child.restart_type,
   953 					       State#state.dynamics)),
   954     case do_start_child_i(M, F, A) of
   955 	{ok, Pid} ->
   956 	    NState = State#state{dynamics = ?DICT:store(Pid, A, Dynamics)},
   957 	    {ok, NState};
   958 	{ok, Pid, _Extra} ->
   959 	    NState = State#state{dynamics = ?DICT:store(Pid, A, Dynamics)},
   960 	    {ok, NState};
   961 	{error, Error} ->
   962 	    NState = State#state{dynamics = ?DICT:store(restarting(OldPid), A,
   963 							Dynamics)},
   964 	    report_error(start_error, Error, Child, State#state.name),
   965 	    {try_again, Error, NState}
   966     end;
   967 restart(one_for_one, Child, State) ->
   968     OldPid = Child#child.pid,
   969     case do_start_child(State#state.name, Child) of
   970 	{ok, Pid} ->
   971 	    NState = replace_child(Child#child{pid = Pid}, State),
   972 	    {ok, NState};
   973 	{ok, Pid, _Extra} ->
   974 	    NState = replace_child(Child#child{pid = Pid}, State),
   975 	    {ok, NState};
   976 	{error, Reason} ->
   977 	    NState = replace_child(Child#child{pid = restarting(OldPid)}, State),
   978 	    report_error(start_error, Reason, Child, State#state.name),
   979 	    {try_again, Reason, NState}
   980     end;
   981 restart(rest_for_one, Child, State) ->
   982     {ChAfter, ChBefore} = split_child(Child#child.pid, State#state.children),
   983     ChAfter2 = terminate_children(ChAfter, State#state.name),
   984     case start_children(ChAfter2, State#state.name) of
   985 	{ok, ChAfter3} ->
   986 	    {ok, State#state{children = ChAfter3 ++ ChBefore}};
   987 	{error, ChAfter3, Reason} ->
   988 	    NChild = Child#child{pid=restarting(Child#child.pid)},
   989 	    NState = State#state{children = ChAfter3 ++ ChBefore},
   990 	    {try_again, Reason, replace_child(NChild,NState)}
   991     end;
   992 restart(one_for_all, Child, State) ->
   993     Children1 = del_child(Child#child.pid, State#state.children),
   994     Children2 = terminate_children(Children1, State#state.name),
   995     case start_children(Children2, State#state.name) of
   996 	{ok, NChs} ->
   997 	    {ok, State#state{children = NChs}};
   998 	{error, NChs, Reason} ->
   999 	    NChild = Child#child{pid=restarting(Child#child.pid)},
  1000 	    NState = State#state{children = NChs},
  1001 	    {try_again, Reason, replace_child(NChild,NState)}
  1002     end.
  1003 
  1004 restarting(Pid) when is_pid(Pid) -> ?restarting(Pid);
  1005 restarting(RPid) -> RPid.
  1006 
  1007 %%-----------------------------------------------------------------
  1008 %% Func: terminate_children/2
  1009 %% Args: Children = [child_rec()] in termination order
  1010 %%       SupName = {local, atom()} | {global, atom()} | {pid(),Mod}
  1011 %% Returns: NChildren = [child_rec()] in
  1012 %%          startup order (reversed termination order)
  1013 %%-----------------------------------------------------------------
  1014 terminate_children(Children, SupName) ->
  1015     terminate_children(Children, SupName, []).
  1016 
  1017 %% Temporary children should not be restarted and thus should
  1018 %% be skipped when building the list of terminated children, although
  1019 %% we do want them to be shut down as many functions from this module
  1020 %% use this function to just clear everything.
  1021 terminate_children([Child = #child{restart_type=temporary} | Children], SupName, Res) ->
  1022     do_terminate(Child, SupName),
  1023     terminate_children(Children, SupName, Res);
  1024 terminate_children([Child | Children], SupName, Res) ->
  1025     NChild = do_terminate(Child, SupName),
  1026     terminate_children(Children, SupName, [NChild | Res]);
  1027 terminate_children([], _SupName, Res) ->
  1028     Res.
  1029 
  1030 do_terminate(Child, SupName) when is_pid(Child#child.pid) ->
  1031     case shutdown(Child#child.pid, Child#child.shutdown) of
  1032         ok ->
  1033             ok;
  1034         {error, normal} when not ?is_permanent(Child#child.restart_type) ->
  1035             ok;
  1036         {error, OtherReason} ->
  1037             report_error(shutdown_error, OtherReason, Child, SupName)
  1038     end,
  1039     Child#child{pid = undefined};
  1040 do_terminate(Child, _SupName) ->
  1041     Child#child{pid = undefined}.
  1042 
  1043 %%-----------------------------------------------------------------
  1044 %% Shutdowns a child. We must check the EXIT value 
  1045 %% of the child, because it might have died with another reason than
  1046 %% the wanted. In that case we want to report the error. We put a 
  1047 %% monitor on the child an check for the 'DOWN' message instead of 
  1048 %% checking for the 'EXIT' message, because if we check the 'EXIT' 
  1049 %% message a "naughty" child, who does unlink(Sup), could hang the 
  1050 %% supervisor. 
  1051 %% Returns: ok | {error, OtherReason}  (this should be reported)
  1052 %%-----------------------------------------------------------------
  1053 shutdown(Pid, brutal_kill) ->
  1054     case monitor_child(Pid) of
  1055 	ok ->
  1056 	    exit(Pid, kill),
  1057 	    receive
  1058 		{'DOWN', _MRef, process, Pid, killed} ->
  1059 		    ok;
  1060 		{'DOWN', _MRef, process, Pid, OtherReason} ->
  1061 		    {error, OtherReason}
  1062 	    end;
  1063 	{error, Reason} ->      
  1064 	    {error, Reason}
  1065     end;
  1066 shutdown(Pid, Time) ->
  1067     case monitor_child(Pid) of
  1068 	ok ->
  1069 	    exit(Pid, shutdown), %% Try to shutdown gracefully
  1070 	    receive 
  1071 		{'DOWN', _MRef, process, Pid, shutdown} ->
  1072 		    ok;
  1073 		{'DOWN', _MRef, process, Pid, OtherReason} ->
  1074 		    {error, OtherReason}
  1075 	    after Time ->
  1076 		    exit(Pid, kill),  %% Force termination.
  1077 		    receive
  1078 			{'DOWN', _MRef, process, Pid, OtherReason} ->
  1079 			    {error, OtherReason}
  1080 		    end
  1081 	    end;
  1082 	{error, Reason} ->      
  1083 	    {error, Reason}
  1084     end.
  1085 
  1086 %% Help function to shutdown/2 switches from link to monitor approach
  1087 monitor_child(Pid) ->
  1088     
  1089     %% Do the monitor operation first so that if the child dies 
  1090     %% before the monitoring is done causing a 'DOWN'-message with
  1091     %% reason noproc, we will get the real reason in the 'EXIT'-message
  1092     %% unless a naughty child has already done unlink...
  1093     erlang:monitor(process, Pid),
  1094     unlink(Pid),
  1095 
  1096     receive
  1097 	%% If the child dies before the unlik we must empty
  1098 	%% the mail-box of the 'EXIT'-message and the 'DOWN'-message.
  1099 	{'EXIT', Pid, Reason} -> 
  1100 	    receive 
  1101 		{'DOWN', _, process, Pid, _} ->
  1102 		    {error, Reason}
  1103 	    end
  1104     after 0 -> 
  1105 	    %% If a naughty child did unlink and the child dies before
  1106 	    %% monitor the result will be that shutdown/2 receives a 
  1107 	    %% 'DOWN'-message with reason noproc.
  1108 	    %% If the child should die after the unlink there
  1109 	    %% will be a 'DOWN'-message with a correct reason
  1110 	    %% that will be handled in shutdown/2. 
  1111 	    ok   
  1112     end.
  1113 
  1114 
  1115 %%-----------------------------------------------------------------
  1116 %% Func: terminate_dynamic_children/3
  1117 %% Args: Child    = child_rec()
  1118 %%       Dynamics = ?DICT() | ?SET()
  1119 %%       SupName  = {local, atom()} | {global, atom()} | {pid(),Mod}
  1120 %% Returns: ok
  1121 %%
  1122 %%
  1123 %% Shutdown all dynamic children. This happens when the supervisor is
  1124 %% stopped. Because the supervisor can have millions of dynamic children, we
  1125 %% can have an significative overhead here.
  1126 %%-----------------------------------------------------------------
  1127 terminate_dynamic_children(Child, Dynamics, SupName) ->
  1128     {Pids, EStack0} = monitor_dynamic_children(Child, Dynamics),
  1129     Sz = ?SETS:size(Pids),
  1130     EStack = case Child#child.shutdown of
  1131                  brutal_kill ->
  1132                      ?SETS:fold(fun(P, _) -> exit(P, kill) end, ok, Pids),
  1133                      wait_dynamic_children(Child, Pids, Sz, undefined, EStack0);
  1134                  infinity ->
  1135                      ?SETS:fold(fun(P, _) -> exit(P, shutdown) end, ok, Pids),
  1136                      wait_dynamic_children(Child, Pids, Sz, undefined, EStack0);
  1137                  Time ->
  1138                      ?SETS:fold(fun(P, _) -> exit(P, shutdown) end, ok, Pids),
  1139                      TRef = erlang:start_timer(Time, self(), kill),
  1140                      wait_dynamic_children(Child, Pids, Sz, TRef, EStack0)
  1141              end,
  1142     %% Unroll stacked errors and report them
  1143     ?DICT:fold(fun(Reason, Ls, _) ->
  1144                        report_error(shutdown_error, Reason,
  1145                                     Child#child{pid=Ls}, SupName)
  1146                end, ok, EStack).
  1147 
  1148 
  1149 monitor_dynamic_children(#child{restart_type=temporary}, Dynamics) ->
  1150     ?SETS:fold(fun(P, {Pids, EStack}) ->
  1151                        case monitor_child(P) of
  1152                            ok ->
  1153                                {?SETS:add_element(P, Pids), EStack};
  1154                            {error, normal} ->
  1155                                {Pids, EStack};
  1156                            {error, Reason} ->
  1157                                {Pids, ?DICT:append(Reason, P, EStack)}
  1158                        end
  1159                end, {?SETS:new(), ?DICT:new()}, Dynamics);
  1160 monitor_dynamic_children(#child{restart_type=RType}, Dynamics) ->
  1161     ?DICT:fold(fun(P, _, {Pids, EStack}) when is_pid(P) ->
  1162                        case monitor_child(P) of
  1163                            ok ->
  1164                                {?SETS:add_element(P, Pids), EStack};
  1165                            {error, normal} when not ?is_permanent(RType) ->
  1166                                {Pids, EStack};
  1167                            {error, Reason} ->
  1168                                {Pids, ?DICT:append(Reason, P, EStack)}
  1169                        end;
  1170 		  (?restarting(_), _, {Pids, EStack}) ->
  1171 		       {Pids, EStack}
  1172                end, {?SETS:new(), ?DICT:new()}, Dynamics).
  1173 
  1174 wait_dynamic_children(_Child, _Pids, 0, undefined, EStack) ->
  1175     EStack;
  1176 wait_dynamic_children(_Child, _Pids, 0, TRef, EStack) ->
  1177 	%% If the timer has expired before its cancellation, we must empty the
  1178 	%% mail-box of the 'timeout'-message.
  1179     erlang:cancel_timer(TRef),
  1180     receive
  1181         {timeout, TRef, kill} ->
  1182             EStack
  1183     after 0 ->
  1184             EStack
  1185     end;
  1186 wait_dynamic_children(#child{shutdown=brutal_kill} = Child, Pids, Sz,
  1187                       TRef, EStack) ->
  1188     receive
  1189         {'DOWN', _MRef, process, Pid, killed} ->
  1190             wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
  1191                                   TRef, EStack);
  1192 
  1193         {'DOWN', _MRef, process, Pid, Reason} ->
  1194             wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
  1195                                   TRef, ?DICT:append(Reason, Pid, EStack))
  1196     end;
  1197 wait_dynamic_children(#child{restart_type=RType} = Child, Pids, Sz,
  1198                       TRef, EStack) ->
  1199     receive
  1200         {'DOWN', _MRef, process, Pid, shutdown} ->
  1201             wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
  1202                                   TRef, EStack);
  1203 
  1204         {'DOWN', _MRef, process, Pid, normal} when not ?is_permanent(RType) ->
  1205             wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
  1206                                   TRef, EStack);
  1207 
  1208         {'DOWN', _MRef, process, Pid, Reason} ->
  1209             wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
  1210                                   TRef, ?DICT:append(Reason, Pid, EStack));
  1211 
  1212         {timeout, TRef, kill} ->
  1213             ?SETS:fold(fun(P, _) -> exit(P, kill) end, ok, Pids),
  1214             wait_dynamic_children(Child, Pids, Sz-1, undefined, EStack)
  1215     end.
  1216 
  1217 %%-----------------------------------------------------------------
  1218 %% Child/State manipulating functions.
  1219 %%-----------------------------------------------------------------
  1220 
  1221 %% Note we do not want to save the parameter list for temporary processes as
  1222 %% they will not be restarted, and hence we do not need this information.
  1223 %% Especially for dynamic children to simple_one_for_one supervisors
  1224 %% it could become very costly as it is not uncommon to spawn
  1225 %% very many such processes.
  1226 save_child(#child{restart_type = temporary,
  1227 		  mfargs = {M, F, _}} = Child, #state{children = Children} = State) ->
  1228     State#state{children = [Child#child{mfargs = {M, F, undefined}} |Children]};
  1229 save_child(Child, #state{children = Children} = State) ->
  1230     State#state{children = [Child |Children]}.
  1231 
  1232 save_dynamic_child(temporary, Pid, _, #state{dynamics = Dynamics} = State) ->
  1233     State#state{dynamics = ?SETS:add_element(Pid, dynamics_db(temporary, Dynamics))};
  1234 save_dynamic_child(RestartType, Pid, Args, #state{dynamics = Dynamics} = State) ->
  1235     State#state{dynamics = ?DICT:store(Pid, Args, dynamics_db(RestartType, Dynamics))}.
  1236 
  1237 dynamics_db(temporary, undefined) ->
  1238     ?SETS:new();
  1239 dynamics_db(_, undefined) ->
  1240     ?DICT:new();
  1241 dynamics_db(_,Dynamics) ->
  1242     Dynamics.
  1243 
  1244 dynamic_child_args(Pid, Dynamics) ->
  1245     case ?SETS:is_set(Dynamics) of
  1246         true ->
  1247             {ok, undefined};
  1248         false ->
  1249             ?DICT:find(Pid, Dynamics)
  1250     end.
  1251 
  1252 state_del_child(#child{pid = Pid, restart_type = temporary}, State) when ?is_simple(State) ->
  1253     NDynamics = ?SETS:del_element(Pid, dynamics_db(temporary, State#state.dynamics)),
  1254     State#state{dynamics = NDynamics};
  1255 state_del_child(#child{pid = Pid, restart_type = RType}, State) when ?is_simple(State) ->
  1256     NDynamics = ?DICT:erase(Pid, dynamics_db(RType, State#state.dynamics)),
  1257     State#state{dynamics = NDynamics};
  1258 state_del_child(Child, State) ->
  1259     NChildren = del_child(Child#child.name, State#state.children),
  1260     State#state{children = NChildren}.
  1261 
  1262 del_child(Name, [Ch=#child{pid = ?restarting(_)}|_]=Chs) when Ch#child.name =:= Name ->
  1263     Chs;
  1264 del_child(Name, [Ch|Chs]) when Ch#child.name =:= Name, Ch#child.restart_type =:= temporary ->
  1265     Chs;
  1266 del_child(Name, [Ch|Chs]) when Ch#child.name =:= Name ->
  1267     [Ch#child{pid = undefined} | Chs];
  1268 del_child(Pid, [Ch|Chs]) when Ch#child.pid =:= Pid, Ch#child.restart_type =:= temporary ->
  1269     Chs;
  1270 del_child(Pid, [Ch|Chs]) when Ch#child.pid =:= Pid ->
  1271     [Ch#child{pid = undefined} | Chs];
  1272 del_child(Name, [Ch|Chs]) ->
  1273     [Ch|del_child(Name, Chs)];
  1274 del_child(_, []) ->
  1275     [].
  1276 
  1277 %% Chs = [S4, S3, Ch, S1, S0]
  1278 %% Ret: {[S4, S3, Ch], [S1, S0]}
  1279 split_child(Name, Chs) ->
  1280     split_child(Name, Chs, []).
  1281 
  1282 split_child(Name, [Ch|Chs], After) when Ch#child.name =:= Name ->
  1283     {lists:reverse([Ch#child{pid = undefined} | After]), Chs};
  1284 split_child(Pid, [Ch|Chs], After) when Ch#child.pid =:= Pid ->
  1285     {lists:reverse([Ch#child{pid = undefined} | After]), Chs};
  1286 split_child(Name, [Ch|Chs], After) ->
  1287     split_child(Name, Chs, [Ch | After]);
  1288 split_child(_, [], After) ->
  1289     {lists:reverse(After), []}.
  1290 
  1291 get_child(Name, State) ->
  1292     get_child(Name, State, false).
  1293 get_child(Pid, State, AllowPid) when AllowPid, is_pid(Pid) ->
  1294     get_dynamic_child(Pid, State);
  1295 get_child(Name, State, _) ->
  1296     lists:keysearch(Name, #child.name, State#state.children).
  1297 
  1298 get_dynamic_child(Pid, #state{children=[Child], dynamics=Dynamics}) ->
  1299     DynamicsDb = dynamics_db(Child#child.restart_type, Dynamics),
  1300     case is_dynamic_pid(Pid, DynamicsDb) of
  1301 	true ->
  1302 	    {value, Child#child{pid=Pid}};
  1303 	false ->
  1304 	    RPid = restarting(Pid),
  1305 	    case is_dynamic_pid(RPid, DynamicsDb) of
  1306 		true ->
  1307 		    {value, Child#child{pid=RPid}};
  1308 		false ->
  1309 		    case erlang:is_process_alive(Pid) of
  1310 			true -> false;
  1311 			false -> {value, Child}
  1312 		    end
  1313 	    end
  1314     end.
  1315 
  1316 is_dynamic_pid(Pid, Dynamics) ->
  1317     case ?SETS:is_set(Dynamics) of
  1318 	true ->
  1319 	    ?SETS:is_element(Pid, Dynamics);
  1320 	false ->
  1321 	    ?DICT:is_key(Pid, Dynamics)
  1322     end.
  1323 
  1324 replace_child(Child, State) ->
  1325     Chs = do_replace_child(Child, State#state.children),
  1326     State#state{children = Chs}.
  1327 
  1328 do_replace_child(Child, [Ch|Chs]) when Ch#child.name =:= Child#child.name ->
  1329     [Child | Chs];
  1330 do_replace_child(Child, [Ch|Chs]) ->
  1331     [Ch|do_replace_child(Child, Chs)].
  1332 
  1333 remove_child(Child, State) ->
  1334     Chs = lists:keydelete(Child#child.name, #child.name, State#state.children),
  1335     State#state{children = Chs}.
  1336 
  1337 %%-----------------------------------------------------------------
  1338 %% Func: init_state/4
  1339 %% Args: SupName = {local, atom()} | {global, atom()} | self
  1340 %%       Type = {Strategy, MaxIntensity, Period}
  1341 %%         Strategy = one_for_one | one_for_all | simple_one_for_one |
  1342 %%                    rest_for_one
  1343 %%         MaxIntensity = integer() >= 0
  1344 %%         Period = integer() > 0
  1345 %%       Mod :== atom()
  1346 %%       Args :== term()
  1347 %% Purpose: Check that Type is of correct type (!)
  1348 %% Returns: {ok, state()} | Error
  1349 %%-----------------------------------------------------------------
  1350 init_state(SupName, Type, Mod, Args) ->
  1351     case catch init_state1(SupName, Type, Mod, Args) of
  1352 	{ok, State} ->
  1353 	    {ok, State};
  1354 	Error ->
  1355 	    Error
  1356     end.
  1357 
  1358 init_state1(SupName, {Strategy, MaxIntensity, Period}, Mod, Args) ->
  1359     validStrategy(Strategy),
  1360     validIntensity(MaxIntensity),
  1361     validPeriod(Period),
  1362     {ok, #state{name = supname(SupName,Mod),
  1363 		strategy = Strategy,
  1364 		intensity = MaxIntensity,
  1365 		period = Period,
  1366 		module = Mod,
  1367 		args = Args}};
  1368 init_state1(_SupName, Type, _, _) ->
  1369     {invalid_type, Type}.
  1370 
  1371 validStrategy(simple_one_for_one) -> true;
  1372 validStrategy(one_for_one)        -> true;
  1373 validStrategy(one_for_all)        -> true;
  1374 validStrategy(rest_for_one)       -> true;
  1375 validStrategy(What)               -> throw({invalid_strategy, What}).
  1376 
  1377 validIntensity(Max) when is_integer(Max),
  1378                          Max >=  0 -> true;
  1379 validIntensity(What)               -> throw({invalid_intensity, What}).
  1380 
  1381 validPeriod(Period) when is_integer(Period),
  1382                          Period > 0 -> true;
  1383 validPeriod(What)                   -> throw({invalid_period, What}).
  1384 
  1385 supname(self, Mod) -> {self(), Mod};
  1386 supname(N, _)      -> N.
  1387 
  1388 %%% ------------------------------------------------------
  1389 %%% Check that the children start specification is valid.
  1390 %%% Shall be a six (6) tuple
  1391 %%%    {Name, Func, RestartType, Shutdown, ChildType, Modules}
  1392 %%% where Name is an atom
  1393 %%%       Func is {Mod, Fun, Args} == {atom(), atom(), list()}
  1394 %%%       RestartType is permanent | temporary | transient |
  1395 %%%                      intrinsic | {permanent, Delay} |
  1396 %%%                      {transient, Delay} | {intrinsic, Delay}
  1397 %%                       where Delay >= 0
  1398 %%%       Shutdown = integer() > 0 | infinity | brutal_kill
  1399 %%%       ChildType = supervisor | worker
  1400 %%%       Modules = [atom()] | dynamic
  1401 %%% Returns: {ok, [child_rec()]} | Error
  1402 %%% ------------------------------------------------------
  1403 
  1404 check_startspec(Children) -> check_startspec(Children, []).
  1405 
  1406 check_startspec([ChildSpec|T], Res) ->
  1407     case check_childspec(ChildSpec) of
  1408 	{ok, Child} ->
  1409 	    case lists:keymember(Child#child.name, #child.name, Res) of
  1410 		true -> {duplicate_child_name, Child#child.name};
  1411 		false -> check_startspec(T, [Child | Res])
  1412 	    end;
  1413 	Error -> Error
  1414     end;
  1415 check_startspec([], Res) ->
  1416     {ok, lists:reverse(Res)}.
  1417 
  1418 check_childspec({Name, Func, RestartType, Shutdown, ChildType, Mods}) ->
  1419     catch check_childspec(Name, Func, RestartType, Shutdown, ChildType, Mods);
  1420 check_childspec(X) -> {invalid_child_spec, X}.
  1421 
  1422 check_childspec(Name, Func, RestartType, Shutdown, ChildType, Mods) ->
  1423     validName(Name),
  1424     validFunc(Func),
  1425     validRestartType(RestartType),
  1426     validChildType(ChildType),
  1427     validShutdown(Shutdown, ChildType),
  1428     validMods(Mods),
  1429     {ok, #child{name = Name, mfargs = Func, restart_type = RestartType,
  1430 		shutdown = Shutdown, child_type = ChildType, modules = Mods}}.
  1431 
  1432 validChildType(supervisor) -> true;
  1433 validChildType(worker) -> true;
  1434 validChildType(What) -> throw({invalid_child_type, What}).
  1435 
  1436 validName(_Name) -> true.
  1437 
  1438 validFunc({M, F, A}) when is_atom(M), 
  1439                           is_atom(F), 
  1440                           is_list(A) -> true;
  1441 validFunc(Func)                      -> throw({invalid_mfa, Func}).
  1442 
  1443 validRestartType(permanent)          -> true;
  1444 validRestartType(temporary)          -> true;
  1445 validRestartType(transient)          -> true;
  1446 validRestartType(intrinsic)          -> true;
  1447 validRestartType({permanent, Delay}) -> validDelay(Delay);
  1448 validRestartType({intrinsic, Delay}) -> validDelay(Delay);
  1449 validRestartType({transient, Delay}) -> validDelay(Delay);
  1450 validRestartType(RestartType)        -> throw({invalid_restart_type,
  1451                                                RestartType}).
  1452 
  1453 validDelay(Delay) when is_number(Delay),
  1454                        Delay >= 0 -> true;
  1455 validDelay(What)                  -> throw({invalid_delay, What}).
  1456 
  1457 validShutdown(Shutdown, _) 
  1458   when is_integer(Shutdown), Shutdown > 0 -> true;
  1459 validShutdown(infinity, _)             -> true;
  1460 validShutdown(brutal_kill, _)          -> true;
  1461 validShutdown(Shutdown, _)             -> throw({invalid_shutdown, Shutdown}).
  1462 
  1463 validMods(dynamic) -> true;
  1464 validMods(Mods) when is_list(Mods) ->
  1465     lists:foreach(fun(Mod) ->
  1466 		    if
  1467 			is_atom(Mod) -> ok;
  1468 			true -> throw({invalid_module, Mod})
  1469 		    end
  1470 		  end,
  1471 		  Mods);
  1472 validMods(Mods) -> throw({invalid_modules, Mods}).
  1473 
  1474 %%% ------------------------------------------------------
  1475 %%% Add a new restart and calculate if the max restart
  1476 %%% intensity has been reached (in that case the supervisor
  1477 %%% shall terminate).
  1478 %%% All restarts accured inside the period amount of seconds
  1479 %%% are kept in the #state.restarts list.
  1480 %%% Returns: {ok, State'} | {terminate, State'}
  1481 %%% ------------------------------------------------------
  1482 
  1483 add_restart(State) ->  
  1484     I = State#state.intensity,
  1485     P = State#state.period,
  1486     R = State#state.restarts,
  1487     Now = erlang:now(),
  1488     R1 = add_restart([Now|R], Now, P),
  1489     State1 = State#state{restarts = R1},
  1490     case length(R1) of
  1491 	CurI when CurI  =< I ->
  1492 	    {ok, State1};
  1493 	_ ->
  1494 	    {terminate, State1}
  1495     end.
  1496 
  1497 add_restart([R|Restarts], Now, Period) ->
  1498     case inPeriod(R, Now, Period) of
  1499 	true ->
  1500 	    [R|add_restart(Restarts, Now, Period)];
  1501 	_ ->
  1502 	    []
  1503     end;
  1504 add_restart([], _, _) ->
  1505     [].
  1506 
  1507 inPeriod(Time, Now, Period) ->
  1508     case difference(Time, Now) of
  1509 	T when T > Period ->
  1510 	    false;
  1511 	_ ->
  1512 	    true
  1513     end.
  1514 
  1515 %%
  1516 %% Time = {MegaSecs, Secs, MicroSecs} (NOTE: MicroSecs is ignored)
  1517 %% Calculate the time elapsed in seconds between two timestamps.
  1518 %% If MegaSecs is equal just subtract Secs.
  1519 %% Else calculate the Mega difference and add the Secs difference,
  1520 %% note that Secs difference can be negative, e.g.
  1521 %%      {827, 999999, 676} diff {828, 1, 653753} == > 2 secs.
  1522 %%
  1523 difference({TimeM, TimeS, _}, {CurM, CurS, _}) when CurM > TimeM ->
  1524     ((CurM - TimeM) * 1000000) + (CurS - TimeS);
  1525 difference({_, TimeS, _}, {_, CurS, _}) ->
  1526     CurS - TimeS.
  1527 
  1528 %%% ------------------------------------------------------
  1529 %%% Error and progress reporting.
  1530 %%% ------------------------------------------------------
  1531 
  1532 report_error(Error, Reason, Child, SupName) ->
  1533     ErrorMsg = [{supervisor, SupName},
  1534 		{errorContext, Error},
  1535 		{reason, Reason},
  1536 		{offender, extract_child(Child)}],
  1537     error_logger:error_report(supervisor_report, ErrorMsg).
  1538 
  1539 
  1540 extract_child(Child) when is_list(Child#child.pid) ->
  1541     [{nb_children, length(Child#child.pid)},
  1542      {name, Child#child.name},
  1543      {mfargs, Child#child.mfargs},
  1544      {restart_type, Child#child.restart_type},
  1545      {shutdown, Child#child.shutdown},
  1546      {child_type, Child#child.child_type}];
  1547 extract_child(Child) ->
  1548     [{pid, Child#child.pid},
  1549      {name, Child#child.name},
  1550      {mfargs, Child#child.mfargs},
  1551      {restart_type, Child#child.restart_type},
  1552      {shutdown, Child#child.shutdown},
  1553      {child_type, Child#child.child_type}].
  1554 
  1555 report_progress(Child, SupName) ->
  1556     Progress = [{supervisor, SupName},
  1557 		{started, extract_child(Child)}],
  1558     error_logger:info_report(progress, Progress).