OTP中supervisor启动过程

来源:互联网 发布:基础代谢 知乎 编辑:程序博客网 时间:2024/06/15 08:39

 转载自庆亮的博客-webgame架构

rabbit_sup模块开始看起:

rabbit_sup模块的start_link是被rabbit app模块的start/2方法所调用的

rabbit.erl文件:

start(normal, []) ->

{ok, SupPid} = rabbit_sup:start_link(),

rabbit_sup.erl文件:

-define(SERVER, ?MODULE).

start_link() ->

supervisor:start_link({local, ?SERVER}, ?MODULE, []).

这里的?SERVER和?MODULE是一样的值,都为rabbit_sup 。

跳转到supervisor.erl文件:

start_link(SupName, Mod, Args) ->

gen_server:start_link(SupName, supervisor, {SupName, Mod, Args}, []).

看到supervisor的start_link实际上调用的是gen_server的start_link方法,调用的时候将supervisor作为一个参数传递过去了。

这样到目前为止我们的调用实际为:

gen_server:start_link({local, rabbit_sup}, supervisor, {{local, rabbit_sup}, rabbit_sup, []}, []).

gen_server.erl文件:

start_link(Mod, Args, Options) ->

    gen:start(?MODULE, link, Mod, Args, Options).

start_link(Name, Mod, Args, Options) ->

gen:start(?MODULE, link, Name, Mod, Args, Options).

gen_serverstart_link方法调用了gen模块的start方法,实际调用为:

gen:start(gen_server, link, {local, rabbit_sup},supervisor, {{local, rabbit_sup}, rabbit_sup, []}, []).

gen.erl文件:

start(GenMod, LinkP, Name, Mod, Args, Options) ->

    case where(Name) of

undefined ->

    do_spawn(GenMod, LinkP, Name, Mod, Args, Options);

Pid ->

    {error, {already_started, Pid}}

end.

start之前判断是否已经创建了该process,没有则创建,有则返回错误!

do_spawn(GenMod, link, Name, Mod, Args, Options) ->

    Time = timeout(Options),

    proc_lib:start_link(?MODULE, init_it,

[GenMod, self(), self(), Name, Mod, Args, Options],

Time,

spawn_opts(Options));

do_spawn(GenMod, _, Name, Mod, Args, Options) ->

    Time = timeout(Options),

    proc_lib:start(?MODULE, init_it,

   [GenMod, self(), self, Name, Mod, Args, Options], 

   Time,

   spawn_opts(Options)).

实际又是调用了gen模块的init_it方法,采用的linkspawn方式。

init_it(GenMod, Starter, Parent, Mod, Args, Options) ->

    init_it2(GenMod, Starter, Parent, self(), Mod, Args, Options).

init_it(GenMod, Starter, Parent, Name, Mod, Args, Options) ->

    case name_register(Name) of

true ->

    init_it2(GenMod, Starter, Parent, Name, Mod, Args, Options);

{false, Pid} ->

    proc_lib:init_ack(Starter, {error, {already_started, Pid}})

    end.

首先尝试注册这个名字,如果发现已经注册,则通知父进程已经创建了。否则跳转到init_in2,

init_it2(GenMod, Starter, Parent, Name, Mod, Args, Options) ->

GenMod:init_it(Starter, Parent, Name, Mod, Args, Options).

这时又跳转到gen_server:init_it方法。

init_it(Starter, self, Name, Mod, Args, Options) ->

    init_it(Starter, self(), Name, Mod, Args, Options);

init_it(Starter, Parent, Name0, Mod, Args, Options) ->

    Name = name(Name0),

    Debug = debug_options(Name, Options),

    case catch Mod:init(Args) of

{ok, State} ->

    proc_lib:init_ack(Starter, {ok, self()}),      

    loop(Parent, Name, State, Mod, infinity, Debug);

{ok, State, Timeout} ->

    proc_lib:init_ack(Starter, {ok, self()}),      

    loop(Parent, Name, State, Mod, Timeout, Debug);

{stop, Reason} ->

    %% For consistency, we must make sure that the

    %% registered name (if any) is unregistered before

    %% the parent process is notified about the failure.

    %% (Otherwise, the parent process could get

    %% an 'already_started' error if it immediately

    %% tried starting the process again.)

    unregister_name(Name0),

    proc_lib:init_ack(Starter, {error, Reason}),

    exit(Reason);

ignore ->

    unregister_name(Name0),

    proc_lib:init_ack(Starter, ignore),

    exit(normal);

{'EXIT', Reason} ->

    unregister_name(Name0),

    proc_lib:init_ack(Starter, {error, Reason}),

    exit(Reason);

Else ->

    Error = {bad_return_value, Else},

    proc_lib:init_ack(Starter, {error, Error}),

    exit(Error)

end.

又是调用了supervisor的init方法

    init({SupName, Mod, Args}) ->

    process_flag(trap_exit, true),

    case Mod:init(Args) of

{ok, {SupFlags, StartSpec}} ->

    case init_state(SupName, SupFlags, Mod, Args) of

{ok, State} when ?is_simple(State) ->

    init_dynamic(State, StartSpec);

{ok, State} ->

    init_children(State, StartSpec);

Error ->

    {stop, {supervisor_data, Error}}

    end;

ignore ->

    ignore;

Error ->

    {stop, {bad_return, {Mod, init, Error}}}

    end.

呵呵,到了这里终于调用了rabbit_sup的init方法了,根据不同的init返回值做不同的启动子进程的操作。