Skip to content

Applications_and_OTP_startup

Bartosz Błaszków edited this page Jun 24, 2025 · 1 revision

Applications & OTP Startup

It seems that the whole BEAM VM is started by running init:boot that:

  • doesn't return
  • Parses command line args
  • Starts a process registered as init
  • Reads and interprets the boot script (See below)

I couldn't find any explicit call to init:boot in code, the docs only say:

This function is called when the emulator is started and coordinates system startup.

References:

Boot script & application_controller

AtomVM is missing boot script support. https://www.erlang.org/doc/system/system_principles.html#boot-scripts.

In short, this is BEAMs entrypoint, starting what's needed to start new apps

A default one in both binary (.boot) and textual (.script) is present next to erlang binary. https://www.erlang.org/doc/system/system_principles.html#default-boot-scripts

Contents of ./bin/start.script:

   1   │ %% coding: utf-8
   2   │ {script,
   3   │     {"Erlang/OTP","26"},
   4   │     [{preLoaded,
   5   │          [atomics,counters,erl_init,erl_prim_loader,erl_tracer,erlang,
   6   │           erts_code_purger,erts_dirty_process_signal_handler,erts_internal,
   7   │           erts_literal_area_collector,init,persistent_term,prim_buffer,
   8   │           prim_eval,prim_file,prim_inet,prim_net,prim_socket,prim_zip,
   9   │           socket_registry,zlib]},
  10   │      {progress,preloaded},
  11   │      {path,["$ROOT/lib/kernel-9.0.2/ebin","$ROOT/lib/stdlib-5.0.2/ebin"]},
  12   │      {primLoad,
  13   │          [error_handler,application,application_controller,application_master,
  14   │           code,code_server,erl_eval,erl_lint,erl_parse,error_logger,ets,file,
  15   │           filename,file_server,file_io_server,gen,gen_event,gen_server,heart,
  16   │           kernel,logger,logger_filters,logger_server,logger_backend,
  17   │           logger_config,logger_simple_h,lists,proc_lib,supervisor]},
  18   │      {kernel_load_completed},
  19   │      {progress,kernel_load_completed},
  20   │      {path,["$ROOT/lib/kernel-9.0.2/ebin"]},
  21   │      {primLoad,
  22   │          [application_starter,auth,disk_log,disk_log_1,disk_log_server,
  23   │           disk_log_sup,dist_ac,dist_util,erl_boot_server,erl_compile_server,
  24   │           erl_ddll,erl_distribution,erl_epmd,erl_erts_errors,
  25   │           erl_kernel_errors,erl_reply,erl_signal_handler,erpc,erts_debug,
  26   │           gen_sctp,gen_tcp,gen_tcp_socket,gen_udp,gen_udp_socket,global,
  27   │           global_group,global_search,group,group_history,inet,inet6_sctp,
  28   │           inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_db,inet_dns,
  29   │           inet_epmd_dist,inet_epmd_socket,inet_gethost_native,inet_hosts,
  30   │           inet_parse,inet_res,inet_sctp,inet_tcp,inet_tcp_dist,inet_udp,
  31   │           kernel_config,kernel_refc,local_tcp,local_udp,logger_disk_log_h,
  32   │           logger_formatter,logger_h_common,logger_handler_watcher,logger_olp,
  33   │           logger_proxy,logger_std_h,logger_sup,net,net_adm,net_kernel,os,pg,
  34   │           pg2,prim_tty,ram_file,raw_file_io,raw_file_io_compressed,
  35   │           raw_file_io_deflate,raw_file_io_delayed,raw_file_io_inflate,
  36   │           raw_file_io_list,rpc,seq_trace,socket,standard_error,user_drv,
  37   │           user_sup,wrap_log_reader]},
  38   │      {path,["$ROOT/lib/stdlib-5.0.2/ebin"]},
  39   │      {primLoad,
  40   │          [argparse,array,base64,beam_lib,binary,c,calendar,dets,dets_server,
  41   │           dets_sup,dets_utils,dets_v9,dict,digraph,digraph_utils,edlin,
  42   │           edlin_context,edlin_expand,edlin_type_suggestion,epp,
  43   │           erl_abstract_code,erl_anno,erl_bits,erl_compile,erl_error,
  44   │           erl_expand_records,erl_features,erl_internal,erl_posix_msg,erl_pp,
  45   │           erl_scan,erl_stdlib_errors,erl_tar,error_logger_file_h,
  46   │           error_logger_tty_h,escript,eval_bits,file_sorter,filelib,gb_sets,
  47   │           gb_trees,gen_fsm,gen_statem,io,io_lib,io_lib_format,io_lib_fread,
  48   │           io_lib_pretty,log_mf_h,maps,math,ms_transform,orddict,ordsets,
  49   │           otp_internal,peer,pool,proplists,qlc,qlc_pt,queue,rand,random,re,
  50   │           sets,shell,shell_default,shell_docs,slave,sofs,string,
  51   │           supervisor_bridge,sys,timer,unicode,unicode_util,uri_string,
  52   │           win32reg,zip]},
  53   │      {progress,modules_loaded},
  54   │      {path,["$ROOT/lib/kernel-9.0.2/ebin","$ROOT/lib/stdlib-5.0.2/ebin"]},
  55   │      {kernelProcess,heart,{heart,start,[]}},
  56   │      {kernelProcess,logger,{logger_server,start_link,[]}},
  57   │      {kernelProcess,application_controller,
  58   │          {application_controller,start,
  59   │              [{application,kernel,
  60   │                   [{description,"ERTS  CXC 138 10"},
  61   │                    {vsn,"9.0.2"},
  62   │                    {id,[]},
  63   │                    {modules,
  64   │                        [application,application_controller,application_master,
  65   │                         application_starter,auth,code,code_server,dist_util,
  66   │                         erl_boot_server,erl_compile_server,erl_distribution,
  67   │                         erl_erts_errors,erl_reply,erl_kernel_errors,
  68   │                         erl_signal_handler,erpc,error_handler,error_logger,
  69   │                         file,file_server,file_io_server,global,global_group,
  70   │                         global_search,group,group_history,heart,inet6_tcp,
  71   │                         inet6_tcp_dist,inet6_udp,inet6_sctp,inet_config,
  72   │                         inet_epmd_dist,inet_epmd_socket,inet_hosts,
  73   │                         inet_gethost_native,inet_tcp_dist,kernel,
  74   │                         kernel_config,kernel_refc,local_tcp,local_udp,logger,
  75   │                         logger_backend,logger_config,logger_disk_log_h,
  76   │                         logger_filters,logger_formatter,logger_h_common,
  77   │                         logger_handler_watcher,logger_olp,logger_proxy,
  78   │                         logger_server,logger_simple_h,logger_std_h,logger_sup,
  79   │                         net,net_adm,net_kernel,os,ram_file,rpc,user_drv,
  80   │                         user_sup,prim_tty,disk_log,disk_log_1,disk_log_server,
  81   │                         disk_log_sup,dist_ac,erl_ddll,erl_epmd,erts_debug,
  82   │                         gen_tcp,gen_tcp_socket,gen_udp,gen_udp_socket,
  83   │                         gen_sctp,inet,inet_db,inet_dns,inet_parse,inet_res,
  84   │                         inet_tcp,inet_udp,inet_sctp,pg,pg2,raw_file_io,
  85   │                         raw_file_io_compressed,raw_file_io_deflate,
  86   │                         raw_file_io_delayed,raw_file_io_inflate,
  87   │                         raw_file_io_list,seq_trace,socket,standard_error,
  88   │                         wrap_log_reader]},
  89   │                    {registered,
  90   │                        [application_controller,erl_reply,auth,boot_server,
  91   │                         code_server,disk_log_server,disk_log_sup,
  92   │                         erl_prim_loader,error_logger,file_server_2,
  93   │                         fixtable_server,global_group,global_name_server,heart,
  94   │                         init,kernel_config,kernel_refc,kernel_sup,logger,
  95   │                         logger_handler_watcher,logger_sup,net_kernel,net_sup,
  96   │                         rex,user,os_server,ddll_server,erl_epmd,inet_db,pg]},
  97   │                    {applications,[]},
  98   │                    {optional_applications,[]},
  99   │                    {included_applications,[]},
 100   │                    {env,
 101   │                        [{logger_level,notice},
 102   │                         {logger_sasl_compatible,false},
 103   │                         {net_tickintensity,4},
 104   │                         {net_ticktime,60},
 105   │                         {prevent_overlapping_partitions,true},
 106   │                         {shell_docs_ansi,auto}]},
 107   │                    {maxT,infinity},
 108   │                    {maxP,infinity},
 109   │                    {mod,{kernel,[]}}]}]}},
 110   │      {progress,init_kernel_started},
 111   │      {apply,
 112   │          {application,load,
 113   │              [{application,stdlib,
 114   │                   [{description,"ERTS  CXC 138 10"},
 115   │                    {vsn,"5.0.2"},
 116   │                    {id,[]},
 117   │                    {modules,
 118   │                        [argparse,array,base64,beam_lib,binary,c,calendar,dets,
 119   │                         dets_server,dets_sup,dets_utils,dets_v9,dict,digraph,
 120   │                         digraph_utils,edlin,edlin_context,edlin_expand,
 121   │                         edlin_type_suggestion,epp,eval_bits,erl_abstract_code,
 122   │                         erl_anno,erl_bits,erl_compile,erl_error,erl_eval,
 123   │                         erl_expand_records,erl_features,erl_internal,erl_lint,
 124   │                         erl_parse,erl_posix_msg,erl_pp,erl_scan,
 125   │                         erl_stdlib_errors,erl_tar,error_logger_file_h,
 126   │                         error_logger_tty_h,escript,ets,file_sorter,filelib,
 127   │                         filename,gb_trees,gb_sets,gen,gen_event,gen_fsm,
 128   │                         gen_server,gen_statem,io,io_lib,io_lib_format,
 129   │                         io_lib_fread,io_lib_pretty,lists,log_mf_h,maps,math,
 130   │                         ms_transform,orddict,ordsets,otp_internal,peer,pool,
 131   │                         proc_lib,proplists,qlc,qlc_pt,queue,rand,random,re,
 132   │                         sets,shell,shell_default,shell_docs,slave,sofs,string,
 133   │                         supervisor,supervisor_bridge,sys,timer,unicode,
 134   │                         unicode_util,uri_string,win32reg,zip]},
 135   │                    {registered,
 136   │                        [timer_server,rsh_starter,take_over_monitor,
 137   │                         pool_master,dets]},
 138   │                    {applications,[kernel]},
 139   │                    {optional_applications,[]},
 140   │                    {included_applications,[]},
 141   │                    {env,[]},
 142   │                    {maxT,infinity},
 143   │                    {maxP,infinity}]}]}},
 144   │      {progress,applications_loaded},
 145   │      {apply,{application,start_boot,[kernel,permanent]}},
 146   │      {apply,{application,start_boot,[stdlib,permanent]}},
 147   │      {apply,{c,erlangrc,[]}},
 148   │      {progress,started}]}.

This means based on https://www.erlang.org/doc/apps/sasl/script:

  1. Name = Erlang/OTP, Version = "26"
  2. List of preloaded modules - no docs (xD) so no idea if it declares or actually preloads them
  3. {progress, X} sets status of init, obtainable via init:get_status/0
  4. Using path and primLoad modules of kernel and stdlib are loaded
  5. Three kernel processes are started:
    1. heart by running heart:start()
    2. logger by running logger_server:start_link()
    3. application_controller by running application_controller:start([{application, kernel, Spec}]) where Spec is a hardcoded specification of kernel app
  6. Specification of stdlib application is loaded via application:load(HardcodedSpec)
  7. Call to application:start_boot(kernel, permament)
  8. Call to application:start_boot(stdlib, permament)
  9. Call to c:erlangrc() - loads .erlang resource file

Kernel process

In a Popcorn-patched version of :kernel module, it is a noop. In OTP however, it starts a whole supervision tree documented here.

Among the missing processes, here are the ones that I investigated due to errors:

  • user_sup starting user process responsible for hanling IO of stadard input/output Some internal functions assume user process exists and forward io_requests there, and work incorrectly if it's missing, e.g. application_master
  • standard_error handling io_requests to stderr
  • logger_sup starting logger-related processes
  • file_server_2 - handling file IO. Might be called when trying to start an application that doesn't have its spec loaded, resulting in attempt to find proper *.app file

Application master

When application is started, application master process is started, that is a group leader for all the processes of the app. See: https://www.erlang.org/docs/28/system/applications#starting-and-stopping-applications Internally there's an additional process, between App supervisor and application_master https://github.com/erlang/otp/blob/d051172925a5c84b2f21850a188a533f885f201c/lib/kernel/src/application_master.erl#L84

Clone this wiki locally