Permalink
Browse files

Initial source code import

  • Loading branch information...
0 parents commit 7958cc4ea61d6f0aa38ad237a8b3c1479b33389a @yrashk yrashk committed Jul 12, 2011
Showing with 353 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +64 −0 include/gen_supervisor.hrl
  3. +11 −0 src/gen_supervisor.app.src
  4. +216 −0 src/gen_supervisor.erl
  5. +25 −0 test/gen_supervisor_tests.erl
  6. +35 −0 test/test_sup.erl
@@ -0,0 +1,2 @@
+.eunit
+ebin
@@ -0,0 +1,64 @@
+-record(child, {
+ id :: term(),
+ start_func :: {module(), atom(), [term()] | undefined } | undefined,
+ restart = permanent :: permanent | transient | temporary,
+ shutdown = 5000 :: brutal_kill | timeout() | infinity,
+ type :: worker | supervisor,
+ modules :: [module()] | dynamic | undefined
+ }).
+
+-record(worker, {
+ id :: term(),
+ start_func :: {module(), atom(), [term()] | undefined } | undefined,
+ restart = permanent:: permanent | transient | temporary,
+ shutdown = 5000 :: brutal_kill | timeout() | infinity,
+ modules :: [module()] | dynamic | undefined
+ }).
+
+-record(supervisor, {
+ id :: term(),
+ restart_strategy = one_for_one :: one_for_one | one_for_all | rest_for_one |
+ simple_one_for_one,
+ max_restarts = {1, 60} :: {pos_integer(), pos_integer()},
+ children = [] :: [gen_supervisor:supervisable()],
+ %%
+ restart = permanent :: permanent | transient | temporary,
+ shutdown = infinity :: brutal_kill | timeout() | infinity
+ }).
+
+-record(one_for_one, {
+ id :: term(),
+ max_restarts = {1,60} :: {pos_integer(), pos_integer()},
+ children = [] :: [gen_supervisor:supervisable()],
+ %%
+ restart = permanent :: permanent | transient | temporary,
+ shutdown = infinity :: brutal_kill | timeout() | infinity
+ }).
+
+-record(one_for_all, {
+ id :: term(),
+ max_restarts = {1,60} :: {pos_integer(), pos_integer()},
+ children = [] :: [gen_supervisor:supervisable()],
+ %%
+ restart = permanent :: permanent | transient | temporary,
+ shutdown = infinity :: brutal_kill | timeout() | infinity
+ }).
+
+-record(rest_for_one, {
+ id :: term(),
+ max_restarts = {1,60} :: {pos_integer(), pos_integer()},
+ children = [] :: [gen_supervisor:supervisable()],
+ %%
+ restart = permanent :: permanent | transient | temporary,
+ shutdown = infinity :: brutal_kill | timeout() | infinity
+ }).
+
+-record(simple_one_for_one, {
+ id :: term(),
+ max_restarts = {1,60} :: {pos_integer(), pos_integer()},
+ children = [] :: [gen_supervisor:supervisable()],
+ %%
+ restart = permanent :: permanent | transient | temporary,
+ shutdown = infinity :: brutal_kill | timeout() | infinity
+ }).
+
@@ -0,0 +1,11 @@
+{application, gen_supervisor,
+ [
+ {description, "'Least surprise' supervisor API"},
+ {vsn, git},
+ {registered, []},
+ {applications, [
+ kernel,
+ stdlib
+ ]},
+ {env, []}
+ ]}.
@@ -0,0 +1,216 @@
+-module(gen_supervisor).
+-behaviour(supervisor).
+-include_lib("gen_supervisor/include/gen_supervisor.hrl").
+
+-export([start_link/2, start_link/3]).
+-export([behaviour_info/1]).
+-export([start_sup/2]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+-export_type([supervisable/0]).
+
+-type supervisor() :: #supervisor{} | #one_for_one{} |
+ #one_for_all{} | #rest_for_one{} |
+ #simple_one_for_one{}.
+
+-type child() :: #child{} | #worker{}.
+
+-type supervisable() :: child() | supervisor().
+
+behaviour_info(callbacks) ->
+ [{init,1}];
+behaviour_info(_) ->
+ undefined.
+
+-include_lib("eunit/include/eunit.hrl").
+
+init({spec, Spec}) ->
+ init_result(Spec);
+init({Module, Args}) ->
+ init_result(Module:init(Args)).
+
+-spec start_link(module(), term()) -> supervisor:start_link_ret().
+
+start_link(Module, Args) ->
+ supervisor:start_link(?MODULE, {Module, Args}).
+
+start_link(SupName, Module, Args) ->
+ supervisor:start_link(SupName, ?MODULE, {Module, Args}).
+
+-spec start_sup(atom(), supervisor()) -> {ok, pid()}.
+
+start_sup(Id, SupervisorSpec) ->
+ supervisor:start_link({local, Id}, ?MODULE, {spec, SupervisorSpec}).
+
+%% Internal functions
+init_result(ignore) ->
+ ignore;
+init_result(Result) ->
+ {ok, spec(Result)}.
+
+specs([]) ->
+ [];
+specs([Spec|Rest]) ->
+ [spec(Spec)|specs(Rest)].
+
+spec(#worker{
+ id = Id,
+ start_func = StartFunc,
+ restart = Restart,
+ shutdown = Shutdown,
+ modules = Modules
+ }) ->
+ spec(#child{
+ type = worker,
+ id = Id,
+ start_func = StartFunc,
+ restart = Restart,
+ shutdown = Shutdown,
+ modules = Modules
+ });
+spec(#child{
+ id = Id,
+ start_func = undefined
+ } = Child) ->
+ spec(Child#child{ start_func = {Id, start_link, []}});
+spec(#child{
+ id = Id,
+ modules = undefined
+ } = Child) ->
+ spec(Child#child{ modules = [Id] });
+spec(#child{
+ id = Id,
+ start_func = StartFunc,
+ restart = Restart,
+ shutdown = Shutdown,
+ modules = Modules,
+ type = Type
+ }) ->
+ Child = {Id, StartFunc, Restart, Shutdown, Type, Modules},
+ ok = supervisor:check_childspecs([Child]),
+ Child;
+
+spec(#one_for_one{
+ id = Id,
+ max_restarts = MaxRT,
+ children = Children
+ }) ->
+ spec(#supervisor{ id = Id,
+ restart_strategy = one_for_one,
+ max_restarts = MaxRT,
+ children = Children });
+
+spec(#one_for_all{
+ id = Id,
+ max_restarts = MaxRT,
+ children = Children
+ }) ->
+ spec(#supervisor{ id = Id,
+ restart_strategy = one_for_all,
+ max_restarts = MaxRT,
+ children = Children });
+
+spec(#rest_for_one{
+ id = Id,
+ max_restarts = MaxRT,
+ children = Children
+ }) ->
+ spec(#supervisor{ id = Id,
+ restart_strategy = rest_for_one,
+ max_restarts = MaxRT,
+ children = Children });
+
+spec(#simple_one_for_one{
+ id = Id,
+ max_restarts = MaxRT,
+ children = Children
+ }) ->
+ spec(#supervisor{ id = Id,
+ restart_strategy = simple_one_for_one,
+ max_restarts = MaxRT,
+ children = Children });
+
+spec(#supervisor{
+ id = _Id,
+ restart_strategy = Restart,
+ max_restarts = {MaxR, MaxT},
+ children = Children
+ }) ->
+ {{Restart, MaxR, MaxT}, specs(maybe_convert_supervisors(Children))}.
+
+
+maybe_convert_supervisors([]) ->
+ [];
+maybe_convert_supervisors([Spec|Specs]) ->
+ [maybe_convert_supervisor(Spec)|maybe_convert_supervisors(Specs)].
+
+maybe_convert_supervisor(#one_for_one{
+ id = Id, restart = Restart,
+ shutdown = Shutdown
+ } = Sup) ->
+ #child{
+ id = Id,
+ type = supervisor,
+ start_func = {?MODULE, start_sup, [Id, Sup]},
+ restart = Restart,
+ shutdown = Shutdown,
+ modules = [?MODULE]
+ };
+
+maybe_convert_supervisor(#one_for_all{
+ id = Id, restart = Restart,
+ shutdown = Shutdown
+ } = Sup) ->
+ #child{
+ id = Id,
+ type = supervisor,
+ start_func = {?MODULE, start_sup, [Id, Sup]},
+ restart = Restart,
+ shutdown = Shutdown,
+ modules = [?MODULE]
+ };
+
+maybe_convert_supervisor(#rest_for_one{
+ id = Id, restart = Restart,
+ shutdown = Shutdown
+ } = Sup) ->
+ #child{
+ id = Id,
+ type = supervisor,
+ start_func = {?MODULE, start_sup, [Id, Sup]},
+ restart = Restart,
+ shutdown = Shutdown,
+ modules = [?MODULE]
+ };
+
+maybe_convert_supervisor(#simple_one_for_one{
+ id = Id, restart = Restart,
+ shutdown = Shutdown
+ } = Sup) ->
+ #child{
+ id = Id,
+ type = supervisor,
+ start_func = {?MODULE, start_sup, [Id, Sup]},
+ restart = Restart,
+ shutdown = Shutdown,
+ modules = [?MODULE]
+ };
+
+maybe_convert_supervisor(#supervisor{
+ id = Id, restart = Restart,
+ shutdown = Shutdown
+ } = Sup) ->
+ #child{
+ id = Id,
+ type = supervisor,
+ start_func = {?MODULE, start_sup, [Id, Sup]},
+ restart = Restart,
+ shutdown = Shutdown,
+ modules = [?MODULE]
+ };
+
+
+maybe_convert_supervisor(Other) ->
+ Other.
@@ -0,0 +1,25 @@
+-module(gen_supervisor_tests).
+-include_lib("eunit/include/eunit.hrl").
+
+t_starts_supervisor() ->
+ ?assertMatch([{some_sup, _, _, _}], supervisor:which_children(test_sup)).
+
+t_nested_supervisor() ->
+ [{some_sup, Pid, _, _}] = supervisor:which_children(test_sup),
+ ?assertMatch([{some, _, _, _}], supervisor:which_children(Pid)).
+
+gen_supervisor_test_() ->
+ {setup,
+ fun () ->
+ application:start(gen_supervisor),
+ {ok, SupPid} = test_sup:start_link(),
+ SupPid
+ end,
+ fun (SupPid) ->
+ application:stop(gen_supervisor)
+ end,
+ [
+ {"starts supervisor", ?_test(t_starts_supervisor())},
+ {"nested supervisor is handled properly", ?_test(t_nested_supervisor())}
+
+ ]}.
@@ -0,0 +1,35 @@
+-module(test_sup).
+-behaviour(gen_supervisor).
+-include_lib("gen_supervisor/include/gen_supervisor.hrl").
+
+%% API
+-export([start_link/0]).
+
+-export([some_start_link/1]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+start_link() ->
+ gen_supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+init([]) ->
+ #one_for_one{
+ children = [
+ #one_for_one{
+ id = some_sup,
+ children = [
+ #worker{
+ id = some,
+ restart = permanent,
+ start_func = {?MODULE, some_start_link, [some]}
+ }
+ ]
+ }
+ ]
+
+ }.
+
+some_start_link(_Name) ->
+ {ok, spawn_link(fun() -> receive nothing -> ok end end)}.
+

0 comments on commit 7958cc4

Please sign in to comment.