关注LAMP|PHP源代码分析|web架构|PHP扩展|Erlang|服务端架构

erlang init stop浅析

2010-08-03

原创文章,转载请注明: 转载自庆亮的博客-webgame架构

本文链接地址: erlang init stop浅析

作者:庆亮 (qing.liang.cn@gmail.com)

日期:2010-08-03

 

 

boot之后关注的自然是stop,直接打开erts-5.7.5/src/init.erl源码看了看:

 

-spec stop() -> no_return().
stop() -> init !
{stop,stop}, ok.

{stop,Reason} ->
            stop(
Reason,State);

 

最终的调用:

stop(Reason,State) ->
   
BootPid = State#state.bootpid,
    {_,
Progress} = State#state.status
,
   
State1 = State#state{status = {stopping, Progress
}},
    clear_system(
BootPid,State1
),
    do_stop(
Reason,State1).

 

看看 clear_system/2

 

clear_system(BootPid,State) ->
   
Heart = get_heart(State#state.kernel),
    shutdown_pids(
Heart,BootPid,State
),
    unload(
Heart
).
   
shutdown_pids(Heart,BootPid,State) ->

   
Timer = shutdown_timer(State#state.flags),
   
catch shutdown(State#state.kernel,BootPid,Timer,State
),
    kill_all_pids(
Heart), % Even the shutdown timer.

    kill_all_ports(
Heart),
    flush_timout(
Timer
).
   
%%

%% Kill all existing pids in the system (except init and heart).
kill_all_pids(Heart) ->
   
case get_pids(Heart) of
        []
->
            ok;
       
Pids ->
            kill_em(
Pids),
            kill_all_pids(
Heart% Continue until all are really killed.

   
end.

kill_em([Pid|Pids]) ->
   
exit(Pid,kill),
    kill_em(
Pids
);
kill_em([]) ->

    ok.

 

看到这里得到两个结论:

1. 除了kernelinit之外的所有的进程都是以kill的形式干掉的。注意这里的kernel是个list,包含多了pid

2. shutdown所有的kernel进程,后kill掉其他进程,最终haltshutdown的形式则是一条EXIT消息

 

shutdown([{heart,_Pid}|Kernel],BootPid,Timer,State) ->
    shutdown(
Kernel, BootPid, Timer, State);
shutdown([{_Name,Pid}|Kernel],BootPid,Timer,State) ->

    shutdown_kernel_pid(
Pid, BootPid, Timer, State),
    shutdown(
Kernel,BootPid,Timer,State
);
shutdown(_,_,_,_) ->

    true.

%%
%% A kernel pid must handle the special case message
%% {'EXIT',Parent,Reason} and terminate upon it!
%%
shutdown_kernel_pid(Pid, BootPid, Timer, State) ->
   
Pid ! {'EXIT',BootPid,shutdown},
    shutdown_loop(
Pid, Timer, State, []).

 

发送EXIT消息,shutdown_loop/4等待结果。

 

根据上一篇分析的结果,application_controllerkernel pids的一员,查看application_controller的源码:

terminate(Reason, S) ->
   
case application:get_env(kernel, shutdown_func) of
    {ok, {
M, F}} ->
       
catch M:F(Reason);
    _
->

        ok
   
end,
    foreach(
fun({_AppName, Id}) when is_pid(Id) ->

           
exit(Id
, shutdown),
           
receive

            {'EXIT',
Id, _} -> ok
           
end
;
           (_)
->
ok
       
end
,
        S
#state.running
),
ets:delete(ac_tab).

 

S#state.running中保存了所有已经在运行的application,对于每一个application,都以exit(Id, shutdown)形式让其退出,并一直等待。

 

到了这里不用继续看源码大致也能理清思路了,结论:

 

init:stop 

  向所有kernel进程发送shutdown Exit消息

application 依次关闭子sup树(等待)

  kill所有其他的非kernel进程

 

对于我们的app,一般都是最后启动,最先停止,如此,在停止我们的app的时候所有的系统服务都还是可用的(分布式、mnesia等等)。

作者:庆亮 | 分类目录:Erlang | 标签:

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>