Friends who are familiar with erlang/elixir should know the concept of application, which is a special structure used to start and stop an application. Whenever we create a new erlang/elixir project, we also create a new application with the same name. When using dependent libraries, generally each dependent 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 where :application_controller into play. All application loading, startup and other state saving and changes must go through this process.

# 列出当前的全部应用状态
> :application_controller.info()

Virtual application

Not all applications start the process tree. Some applications do not start any processes :started Let's call this application a virtual application.

track

bony_trance library mentioned in my previous article :application_controller process did when an application was load and start.

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
:ok
#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 confirm to code_server that some necessary modules for log printing are loaded, the results of this step will be cached, and there is no need to repeat the query afterwards. If the application has an application process, it will send a :stop message. Finally, print out the log that the application has stopped.

Start and unload do not require too complicated message interaction, 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'}}
:ok
#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}

When loading the application, AC obtained the file paths of all applications through code_server, and then obtained the exact modules and .app files of this application. Then request the parameters of this application from the :init I won't go into the specific role of these interactions here, and I can interpret the role of the :init It is equivalent to the creator of the erlang world and has PID<0.0.0>.


Ljzn
399 声望102 粉丝

网络安全;函数式编程;数字货币;人工智能