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

erlang init boot 浅析

2010-08-03

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

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

说明:遇到一个OTP的问题,疑惑了很久,也就有了这篇文章。

目的:跟踪Erlang的启动过程

 

参考这里 http://erlangdisplay.javaeye.com/blog/315497 ,直接从erts-5.7.5/src/init.erl boot/1函数开始(关于这个链接给出的结论以后会继续研究分析):

 

-spec boot([binary()]) -> no_return().
boot(BootArgs) ->

   
register(init, self()),
   
process_flag
(trap_exit, true),
    start_on_load_handler_process(),
    {
Start0,Flags,Args} = parse_boot_args(BootArgs
),
   
Start = map(fun prepare_run_args/1, Start0
),
   
Flags0 = flags_to_atoms_again(Flags
),
    boot(
Start,Flags0,Args).

 

do_boot(Init,Flags,Start) ->
   
process_flag(trap_exit,true),
    {
Pgm0,Nodes,Id,Path} = prim_load_flags(Flags
),
   
Root = b2s(get_flag('-root',Flags
)),
   
PathFls = path_flags(Flags
),
   
Pgm = b2s(Pgm0
),
    _
Pid = start_prim_loader(Init,b2a(Id),Pgm,bs2as(Nodes
),
                 bs2ss(
Path),PathFls
),
   
BootFile = bootfile(Flags,Root
),
   
BootList = get_boot(BootFile,Root
),
   
LoadMode = b2a(get_flag('-mode',Flags
,false)),
   
Deb = b2a(get_flag('-init_debug',Flags
,false)),
   
BootVars = get_flag_args('-boot_var',Flags
),
   
ParallelLoad =

    (
Pgm =:= "efile") and (erlang:system_info(thread_pool_size) > 0
),

    PathChoice = code_path_choice(),
    eval_script(
BootList,Init,PathFls,{Root,BootVars},Path
,
        {true,
LoadMode,ParallelLoad},Deb,PathChoice
),

    %% To help identifying Purify windows that pop up,
   
%% print the node name into the Purify log.
    (
catch erlang:system_info({purify, "Node: " ++ atom_to_list(node())})),

    start_em(Start).

 

boot/3的基本流程为 start_prim_loader/6 eval_script/8 start_em/1

1. start_prim_loader/6启动了erl_prim_loader模块,负责代码加载(远程或者本地等)

2. eval_script/8 负责启动一些关键的进程

来看个eval_script/8参数的例子:

{[{preLoaded,[erl_prim_loader,erlang,init,otp_ring0,

              prim_file,prim_inet,prim_zip,zlib]},

  {progress,preloaded},

  {path,["$ROOT/lib/kernel-2.13.5/ebin",

         "$ROOT/lib/stdlib-1.16.5/ebin"]},

  {primLoad,[error_handler]},

  {kernel_load_completed},

  {progress,kernel_load_completed},

  {path,["$ROOT/lib/kernel-2.13.5/ebin"]},

  {primLoad,[application,application_controller,

             application_master,application_starter,auth,code,

             code_server,disk_log,disk_log_1,disk_log_server,

             disk_log_sup,dist_ac,dist_util,erl_boot_server,erl_ddll,

             erl_distribution,erl_epmd,erl_reply|...]},

  {path,["$ROOT/lib/stdlib-1.16.5/ebin"]},

  {primLoad,[array,base64,beam_lib,c,calendar,dets,

             dets_server,dets_sup,dets_utils,dets_v8,dets_v9,dict,

             digraph,digraph_utils,edlin,edlin_expand|...]},

  {progress,modules_loaded},

  {path,["$ROOT/lib/kernel-2.13.5/ebin",

         "$ROOT/lib/stdlib-1.16.5/ebin"]},

  {kernelProcess,heart,{heart,start,[]}},

  {kernelProcess,error_logger,{error_logger,start_link,[]}},

  {kernelProcess,application_controller,

                 {application_controller,start,

                                         [{application,kernel,

                                                       [{description,[...]},{vsn,…},{…}|…]}]}},

  {progress,init_kernel_started},

  {apply,{application,load,

                      [{application,stdlib,[{description,...},{...}|...]}]}},

  {progress,applications_loaded},

  {apply,{application,start_boot,[kernel,permanent]}},

  {apply,{application,start_boot,[stdlib,permanent]}},

  {apply,{c,erlangrc,[]}},

  {progress,started}],

 <0.0.0>,

 {[],[]},

 {"/usr/local/lib/erlang",[]},

 false,

 {true,false,false},

 false,relaxed}

 

查看eval_script/8的实现(代码就不贴了),发现启动了上面参数中 kernelProcess对应键值的进程,如:

 

{kernelProcess,heart,{heart,start,[]}},

  {kernelProcess,error_logger,{error_logger,start_link,[]}},

  {kernelProcess,application_controller,

                 {application_controller,start,

                                         [{application,kernel,

 

 

eval_script([{kernelProcess,Server,{Mod,Fun,Args}}|CfgL],Init,
       
PathFs,Vars,P,Ph,Deb,PathChoice) ->

    debug(
Deb,{start,Server}),
    start_in_kernel(
Server,Mod,Fun,Args,Init
),
    eval_script(
CfgL,Init,PathFs,Vars,P,Ph,Deb,PathChoice);

 

start_in_kernel(Server,Mod,Fun,Args,Init) ->
   
Res = apply(Mod,Fun,Args),
   
Init ! {self(),started,{Server,Res
}},
   
receive

    {
Init,ok,Pid} ->
       
unlink(Pid),  %% Just for sure…
        ok;
    {
Init,ignore} ->
        ignore
   
end.

 

最终产生一条消息给init

Init ! {self(),started,{Server,Res}},



 

{BootPid,started,KernelPid} ->

        boot_loop(BootPid, new_kernelpid(KernelPid, BootPid, State));

 

init收到消息后,就将该进程加入到kernel pids的队列中了。

 

new_kernelpid({Name,{ok,Pid}},BootPid,State) when is_pid(Pid) ->
   
link(Pid),
   
BootPid ! {self(),ok,Pid
},
   
Kernel = State#state.kernel
,
   
State#state{kernel = [{Name,Pid}|Kernel
]};
new_kernelpid({_Name,ignore},BootPid,State) ->

   
BootPid ! {self(),ignore},
   
State
;
new_kernelpid({Name,What},BootPid,State) ->

   
erlang:display({"could not start kernel pid",Name,What}),
    clear_system(
BootPid,State
),
    crash(
"could not start kernel pid", [Name, What]).

 

 

{kernelProcess,application_controller,

                 {application_controller,start,

                                         [{application,kernel,

 

application_controller启动后会启动kernel app,至此erlang的启动过程就大致的有个了解了,而关于application的启动过程就不在本次分析范围之内了。

 

结论:

 

系统从init<0.0.0>开始,一些关键的进程如:error_loggerapplication_controllererl_prim_load等都会预先启动并加入到kernel pids中。

 

附言:

本次跟踪自然又离不开余锋老大(http://blog.yufeng.info/ )的指点,init.erlpreloaded模块:

{preLoaded,[erl_prim_loader,erlang,init,otp_ring0,

              prim_file,prim_inet,prim_zip,zlib]},

 

而由于本文之前的无知,导致我去尝试修改init.erl 如果大家需要跟踪init.erl的启动细节,需要修改源码包中的 erts/preloaded/src/init.erlmake && make install,由于此时系统还没跑起来,所以error_logger io之类的模块是没有用的,幸运的是preloaded里面有 prim_file,可以通过 prim_file:write_file/2把一些状态写入到文件中以便查看。

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

发表评论

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

*

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