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>.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。