[elixir! #0082] how is the application controller loaded and started

Keywords: Erlang elixir

Friends familiar with erlang/elixir should know the concept of application. It is a special structure used to start and stop an application. Whenever we create an erlang/elixir project, we also create an application with the same name. When using dependency libraries, generally, each dependency library is also an application, which will be loaded and started when we run the project.

So how does erlang manage these applications? This is: application_ Where the controller works. All application loading, startup and other state saving and changes must go through this process.

# List all current application status
> :application_controller.info()

Virtual application

Not all applications will start the process tree. Some applications do not start any process even if they are in the: started state. Let's call this application virtual application.


Use bony I mentioned in my previous article_ Trace library to track when load ing and start ing an application:_ What did the controller process do.

stop application

iex(3)> :application_controller.stop_application :play
#PID<0.44.0> RECEIVED                                                 +67.069019s
MESSAGE: {:"$gen_call", {#PID<0.199.0>, #Reference<0.2783639343.3287547907.121340>}, {:stop_application, :play}}
#PID<0.44.0> SENT TO: :code_server                                    +0.000047s
MESSAGE: {:code_call, #PID<0.44.0>, {:ensure_loaded, Logger.Translator}}
#PID<0.44.0> RECEIVED                                                 +0.004582s
MESSAGE: {:code_server, {:module, Logger.Translator}}
#PID<0.44.0> SENT TO: :code_server                                    +0.000033s
MESSAGE: {:code_call, #PID<0.44.0>, {:ensure_loaded, Logger.Utils}}
#PID<0.44.0> RECEIVED                                                 +0.002413s
MESSAGE: {:code_server, {:module, Logger.Utils}}
#PID<0.44.0> SENT TO: :code_server                                    +0.000012s
MESSAGE: {:code_call, #PID<0.44.0>, {:ensure_loaded, :calendar}}
#PID<0.44.0> RECEIVED                                                 +0.012388s
MESSAGE: {:code_server, {:module, :calendar}}

12:38:54.714 [info]  Application play exited: :stopped
#PID<0.44.0> SENT TO: Logger                                          +0.000015s
MESSAGE: {:notify, {:info, #PID<0.64.0>, {Logger, ["Application ", "play", " exited: " | ":stopped"], {{2021, 11, 28}, {12, 38, 54, 714}}, [erl_level: :notice, domain: [:otp], error_logger: %{report_cb: &:application_controller.format_log/1, tag: :info_report, type: :std_info}, file: "application_controller.erl", function: "info_exited/3", gl: #PID<0.64.0>, line: 2119, mfa: {:application_controller, :info_exited, 3}, module: :application_controller, pid: #PID<0.44.0>, report_cb: &:application_controller.format_log/2, time: 1638074334714339]}}}
#PID<0.44.0> SENT TO: #PID<0.199.0>                                   +0.000015s
MESSAGE: {#Reference<0.2783639343.3287547907.121340>, :ok}

First to code_ The server confirms that some necessary modules for printing log have been loaded, and the results of this step will be cached. There is no need to ask again later. If the application has an application process, a: stop message will be sent to it. Finally, print out the log that the application has stopped.

start and unload do not require too complex message interaction, which is similar to stop.

load application

iex(9)> :application_controller.load_application :play
#PID<0.44.0> RECEIVED                                                 +26.948851s
MESSAGE: {:"$gen_call", {#PID<0.199.0>, #Reference<0.2783639343.3287547907.121460>}, {:load_application, :play}}
#PID<0.44.0> SENT TO: :code_server                                    +0.000014s
MESSAGE: {:code_call, #PID<0.44.0>, :get_path}
#PID<0.44.0> RECEIVED                                                 +0.000210s
MESSAGE: {:code_server, [...]}
#PID<0.44.0> SENT TO: #PID<0.10.0>                                    +0.000043s
MESSAGE: {#PID<0.44.0>, {:list_dir, '.../play/_build/dev/lib/play/consolidated'}}
#PID<0.44.0> RECEIVED                                                 +0.008352s
MESSAGE: {#PID<0.10.0>, {:ok, ['Elixir.Inspect.beam', 'Elixir.IEx.Info.beam', 'Elixir.String.Chars.beam', 'Elixir.List.Chars.beam', 'Elixir.Collectable.beam', 'Elixir.Enumerable.beam']}}
#PID<0.44.0> SENT TO: #PID<0.10.0>                                    +0.000018s
MESSAGE: {#PID<0.44.0>, {:list_dir, '/Users/linjiezhang/Documents/play/_build/dev/lib/play/ebin'}}
#PID<0.44.0> RECEIVED                                                 +0.010195s
MESSAGE: {#PID<0.10.0>, {:ok, ['Elixir.MyTracer.beam', 'Elixir.Play.beam', 'play.app', 'Elixir.Demo.beam']}}
#PID<0.44.0> SENT TO: #PID<0.10.0>                                    +0.000026s
MESSAGE: {#PID<0.44.0>, {:get_file, '/Users/linjiezhang/Documents/play/_build/dev/lib/play/ebin/play.app'}}
#PID<0.44.0> RECEIVED                                                 +0.000519s
MESSAGE: {#PID<0.10.0>, {:ok, "{application,play,\n             [{applications,[kernel,stdlib,elixir,logger,syntax_tools,\n                             bony_trace]},\n              {description,\"play\"},\n              {modules,['Elixir.Demo','Elixir.MyTracer','Elixir.Play']},\n              {registered,[]},\n              {vsn,\"0.1.0\"}]}.\n", '/Users/linjiezhang/Documents/play/_build/dev/lib/play/ebin/play.app'}}
#PID<0.44.0> SENT TO: :init                                           +0.000149s
MESSAGE: {#PID<0.44.0>, {:get_argument, :play}}
#PID<0.44.0> RECEIVED                                                 +0.000102s
MESSAGE: {:init, :error}
#PID<0.44.0> SENT TO: #PID<0.199.0>                                   +0.000009s
MESSAGE: {#Reference<0.2783639343.3287547907.121460>, :ok}

During load application, AC passes code_ The server obtains the file paths of all applications, and then obtains the exact modules and. app files of the application. Then request the parameters of this application from the: init process. We won't delve into the specific effects of these interactions here. We can interpret them in detail in the following articles: the role of the init process. It is equivalent to the creator in erlang world, with PID < 0.0.0 >.

Posted by activeserver on Sun, 28 Nov 2021 00:13:27 -0800