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