gen.erl 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  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).
  19. %%%-----------------------------------------------------------------
  20. %%% This module implements the really generic stuff of the generic
  21. %%% standard behaviours (e.g. gen_server, gen_fsm).
  22. %%%
  23. %%% The standard behaviour should export init_it/6.
  24. %%%-----------------------------------------------------------------
  25. -export([start/5, start/6, debug_options/1,
  26. call/3, call/4, reply/2]).
  27. -export([reg_behaviour/1]).
  28. -export([init_it/6, init_it/7]).
  29. -define(default_timeout, 5000).
  30. %%-----------------------------------------------------------------
  31. %% Starts a generic process.
  32. %% start(GenMod, LinkP, Mod, Args, Options)
  33. %% start(GenMod, LinkP, Name, Mod, Args, Options)
  34. %% start_link(Mod, Args, Options)
  35. %% start_link(Name, Mod, Args, Options) where:
  36. %% Name = {local, atom()} | {global, atom()}
  37. %% Mod = atom(), callback module implementing the 'real' fsm
  38. %% Args = term(), init arguments (to Mod:init/1)
  39. %% Options = [{debug, [Flag]}]
  40. %% Flag = trace | log | {logfile, File} | statistics | debug
  41. %% (debug == log && statistics)
  42. %% Returns: {ok, Pid} |
  43. %% {error, {already_started, Pid}} |
  44. %% {error, Reason}
  45. %%-----------------------------------------------------------------
  46. start(GenMod, LinkP, Name, Mod, Args, Options) ->
  47. case where(Name) of
  48. undefined ->
  49. do_spawn(GenMod, LinkP, Name, Mod, Args, Options);
  50. Pid ->
  51. {error, {already_started, Pid}}
  52. end.
  53. start(GenMod, LinkP, Mod, Args, Options) ->
  54. do_spawn(GenMod, LinkP, Mod, Args, Options).
  55. %%-----------------------------------------------------------------
  56. %% Spawn the process (and link) maybe at another node.
  57. %% If spawn without link, set parent to our selves "self"!!!
  58. %%-----------------------------------------------------------------
  59. do_spawn(GenMod, link, Mod, Args, Options) ->
  60. Time = timeout(Options),
  61. proc_lib:start_link(gen, init_it,
  62. [GenMod, self(), self(), Mod, Args, Options],
  63. Time,
  64. spawn_opts(Options));
  65. do_spawn(GenMod, _, Mod, Args, Options) ->
  66. Time = timeout(Options),
  67. proc_lib:start(gen, init_it,
  68. [GenMod, self(), self, Mod, Args, Options],
  69. Time,
  70. spawn_opts(Options)).
  71. do_spawn(GenMod, link, Name, Mod, Args, Options) ->
  72. Time = timeout(Options),
  73. proc_lib:start_link(gen, init_it,
  74. [GenMod, self(), self(), Name, Mod, Args, Options],
  75. Time,
  76. spawn_opts(Options));
  77. do_spawn(GenMod, _, Name, Mod, Args, Options) ->
  78. Time = timeout(Options),
  79. proc_lib:start(gen, init_it,
  80. [GenMod, self(), self, Name, Mod, Args, Options],
  81. Time,
  82. spawn_opts(Options)).
  83. reg_behaviour(B) ->
  84. catch begin
  85. Key = {p,l,behaviour},
  86. try gproc:reg(Key, B)
  87. catch
  88. error:badarg ->
  89. gproc:set_value(Key, B)
  90. end
  91. end.
  92. %%-----------------------------------------------------------------
  93. %% Initiate the new process.
  94. %% Register the name using the Rfunc function
  95. %% Calls the Mod:init/Args function.
  96. %% Finally an acknowledge is sent to Parent and the main
  97. %% loop is entered.
  98. %%-----------------------------------------------------------------
  99. init_it(GenMod, Starter, Parent, Mod, Args, Options) ->
  100. init_it2(GenMod, Starter, Parent, self(), Mod, Args, Options).
  101. init_it(GenMod, Starter, Parent, Name, Mod, Args, Options) ->
  102. case name_register(Name) of
  103. true ->
  104. init_it2(GenMod, Starter, Parent, name(Name), Mod, Args, Options);
  105. {false, Pid} ->
  106. proc_lib:init_ack(Starter, {error, {already_started, Pid}})
  107. end.
  108. init_it2(GenMod, Starter, Parent, Name, Mod, Args, Options) ->
  109. GenMod:init_it(Starter, Parent, Name, Mod, Args, Options).
  110. %%-----------------------------------------------------------------
  111. %% Makes a synchronous call to a generic process.
  112. %% Request is sent to the Pid, and the response must be
  113. %% {Tag, _, Reply}.
  114. %%-----------------------------------------------------------------
  115. %%% New call function which uses the new monitor BIF
  116. %%% call(ServerId, Label, Request)
  117. call(Process, Label, Request) ->
  118. call(Process, Label, Request, ?default_timeout).
  119. %% Local or remote by pid
  120. call(Pid, Label, Request, Timeout)
  121. when is_pid(Pid), Timeout =:= infinity;
  122. is_pid(Pid), is_integer(Timeout), Timeout >= 0 ->
  123. do_call(Pid, Label, Request, Timeout);
  124. %% Local by name
  125. call(Name, Label, Request, Timeout)
  126. when is_atom(Name), Timeout =:= infinity;
  127. is_atom(Name), is_integer(Timeout), Timeout >= 0 ->
  128. case whereis(Name) of
  129. Pid when is_pid(Pid) ->
  130. do_call(Pid, Label, Request, Timeout);
  131. undefined ->
  132. exit(noproc)
  133. end;
  134. %% Global by name
  135. call({global, _Name}=Process, Label, Request, Timeout)
  136. when Timeout =:= infinity;
  137. is_integer(Timeout), Timeout >= 0 ->
  138. case where(Process) of
  139. Pid when is_pid(Pid) ->
  140. Node = node(Pid),
  141. case catch do_call(Pid, Label, Request, Timeout) of
  142. {'EXIT', {nodedown, Node}} ->
  143. % A nodedown not yet detected by global, pretend that it
  144. % was.
  145. exit(noproc);
  146. {'EXIT', noproc} ->
  147. exit(noproc);
  148. {'EXIT', OtherExits} ->
  149. exit(OtherExits);
  150. Result ->
  151. Result
  152. end;
  153. undefined ->
  154. exit(noproc)
  155. end;
  156. %% Local by name in disguise
  157. call({Name, Node}, Label, Request, Timeout)
  158. when Node =:= node(), Timeout =:= infinity;
  159. Node =:= node(), is_integer(Timeout), Timeout >= 0 ->
  160. call(Name, Label, Request, Timeout);
  161. %% Remote by name
  162. call({_Name, Node}=Process, Label, Request, Timeout)
  163. when is_atom(Node), Timeout =:= infinity;
  164. is_atom(Node), is_integer(Timeout), Timeout >= 0 ->
  165. if
  166. node() =:= nonode@nohost ->
  167. exit({nodedown, Node});
  168. true ->
  169. do_call(Process, Label, Request, Timeout)
  170. end.
  171. do_call(Process, Label, Request, Timeout) ->
  172. %% We trust the arguments to be correct, i.e
  173. %% Process is either a local or remote pid,
  174. %% or a {Name, Node} tuple (of atoms) and in this
  175. %% case this node (node()) _is_ distributed and Node =/= node().
  176. Node = case Process of
  177. {_S, N} ->
  178. N;
  179. _ when is_pid(Process) ->
  180. node(Process);
  181. _ ->
  182. node()
  183. end,
  184. case catch erlang:monitor(process, Process) of
  185. Mref when is_reference(Mref) ->
  186. receive
  187. {'DOWN', Mref, _, Pid1, noconnection} when is_pid(Pid1) ->
  188. exit({nodedown, node(Pid1)});
  189. {'DOWN', Mref, _, _, noconnection} ->
  190. exit({nodedown, Node});
  191. {'DOWN', Mref, _, _, _} ->
  192. exit(noproc)
  193. after 0 ->
  194. Process ! {Label, {self(), Mref}, Request},
  195. wait_resp_mon(Process, Mref, Timeout)
  196. end;
  197. {'EXIT', _} ->
  198. %% Old node is not supporting the monitor.
  199. %% The other possible case -- this node is not distributed
  200. %% -- should have been handled earlier.
  201. %% Do the best possible with monitor_node/2.
  202. %% This code may hang indefinitely if the Process
  203. %% does not exist. It is only used for old remote nodes.
  204. monitor_node(Node, true),
  205. receive
  206. {nodedown, Node} ->
  207. monitor_node(Node, false),
  208. exit({nodedown, Node})
  209. after 0 ->
  210. Mref = make_ref(),
  211. Process ! {Label, {self(),Mref}, Request},
  212. Res = wait_resp(Node, Mref, Timeout),
  213. monitor_node(Node, false),
  214. Res
  215. end
  216. end.
  217. wait_resp_mon(Process, Mref, Timeout) ->
  218. Node = case Process of
  219. {_S, N} ->
  220. N;
  221. _ when is_pid(Process) ->
  222. node(Process);
  223. _ ->
  224. node()
  225. end,
  226. receive
  227. {Mref, Reply} ->
  228. erlang:demonitor(Mref),
  229. receive
  230. {'DOWN', Mref, _, _, _} ->
  231. {ok, Reply}
  232. after 0 ->
  233. {ok, Reply}
  234. end;
  235. {'DOWN', Mref, _, Pid, Reason} when is_pid(Pid) ->
  236. receive
  237. {'EXIT', Pid, noconnection} ->
  238. exit({nodedown, Node});
  239. {'EXIT', Pid, What} ->
  240. exit(What)
  241. after 1 -> % Give 'EXIT' message time to arrive
  242. case Reason of
  243. noconnection ->
  244. exit({nodedown, Node});
  245. _ ->
  246. exit(Reason)
  247. end
  248. end;
  249. {'DOWN', Mref, _, _, noconnection} ->
  250. %% Here is a hole, when the monitor is remote by name
  251. %% and the remote node goes down, we will never find
  252. %% out the Pid and cannot know which 'EXIT' message
  253. %% to read out. This awkward case should have been
  254. %% handled earlier (except for against rex)
  255. %% by not using remote monitor by name.
  256. case Process of
  257. _ when is_pid(Process) ->
  258. receive
  259. {'EXIT', Process, noconnection} ->
  260. exit({nodedown, Node});
  261. {'EXIT', Process, What} ->
  262. exit(What)
  263. after 1 -> % Give 'EXIT' message time to arrive
  264. exit({nodedown, node(Process)})
  265. end;
  266. _ ->
  267. exit({nodedown, Node})
  268. end;
  269. %% {'DOWN', Mref, _, _, noproc} ->
  270. %% exit(noproc);
  271. {'DOWN', Mref, _Tag, _Item, Reason} ->
  272. exit(Reason)
  273. after Timeout ->
  274. erlang:demonitor(Mref),
  275. receive
  276. {'DOWN', Mref, _, _, _Reason} -> true
  277. after 0 -> true
  278. end,
  279. exit(timeout)
  280. end.
  281. wait_resp(Node, Tag, Timeout) ->
  282. receive
  283. {Tag, Reply} ->
  284. {ok,Reply};
  285. {nodedown, Node} ->
  286. monitor_node(Node, false),
  287. exit({nodedown, Node})
  288. after Timeout ->
  289. monitor_node(Node, false),
  290. exit(timeout)
  291. end.
  292. %
  293. % Send a reply to the client.
  294. %
  295. reply({To, Tag}, Reply) ->
  296. catch To ! {Tag, Reply}.
  297. %%%-----------------------------------------------------------------
  298. %%% Misc. functions.
  299. %%%-----------------------------------------------------------------
  300. where({global, Name}) -> global:safe_whereis_name(Name);
  301. where({local, Name}) -> whereis(Name).
  302. name({global, Name}) -> Name;
  303. name({local, Name}) -> Name.
  304. name_register({local, Name}) ->
  305. case catch register(Name, self()) of
  306. true -> true;
  307. {'EXIT', _} ->
  308. {false, where({local, Name})}
  309. end;
  310. name_register({global, Name}) ->
  311. case global:register_name(Name, self()) of
  312. yes -> true;
  313. no -> {false, where({global, Name})}
  314. end.
  315. timeout(Options) ->
  316. case opt(timeout, Options) of
  317. {ok, Time} ->
  318. Time;
  319. _ ->
  320. infinity
  321. end.
  322. spawn_opts(Options) ->
  323. case opt(spawn_opt, Options) of
  324. {ok, Opts} ->
  325. Opts;
  326. _ ->
  327. []
  328. end.
  329. opt(Op, [{Op, Value}|_]) ->
  330. {ok, Value};
  331. opt(Op, [_|Options]) ->
  332. opt(Op, Options);
  333. opt(_, []) ->
  334. false.
  335. debug_options(Opts) ->
  336. case opt(debug, Opts) of
  337. {ok, Options} -> sys:debug_options(Options);
  338. _ -> []
  339. end.