git @ Cat's Eye Technologies pibfi / master src / pibfi_supervisor.erl
master

Tree @master (Download .tar.gz)

pibfi_supervisor.erl @masterraw · history · blame

%%% BEGIN pibfi_supervisor.erl %%%
%%%
%%% pibfi - Platonic Ideal Brainf*ck Interpreter
%%% Copyright (c)2003 Cat's Eye Technologies.  All rights reserved.
%%%
%%% Redistribution and use in source and binary forms, with or without
%%% modification, are permitted provided that the following conditions
%%% are met:
%%%
%%%   Redistributions of source code must retain the above copyright
%%%   notice, this list of conditions and the following disclaimer.
%%%
%%%   Redistributions in binary form must reproduce the above copyright
%%%   notice, this list of conditions and the following disclaimer in
%%%   the documentation and/or other materials provided with the
%%%   distribution.
%%%
%%%   Neither the name of Cat's Eye Technologies nor the names of its
%%%   contributors may be used to endorse or promote products derived
%%%   from this software without specific prior written permission.
%%%
%%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
%%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
%%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
%%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
%%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
%%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
%%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
%%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
%%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
%%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
%%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
%%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
%%% POSSIBILITY OF SUCH DAMAGE. 

%% @doc Supervisor process for <code>pibfi</code>.
%%
%% <p>All error handling is done here.  This allows the other processes
%% to be coded in a more direct, laissez-crash style.  The centralization
%% of error-handling code in this process allows for minimal
%% error-handling code in the other processes, which makes their code
%% clearer and easier to follow.</p>
%%
%% @end

-module(pibfi_supervisor).
-vsn('2003.0505').
-copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').

-export([start/0, server/0, spawn_link/6, link/3]).

start() ->
  spawn(?MODULE, server, []).

server() ->
  process_flag(trap_exit, true),
  loop(dict:new(), dict:new(), 0).
  
loop(CriticalPids, NonCriticalPids, Count) ->
  receive
    {Pid, spawn, Name, critical, Module, Function, Args} ->
      NewPid = spawn_link(Module, Function, Args),
      CriticalPids0 = dict:store(NewPid, Name, CriticalPids),
      whisper("~p->~p critical ~s started ~p", [Count, Count + 1, Name, NewPid]),
      Pid ! {self(), spawned, Module, Function, Args, NewPid},
      loop(CriticalPids0, NonCriticalPids, Count + 1);
    {Pid, spawn, Name, noncritical, Module, Function, Args} ->
      NewPid = spawn_link(Module, Function, Args),
      NonCriticalPids0 = dict:store(NewPid, Name, NonCriticalPids),
      whisper("~p->~p noncritical ~s started ~p", [Count, Count + 1, Name, NewPid]),
      Pid ! {self(), spawned, Module, Function, Args, NewPid},
      loop(CriticalPids, NonCriticalPids0, Count + 1);
    {Pid, link, Name, LPid} ->
      link(LPid),
      NonCriticalPids0 = dict:store(LPid, Name, NonCriticalPids),
      whisper("~p->~p noncritical ~s linked to ~p", [Count, Count + 1, Name, LPid]),
      Pid ! {self(), linked, LPid},
      loop(CriticalPids, NonCriticalPids0, Count + 1);
    {'EXIT', From, OK} when OK == normal; OK == shutdown; OK == terminated ->
      case dict:find(From, CriticalPids) of
        {ok, Name} ->
          whisper("~p->~p critical ~s exited normally", [Count, Count - 1, Name]),
          CriticalPids0 = dict:erase(From, CriticalPids),
          case dict:to_list(CriticalPids0) of
            [] ->
              whisper("all critical processes exited normally, exiting", []),
              pibfi:whisper("---------------END PROGRAM OUTPUT---------------"),
	      case pibfi_options:get_flag(autopsy) of
                true ->
	          pibfi_statistics:dump(autopsy);
	        false ->
		  ok
              end,
              exeunt(NonCriticalPids),
	      erlang:halt();
            _ ->
              loop(CriticalPids0, NonCriticalPids, Count - 1)
          end;
	_ ->
	  case dict:find(From, NonCriticalPids) of
	    {ok, Name} ->
	      whisper("~p->~p noncritical ~s exited normally",
	        [Count, Count - 1, Name]),
	      NonCriticalPids0 = dict:erase(From, NonCriticalPids),
	      loop(CriticalPids, NonCriticalPids0, Count - 1);
	    error ->
	      whisper("??? unknown pid ~p quitting", [From]),
	      loop(CriticalPids, NonCriticalPids, Count)
	  end
      end;
    {'EXIT', From, Reason} ->
      Name = case dict:find(From, CriticalPids) of
        {ok, N} ->
	  N;
	_ ->
	  case dict:find(From, NonCriticalPids) of
	    {ok, N} ->
	      N;
	    _ ->
	      "unknown"
	  end
      end,
      pibfi:whisper("---------------END PROGRAM OUTPUT---------------"),
      io:fwrite("~n***** HALTED~nAn error occurred in the ~s process:~n~p~n",
        [Name, Reason]),
      pibfi_statistics:dump(),
      exeunt(CriticalPids),
      exeunt(NonCriticalPids),
      erlang:halt(1)
  end.

exeunt(Dict) ->
  exeunt0(dict:to_list(Dict)).
  
exeunt0(List) when is_list(List) ->
  lists:foreach(fun({P,N}) ->
    whisper("shutting down ~s ~p", [N, P]),
    exit(P, shutdown)
  end, List).

whisper(FmtString, Args) ->
  case pibfi_options:get_flag(bearflowers) of
    true ->
      io:fwrite(">>> " ++ FmtString ++ "~n", Args);
    false ->
      ok
  end.

%%% interface

spawn_link(Supervisor, Name, Class, Module, Function, Args) ->
  Supervisor ! {self(), spawn, Name, Class, Module, Function, Args},
  receive
    {Supervisor, spawned, Module, Function, Args, Pid} ->
      Pid
  end.

link(Supervisor, Name, Pid) ->
  Supervisor ! {self(), link, Name, Pid},
  receive
    {Supervisor, linked, Pid} ->
      Pid
  end.

%%% END of pibfi_supervisor.erl %%%