application_master.erl 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. %% ``The contents of this file are subject to the Erlang Public License,
  2. %% Version 1.1, (the "License"); you may not use this file except in
  3. %% compliance with the License. You should have received a copy of the
  4. %% Erlang Public License along with this software. If not, it can be
  5. %% retrieved via the world wide web at http://www.erlang.org/.
  6. %%
  7. %% Software distributed under the License is distributed on an "AS IS"
  8. %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  9. %% the License for the specific language governing rights and limitations
  10. %% under the License.
  11. %%
  12. %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
  13. %% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
  14. %% AB. All Rights Reserved.''
  15. %%
  16. %% $Id$
  17. %%
  18. -module(application_master).
  19. %% External exports
  20. -export([start_link/2, start_type/0, stop/1]).
  21. -export([get_child/1]).
  22. %% Internal exports
  23. -export([init/4, start_it/4]).
  24. -include("application_master.hrl").
  25. -record(state, {child, appl_data, children = [], procs = 0, gleader}).
  26. %%-----------------------------------------------------------------
  27. %% Func: start_link/1
  28. %% Args: ApplData = record(appl_data)
  29. %% Purpose: Starts an application master for the application.
  30. %% Called from application_controller. (The application is
  31. %% also started).
  32. %% Returns: {ok, Pid} | {error, Reason} (Pid is unregistered)
  33. %%-----------------------------------------------------------------
  34. start_link(ApplData, Type) ->
  35. Parent = whereis(application_controller),
  36. proc_lib:start_link(application_master, init,
  37. [Parent, self(), ApplData, Type]).
  38. start_type() ->
  39. group_leader() ! {start_type, self()},
  40. receive
  41. {start_type, Type} ->
  42. Type
  43. after 5000 ->
  44. {error, timeout}
  45. end.
  46. %%-----------------------------------------------------------------
  47. %% Func: stop/1
  48. %% Purpose: Stops the application. This function makes sure
  49. %% that all processes belonging to the applicication is
  50. %% stopped (shutdown or killed). The application master
  51. %% is also stopped.
  52. %% Returns: ok
  53. %%-----------------------------------------------------------------
  54. stop(AppMaster) -> call(AppMaster, stop).
  55. %%-----------------------------------------------------------------
  56. %% Func: get_child/1
  57. %% Purpose: Get the topmost supervisor of an application.
  58. %% Returns: {pid(), App}
  59. %%-----------------------------------------------------------------
  60. get_child(AppMaster) -> call(AppMaster, get_child).
  61. call(AppMaster, Req) ->
  62. Tag = make_ref(),
  63. Ref = erlang:monitor(process, AppMaster),
  64. AppMaster ! {Req, Tag, self()},
  65. receive
  66. {'DOWN', Ref, process, _, _Info} ->
  67. ok;
  68. {Tag, Res} ->
  69. erlang:demonitor(Ref),
  70. receive
  71. {'DOWN', Ref, process, _, _Info} ->
  72. Res
  73. after 0 ->
  74. Res
  75. end
  76. end.
  77. %%%-----------------------------------------------------------------
  78. %%% The logical and physical process structrure is as follows:
  79. %%%
  80. %%% logical physical
  81. %%%
  82. %%% -------- --------
  83. %%% |AM(GL)| |AM(GL)|
  84. %%% -------- --------
  85. %%% | |
  86. %%% -------- --------
  87. %%% |Appl P| | X |
  88. %%% -------- --------
  89. %%% |
  90. %%% --------
  91. %%% |Appl P|
  92. %%% --------
  93. %%%
  94. %%% Where AM(GL) == Application Master (Group Leader)
  95. %%% Appl P == The application specific root process (child to AM)
  96. %%% X == A special 'invisible' process
  97. %%% The reason for not using the logical structrure is that
  98. %%% the application start function is synchronous, and
  99. %%% that the AM is GL. This means that if AM executed the start
  100. %%% function, and this function uses spawn_request/1
  101. %%% or io, deadlock would occur. Therefore, this function is
  102. %%% executed by the process X. Also, AM needs three loops;
  103. %%% init_loop (waiting for the start function to return)
  104. %%% main_loop
  105. %%% terminate_loop (waiting for the process to die)
  106. %%% In each of these loops, io and other requests are handled.
  107. %%%-----------------------------------------------------------------
  108. %%% Internal functions
  109. %%%-----------------------------------------------------------------
  110. init(Parent, Starter, ApplData, Type) ->
  111. link(Parent),
  112. process_flag(trap_exit, true),
  113. gen:reg_behaviour(application),
  114. OldGleader = group_leader(),
  115. group_leader(self(), self()),
  116. %% Insert ourselves as master for the process. This ensures that
  117. %% the processes in the application can use get_env/1 at startup.
  118. Name = ApplData#appl_data.name,
  119. ets:insert(ac_tab, {{application_master, Name}, self()}),
  120. State = #state{appl_data = ApplData, gleader = OldGleader},
  121. case start_it(State, Type) of
  122. {ok, Pid} -> % apply(M,F,A) returned ok
  123. set_timer(ApplData#appl_data.maxT),
  124. unlink(Starter),
  125. proc_lib:init_ack(Starter, {ok,self()}),
  126. main_loop(Parent, State#state{child = Pid});
  127. {error, Reason} -> % apply(M,F,A) returned error
  128. exit(Reason);
  129. Else -> % apply(M,F,A) returned erroneous
  130. exit(Else)
  131. end.
  132. %%-----------------------------------------------------------------
  133. %% We want to start the new application synchronously, but we still
  134. %% want to handle io requests. So we spawn off a new process that
  135. %% performs the apply, and we wait for a start ack.
  136. %%-----------------------------------------------------------------
  137. start_it(State, Type) ->
  138. Tag = make_ref(),
  139. Pid = spawn_link(application_master, start_it, [Tag, State, self(), Type]),
  140. init_loop(Pid, Tag, State, Type).
  141. %%-----------------------------------------------------------------
  142. %% These are the three different loops executed by the application_
  143. %% master
  144. %%-----------------------------------------------------------------
  145. init_loop(Pid, Tag, State, Type) ->
  146. receive
  147. IoReq when element(1, IoReq) =:= io_request ->
  148. State#state.gleader ! IoReq,
  149. init_loop(Pid, Tag, State, Type);
  150. {Tag, Res} ->
  151. Res;
  152. {'EXIT', Pid, Reason} ->
  153. {error, Reason};
  154. {start_type, From} ->
  155. From ! {start_type, Type},
  156. init_loop(Pid, Tag, State, Type);
  157. Other ->
  158. NewState = handle_msg(Other, State),
  159. init_loop(Pid, Tag, NewState, Type)
  160. end.
  161. main_loop(Parent, State) ->
  162. receive
  163. IoReq when element(1, IoReq) =:= io_request ->
  164. State#state.gleader ! IoReq,
  165. main_loop(Parent, State);
  166. {'EXIT', Parent, Reason} ->
  167. terminate(Reason, State);
  168. {'EXIT', Child, Reason} when State#state.child =:= Child ->
  169. terminate(Reason, State#state{child=undefined});
  170. {'EXIT', _, timeout} ->
  171. terminate(normal, State);
  172. {'EXIT', Pid, _Reason} ->
  173. Children = lists:delete(Pid, State#state.children),
  174. Procs = State#state.procs - 1,
  175. main_loop(Parent, State#state{children=Children, procs=Procs});
  176. {start_type, From} ->
  177. From ! {start_type, local},
  178. main_loop(Parent, State);
  179. Other ->
  180. NewState = handle_msg(Other, State),
  181. main_loop(Parent, NewState)
  182. end.
  183. terminate_loop(Child, State) ->
  184. receive
  185. IoReq when element(1, IoReq) =:= io_request ->
  186. State#state.gleader ! IoReq,
  187. terminate_loop(Child, State);
  188. {'EXIT', Child, _} ->
  189. ok;
  190. Other ->
  191. NewState = handle_msg(Other, State),
  192. terminate_loop(Child, NewState)
  193. end.
  194. %%-----------------------------------------------------------------
  195. %% The Application Master is linked to *all* processes in the group
  196. %% (application).
  197. %%-----------------------------------------------------------------
  198. handle_msg({get_child, Tag, From}, State) ->
  199. From ! {Tag, get_child_i(State#state.child)},
  200. State;
  201. handle_msg({stop, Tag, From}, State) ->
  202. catch terminate(normal, State),
  203. From ! {Tag, ok},
  204. exit(normal);
  205. handle_msg(_, State) ->
  206. State.
  207. terminate(Reason, State) ->
  208. terminate_child(State#state.child, State),
  209. kill_children(State#state.children),
  210. exit(Reason).
  211. %%======================================================================
  212. %%======================================================================
  213. %%======================================================================
  214. %% This is the process X above...
  215. %%======================================================================
  216. %%======================================================================
  217. %%======================================================================
  218. %%======================================================================
  219. %% Start an application.
  220. %% If the start_phases is defined in the .app file, the application is
  221. %% to be started in one or several start phases.
  222. %% If the Module in the mod-key is set to application_starter then
  223. %% the generic help module application_starter is used to control
  224. %% the start.
  225. %%======================================================================
  226. start_it(Tag, State, From, Type) ->
  227. process_flag(trap_exit, true),
  228. ApplData = State#state.appl_data,
  229. case {ApplData#appl_data.phases, ApplData#appl_data.mod} of
  230. {undefined, _} ->
  231. start_it_old(Tag, From, Type, ApplData);
  232. {Phases, {application_starter, [M, A]}} ->
  233. start_it_new(Tag, From, Type, M, A, Phases,
  234. [ApplData#appl_data.name]);
  235. {Phases, {M, A}} ->
  236. start_it_new(Tag, From, Type, M, A, Phases,
  237. [ApplData#appl_data.name]);
  238. {OtherP, OtherM} ->
  239. From ! {Tag, {error, {bad_keys, {{mod, OtherM},
  240. {start_phases, OtherP}}}}}
  241. end.
  242. %%%-----------------------------------------------------
  243. %%% No start phases are defined
  244. %%%-----------------------------------------------------
  245. start_it_old(Tag, From, Type, ApplData) ->
  246. {M,A} = ApplData#appl_data.mod,
  247. case catch M:start(Type, A) of
  248. {ok, Pid} ->
  249. link(Pid),
  250. {ok, self()},
  251. From ! {Tag, {ok, self()}},
  252. loop_it(From, Pid, M, []);
  253. {ok, Pid, AppState} ->
  254. link(Pid),
  255. {ok, self()},
  256. From ! {Tag, {ok, self()}},
  257. loop_it(From, Pid, M, AppState);
  258. {'EXIT', normal} ->
  259. From ! {Tag, {error, {{'EXIT',normal},{M,start,[Type,A]}}}};
  260. {error, Reason} ->
  261. From ! {Tag, {error, {Reason, {M,start,[Type,A]}}}};
  262. Other ->
  263. From ! {Tag, {error, {bad_return,{{M,start,[Type,A]},Other}}}}
  264. end.
  265. %%%-----------------------------------------------------
  266. %%% Start phases are defined
  267. %%%-----------------------------------------------------
  268. start_it_new(Tag, From, Type, M, A, Phases, Apps) ->
  269. case catch start_the_app(Type, M, A, Phases, Apps) of
  270. {ok, Pid, AppState} ->
  271. From ! {Tag, {ok, self()}},
  272. loop_it(From, Pid, M, AppState);
  273. Error ->
  274. From ! {Tag, Error}
  275. end.
  276. %%%=====================================================
  277. %%% Start the application in the defined phases,
  278. %%% but first the supervisors are starter.
  279. %%%=====================================================
  280. start_the_app(Type, M, A, Phases, Apps) ->
  281. case start_supervisor(Type, M, A) of
  282. {ok, Pid, AppState} ->
  283. link(Pid),
  284. case application_starter:start(Phases, Type, Apps) of
  285. ok ->
  286. {ok, Pid, AppState};
  287. Error2 ->
  288. unlink(Pid),
  289. Error2
  290. end;
  291. Error ->
  292. Error
  293. end.
  294. %%%-------------------------------------------------------------
  295. %%% Start the supervisors
  296. %%%-------------------------------------------------------------
  297. start_supervisor(Type, M, A) ->
  298. case catch M:start(Type, A) of
  299. {ok, Pid} ->
  300. {ok, Pid, []};
  301. {ok, Pid, AppState} ->
  302. {ok, Pid, AppState};
  303. {error, Reason} ->
  304. {error, {Reason, {M, start, [Type, A]}}};
  305. {'EXIT', normal} ->
  306. {error, {{'EXIT', normal}, {M, start, [Type, A]}}};
  307. Other ->
  308. {error, {bad_return, {{M, start, [Type, A]}, Other}}}
  309. end.
  310. %%======================================================================
  311. %%
  312. %%======================================================================
  313. loop_it(Parent, Child, Mod, AppState) ->
  314. receive
  315. {Parent, get_child} ->
  316. Parent ! {self(), Child, Mod},
  317. loop_it(Parent, Child, Mod, AppState);
  318. {Parent, terminate} ->
  319. NewAppState = prep_stop(Mod, AppState),
  320. exit(Child, shutdown),
  321. receive
  322. {'EXIT', Child, _} -> ok
  323. end,
  324. catch Mod:stop(NewAppState),
  325. exit(normal);
  326. {'EXIT', Parent, Reason} ->
  327. NewAppState = prep_stop(Mod, AppState),
  328. exit(Child, Reason),
  329. receive
  330. {'EXIT', Child, Reason2} ->
  331. exit(Reason2)
  332. end,
  333. catch Mod:stop(NewAppState);
  334. {'EXIT', Child, Reason} -> % forward *all* exit reasons (inc. normal)
  335. NewAppState = prep_stop(Mod, AppState),
  336. catch Mod:stop(NewAppState),
  337. exit(Reason);
  338. _ ->
  339. loop_it(Parent, Child, Mod, AppState)
  340. end.
  341. prep_stop(Mod, AppState) ->
  342. case catch Mod:prep_stop(AppState) of
  343. {'EXIT', {undef, _}} ->
  344. AppState;
  345. {'EXIT', Reason} ->
  346. error_logger:error_report([{?MODULE, shutdown_error},
  347. {Mod, {prep_stop, [AppState]}},
  348. {error_info, Reason}]),
  349. AppState;
  350. NewAppState ->
  351. NewAppState
  352. end.
  353. get_child_i(Child) ->
  354. Child ! {self(), get_child},
  355. receive
  356. {Child, GrandChild, Mod} -> {GrandChild, Mod}
  357. end.
  358. terminate_child_i(Child, State) ->
  359. Child ! {self(), terminate},
  360. terminate_loop(Child, State).
  361. %% Try to shutdown the child gently
  362. terminate_child(undefined, _) -> ok;
  363. terminate_child(Child, State) ->
  364. terminate_child_i(Child, State).
  365. kill_children(Children) ->
  366. lists:foreach(fun(Pid) -> exit(Pid, kill) end, Children),
  367. kill_all_procs().
  368. kill_all_procs() ->
  369. kill_all_procs_1(processes(), self(), 0).
  370. kill_all_procs_1([Self|Ps], Self, N) ->
  371. kill_all_procs_1(Ps, Self, N);
  372. kill_all_procs_1([P|Ps], Self, N) ->
  373. case process_info(P, group_leader) of
  374. {group_leader,Self} ->
  375. exit(P, kill),
  376. kill_all_procs_1(Ps, Self, N+1);
  377. _ ->
  378. kill_all_procs_1(Ps, Self, N)
  379. end;
  380. kill_all_procs_1([], _, 0) -> ok;
  381. kill_all_procs_1([], _, _) -> kill_all_procs().
  382. set_timer(infinity) -> ok;
  383. set_timer(Time) -> timer:exit_after(Time, timeout).