Erlang Application的启动方式

  1. 整体流程图如下所示

    Erlang Applicaiton启动过程

    Erlang Applicaiton启动过程

  2. 启动start

    1. 调用过程application:start;application:ensure_all_started

      • application:load

      • application_controller:start_application

      • gen_server:call(application_controller, {start_application, AppName, RestartType}, infinity) 
        发消息给application_controller,通过application_controller来控制application

    2. application_controller接着启动app

      • spawn_starter(From, AppName, S, normal) 
        spawn_link(application_controller, init_starter, [From, AppName, S, normal]) 
        异步启动相应的application

      • application_controller:start_appl(Appl, S, Type)

      • application_master:start_link(ApplData, Type)启动相应的application_master

      • proc_lib:start_link(application_master, init, [application_controller, self(), ApplData, Type]) 
        因为需要在application没有完全启动完成之前,给调用者返回

    3. application_master:init启动master进程

      1. link(Parent)与父进程启动关联

      2. 修改application的group_leader

      3. 插入ac_tab这个application的主进程,进程进入init_loop等待loop进程启动完成

    4. start_it(State,Type)启动

      1. process_flag(trap_exit, true)

      2. 启动相应的进程

        1. start_it_old/4旧版本启动进程

          1. Mod(.app中设置的application的启动mod):start(Type, A),启动成功返回相应的Pid

          2. link(Pid)

          3. 给application_master启动的主进程发送启动成功的消息 From ! {Tag, {ok, self()}}

          4. 进程进入loop_it的进程

        2. start_it_new/4新版本启动进程

          1. application_master:start_the_app/5

            1. application_master:start_supervisor/3 
              Mod:start/2启动

            2. link(Pid)

            3. application_starter:start/3循环启动相应的apps

          2. 给application_master启动的主进程发送启动成功的消息 From ! {Tag, {ok, self()}}

          3. 进程进入loop_it的进程

      3. 进程进入init_loop/4的循环,直到收到{Tag, Res}的返回,start_it/2返回新产生的Pid

    5. set_timer设置超时时间

      1. unlink(Starter)取消和Starter的关联,启动进程为临时进程

      2. proc_lib:init_ack(Starter, {ok, self()}) 返回启动进程

      3. 进程进入main_loop(Parent, State)循环

    6. gen_server:cast(application_controller, {application_started, AppName, {ok, PID}})

  3. 停止stop

    1. application:stop 调用过程

      1. application_controller:stop_application/1

      2. gen_server:call(application_controller, {stop_application, AppName}, infinity)

    2. application_controller:stop_appl/3

      1. unlink/1 取消和app的根进程的关联关系

      2. application_master:stop(ID)

        1. 此处为同步stop的操作 send, receive的方式

        2. AppMaster ! {Req, Tag(make_ref()产生的), self()}

    3. 此处的操作交给master进程main_loop,handle_msg({stop,..})

      1. catch terminate(normal, State)终止进程

        1. _ = [From ! {Tag, error} || {_, Tag, From} <- Reqs],所有的请求全部返回error

        2. terminate_child停掉所有的child(这里的child指的是loop进程)

          1. Child ! {self(), terminate} %% 停止掉此处控制群移交到loop进程
      2. loop进程在loop_it接收到terminate的消息

        1. Mod:prep_stop(Mod, AppState)

        2. exit(Child, shutdown)这里的child指的是application启动的app的根进程

        3. receive ‘EXIT’ application全部停止之后,loop进程会收到终止的EXIT singnal

        4. Mod:stop(NewAppState)停止application之后的清理工作

        5. exit(normal)停止相应的loop进程,接下来的清理工作交换

      3. terminate_loop阻塞等待loop的终止

        1. From ! {Tag, ok}
      4. receive {‘Tag’, ok} 通过erlang:monitor(process, AppMaster)

        1. info_exited(AppName, stopped, Type) error_logger打印出App停止的日志

        2. ets:delete(ac_tab, {application_master, AppName}) 从ac_tab中移除相应的App

      5. application_controller:cntrl/3 通知control进程application已经停止

  4. init:stop调用过程

    1. init ! {stop, stop}

    2. init:stop(stop, State)

      1. clear_system/2

        1. shutdown_pids

          • shutdown_timer

          • catch shutdown(Kernel, BootPid, Timer, State)

            shutdown_kernel_pid/4

            1. Pid ! {‘EXIT’, BootPid, shutdown}

            2. shutdown_loop等待application_controller正常终止

              接下来控制权交给AC进程

              1. application_controller:terminate/2 
                循环停止所有的app,逻辑和applicaiton:stop的逻辑可以统一
          • kill_app_pids

          • kill_all_ports

          • flush_timout

        2. unload(Heart)

      2. do_stop(stop, State)

相关文章: