这个启动脚本默认是在$ROOT/bin/start.boot文件,所以我们查看一下相应的start.script文件,内容如下
%% script generated at {2012,11,27} {19,37,10}
{script,
{"OTP APN 181 01","R15B03"},
[{preLoaded,
[erl_prim_loader,erlang,init,otp_ring0,prim_file,prim_inet,prim_zip,
zlib]},
{progress,preloaded},
{path,["$ROOT/lib/kernel-2.15.3/ebin","$ROOT/lib/stdlib-1.18.3/ebin"]},
{primLoad,[error_handler]},
{kernel_load_completed},
{progress,kernel_load_completed},
{path,["$ROOT/lib/kernel-2.15.3/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,error_logger,
erts_debug,file,file_io_server,file_server,gen_sctp,gen_tcp,gen_udp,
global,global_group,global_search,group,heart,hipe_unified_loader,
inet,inet6_sctp,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,
inet_db,inet_dns,inet_gethost_native,inet_hosts,inet_parse,inet_res,
inet_sctp,inet_tcp,inet_tcp_dist,inet_udp,kernel,kernel_config,net,
net_adm,net_kernel,os,packages,pg2,ram_file,rpc,seq_trace,
standard_error,user,user_drv,user_sup,wrap_log_reader]},
{path,["$ROOT/lib/stdlib-1.18.3/ebin"]},
{primLoad,
[array,base64,beam_lib,binary,c,calendar,dets,dets_server,dets_sup,
dets_utils,dets_v8,dets_v9,dict,digraph,digraph_utils,edlin,
edlin_expand,epp,erl_bits,erl_compile,erl_eval,erl_expand_records,
erl_internal,erl_lint,erl_parse,erl_posix_msg,erl_pp,erl_scan,
erl_tar,error_logger_file_h,error_logger_tty_h,escript,ets,
eval_bits,file_sorter,filelib,filename,gb_sets,gb_trees,gen,
gen_event,gen_fsm,gen_server,io,io_lib,io_lib_format,io_lib_fread,
io_lib_pretty,lib,lists,log_mf_h,math,ms_transform,orddict,ordsets,
otp_internal,pg,pool,proc_lib,proplists,qlc,qlc_pt,queue,random,re,
sets,shell,shell_default,slave,sofs,string,supervisor,
supervisor_bridge,sys,timer,unicode,win32reg,zip]},
{progress,modules_loaded},
{path,["$ROOT/lib/kernel-2.15.3/ebin","$ROOT/lib/stdlib-1.18.3/ebin"]},
{kernelProcess,heart,{heart,start,[]}},
{kernelProcess,error_logger,{error_logger,start_link,[]}},
{kernelProcess,application_controller,
{application_controller,start,
[{application,kernel,
[{description,"ERTS CXC 138 10"},
{vsn,"2.15.3"},
{id,[]},
{modules,
[application,application_controller,application_master,
application_starter,auth,code,packages,code_server,
dist_util,erl_boot_server,erl_distribution,erl_reply,
error_handler,error_logger,file,file_server,
file_io_server,global,global_group,global_search,
group,heart,hipe_unified_loader,inet6_tcp,
inet6_tcp_dist,inet6_udp,inet6_sctp,inet_config,
inet_hosts,inet_gethost_native,inet_tcp_dist,kernel,
kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,
user,user_drv,user_sup,disk_log,disk_log_1,
disk_log_server,disk_log_sup,dist_ac,erl_ddll,
erl_epmd,erts_debug,gen_tcp,gen_udp,gen_sctp,inet,
inet_db,inet_dns,inet_parse,inet_res,inet_tcp,
inet_udp,inet_sctp,pg2,seq_trace,standard_error,
wrap_log_reader]},
{registered,
[application_controller,erl_reply,auth,boot_server,
code_server,disk_log_server,disk_log_sup,
erl_prim_loader,error_logger,file_server_2,
fixtable_server,global_group,global_name_server,heart,
init,kernel_config,kernel_sup,net_kernel,net_sup,rex,
user,os_server,ddll_server,erl_epmd,inet_db,pg2]},
{applications,[]},
{included_applications,[]},
{env,[{error_logger,tty}]},
{maxT,infinity},
{maxP,infinity},
{mod,{kernel,[]}}]}]}},
{progress,init_kernel_started},
{apply,
{application,load,
[{application,stdlib,
[{description,"ERTS CXC 138 10"},
{vsn,"1.18.3"},
{id,[]},
{modules,
[array,base64,beam_lib,binary,c,calendar,dets,
dets_server,dets_sup,dets_utils,dets_v8,dets_v9,dict,
digraph,digraph_utils,edlin,edlin_expand,epp,
eval_bits,erl_bits,erl_compile,erl_eval,
erl_expand_records,erl_internal,erl_lint,erl_parse,
erl_posix_msg,erl_pp,erl_scan,erl_tar,
error_logger_file_h,error_logger_tty_h,escript,ets,
file_sorter,filelib,filename,gb_trees,gb_sets,gen,
gen_event,gen_fsm,gen_server,io,io_lib,io_lib_format,
io_lib_fread,io_lib_pretty,lib,lists,log_mf_h,math,
ms_transform,orddict,ordsets,otp_internal,pg,pool,
proc_lib,proplists,qlc,qlc_pt,queue,random,re,sets,
shell,shell_default,slave,sofs,string,supervisor,
supervisor_bridge,sys,timer,unicode,win32reg,zip]},
{registered,
[timer_server,rsh_starter,take_over_monitor,
pool_master,dets]},
{applications,[kernel]},
{included_applications,[]},
{env,[]},
{maxT,infinity},
{maxP,infinity}]}]}},
{progress,applications_loaded},
{apply,{application,start_boot,[kernel,permanent]}},
{apply,{application,start_boot,[stdlib,permanent]}},
{apply,{c,erlangrc,[]}},
{progress,started}]}.
以下是init模块中关于启动脚本解析执行的一段源码:
%解析到process标签时,输出调试信息,通知init主进程
eval_script([{progress,Info}|CfgL],Init,PathFs,Vars,P,Ph,Deb,PathChoice) -> debug(Deb,{progress,Info}), init ! {self(),progress,Info}, eval_script(CfgL,Init,PathFs,Vars,P,Ph,Deb,PathChoice);
%解析到preLoaded标签,直接略过 eval_script([{preLoaded,_}|CfgL],Init,PathFs,Vars,P,Ph,Deb,PathChoice) -> eval_script(CfgL,Init,PathFs,Vars,P,Ph,Deb,PathChoice);
%解析到path标签时,根据启动参数中'-path'的设置来确定是否整合路径,false则将Path与启动参数中'-pa' '-pz'的路径进行整合,设置erl_prim_loader的加载路径 eval_script([{path,Path}|CfgL],Init,{Pa,Pz},Vars,false,Ph,Deb,PathChoice) -> RealPath0 = make_path(Pa, Pz, Path, Vars), RealPath = patch_path(RealPath0, PathChoice), erl_prim_loader:set_path(RealPath), eval_script(CfgL,Init,{Pa,Pz},Vars,false,Ph,Deb,PathChoice); eval_script([{path,_}|CfgL],Init,PathFs,Vars,P,Ph,Deb,PathChoice) -> %% Ignore, use the command line -path flag. eval_script(CfgL,Init,PathFs,Vars,P,Ph,Deb,PathChoice);
%解析到kernel_load_completed标签时候, 根据启动mode的不同,区分interactive | embedded,
分别标示,在后面的primLoad时候,embedded时候,标示为true,则必须加载模块,否则在interactive模式下,由code_server动态加载模块 eval_script([{kernel_load_completed}|CfgL],Init,PathFs,Vars,P,{_,embedded,Par},Deb,PathChoice) -> eval_script(CfgL,Init,PathFs,Vars,P,{true,embedded,Par},Deb,PathChoice); eval_script([{kernel_load_completed}|CfgL],Init,PathFs,Vars,P,{_,E,Par},Deb,PathChoice) -> eval_script(CfgL,Init,PathFs,Vars,P,{false,E,Par},Deb,PathChoice);
%解析到primLoad标签时候,首先根据mode不同,确定是否加载,确定是一般加载方式还是并行加载方式。 eval_script([{primLoad,Mods}|CfgL],Init,PathFs,Vars,P,{true,E,Par},Deb,PathChoice) when is_list(Mods) -> if Par =:= true -> par_load_modules(Mods,Init); true -> load_modules(Mods) end, eval_script(CfgL,Init,PathFs,Vars,P,{true,E,Par},Deb,PathChoice);
eval_script([{primLoad,_Mods}|CfgL],Init,PathFs,Vars,P,{false,E,Par},Deb,PathChoice) -> %% Do not load now, code_server does that dynamically! eval_script(CfgL,Init,PathFs,Vars,P,{false,E,Par},Deb,PathChoice);
%解析到kernelProcess标签时,启动一些特别的进程,这些进程直接被init进程link和监控,
在这个启动脚本中,主要就是heart进程,error_logger进程,还有application_controller进程 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);
%解析到apply标签,则直接调用函数。 eval_script([{apply,{Mod,Fun,Args}}|CfgL],Init,PathFs,Vars,P,Ph,Deb,PathChoice) -> debug(Deb,{apply,{Mod,Fun,Args}}), apply(Mod,Fun,Args), eval_script(CfgL,Init,PathFs,Vars,P,Ph,Deb,PathChoice); eval_script([],_,_,_,_,_,_,_) -> ok; eval_script(What,_,_,_,_,_,_,_) -> exit({'unexpected command in bootfile',What}).
以上的启动脚本,我们可以看到在启动过程中执行了启动kernel应用的操作,和stdlib的操作,
而当我启动完虚拟机后,发觉启动的application只有一个,就是kernel,这是因为:
The mod key can be omitted for applications without processes, typically code libraries such as the application STDLIB.
在app文件中如果没有定义key的话是不会有进程作为application启动的,
所以真正在引导程序中启动的application只有kernel. stdlib只是单纯将所有涉及modules载入而已
这里应用启动是直接使用的application:start_boot,而其底层调用的实际是application_controller:start_boot_application方法,
其实application:start_boot和application:start方法本质上没太大区别,
但底层使用的application_controller:start_boot_application方法是不被暴露的,仅仅在启动引导时候使用的。
启动脚本的最后还调用了c:erlangrc/0函数这个是用来执行目录下.erlang文件代码的。基本就是虚拟机启动时的一个钩子。你可以放些路径设置神马的在里面。
That's all.
posted on
浙公网安备 33010602011771号