gen_server.erl 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  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(gen_server).
  19. %%% ---------------------------------------------------
  20. %%%
  21. %%% The idea behind THIS server is that the user module
  22. %%% provides (different) functions to handle different
  23. %%% kind of inputs.
  24. %%% If the Parent process terminates the Module:terminate/2
  25. %%% function is called.
  26. %%%
  27. %%% The user module should export:
  28. %%%
  29. %%% init(Args)
  30. %%% ==> {ok, State}
  31. %%% {ok, State, Timeout}
  32. %%% ignore
  33. %%% {stop, Reason}
  34. %%%
  35. %%% handle_call(Msg, {From, Tag}, State)
  36. %%%
  37. %%% ==> {reply, Reply, State}
  38. %%% {reply, Reply, State, Timeout}
  39. %%% {noreply, State}
  40. %%% {noreply, State, Timeout}
  41. %%% {stop, Reason, Reply, State}
  42. %%% Reason = normal | shutdown | Term terminate(State) is called
  43. %%%
  44. %%% handle_cast(Msg, State)
  45. %%%
  46. %%% ==> {noreply, State}
  47. %%% {noreply, State, Timeout}
  48. %%% {stop, Reason, State}
  49. %%% Reason = normal | shutdown | Term terminate(State) is called
  50. %%%
  51. %%% handle_info(Info, State) Info is e.g. {'EXIT', P, R}, {nodedown, N}, ...
  52. %%%
  53. %%% ==> {noreply, State}
  54. %%% {noreply, State, Timeout}
  55. %%% {stop, Reason, State}
  56. %%% Reason = normal | shutdown | Term, terminate(State) is called
  57. %%%
  58. %%% terminate(Reason, State) Let the user module clean up
  59. %%% always called when server terminates
  60. %%%
  61. %%% ==> ok
  62. %%%
  63. %%%
  64. %%% The work flow (of the server) can be described as follows:
  65. %%%
  66. %%% User module Generic
  67. %%% ----------- -------
  68. %%% start -----> start
  69. %%% init <----- .
  70. %%%
  71. %%% loop
  72. %%% handle_call <----- .
  73. %%% -----> reply
  74. %%%
  75. %%% handle_cast <----- .
  76. %%%
  77. %%% handle_info <----- .
  78. %%%
  79. %%% terminate <----- .
  80. %%%
  81. %%% -----> reply
  82. %%%
  83. %%%
  84. %%% ---------------------------------------------------
  85. %% API
  86. -export([start/3, start/4,
  87. start_link/3, start_link/4,
  88. call/2, call/3,
  89. cast/2, reply/2,
  90. abcast/2, abcast/3,
  91. multi_call/2, multi_call/3, multi_call/4,
  92. enter_loop/3, enter_loop/4, enter_loop/5]).
  93. -export([behaviour_info/1]).
  94. %% System exports
  95. -export([system_continue/3,
  96. system_terminate/4,
  97. system_code_change/4,
  98. format_status/2]).
  99. %% Internal exports
  100. -export([init_it/6, print_event/3]).
  101. -import(error_logger, [format/2]).
  102. %%%=========================================================================
  103. %%% API
  104. %%%=========================================================================
  105. behaviour_info(callbacks) ->
  106. [{init,1},{handle_call,3},{handle_cast,2},{handle_info,2},
  107. {terminate,2},{code_change,3}];
  108. behaviour_info(_Other) ->
  109. undefined.
  110. %%% -----------------------------------------------------------------
  111. %%% Starts a generic server.
  112. %%% start(Mod, Args, Options)
  113. %%% start(Name, Mod, Args, Options)
  114. %%% start_link(Mod, Args, Options)
  115. %%% start_link(Name, Mod, Args, Options) where:
  116. %%% Name ::= {local, atom()} | {global, atom()}
  117. %%% Mod ::= atom(), callback module implementing the 'real' server
  118. %%% Args ::= term(), init arguments (to Mod:init/1)
  119. %%% Options ::= [{timeout, Timeout} | {debug, [Flag]}]
  120. %%% Flag ::= trace | log | {logfile, File} | statistics | debug
  121. %%% (debug == log && statistics)
  122. %%% Returns: {ok, Pid} |
  123. %%% {error, {already_started, Pid}} |
  124. %%% {error, Reason}
  125. %%% -----------------------------------------------------------------
  126. start(Mod, Args, Options) ->
  127. gen:start(?MODULE, nolink, Mod, Args, Options).
  128. start(Name, Mod, Args, Options) ->
  129. gen:start(?MODULE, nolink, Name, Mod, Args, Options).
  130. start_link(Mod, Args, Options) ->
  131. gen:start(?MODULE, link, Mod, Args, Options).
  132. start_link(Name, Mod, Args, Options) ->
  133. gen:start(?MODULE, link, Name, Mod, Args, Options).
  134. %% -----------------------------------------------------------------
  135. %% Make a call to a generic server.
  136. %% If the server is located at another node, that node will
  137. %% be monitored.
  138. %% If the client is trapping exits and is linked server termination
  139. %% is handled here (? Shall we do that here (or rely on timeouts) ?).
  140. %% -----------------------------------------------------------------
  141. call(Name, Request) ->
  142. case catch gen:call(Name, '$gen_call', Request) of
  143. {ok,Res} ->
  144. Res;
  145. {'EXIT',Reason} ->
  146. exit({Reason, {?MODULE, call, [Name, Request]}})
  147. end.
  148. call(Name, Request, Timeout) ->
  149. case catch gen:call(Name, '$gen_call', Request, Timeout) of
  150. {ok,Res} ->
  151. Res;
  152. {'EXIT',Reason} ->
  153. exit({Reason, {?MODULE, call, [Name, Request, Timeout]}})
  154. end.
  155. %% -----------------------------------------------------------------
  156. %% Make a cast to a generic server.
  157. %% -----------------------------------------------------------------
  158. cast({global,Name}, Request) ->
  159. catch global:send(Name, cast_msg(Request)),
  160. ok;
  161. cast({Name,Node}=Dest, Request) when is_atom(Name), is_atom(Node) ->
  162. do_cast(Dest, Request);
  163. cast(Dest, Request) when is_atom(Dest) ->
  164. do_cast(Dest, Request);
  165. cast(Dest, Request) when is_pid(Dest) ->
  166. do_cast(Dest, Request).
  167. do_cast(Dest, Request) ->
  168. do_send(Dest, cast_msg(Request)),
  169. ok.
  170. cast_msg(Request) -> {'$gen_cast',Request}.
  171. %% -----------------------------------------------------------------
  172. %% Send a reply to the client.
  173. %% -----------------------------------------------------------------
  174. reply({To, Tag}, Reply) ->
  175. catch To ! {Tag, Reply}.
  176. %% -----------------------------------------------------------------
  177. %% Asyncronous broadcast, returns nothing, it's just send'n prey
  178. %%-----------------------------------------------------------------
  179. abcast(Name, Request) when is_atom(Name) ->
  180. do_abcast([node() | nodes()], Name, cast_msg(Request)).
  181. abcast(Nodes, Name, Request) when is_list(Nodes), is_atom(Name) ->
  182. do_abcast(Nodes, Name, cast_msg(Request)).
  183. do_abcast([Node|Nodes], Name, Msg) when is_atom(Node) ->
  184. do_send({Name,Node},Msg),
  185. do_abcast(Nodes, Name, Msg);
  186. do_abcast([], _,_) -> abcast.
  187. %%% -----------------------------------------------------------------
  188. %%% Make a call to servers at several nodes.
  189. %%% Returns: {[Replies],[BadNodes]}
  190. %%% A Timeout can be given
  191. %%%
  192. %%% A middleman process is used in case late answers arrives after
  193. %%% the timeout. If they would be allowed to glog the callers message
  194. %%% queue, it would probably become confused. Late answers will
  195. %%% now arrive to the terminated middleman and so be discarded.
  196. %%% -----------------------------------------------------------------
  197. multi_call(Name, Req)
  198. when is_atom(Name) ->
  199. do_multi_call([node() | nodes()], Name, Req, infinity).
  200. multi_call(Nodes, Name, Req)
  201. when is_list(Nodes), is_atom(Name) ->
  202. do_multi_call(Nodes, Name, Req, infinity).
  203. multi_call(Nodes, Name, Req, infinity) ->
  204. do_multi_call(Nodes, Name, Req, infinity);
  205. multi_call(Nodes, Name, Req, Timeout)
  206. when is_list(Nodes), is_atom(Name), is_integer(Timeout), Timeout >= 0 ->
  207. do_multi_call(Nodes, Name, Req, Timeout).
  208. %%-----------------------------------------------------------------
  209. %% enter_loop(Mod, Options, State, <ServerName>, <TimeOut>) ->_
  210. %%
  211. %% Description: Makes an existing process into a gen_server.
  212. %% The calling process will enter the gen_server receive
  213. %% loop and become a gen_server process.
  214. %% The process *must* have been started using one of the
  215. %% start functions in proc_lib, see proc_lib(3).
  216. %% The user is responsible for any initialization of the
  217. %% process, including registering a name for it.
  218. %%-----------------------------------------------------------------
  219. enter_loop(Mod, Options, State) ->
  220. enter_loop(Mod, Options, State, self(), infinity).
  221. enter_loop(Mod, Options, State, ServerName = {_, _}) ->
  222. enter_loop(Mod, Options, State, ServerName, infinity);
  223. enter_loop(Mod, Options, State, Timeout) ->
  224. enter_loop(Mod, Options, State, self(), Timeout).
  225. enter_loop(Mod, Options, State, ServerName, Timeout) ->
  226. Name = get_proc_name(ServerName),
  227. Parent = get_parent(),
  228. Debug = debug_options(Name, Options),
  229. loop(Parent, Name, State, Mod, Timeout, Debug).
  230. %%%========================================================================
  231. %%% Gen-callback functions
  232. %%%========================================================================
  233. %%% ---------------------------------------------------
  234. %%% Initiate the new process.
  235. %%% Register the name using the Rfunc function
  236. %%% Calls the Mod:init/Args function.
  237. %%% Finally an acknowledge is sent to Parent and the main
  238. %%% loop is entered.
  239. %%% ---------------------------------------------------
  240. init_it(Starter, self, Name, Mod, Args, Options) ->
  241. init_it(Starter, self(), Name, Mod, Args, Options);
  242. init_it(Starter, Parent, Name, Mod, Args, Options) ->
  243. Debug = debug_options(Name, Options),
  244. gen:reg_behaviour(?MODULE),
  245. case catch Mod:init(Args) of
  246. {ok, State} ->
  247. proc_lib:init_ack(Starter, {ok, self()}),
  248. loop(Parent, Name, State, Mod, infinity, Debug);
  249. {ok, State, Timeout} ->
  250. proc_lib:init_ack(Starter, {ok, self()}),
  251. loop(Parent, Name, State, Mod, Timeout, Debug);
  252. {stop, Reason} ->
  253. proc_lib:init_ack(Starter, {error, Reason}),
  254. exit(Reason);
  255. ignore ->
  256. proc_lib:init_ack(Starter, ignore),
  257. exit(normal);
  258. {'EXIT', Reason} ->
  259. proc_lib:init_ack(Starter, {error, Reason}),
  260. exit(Reason);
  261. Else ->
  262. Error = {bad_return_value, Else},
  263. proc_lib:init_ack(Starter, {error, Error}),
  264. exit(Error)
  265. end.
  266. %%%========================================================================
  267. %%% Internal functions
  268. %%%========================================================================
  269. %%% ---------------------------------------------------
  270. %%% The MAIN loop.
  271. %%% ---------------------------------------------------
  272. loop(Parent, Name, State, Mod, Time, Debug) ->
  273. Msg = receive
  274. Input ->
  275. Input
  276. after Time ->
  277. timeout
  278. end,
  279. case Msg of
  280. {system, From, Req} ->
  281. sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
  282. [Name, State, Mod, Time]);
  283. {'EXIT', Parent, Reason} ->
  284. terminate(Reason, Name, Msg, Mod, State, Debug);
  285. _Msg when Debug =:= [] ->
  286. handle_msg(Msg, Parent, Name, State, Mod, Time);
  287. _Msg ->
  288. Debug1 = sys:handle_debug(Debug, {?MODULE, print_event},
  289. Name, {in, Msg}),
  290. handle_msg(Msg, Parent, Name, State, Mod, Time, Debug1)
  291. end.
  292. %%% ---------------------------------------------------
  293. %%% Send/recive functions
  294. %%% ---------------------------------------------------
  295. do_send(Dest, Msg) ->
  296. case catch erlang:send(Dest, Msg, [noconnect]) of
  297. noconnect ->
  298. spawn(erlang, send, [Dest,Msg]);
  299. Other ->
  300. Other
  301. end.
  302. do_multi_call(Nodes, Name, Req, infinity) ->
  303. Tag = make_ref(),
  304. Monitors = send_nodes(Nodes, Name, Tag, Req),
  305. rec_nodes(Tag, Monitors, Name, undefined);
  306. do_multi_call(Nodes, Name, Req, Timeout) ->
  307. Tag = make_ref(),
  308. Caller = self(),
  309. Receiver =
  310. spawn(
  311. fun() ->
  312. %% Middleman process. Should be unsensitive to regular
  313. %% exit signals. The sychronization is needed in case
  314. %% the receiver would exit before the caller started
  315. %% the monitor.
  316. process_flag(trap_exit, true),
  317. Mref = erlang:monitor(process, Caller),
  318. receive
  319. {Caller,Tag} ->
  320. Monitors = send_nodes(Nodes, Name, Tag, Req),
  321. TimerId = erlang:start_timer(Timeout, self(), ok),
  322. Result = rec_nodes(Tag, Monitors, Name, TimerId),
  323. exit({self(),Tag,Result});
  324. {'DOWN',Mref,_,_,_} ->
  325. %% Caller died before sending us the go-ahead.
  326. %% Give up silently.
  327. exit(normal)
  328. end
  329. end),
  330. Mref = erlang:monitor(process, Receiver),
  331. Receiver ! {self(),Tag},
  332. receive
  333. {'DOWN',Mref,_,_,{Receiver,Tag,Result}} ->
  334. Result;
  335. {'DOWN',Mref,_,_,Reason} ->
  336. %% The middleman code failed. Or someone did
  337. %% exit(_, kill) on the middleman process => Reason==killed
  338. exit(Reason)
  339. end.
  340. send_nodes(Nodes, Name, Tag, Req) ->
  341. send_nodes(Nodes, Name, Tag, Req, []).
  342. send_nodes([Node|Tail], Name, Tag, Req, Monitors)
  343. when is_atom(Node) ->
  344. Monitor = start_monitor(Node, Name),
  345. %% Handle non-existing names in rec_nodes.
  346. catch {Name, Node} ! {'$gen_call', {self(), {Tag, Node}}, Req},
  347. send_nodes(Tail, Name, Tag, Req, [Monitor | Monitors]);
  348. send_nodes([_Node|Tail], Name, Tag, Req, Monitors) ->
  349. %% Skip non-atom Node
  350. send_nodes(Tail, Name, Tag, Req, Monitors);
  351. send_nodes([], _Name, _Tag, _Req, Monitors) ->
  352. Monitors.
  353. %% Against old nodes:
  354. %% If no reply has been delivered within 2 secs. (per node) check that
  355. %% the server really exists and wait for ever for the answer.
  356. %%
  357. %% Against contemporary nodes:
  358. %% Wait for reply, server 'DOWN', or timeout from TimerId.
  359. rec_nodes(Tag, Nodes, Name, TimerId) ->
  360. rec_nodes(Tag, Nodes, Name, [], [], 2000, TimerId).
  361. rec_nodes(Tag, [{N,R}|Tail], Name, Badnodes, Replies, Time, TimerId ) ->
  362. receive
  363. {'DOWN', R, _, _, _} ->
  364. rec_nodes(Tag, Tail, Name, [N|Badnodes], Replies, Time, TimerId);
  365. {{Tag, N}, Reply} -> %% Tag is bound !!!
  366. unmonitor(R),
  367. rec_nodes(Tag, Tail, Name, Badnodes,
  368. [{N,Reply}|Replies], Time, TimerId);
  369. {timeout, TimerId, _} ->
  370. unmonitor(R),
  371. %% Collect all replies that already have arrived
  372. rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies)
  373. end;
  374. rec_nodes(Tag, [N|Tail], Name, Badnodes, Replies, Time, TimerId) ->
  375. %% R6 node
  376. receive
  377. {nodedown, N} ->
  378. monitor_node(N, false),
  379. rec_nodes(Tag, Tail, Name, [N|Badnodes], Replies, 2000, TimerId);
  380. {{Tag, N}, Reply} -> %% Tag is bound !!!
  381. receive {nodedown, N} -> ok after 0 -> ok end,
  382. monitor_node(N, false),
  383. rec_nodes(Tag, Tail, Name, Badnodes,
  384. [{N,Reply}|Replies], 2000, TimerId);
  385. {timeout, TimerId, _} ->
  386. receive {nodedown, N} -> ok after 0 -> ok end,
  387. monitor_node(N, false),
  388. %% Collect all replies that already have arrived
  389. rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies)
  390. after Time ->
  391. case rpc:call(N, erlang, whereis, [Name]) of
  392. Pid when is_pid(Pid) -> % It exists try again.
  393. rec_nodes(Tag, [N|Tail], Name, Badnodes,
  394. Replies, infinity, TimerId);
  395. _ -> % badnode
  396. receive {nodedown, N} -> ok after 0 -> ok end,
  397. monitor_node(N, false),
  398. rec_nodes(Tag, Tail, Name, [N|Badnodes],
  399. Replies, 2000, TimerId)
  400. end
  401. end;
  402. rec_nodes(_, [], _, Badnodes, Replies, _, TimerId) ->
  403. case catch erlang:cancel_timer(TimerId) of
  404. false -> % It has already sent it's message
  405. receive
  406. {timeout, TimerId, _} -> ok
  407. after 0 ->
  408. ok
  409. end;
  410. _ -> % Timer was cancelled, or TimerId was 'undefined'
  411. ok
  412. end,
  413. {Replies, Badnodes}.
  414. %% Collect all replies that already have arrived
  415. rec_nodes_rest(Tag, [{N,R}|Tail], Name, Badnodes, Replies) ->
  416. receive
  417. {'DOWN', R, _, _, _} ->
  418. rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies);
  419. {{Tag, N}, Reply} -> %% Tag is bound !!!
  420. unmonitor(R),
  421. rec_nodes_rest(Tag, Tail, Name, Badnodes, [{N,Reply}|Replies])
  422. after 0 ->
  423. unmonitor(R),
  424. rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies)
  425. end;
  426. rec_nodes_rest(Tag, [N|Tail], Name, Badnodes, Replies) ->
  427. %% R6 node
  428. receive
  429. {nodedown, N} ->
  430. monitor_node(N, false),
  431. rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies);
  432. {{Tag, N}, Reply} -> %% Tag is bound !!!
  433. receive {nodedown, N} -> ok after 0 -> ok end,
  434. monitor_node(N, false),
  435. rec_nodes_rest(Tag, Tail, Name, Badnodes, [{N,Reply}|Replies])
  436. after 0 ->
  437. receive {nodedown, N} -> ok after 0 -> ok end,
  438. monitor_node(N, false),
  439. rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies)
  440. end;
  441. rec_nodes_rest(_Tag, [], _Name, Badnodes, Replies) ->
  442. {Replies, Badnodes}.
  443. %%% ---------------------------------------------------
  444. %%% Monitor functions
  445. %%% ---------------------------------------------------
  446. start_monitor(Node, Name) when is_atom(Node), is_atom(Name) ->
  447. if node() =:= nonode@nohost, Node =/= nonode@nohost ->
  448. Ref = make_ref(),
  449. self() ! {'DOWN', Ref, process, {Name, Node}, noconnection},
  450. {Node, Ref};
  451. true ->
  452. case catch erlang:monitor(process, {Name, Node}) of
  453. {'EXIT', _} ->
  454. %% Remote node is R6
  455. monitor_node(Node, true),
  456. Node;
  457. Ref when is_reference(Ref) ->
  458. {Node, Ref}
  459. end
  460. end.
  461. %% Cancels a monitor started with Ref=erlang:monitor(_, _).
  462. unmonitor(Ref) when is_reference(Ref) ->
  463. erlang:demonitor(Ref),
  464. receive
  465. {'DOWN', Ref, _, _, _} ->
  466. true
  467. after 0 ->
  468. true
  469. end.
  470. %%% ---------------------------------------------------
  471. %%% Message handling functions
  472. %%% ---------------------------------------------------
  473. dispatch({'$gen_cast', Msg}, Mod, State) ->
  474. Mod:handle_cast(Msg, State);
  475. dispatch(Info, Mod, State) ->
  476. Mod:handle_info(Info, State).
  477. handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod, _Time) ->
  478. case catch Mod:handle_call(Msg, From, State) of
  479. {reply, Reply, NState} ->
  480. reply(From, Reply),
  481. loop(Parent, Name, NState, Mod, infinity, []);
  482. {reply, Reply, NState, Time1} ->
  483. reply(From, Reply),
  484. loop(Parent, Name, NState, Mod, Time1, []);
  485. {noreply, NState} ->
  486. loop(Parent, Name, NState, Mod, infinity, []);
  487. {noreply, NState, Time1} ->
  488. loop(Parent, Name, NState, Mod, Time1, []);
  489. {stop, Reason, Reply, NState} ->
  490. {'EXIT', R} =
  491. (catch terminate(Reason, Name, Msg, Mod, NState, [])),
  492. reply(From, Reply),
  493. exit(R);
  494. Other -> handle_common_reply(Other, Parent, Name, Msg, Mod, State)
  495. end;
  496. handle_msg(Msg, Parent, Name, State, Mod, _Time) ->
  497. Reply = (catch dispatch(Msg, Mod, State)),
  498. handle_common_reply(Reply, Parent, Name, Msg, Mod, State).
  499. handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod, _Time, Debug) ->
  500. case catch Mod:handle_call(Msg, From, State) of
  501. {reply, Reply, NState} ->
  502. Debug1 = reply(Name, From, Reply, NState, Debug),
  503. loop(Parent, Name, NState, Mod, infinity, Debug1);
  504. {reply, Reply, NState, Time1} ->
  505. Debug1 = reply(Name, From, Reply, NState, Debug),
  506. loop(Parent, Name, NState, Mod, Time1, Debug1);
  507. {noreply, NState} ->
  508. Debug1 = sys:handle_debug(Debug, {?MODULE, print_event}, Name,
  509. {noreply, NState}),
  510. loop(Parent, Name, NState, Mod, infinity, Debug1);
  511. {noreply, NState, Time1} ->
  512. Debug1 = sys:handle_debug(Debug, {?MODULE, print_event}, Name,
  513. {noreply, NState}),
  514. loop(Parent, Name, NState, Mod, Time1, Debug1);
  515. {stop, Reason, Reply, NState} ->
  516. {'EXIT', R} =
  517. (catch terminate(Reason, Name, Msg, Mod, NState, Debug)),
  518. reply(Name, From, Reply, NState, Debug),
  519. exit(R);
  520. Other ->
  521. handle_common_reply(Other, Parent, Name, Msg, Mod, State, Debug)
  522. end;
  523. handle_msg(Msg, Parent, Name, State, Mod, _Time, Debug) ->
  524. Reply = (catch dispatch(Msg, Mod, State)),
  525. handle_common_reply(Reply, Parent, Name, Msg, Mod, State, Debug).
  526. handle_common_reply(Reply, Parent, Name, Msg, Mod, State) ->
  527. case Reply of
  528. {noreply, NState} ->
  529. loop(Parent, Name, NState, Mod, infinity, []);
  530. {noreply, NState, Time1} ->
  531. loop(Parent, Name, NState, Mod, Time1, []);
  532. {stop, Reason, NState} ->
  533. terminate(Reason, Name, Msg, Mod, NState, []);
  534. {'EXIT', What} ->
  535. terminate(What, Name, Msg, Mod, State, []);
  536. _ ->
  537. terminate({bad_return_value, Reply}, Name, Msg, Mod, State, [])
  538. end.
  539. handle_common_reply(Reply, Parent, Name, Msg, Mod, State, Debug) ->
  540. case Reply of
  541. {noreply, NState} ->
  542. Debug1 = sys:handle_debug(Debug, {?MODULE, print_event}, Name,
  543. {noreply, NState}),
  544. loop(Parent, Name, NState, Mod, infinity, Debug1);
  545. {noreply, NState, Time1} ->
  546. Debug1 = sys:handle_debug(Debug, {?MODULE, print_event}, Name,
  547. {noreply, NState}),
  548. loop(Parent, Name, NState, Mod, Time1, Debug1);
  549. {stop, Reason, NState} ->
  550. terminate(Reason, Name, Msg, Mod, NState, Debug);
  551. {'EXIT', What} ->
  552. terminate(What, Name, Msg, Mod, State, Debug);
  553. _ ->
  554. terminate({bad_return_value, Reply}, Name, Msg, Mod, State, Debug)
  555. end.
  556. reply(Name, {To, Tag}, Reply, State, Debug) ->
  557. reply({To, Tag}, Reply),
  558. sys:handle_debug(Debug, {?MODULE, print_event}, Name,
  559. {out, Reply, To, State} ).
  560. %%-----------------------------------------------------------------
  561. %% Callback functions for system messages handling.
  562. %%-----------------------------------------------------------------
  563. system_continue(Parent, Debug, [Name, State, Mod, Time]) ->
  564. loop(Parent, Name, State, Mod, Time, Debug).
  565. system_terminate(Reason, _Parent, Debug, [Name, State, Mod, _Time]) ->
  566. terminate(Reason, Name, [], Mod, State, Debug).
  567. system_code_change([Name, State, Mod, Time], _Module, OldVsn, Extra) ->
  568. case catch Mod:code_change(OldVsn, State, Extra) of
  569. {ok, NewState} -> {ok, [Name, NewState, Mod, Time]};
  570. Else -> Else
  571. end.
  572. %%-----------------------------------------------------------------
  573. %% Format debug messages. Print them as the call-back module sees
  574. %% them, not as the real erlang messages. Use trace for that.
  575. %%-----------------------------------------------------------------
  576. print_event(Dev, {in, Msg}, Name) ->
  577. case Msg of
  578. {'$gen_call', {From, _Tag}, Call} ->
  579. io:format(Dev, "*DBG* ~p got call ~p from ~w~n",
  580. [Name, Call, From]);
  581. {'$gen_cast', Cast} ->
  582. io:format(Dev, "*DBG* ~p got cast ~p~n",
  583. [Name, Cast]);
  584. _ ->
  585. io:format(Dev, "*DBG* ~p got ~p~n", [Name, Msg])
  586. end;
  587. print_event(Dev, {out, Msg, To, State}, Name) ->
  588. io:format(Dev, "*DBG* ~p sent ~p to ~w, new state ~w~n",
  589. [Name, Msg, To, State]);
  590. print_event(Dev, {noreply, State}, Name) ->
  591. io:format(Dev, "*DBG* ~p new state ~w~n", [Name, State]);
  592. print_event(Dev, Event, Name) ->
  593. io:format(Dev, "*DBG* ~p dbg ~p~n", [Name, Event]).
  594. %%% ---------------------------------------------------
  595. %%% Terminate the server.
  596. %%% ---------------------------------------------------
  597. terminate(Reason, Name, Msg, Mod, State, Debug) ->
  598. case catch Mod:terminate(Reason, State) of
  599. {'EXIT', R} ->
  600. error_info(R, Name, Msg, State, Debug),
  601. exit(R);
  602. _ ->
  603. case Reason of
  604. normal ->
  605. exit(normal);
  606. shutdown ->
  607. exit(shutdown);
  608. _ ->
  609. error_info(Reason, Name, Msg, State, Debug),
  610. exit(Reason)
  611. end
  612. end.
  613. error_info(_Reason, application_controller, _Msg, _State, _Debug) ->
  614. %% OTP-5811 Don't send an error report if it's the system process
  615. %% application_controller which is terminating - let init take care
  616. %% of it instead
  617. ok;
  618. error_info(Reason, Name, Msg, State, Debug) ->
  619. Reason1 =
  620. case Reason of
  621. {undef,[{M,F,A}|MFAs]} ->
  622. case code:is_loaded(M) of
  623. false ->
  624. {'module could not be loaded',[{M,F,A}|MFAs]};
  625. _ ->
  626. case erlang:function_exported(M, F, length(A)) of
  627. true ->
  628. Reason;
  629. false ->
  630. {'function not exported',[{M,F,A}|MFAs]}
  631. end
  632. end;
  633. _ ->
  634. Reason
  635. end,
  636. format("** Generic server ~p terminating \n"
  637. "** Last message in was ~p~n"
  638. "** When Server state == ~p~n"
  639. "** Reason for termination == ~n** ~p~n",
  640. [Name, Msg, State, Reason1]),
  641. sys:print_log(Debug),
  642. ok.
  643. %%% ---------------------------------------------------
  644. %%% Misc. functions.
  645. %%% ---------------------------------------------------
  646. opt(Op, [{Op, Value}|_]) ->
  647. {ok, Value};
  648. opt(Op, [_|Options]) ->
  649. opt(Op, Options);
  650. opt(_, []) ->
  651. false.
  652. debug_options(Name, Opts) ->
  653. case opt(debug, Opts) of
  654. {ok, Options} -> dbg_options(Name, Options);
  655. _ -> dbg_options(Name, [])
  656. end.
  657. dbg_options(Name, []) ->
  658. Opts =
  659. case init:get_argument(generic_debug) of
  660. error ->
  661. [];
  662. _ ->
  663. [log, statistics]
  664. end,
  665. dbg_opts(Name, Opts);
  666. dbg_options(Name, Opts) ->
  667. dbg_opts(Name, Opts).
  668. dbg_opts(Name, Opts) ->
  669. case catch sys:debug_options(Opts) of
  670. {'EXIT',_} ->
  671. format("~p: ignoring erroneous debug options - ~p~n",
  672. [Name, Opts]),
  673. [];
  674. Dbg ->
  675. Dbg
  676. end.
  677. get_proc_name(Pid) when is_pid(Pid) ->
  678. Pid;
  679. get_proc_name({local, Name}) ->
  680. case process_info(self(), registered_name) of
  681. {registered_name, Name} ->
  682. Name;
  683. {registered_name, _Name} ->
  684. exit(process_not_registered);
  685. [] ->
  686. exit(process_not_registered)
  687. end;
  688. get_proc_name({global, Name}) ->
  689. case global:safe_whereis_name(Name) of
  690. undefined ->
  691. exit(process_not_registered_globally);
  692. Pid when Pid =:= self() ->
  693. Name;
  694. _Pid ->
  695. exit(process_not_registered_globally)
  696. end.
  697. get_parent() ->
  698. case get('$ancestors') of
  699. [Parent | _] when is_pid(Parent)->
  700. Parent;
  701. [Parent | _] when is_atom(Parent)->
  702. name_to_pid(Parent);
  703. _ ->
  704. exit(process_was_not_started_by_proc_lib)
  705. end.
  706. name_to_pid(Name) ->
  707. case whereis(Name) of
  708. undefined ->
  709. case global:safe_whereis_name(Name) of
  710. undefined ->
  711. exit(could_not_find_registerd_name);
  712. Pid ->
  713. Pid
  714. end;
  715. Pid ->
  716. Pid
  717. end.
  718. %%-----------------------------------------------------------------
  719. %% Status information
  720. %%-----------------------------------------------------------------
  721. format_status(Opt, StatusData) ->
  722. [PDict, SysState, Parent, Debug, [Name, State, Mod, _Time]] = StatusData,
  723. NameTag = if is_pid(Name) ->
  724. pid_to_list(Name);
  725. is_atom(Name) ->
  726. Name
  727. end,
  728. Header = lists:concat(["Status for generic server ", NameTag]),
  729. Log = sys:get_debug(log, Debug, []),
  730. Specfic =
  731. case erlang:function_exported(Mod, format_status, 2) of
  732. true ->
  733. case catch Mod:format_status(Opt, [PDict, State]) of
  734. {'EXIT', _} -> [{data, [{"State", State}]}];
  735. Else -> Else
  736. end;
  737. _ ->
  738. [{data, [{"State", State}]}]
  739. end,
  740. [{header, Header},
  741. {data, [{"Status", SysState},
  742. {"Parent", Parent},
  743. {"Logged events", Log}]} |
  744. Specfic].