各种有用的erlang行为
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

1267 рядки
46 KiB

5 роки тому
4 роки тому
4 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
4 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
4 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
3 роки тому
5 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
5 роки тому
5 роки тому
4 роки тому
5 роки тому
5 роки тому
3 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
3 роки тому
5 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
5 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
5 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
5 роки тому
5 роки тому
4 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
4 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
4 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
4 роки тому
5 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
4 роки тому
5 роки тому
3 роки тому
4 роки тому
3 роки тому
4 роки тому
5 роки тому
3 роки тому
4 роки тому
5 роки тому
4 роки тому
3 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
3 роки тому
4 роки тому
5 роки тому
3 роки тому
4 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
3 роки тому
4 роки тому
5 роки тому
5 роки тому
3 роки тому
4 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
4 роки тому
5 роки тому
4 роки тому
5 роки тому
5 роки тому
4 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
  1. -module(gen_srv).
  2. -compile(inline).
  3. -compile({inline_size, 128}).
  4. -include_lib("kernel/include/logger.hrl").
  5. -export([
  6. %% API for gen_srv
  7. start/3, start/4, start_link/3, start_link/4
  8. , start_monitor/3, start_monitor/4
  9. , stop/1, stop/3
  10. , call/2, call/3
  11. , send_request/2, wait_response/2, receive_response/2, check_response/2
  12. , cast/2, send/2, reply/1, reply/2
  13. , abcast/2, abcast/3
  14. , multi_call/2, multi_call/3, multi_call/4
  15. , enter_loop/3, enter_loop/4, enter_loop/5
  16. %% gen callbacks
  17. , init_it/6
  18. %% sys callbacks
  19. , system_continue/3
  20. , system_terminate/4
  21. , system_code_change/4
  22. , system_get_state/1
  23. , system_replace_state/2
  24. , format_status/2
  25. %% Internal callbacks
  26. , wakeupFromHib/8
  27. %% logger callback
  28. , format_log/1, format_log/2
  29. ]).
  30. -define(STACKTRACE(), element(2, erlang:process_info(self(), current_stacktrace))).
  31. %% debug 调试相关宏定义
  32. -define(NOT_DEBUG, []).
  33. -define(SYS_DEBUG(Debug, Name, Msg),
  34. case Debug of
  35. ?NOT_DEBUG ->
  36. Debug;
  37. _ ->
  38. sys:handle_debug(Debug, fun print_event/3, Name, Msg)
  39. end).
  40. -type serverName() ::
  41. {'local', atom()} |
  42. {'global', GlobalName :: term()} |
  43. {'via', RegMod :: module(), Name :: term()}.
  44. -type serverRef() ::
  45. pid()
  46. | (LocalName :: atom())
  47. | {Name :: atom(), Node :: atom()}
  48. | {'global', GlobalName :: term()}
  49. | {'via', RegMod :: module(), ViaName :: term()}.
  50. -type startOpt() ::
  51. {'timeout', Time :: timeout()} |
  52. {'spawn_opt', [proc_lib:spawn_option()]} |
  53. enterLoopOpt().
  54. -type enterLoopOpt() ::
  55. {'debug', Debugs :: [sys:debug_option()]} |
  56. {'hibernate_after', HibernateAfterTimeout :: timeout()}.
  57. -type startRet() ::
  58. 'ignore' |
  59. {'ok', pid()} |
  60. {'ok', {pid(), reference()}} |
  61. {'error', term()}.
  62. -type action() ::
  63. timeout() |
  64. hibernate |
  65. {'doAfter', Args :: term()} |
  66. {'nTimeout', Name :: term(), Time :: timeouts(), TimeoutMsg :: term()} |
  67. {'nTimeout', Name :: term(), Time :: timeouts(), TimeoutMsg :: term(), Options :: ([timeoutOption()])} |
  68. {'uTimeout', Name :: term(), TimeoutMsg :: term()} |
  69. {'cTimeout', Name :: term()}.
  70. -type actions() ::
  71. action() |
  72. [action(), ...].
  73. -type timeouts() :: Time :: timeout() | integer().
  74. -type timeoutOption() :: {abs, Abs :: boolean()}.
  75. %% -type timer() :: #{TimeoutName :: atom() => {TimerRef :: reference(), TimeoutMsg :: term()}}.
  76. %% gen_call:call 发送消息来源进程格式类型
  77. -type from() :: {To :: pid(), Tag :: term()}.
  78. -type requestId() :: term().
  79. -type replyAction() ::
  80. {'reply', From :: from(), Reply :: term()}.
  81. -callback init(Args :: term()) ->
  82. {ok, State :: term()} |
  83. {ok, State :: term(), Actions :: actions()} |
  84. {stop, Reason :: term()} |
  85. ignore.
  86. -callback handleCall(Request :: term(), State :: term(), From :: {pid(), Tag :: term()}) ->
  87. kpS |
  88. {reply, Reply :: term()} |
  89. {reply, Reply :: term(), NewState :: term()} |
  90. {reply, Reply :: term(), NewState :: term(), Actions :: actions()} |
  91. {noreply, NewState :: term()} |
  92. {noreply, NewState :: term(), Actions :: actions()} |
  93. {stop, Reason :: term(), NewState :: term()} |
  94. {stopReply, Reason :: term(), Reply :: term(), NewState :: term()}.
  95. -callback handleCast(Request :: term(), State :: term()) ->
  96. kpS |
  97. {noreply, NewState :: term()} |
  98. {noreply, NewState :: term(), Actions :: actions()} |
  99. {stop, Reason :: term(), NewState :: term()}.
  100. -callback handleInfo(Info :: timeout | term(), State :: term()) ->
  101. kpS |
  102. {noreply, NewState :: term()} |
  103. {noreply, NewState :: term(), Actions :: actions()} |
  104. {stop, Reason :: term(), NewState :: term()}.
  105. -callback handleAfter(Info :: term(), State :: term()) ->
  106. kpS |
  107. {noreply, NewState :: term()} |
  108. {noreply, NewState :: term(), Actions :: actions()} |
  109. {stop, Reason :: term(), NewState :: term()}.
  110. -callback terminate(Reason :: (normal | shutdown | {shutdown, term()} |term()), State :: term()) ->
  111. term().
  112. -callback code_change(OldVsn :: (term() | {down, term()}), State :: term(), Extra :: term()) ->
  113. {ok, NewState :: term()} | {error, Reason :: term()}.
  114. -callback formatStatus(Opt, StatusData) -> Status when
  115. Opt :: 'normal' | 'terminate',
  116. StatusData :: [PDict | State],
  117. PDict :: [{Key :: term(), Value :: term()}],
  118. State :: term(),
  119. Status :: term().
  120. -optional_callbacks([
  121. handleAfter/2
  122. , terminate/2
  123. , code_change/3
  124. , formatStatus/2
  125. ]).
  126. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% start stop API start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  127. -spec start(Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet().
  128. start(Module, Args, Options) ->
  129. gen:start(?MODULE, nolink, Module, Args, Options).
  130. -spec start(ServerName :: serverName(), Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet().
  131. start(ServerName, Module, Args, Options) ->
  132. gen:start(?MODULE, nolink, ServerName, Module, Args, Options).
  133. -spec start_link(Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet().
  134. start_link(Module, Args, Options) ->
  135. gen:start(?MODULE, link, Module, Args, Options).
  136. -spec start_link(ServerName :: serverName(), Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet().
  137. start_link(ServerName, Module, Args, Options) ->
  138. gen:start(?MODULE, link, ServerName, Module, Args, Options).
  139. -spec start_monitor(Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet().
  140. start_monitor(Module, Args, Options) ->
  141. gen:start(?MODULE, monitor, Module, Args, Options).
  142. -spec start_monitor(ServerName :: serverName(), Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet().
  143. start_monitor(ServerName, Module, Args, Options) ->
  144. gen:start(?MODULE, monitor, ServerName, Module, Args, Options).
  145. %%停止通用服务器并等待其终止。如果服务器位于另一个节点上,则将监视该节点。
  146. -spec stop(ServerRef :: serverRef()) -> ok.
  147. stop(ServerRef) ->
  148. gen:stop(ServerRef).
  149. -spec stop(ServerRef :: serverRef(), Reason :: term(), Timeout :: timeout()) -> ok.
  150. stop(ServerRef, Reason, Timeout) ->
  151. gen:stop(ServerRef, Reason, Timeout).
  152. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% start stop API end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  153. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gen callbacks start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  154. doModuleInit(Module, Args) ->
  155. try
  156. Module:init(Args)
  157. catch
  158. throw:Ret -> Ret;
  159. Class:Reason:Strace -> {'EXIT', Class, Reason, Strace}
  160. end.
  161. init_it(Starter, self, ServerRef, Module, Args, Options) ->
  162. init_it(Starter, self(), ServerRef, Module, Args, Options);
  163. init_it(Starter, Parent, ServerRef, Module, Args, Options) ->
  164. Name = gen:name(ServerRef),
  165. Debug = gen:debug_options(Name, Options),
  166. HibernateAfterTimeout = gen:hibernate_after(Options),
  167. case doModuleInit(Module, Args) of
  168. {ok, State} ->
  169. proc_lib:init_ack(Starter, {ok, self()}),
  170. receiveIng(Parent, Name, Module, HibernateAfterTimeout, Debug, #{}, State, false);
  171. {ok, State, Actions} ->
  172. proc_lib:init_ack(Starter, {ok, self()}),
  173. loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, #{}, State, listify(Actions));
  174. {stop, Reason} ->
  175. % 为了保持一致性,我们必须确保在
  176. % %%父进程收到有关失败的通知之前,必须先注销%%注册名称(如果有)。
  177. % %%(否则,如果父进程立即%%再次尝试启动该进程,则其父进程可能会收到%already_started错误)。
  178. gen:unregister_name(ServerRef),
  179. proc_lib:init_ack(Starter, {error, Reason}),
  180. exit(Reason);
  181. ignore ->
  182. gen:unregister_name(ServerRef),
  183. proc_lib:init_ack(Starter, ignore),
  184. exit(normal);
  185. {'EXIT', Class, Reason, Stacktrace} ->
  186. gen:unregister_name(ServerRef),
  187. proc_lib:init_ack(Starter, {error, terminate_reason(Class, Reason, Stacktrace)}),
  188. erlang:raise(Class, Reason, Stacktrace);
  189. _Ret ->
  190. Error = {bad_return_value, _Ret},
  191. proc_lib:init_ack(Starter, {error, Error}),
  192. exit(Error)
  193. end.
  194. %%-----------------------------------------------------------------
  195. %% enter_loop(Module, Options, State, <ServerName>, <TimeOut>) ->_
  196. %%
  197. %% Description: Makes an existing process into a gen_srv.
  198. %% The calling process will enter the gen_srv receive
  199. %% loop and become a gen_srv process.
  200. %% The process *must* have been started using one of the
  201. %% start functions in proc_lib, see proc_lib(3).
  202. %% The user is responsible for any initialization of the
  203. %% process, including registering a name for it.
  204. %%-----------------------------------------------------------------
  205. -spec enter_loop(Module :: module(), State :: term(), Opts :: [enterLoopOpt()]) -> no_return().
  206. enter_loop(Module, State, Opts) ->
  207. enter_loop(Module, State, Opts, self(), infinity).
  208. -spec enter_loop(Module :: module(), State :: term(), Opts :: [enterLoopOpt()], serverName() | pid()) -> no_return().
  209. enter_loop(Module, State, Opts, ServerName) ->
  210. enter_loop(Module, State, Opts, ServerName, infinity).
  211. -spec enter_loop(Module :: module(), State :: term(), Opts :: [enterLoopOpt()], Server :: serverName() | pid(), Actions :: actions()) -> no_return().
  212. enter_loop(Module, State, Opts, ServerName, Actions) ->
  213. Name = gen:get_proc_name(ServerName),
  214. Parent = gen:get_parent(),
  215. Debug = gen:debug_options(Name, Opts),
  216. HibernateAfterTimeout = gen:hibernate_after(Opts),
  217. loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, #{}, State, listify(Actions)).
  218. %%% Internal callbacks
  219. wakeupFromHib(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, IsHib) ->
  220. %% 这是一条新消息,唤醒了我们,因此我们必须立即收到它
  221. receiveIng(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, IsHib).
  222. loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, Actions) ->
  223. case doParseAL(Actions, Name, Debug, false, false, Timers) of
  224. {error, ErrorContent} ->
  225. terminate(error, ErrorContent, ?STACKTRACE(), Name, Module, Debug, Timers, CurState, []);
  226. {NewDebug, IsHib, DoAfter, NewTimers} ->
  227. case DoAfter of
  228. {doAfter, Args} ->
  229. doAfterCall(Parent, Name, Module, HibernateAfterTimeout, NewDebug, NewTimers, CurState, listHib(IsHib), Args);
  230. _ ->
  231. case IsHib of
  232. true ->
  233. proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, Name, Module, HibernateAfterTimeout, NewDebug, NewTimers, CurState, IsHib]);
  234. _ ->
  235. receiveIng(Parent, Name, Module, HibernateAfterTimeout, NewDebug, NewTimers, CurState, false)
  236. end
  237. end
  238. end.
  239. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% sys callbacks start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  240. %%-----------------------------------------------------------------
  241. %% Callback functions for system messages handling.
  242. %%-----------------------------------------------------------------
  243. system_continue(Parent, Debug, {Name, Module, HibernateAfterTimeout, Timers, CurState, IsHib}) ->
  244. case IsHib of
  245. true ->
  246. proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, IsHib]);
  247. _ ->
  248. receiveIng(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, IsHib)
  249. end.
  250. -spec system_terminate(_, _, _, [_]) -> no_return().
  251. system_terminate(Reason, _Parent, Debug, {Name, Module, _HibernateAfterTimeout, Timers, CurState, _IsHib}) ->
  252. terminate(exit, Reason, ?STACKTRACE(), Name, Module, Debug, Timers, CurState, []).
  253. system_code_change({Name, Module, HibernateAfterTimeout, Timers, CurState, IsHib}, _Module, OldVsn, Extra) ->
  254. case
  255. try Module:code_change(OldVsn, CurState, Extra)
  256. catch
  257. throw:Result -> Result;
  258. _C:_R -> {_R, _R}
  259. end
  260. of
  261. {ok, NewState} -> {ok, {Name, Module, HibernateAfterTimeout, Timers, NewState, IsHib}};
  262. Error -> Error
  263. end.
  264. system_get_state({_Name, _Module, _HibernateAfterTimeout, _Timers, CurState, _IsHib}) ->
  265. {ok, CurState}.
  266. system_replace_state(StateFun, {Name, Module, HibernateAfterTimeout, Timers, CurState, IsHib}) ->
  267. NewState = StateFun(CurState),
  268. {ok, NewState, {Name, Module, HibernateAfterTimeout, Timers, NewState, IsHib}}.
  269. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% sys callbacks end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  270. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% API helpers start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  271. %% -----------------------------------------------------------------
  272. %% Make a call to a generic server.
  273. %% If the server is located at another node, that node will
  274. %% be monitored.
  275. %% If the client is trapping exits and is linked server termination
  276. %% is handled here (? Shall we do that here (or rely on timeouts) ?).
  277. -spec call(ServerRef :: serverRef(), Request :: term()) -> Reply :: term().
  278. call(ServerRef, Request) ->
  279. try gen_call:call(ServerRef, '$gen_call', Request) of
  280. {ok, Reply} ->
  281. Reply
  282. catch Class:Reason ->
  283. erlang:raise(Class, {Reason, {?MODULE, call, [ServerRef, Request]}}, ?STACKTRACE())
  284. end.
  285. -spec call(ServerRef :: serverRef(), Request :: term(), Timeout :: timeout()) -> Reply :: term().
  286. call(ServerRef, Request, Timeout) ->
  287. try gen_call:call(ServerRef, '$gen_call', Request, Timeout) of
  288. {ok, Reply} ->
  289. Reply
  290. catch Class:Reason ->
  291. erlang:raise(Class, {Reason, {?MODULE, call, [ServerRef, Request]}}, ?STACKTRACE())
  292. end.
  293. %%% -----------------------------------------------------------------
  294. %%% Make a call to servers at several nodes.
  295. %%% Returns: {[Replies],[BadNodes]}
  296. %%% A Timeout can be given
  297. %%%
  298. %%% A middleman process is used in case late answers arrives after
  299. %%% the timeout. If they would be allowed to glog the callers message
  300. %%% queue, it would probably become confused. Late answers will
  301. %%% now arrive to the terminated middleman and so be discarded.
  302. %%% -----------------------------------------------------------------
  303. multi_call(Name, Request) when is_atom(Name) ->
  304. do_multi_call([node() | nodes()], Name, Request, infinity).
  305. multi_call(Nodes, Name, Request) when is_list(Nodes), is_atom(Name) ->
  306. do_multi_call(Nodes, Name, Request, infinity).
  307. multi_call(Nodes, Name, Request, infinity) ->
  308. do_multi_call(Nodes, Name, Request, infinity);
  309. multi_call(Nodes, Name, Request, Timeout) when is_list(Nodes), is_atom(Name), is_integer(Timeout), Timeout >= 0 ->
  310. do_multi_call(Nodes, Name, Request, Timeout).
  311. do_multi_call([Node], Name, Req, infinity) when Node =:= node() ->
  312. % Special case when multi_call is used with local node only.
  313. % In that case we can leverage the benefit of recv_mark optimisation
  314. % existing in simple gen_call:call.
  315. try gen_call:call(Name, '$gen_call', Req, infinity) of
  316. {ok, Res} -> {[{Node, Res}], []}
  317. catch exit:_ ->
  318. {[], [Node]}
  319. end;
  320. do_multi_call(Nodes, Name, Request, infinity) ->
  321. Tag = make_ref(),
  322. Monitors = send_nodes(Nodes, Name, Tag, Request),
  323. rec_nodes(Tag, Monitors, Name, undefined);
  324. do_multi_call(Nodes, Name, Request, Timeout) ->
  325. Tag = make_ref(),
  326. Caller = self(),
  327. Receiver = spawn(
  328. fun() ->
  329. process_flag(trap_exit, true),
  330. Mref = erlang:monitor(process, Caller),
  331. receive
  332. {Caller, Tag} ->
  333. Monitors = send_nodes(Nodes, Name, Tag, Request),
  334. TimerId = erlang:start_timer(Timeout, self(), ok),
  335. Result = rec_nodes(Tag, Monitors, Name, TimerId),
  336. exit({self(), Tag, Result});
  337. {'DOWN', Mref, _, _, _} ->
  338. exit(normal)
  339. end
  340. end
  341. ),
  342. Mref = erlang:monitor(process, Receiver),
  343. Receiver ! {self(), Tag},
  344. receive
  345. {'DOWN', Mref, _, _, {Receiver, Tag, Result}} ->
  346. Result;
  347. {'DOWN', Mref, _, _, Reason} ->
  348. exit(Reason)
  349. end.
  350. -spec cast(ServerRef :: serverRef(), Msg :: term()) -> ok.
  351. cast({global, Name}, Msg) ->
  352. try global:send(Name, {'$gen_cast', Msg}),
  353. ok
  354. catch _:_ -> ok
  355. end;
  356. cast({via, RegMod, Name}, Msg) ->
  357. try RegMod:send(Name, {'$gen_cast', Msg}),
  358. ok
  359. catch _:_ -> ok
  360. end;
  361. cast(Dest, Msg) ->
  362. try erlang:send(Dest, {'$gen_cast', Msg}),
  363. ok
  364. catch _:_ -> ok
  365. end.
  366. -spec send(ServerRef :: serverRef(), Msg :: term()) -> ok.
  367. send({global, Name}, Msg) ->
  368. try global:send(Name, Msg),
  369. ok
  370. catch _:_ -> ok
  371. end;
  372. send({via, RegMod, Name}, Msg) ->
  373. try RegMod:send(Name, Msg),
  374. ok
  375. catch _:_ -> ok
  376. end;
  377. send(Dest, Msg) ->
  378. try erlang:send(Dest, Msg),
  379. ok
  380. catch _:_ -> ok
  381. end.
  382. %% 异步广播,不返回任何内容,只是发送“ n”祈祷
  383. abcast(Name, Msg) when is_atom(Name) ->
  384. doAbcast([node() | nodes()], Name, Msg).
  385. abcast(Nodes, Name, Msg) when is_list(Nodes), is_atom(Name) ->
  386. doAbcast(Nodes, Name, Msg).
  387. doAbcast(Nodes, Name, Msg) ->
  388. [
  389. begin
  390. try erlang:send({Name, Node}, {'$gen_cast', Msg}),
  391. ok
  392. catch
  393. _:_ -> ok
  394. end
  395. end || Node <- Nodes
  396. ],
  397. ok.
  398. %% -----------------------------------------------------------------
  399. %% Send a reply to the client.
  400. %% -----------------------------------------------------------------
  401. %% Reply from a status machine callback to whom awaits in call/2
  402. -spec reply([replyAction(), ...] | replyAction()) -> ok.
  403. reply({reply, {To, Tag}, Reply}) ->
  404. try To ! {Tag, Reply},
  405. ok
  406. catch _:_ ->
  407. ok
  408. end;
  409. reply(Replies) when is_list(Replies) ->
  410. [
  411. begin
  412. try To ! {Tag, Reply},
  413. ok
  414. catch _:_ ->
  415. ok
  416. end
  417. end || {reply, {To, Tag}, Reply} <- Replies
  418. ],
  419. ok.
  420. -spec reply(From :: from(), Reply :: term()) -> ok.
  421. reply({_To, [alias|Alias] = Tag}, Reply) ->
  422. Alias ! {Tag, Reply},
  423. ok;
  424. reply({To, Tag}, Reply) ->
  425. try To ! {Tag, Reply},
  426. ok
  427. catch _:_ ->
  428. ok
  429. end.
  430. %% -----------------------------------------------------------------
  431. %% Send a request to a generic server and return a Key which should be
  432. %% used with wait_response/2 or check_response/2 to fetch the
  433. %% result of the request.
  434. -spec send_request(Name :: serverRef(), Request :: term()) -> requestId().
  435. send_request(Name, Request) ->
  436. gen:send_request(Name, '$gen_call', Request).
  437. -spec wait_response(RequestId :: requestId(), timeout()) ->
  438. {reply, Reply :: term()} | 'timeout' | {error, {Reason :: term(), serverRef()}}.
  439. wait_response(RequestId, Timeout) ->
  440. gen:wait_response(RequestId, Timeout).
  441. -spec receive_response(RequestId::requestId(), timeout()) -> {reply, Reply::term()} | 'timeout' | {error, {Reason::term(), serverRef()}}.
  442. receive_response(RequestId, Timeout) ->
  443. gen:receive_response(RequestId, Timeout).
  444. -spec check_response(Msg :: term(), RequestId :: requestId()) ->
  445. {reply, Reply :: term()} | 'no_reply' | {error, {Reason :: term(), serverRef()}}.
  446. check_response(Msg, RequestId) ->
  447. gen:check_response(Msg, RequestId).
  448. send_nodes(Nodes, Name, Tag, Request) ->
  449. [
  450. begin
  451. Monitor = start_monitor(Node, Name),
  452. try {Name, Node} ! {'$gen_call', {self(), {Tag, Node}}, Request},
  453. ok
  454. catch _:_ -> ok
  455. end,
  456. Monitor
  457. end || Node <- Nodes, is_atom(Node)
  458. ].
  459. %% Against old nodes:
  460. %% If no reply has been delivered within 2 secs. (per node) check that
  461. %% the server really exists and wait for ever for the answer.
  462. %%
  463. %% Against contemporary nodes:
  464. %% Wait for reply, server 'DOWN', or timeout from TimerId.
  465. rec_nodes(Tag, Nodes, Name, TimerId) ->
  466. rec_nodes(Tag, Nodes, Name, [], [], 2000, TimerId).
  467. rec_nodes(Tag, [{N, R} | Tail], Name, Badnodes, Replies, Time, TimerId) ->
  468. receive
  469. {'DOWN', R, _, _, _} ->
  470. rec_nodes(Tag, Tail, Name, [N | Badnodes], Replies, Time, TimerId);
  471. {{Tag, N}, Reply} -> %% Tag is bound !!!
  472. erlang:demonitor(R, [flush]),
  473. rec_nodes(Tag, Tail, Name, Badnodes,
  474. [{N, Reply} | Replies], Time, TimerId);
  475. {timeout, TimerId, _} ->
  476. erlang:demonitor(R, [flush]),
  477. %% Collect all replies that already have arrived
  478. rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies)
  479. end;
  480. rec_nodes(Tag, [N | Tail], Name, Badnodes, Replies, Time, TimerId) ->
  481. %% R6 node
  482. receive
  483. {nodedown, N} ->
  484. monitor_node(N, false),
  485. rec_nodes(Tag, Tail, Name, [N | Badnodes], Replies, 2000, TimerId);
  486. {{Tag, N}, Reply} -> %% Tag is bound !!!
  487. receive {nodedown, N} -> ok after 0 -> ok end,
  488. monitor_node(N, false),
  489. rec_nodes(Tag, Tail, Name, Badnodes,
  490. [{N, Reply} | Replies], 2000, TimerId);
  491. {timeout, TimerId, _} ->
  492. receive {nodedown, N} -> ok after 0 -> ok end,
  493. monitor_node(N, false),
  494. %% Collect all replies that already have arrived
  495. rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies)
  496. after Time ->
  497. case erpc:call(N, erlang, whereis, [Name]) of
  498. Pid when is_pid(Pid) -> % It exists try again.
  499. rec_nodes(Tag, [N | Tail], Name, Badnodes,
  500. Replies, infinity, TimerId);
  501. _ -> % badnode
  502. receive {nodedown, N} -> ok after 0 -> ok end,
  503. monitor_node(N, false),
  504. rec_nodes(Tag, Tail, Name, [N | Badnodes],
  505. Replies, 2000, TimerId)
  506. end
  507. end;
  508. rec_nodes(_, [], _, Badnodes, Replies, _, TimerId) ->
  509. case catch erlang:cancel_timer(TimerId) of
  510. false -> % It has already sent it's message
  511. receive
  512. {timeout, TimerId, _} -> ok
  513. after 0 ->
  514. ok
  515. end;
  516. _ -> % Timer was cancelled, or TimerId was 'undefined'
  517. ok
  518. end,
  519. {Replies, Badnodes}.
  520. %% Collect all replies that already have arrived
  521. rec_nodes_rest(Tag, [{N, R} | Tail], Name, Badnodes, Replies) ->
  522. receive
  523. {'DOWN', R, _, _, _} ->
  524. rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies);
  525. {{Tag, N}, Reply} -> %% Tag is bound !!!
  526. erlang:demonitor(R, [flush]),
  527. rec_nodes_rest(Tag, Tail, Name, Badnodes, [{N, Reply} | Replies])
  528. after 0 ->
  529. erlang:demonitor(R, [flush]),
  530. rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies)
  531. end;
  532. rec_nodes_rest(Tag, [N | Tail], Name, Badnodes, Replies) ->
  533. %% R6 node
  534. receive
  535. {nodedown, N} ->
  536. monitor_node(N, false),
  537. rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies);
  538. {{Tag, N}, Reply} -> %% Tag is bound !!!
  539. receive {nodedown, N} -> ok after 0 -> ok end,
  540. monitor_node(N, false),
  541. rec_nodes_rest(Tag, Tail, Name, Badnodes, [{N, Reply} | Replies])
  542. after 0 ->
  543. receive {nodedown, N} -> ok after 0 -> ok end,
  544. monitor_node(N, false),
  545. rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies)
  546. end;
  547. rec_nodes_rest(_Tag, [], _Name, Badnodes, Replies) ->
  548. {Replies, Badnodes}.
  549. start_monitor(Node, Name) when is_atom(Node), is_atom(Name) ->
  550. if node() =:= nonode@nohost, Node =/= nonode@nohost ->
  551. Ref = make_ref(),
  552. self() ! {'DOWN', Ref, process, {Name, Node}, noconnection},
  553. {Node, Ref};
  554. true ->
  555. case catch erlang:monitor(process, {Name, Node}) of
  556. {'EXIT', _} ->
  557. %% Remote node is R6
  558. monitor_node(Node, true),
  559. Node;
  560. Ref when is_reference(Ref) ->
  561. {Node, Ref}
  562. end
  563. end.
  564. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% API helpers end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  565. receiveIng(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, IsHib) ->
  566. receive
  567. Msg ->
  568. case Msg of
  569. {'$gen_call', From, Request} ->
  570. matchCallMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, From, Request);
  571. {'$gen_cast', Cast} ->
  572. matchCastMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, Cast);
  573. {timeout, TimerRef, TimeoutName} ->
  574. case Timers of
  575. #{TimeoutName := {TimerRef, TimeoutMsg}} ->
  576. NewTimer = maps:remove(TimeoutName, Timers),
  577. matchInfoMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, NewTimer, CurState, TimeoutMsg);
  578. _ ->
  579. matchInfoMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, Msg)
  580. end;
  581. {system, PidFrom, Request} ->
  582. %% 不返回但尾递归调用 system_continue/3
  583. sys:handle_system_msg(Request, PidFrom, Parent, ?MODULE, Debug, {Name, Module, HibernateAfterTimeout, Timers, CurState, IsHib}, IsHib);
  584. {'EXIT', Parent, Reason} ->
  585. terminate(exit, Reason, ?STACKTRACE(), Name, Module, Debug, Timers, CurState, Msg);
  586. _ ->
  587. matchInfoMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, Msg)
  588. end
  589. after HibernateAfterTimeout ->
  590. proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState])
  591. end.
  592. matchCallMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, From, Request) ->
  593. NewDebug = ?SYS_DEBUG(Debug, Name, {in, {{call, From}, Request}}),
  594. try Module:handleCall(Request, CurState, From) of
  595. Result ->
  596. handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, From)
  597. catch
  598. throw:Result ->
  599. handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, From);
  600. Class:Reason:Strace ->
  601. terminate(Class, Reason, Strace, Name, Module, NewDebug, Timers, CurState, {{call, From}, Request})
  602. end.
  603. matchCastMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, Cast) ->
  604. NewDebug = ?SYS_DEBUG(Debug, Name, {in, {cast, Cast}}),
  605. try Module:handleCast(Cast, CurState) of
  606. Result ->
  607. handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, false)
  608. catch
  609. throw:Result ->
  610. handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, false);
  611. Class:Reason:Strace ->
  612. terminate(Class, Reason, Strace, Name, Module, NewDebug, Timers, CurState, {cast, Cast})
  613. end.
  614. matchInfoMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, Msg) ->
  615. NewDebug = ?SYS_DEBUG(Debug, Name, {in, {info, Msg}}),
  616. try Module:handleInfo(Msg, CurState) of
  617. Result ->
  618. handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, false)
  619. catch
  620. throw:Result ->
  621. handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, false);
  622. Class:Reason:Strace ->
  623. terminate(Class, Reason, Strace, Name, Module, NewDebug, Timers, CurState, {info, Msg})
  624. end.
  625. doAfterCall(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, LeftAction, Args) ->
  626. NewDebug = ?SYS_DEBUG(Debug, Name, {in, {doAfter, Args}}),
  627. try Module:handleAfter(Args, CurState) of
  628. Result ->
  629. handleAR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, LeftAction, Result)
  630. catch
  631. throw:Result ->
  632. handleAR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, LeftAction, Result);
  633. Class:Reason:Strace ->
  634. terminate(Class, Reason, Strace, Name, Module, NewDebug, Timers, CurState, {doAfter, Args})
  635. end.
  636. handleCR(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, Result, From) ->
  637. case Result of
  638. kpS ->
  639. receiveIng(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, false);
  640. {reply, Reply} ->
  641. reply(From, Reply),
  642. NewDebug = ?SYS_DEBUG(Debug, Name, {out, Reply, From, CurState}),
  643. receiveIng(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, false);
  644. {noreply, NewState} ->
  645. receiveIng(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, NewState, false);
  646. {reply, Reply, NewState} ->
  647. reply(From, Reply),
  648. NewDebug = ?SYS_DEBUG(Debug, Name, {out, Reply, From, NewState}),
  649. receiveIng(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, NewState, false);
  650. {noreply, NewState, Actions} ->
  651. loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, NewState, listify(Actions));
  652. {stop, Reason, NewState} ->
  653. terminate(exit, Reason, ?STACKTRACE(), Name, Module, Debug, Timers, NewState, {return, stop});
  654. {reply, Reply, NewState, Actions} ->
  655. reply(From, Reply),
  656. NewDebug = ?SYS_DEBUG(Debug, Name, {out, Reply, From, NewState}),
  657. loopEntry(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, NewState, listify(Actions));
  658. {stopReply, Reason, Reply, NewState} ->
  659. NewDebug = ?SYS_DEBUG(Debug, Name, {out, Reply, From, NewState}),
  660. try
  661. terminate(exit, Reason, ?STACKTRACE(), Name, Module, NewDebug, Timers, NewState, {return, stop_reply})
  662. after
  663. _ = reply(From, Reply)
  664. end
  665. end.
  666. handleAR(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, LeftAction, Result) ->
  667. case Result of
  668. kpS ->
  669. loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, LeftAction);
  670. {noreply, NewState} ->
  671. loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, NewState, LeftAction);
  672. {noreply, NewState, Actions} ->
  673. loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, NewState, listify(Actions) ++ LeftAction);
  674. {stop, Reason, NewState} ->
  675. terminate(exit, Reason, ?STACKTRACE(), Name, Module, Debug, Timers, NewState, {return, stop_reply})
  676. end.
  677. %% loopParseActionsList
  678. doParseAL([], _Name, Debug, IsHib, DoAfter, Timers) ->
  679. {Debug, IsHib, DoAfter, Timers};
  680. doParseAL([OneAction | LeftActions], Name, Debug, IsHib, DoAfter, Timers) ->
  681. case OneAction of
  682. hibernate ->
  683. doParseAL(LeftActions, Name, Debug, true, DoAfter, Timers);
  684. {'doAfter', _Args} ->
  685. doParseAL(LeftActions, Name, Debug, IsHib, OneAction, Timers);
  686. {'nTimeout', TimeoutName, Time, TimeoutMsg, Options} ->
  687. case Time of
  688. infinity ->
  689. NewTimers = doCancelTimer(TimeoutName, Timers),
  690. doParseAL(LeftActions, Name, Debug, IsHib, DoAfter, NewTimers);
  691. _ ->
  692. TimerRef = erlang:start_timer(Time, self(), TimeoutName, Options),
  693. NewDebug = ?SYS_DEBUG(Debug, Name, {start_timer, {TimeoutName, Time, TimeoutMsg, Options}}),
  694. NewTimers = doRegisterTimer(TimeoutName, TimerRef, TimeoutMsg, Timers),
  695. doParseAL(LeftActions, Name, NewDebug, IsHib, DoAfter, NewTimers)
  696. end;
  697. {'nTimeout', TimeoutName, Time, TimeoutMsg} ->
  698. case Time of
  699. infinity ->
  700. NewTimers = doCancelTimer(TimeoutName, Timers),
  701. doParseAL(LeftActions, Name, Debug, IsHib, DoAfter, NewTimers);
  702. _ ->
  703. TimerRef = erlang:start_timer(Time, self(), TimeoutName),
  704. NewDebug = ?SYS_DEBUG(Debug, Name, {start_timer, {TimeoutName, Time, TimeoutMsg, []}}),
  705. NewTimers = doRegisterTimer(TimeoutName, TimerRef, TimeoutMsg, Timers),
  706. doParseAL(LeftActions, Name, NewDebug, IsHib, DoAfter, NewTimers)
  707. end;
  708. {'uTimeout', TimeoutName, NewTimeoutMsg} ->
  709. NewTimers = doUpdateTimer(TimeoutName, NewTimeoutMsg, Timers),
  710. doParseAL(LeftActions, Name, Debug, IsHib, DoAfter, NewTimers);
  711. {'cTimeout', TimeoutName} ->
  712. NewTimers = doCancelTimer(TimeoutName, Timers),
  713. doParseAL(LeftActions, Name, Debug, IsHib, DoAfter, NewTimers);
  714. infinity ->
  715. doParseAL(LeftActions, Name, Debug, IsHib, DoAfter, Timers);
  716. Timeout when is_integer(Timeout) ->
  717. erlang:send_after(Timeout, self(), timeout),
  718. NewDebug = ?SYS_DEBUG(Debug, Name, {start_timer, {timeout, Timeout, timeout, []}}),
  719. doParseAL(LeftActions, Name, NewDebug, IsHib, DoAfter, Timers);
  720. _ ->
  721. {error, {bad_ActionType, OneAction}}
  722. end.
  723. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% timer deal start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  724. doRegisterTimer(TimeoutType, NewTimerRef, TimeoutMsg, Timers) ->
  725. case Timers of
  726. #{TimeoutType := {OldTimerRef, _OldTimeMsg}} ->
  727. justCancelTimer(TimeoutType, OldTimerRef),
  728. Timers#{TimeoutType := {NewTimerRef, TimeoutMsg}};
  729. _ ->
  730. Timers#{TimeoutType => {NewTimerRef, TimeoutMsg}}
  731. end.
  732. doCancelTimer(TimeoutType, Timers) ->
  733. case Timers of
  734. #{TimeoutType := {TimerRef, _TimeoutMsg}} ->
  735. cancelTimer(TimeoutType, TimerRef, Timers);
  736. _ ->
  737. Timers
  738. end.
  739. doUpdateTimer(TimeoutType, Timers, TimeoutMsg) ->
  740. case Timers of
  741. #{TimeoutType := {TimerRef, _OldTimeoutMsg}} ->
  742. Timers#{TimeoutType := {TimerRef, TimeoutMsg}};
  743. _ ->
  744. Timers
  745. end.
  746. justCancelTimer(TimeoutType, TimerRef) ->
  747. case erlang:cancel_timer(TimerRef) of
  748. false ->
  749. %% 找不到计时器,我们还没有看到超时消息
  750. receive
  751. {timeout, TimerRef, TimeoutType} ->
  752. %% 丢弃该超时消息
  753. ok
  754. after 0 ->
  755. ok
  756. end;
  757. _ ->
  758. %% Timer 已经运行了
  759. ok
  760. end.
  761. cancelTimer(TimeoutType, TimerRef, Timers) ->
  762. case erlang:cancel_timer(TimerRef) of
  763. false -> % 找不到计时器,我们还没有看到超时消息
  764. receive
  765. {timeout, TimerRef, TimeoutType} ->
  766. ok % 丢弃该超时消息
  767. after 0 ->
  768. ok
  769. end;
  770. _ ->
  771. ok % Timer 已经运行了
  772. end,
  773. maps:remove(TimeoutType, Timers).
  774. listify(Item) when is_list(Item) ->
  775. Item;
  776. listify(Item) ->
  777. [Item].
  778. listHib(false) ->
  779. [];
  780. listHib(_) ->
  781. [hibernate].
  782. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% timer deal end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  783. %%% ---------------------------------------------------
  784. %%% Terminate the server.
  785. %%%
  786. %%% terminate/8 is triggered by {stop, Reason} or bad
  787. %%% return values. The stacktrace is generated via the
  788. %%% ?STACKTRACE() macro and the ReportReason must not
  789. %%% be wrapped in tuples.
  790. %%%
  791. %%% terminate/9 is triggered in case of error/exit in
  792. %%% the user callback. In this case the report reason
  793. %%% always includes the user stacktrace.
  794. %%%
  795. %%% The reason received in the terminate/2 callbacks
  796. %%% always includes the stacktrace for errors and never
  797. %%% for exits.
  798. %%% ---------------------------------------------------
  799. terminate(Class, Reason, Stacktrace, Name, Module, Debug, _Timers, CurState, MsgEvent) ->
  800. Reply = try_terminate(Module, terminate_reason(Class, Reason, Stacktrace), CurState),
  801. case Reply of
  802. {'EXIT', C, R, S} ->
  803. error_info({R, S}, Name, undefined, MsgEvent, Module, Debug, CurState),
  804. erlang:raise(C, R, S);
  805. _ ->
  806. case {Class, Reason} of
  807. {exit, normal} -> ok;
  808. {exit, shutdown} -> ok;
  809. {exit, {shutdown, _}} -> ok;
  810. _ ->
  811. error_info(Reason, Name, undefined, MsgEvent, Module, Debug, CurState)
  812. end
  813. end,
  814. case Stacktrace of
  815. [] ->
  816. erlang:Class(Reason);
  817. _ ->
  818. erlang:raise(Class, Reason, Stacktrace)
  819. end.
  820. try_terminate(Mod, Reason, State) ->
  821. case erlang:function_exported(Mod, terminate, 2) of
  822. true ->
  823. try
  824. {ok, Mod:terminate(Reason, State)}
  825. catch
  826. throw:R ->
  827. {ok, R};
  828. Class:R ->
  829. {'EXIT', Class, R, ?STACKTRACE()}
  830. end;
  831. false ->
  832. {ok, ok}
  833. end.
  834. terminate_reason(error, Reason, Stacktrace) -> {Reason, Stacktrace};
  835. terminate_reason(exit, Reason, _Stacktrace) -> Reason.
  836. error_info(_Reason, application_controller, _From, _Msg, _Mod, _State, _Debug) ->
  837. %% OTP-5811 Don't send an error report if it's the system process
  838. %% application_controller which is terminating - let init take care
  839. %% of it instead
  840. ok;
  841. error_info(Reason, Name, From, Msg, Module, Debug, State) ->
  842. Log = sys:get_log(Debug),
  843. ?LOG_ERROR(#{label => {gen_srv, terminate},
  844. name => Name,
  845. last_message => Msg,
  846. state => format_status(terminate, Module, get(), State),
  847. log => format_log_state(Module, Log),
  848. reason => Reason,
  849. client_info => client_stacktrace(From)},
  850. #{
  851. domain => [otp],
  852. report_cb => fun gen_srv:format_log/2,
  853. error_logger => #{tag => error, report_cb => fun gen_srv:format_log/1}
  854. }),
  855. ok.
  856. client_stacktrace(undefined) ->
  857. undefined;
  858. client_stacktrace({From, _Tag}) ->
  859. client_stacktrace(From);
  860. client_stacktrace(From) when is_pid(From), node(From) =:= node() ->
  861. case process_info(From, [current_stacktrace, registered_name]) of
  862. undefined ->
  863. {From, dead};
  864. [{current_stacktrace, Stacktrace}, {registered_name, []}] ->
  865. {From, {From, Stacktrace}};
  866. [{current_stacktrace, Stacktrace}, {registered_name, Name}] ->
  867. {From, {Name, Stacktrace}}
  868. end;
  869. client_stacktrace(From) when is_pid(From) ->
  870. {From, remote}.
  871. %% format_log/1 is the report callback used by Logger handler
  872. %% error_logger only. It is kept for backwards compatibility with
  873. %% legacy error_logger event handlers. This function must always
  874. %% return {Format,Args} compatible with the arguments in this module's
  875. %% calls to error_logger prior to OTP-21.0.
  876. format_log(Report) ->
  877. Depth = error_logger:get_format_depth(),
  878. FormatOpts = #{chars_limit => unlimited,
  879. depth => Depth,
  880. single_line => false,
  881. encoding => utf8},
  882. format_log_multi(limit_report(Report, Depth), FormatOpts).
  883. limit_report(Report, unlimited) ->
  884. Report;
  885. limit_report(#{label := {gen_srv, terminate},
  886. last_message := Msg,
  887. state := State,
  888. log := Log,
  889. reason := Reason,
  890. client_info := Client} = Report,
  891. Depth) ->
  892. Report#{
  893. last_message => io_lib:limit_term(Msg, Depth),
  894. state => io_lib:limit_term(State, Depth),
  895. log => [io_lib:limit_term(L, Depth) || L <- Log],
  896. reason => io_lib:limit_term(Reason, Depth),
  897. client_info => limit_client_report(Client, Depth)
  898. };
  899. limit_report(#{label := {gen_srv, no_handle_info},
  900. message := Msg} = Report, Depth) ->
  901. Report#{message => io_lib:limit_term(Msg, Depth)}.
  902. limit_client_report({From, {Name, Stacktrace}}, Depth) ->
  903. {From, {Name, io_lib:limit_term(Stacktrace, Depth)}};
  904. limit_client_report(Client, _) ->
  905. Client.
  906. %% format_log/2 is the report callback for any Logger handler, except
  907. %% error_logger.
  908. format_log(Report, FormatOpts0) ->
  909. Default = #{chars_limit => unlimited,
  910. depth => unlimited,
  911. single_line => false,
  912. encoding => utf8},
  913. FormatOpts = maps:merge(Default, FormatOpts0),
  914. IoOpts =
  915. case FormatOpts of
  916. #{chars_limit := unlimited} ->
  917. [];
  918. #{chars_limit := Limit} ->
  919. [{chars_limit, Limit}]
  920. end,
  921. {Format, Args} = format_log_single(Report, FormatOpts),
  922. io_lib:format(Format, Args, IoOpts).
  923. format_log_single(#{label := {gen_srv, terminate},
  924. name := Name,
  925. last_message := Msg,
  926. state := State,
  927. log := Log,
  928. reason := Reason,
  929. client_info := Client},
  930. #{single_line := true, depth := Depth} = FormatOpts) ->
  931. P = p(FormatOpts),
  932. Format1 = lists:append(["Generic server ", P, " terminating. Reason: ", P,
  933. ". Last message: ", P, ". State: ", P, "."]),
  934. {ServerLogFormat, ServerLogArgs} = format_server_log_single(Log, FormatOpts),
  935. {ClientLogFormat, ClientLogArgs} = format_client_log_single(Client, FormatOpts),
  936. Args1 =
  937. case Depth of
  938. unlimited ->
  939. [Name, fix_reason(Reason), Msg, State];
  940. _ ->
  941. [Name, Depth, fix_reason(Reason), Depth, Msg, Depth, State, Depth]
  942. end,
  943. {Format1 ++ ServerLogFormat ++ ClientLogFormat,
  944. Args1 ++ ServerLogArgs ++ ClientLogArgs};
  945. format_log_single(#{label := {gen_srv, no_handle_info},
  946. module := Module,
  947. message := Msg},
  948. #{single_line := true, depth := Depth} = FormatOpts) ->
  949. P = p(FormatOpts),
  950. Format = lists:append(["Undefined handle_info in ", P,
  951. ". Unhandled message: ", P, "."]),
  952. Args =
  953. case Depth of
  954. unlimited ->
  955. [Module, Msg];
  956. _ ->
  957. [Module, Depth, Msg, Depth]
  958. end,
  959. {Format, Args};
  960. format_log_single(Report, FormatOpts) ->
  961. format_log_multi(Report, FormatOpts).
  962. format_log_multi(#{label := {gen_srv, terminate},
  963. name := Name,
  964. last_message := Msg,
  965. state := State,
  966. log := Log,
  967. reason := Reason,
  968. client_info := Client},
  969. #{depth := Depth} = FormatOpts) ->
  970. Reason1 = fix_reason(Reason),
  971. {ClientFmt, ClientArgs} = format_client_log(Client, FormatOpts),
  972. P = p(FormatOpts),
  973. Format =
  974. lists:append(
  975. ["** Generic server ", P, " terminating \n"
  976. "** Last message in was ", P, "~n"
  977. "** When Server state == ", P, "~n"
  978. "** Reason for termination ==~n** ", P, "~n"] ++
  979. case Log of
  980. [] -> [];
  981. _ -> ["** Log ==~n** [" |
  982. lists:join(",~n ", lists:duplicate(length(Log), P))] ++
  983. ["]~n"]
  984. end) ++ ClientFmt,
  985. Args =
  986. case Depth of
  987. unlimited ->
  988. [Name, Msg, State, Reason1] ++ Log ++ ClientArgs;
  989. _ ->
  990. [Name, Depth, Msg, Depth, State, Depth, Reason1, Depth] ++
  991. case Log of
  992. [] -> [];
  993. _ -> lists:flatmap(fun(L) -> [L, Depth] end, Log)
  994. end ++ ClientArgs
  995. end,
  996. {Format, Args};
  997. format_log_multi(#{label := {gen_srv, no_handle_info},
  998. module := Module,
  999. message := Msg},
  1000. #{depth := Depth} = FormatOpts) ->
  1001. P = p(FormatOpts),
  1002. Format =
  1003. "** Undefined handle_info in ~p~n"
  1004. "** Unhandled message: " ++ P ++ "~n",
  1005. Args =
  1006. case Depth of
  1007. unlimited ->
  1008. [Module, Msg];
  1009. _ ->
  1010. [Module, Msg, Depth]
  1011. end,
  1012. {Format, Args}.
  1013. fix_reason({undef, [{M, F, A, L} | MFAs]} = Reason) ->
  1014. case code:is_loaded(M) of
  1015. false ->
  1016. {'module could not be loaded', [{M, F, A, L} | MFAs]};
  1017. _ ->
  1018. case erlang:function_exported(M, F, length(A)) of
  1019. true ->
  1020. Reason;
  1021. false ->
  1022. {'function not exported', [{M, F, A, L} | MFAs]}
  1023. end
  1024. end;
  1025. fix_reason(Reason) ->
  1026. Reason.
  1027. format_server_log_single([], _) ->
  1028. {"", []};
  1029. format_server_log_single(Log, FormatOpts) ->
  1030. Args =
  1031. case maps:get(depth, FormatOpts) of
  1032. unlimited ->
  1033. [Log];
  1034. Depth ->
  1035. [Log, Depth]
  1036. end,
  1037. {" Log: " ++ p(FormatOpts), Args}.
  1038. format_client_log_single(undefined, _) ->
  1039. {"", []};
  1040. format_client_log_single({From, dead}, _) ->
  1041. {" Client ~0p is dead.", [From]};
  1042. format_client_log_single({From, remote}, _) ->
  1043. {" Client ~0p is remote on node ~0p.", [From, node(From)]};
  1044. format_client_log_single({_From, {Name, Stacktrace0}}, FormatOpts) ->
  1045. P = p(FormatOpts),
  1046. %% Minimize the stacktrace a bit for single line reports. This is
  1047. %% hopefully enough to point out the position.
  1048. Stacktrace = lists:sublist(Stacktrace0, 4),
  1049. Args =
  1050. case maps:get(depth, FormatOpts) of
  1051. unlimited ->
  1052. [Name, Stacktrace];
  1053. Depth ->
  1054. [Name, Depth, Stacktrace, Depth]
  1055. end,
  1056. {" Client " ++ P ++ " stacktrace: " ++ P ++ ".", Args}.
  1057. format_client_log(undefined, _) ->
  1058. {"", []};
  1059. format_client_log({From, dead}, _) ->
  1060. {"** Client ~p is dead~n", [From]};
  1061. format_client_log({From, remote}, _) ->
  1062. {"** Client ~p is remote on node ~p~n", [From, node(From)]};
  1063. format_client_log({_From, {Name, Stacktrace}}, FormatOpts) ->
  1064. P = p(FormatOpts),
  1065. Format = lists:append(["** Client ", P, " stacktrace~n",
  1066. "** ", P, "~n"]),
  1067. Args =
  1068. case maps:get(depth, FormatOpts) of
  1069. unlimited ->
  1070. [Name, Stacktrace];
  1071. Depth ->
  1072. [Name, Depth, Stacktrace, Depth]
  1073. end,
  1074. {Format, Args}.
  1075. p(#{single_line := Single, depth := Depth, encoding := Enc}) ->
  1076. "~" ++ single(Single) ++ mod(Enc) ++ p(Depth);
  1077. p(unlimited) ->
  1078. "p";
  1079. p(_Depth) ->
  1080. "P".
  1081. single(true) -> "0";
  1082. single(false) -> "".
  1083. mod(latin1) -> "";
  1084. mod(_) -> "t".
  1085. %%-----------------------------------------------------------------
  1086. %% Status information
  1087. %%-----------------------------------------------------------------
  1088. format_status(Opt, StatusData) ->
  1089. [PDict, SysState, Parent, Debug, {Name, Module, _HibernateAfterTimeout, _Timers, CurState, _IsHib}] = StatusData,
  1090. Header = gen:format_status_header("Status for generic server", Name),
  1091. Log = sys:get_log(Debug),
  1092. Specific =
  1093. case format_status(Opt, Module, PDict, CurState) of
  1094. S when is_list(S) -> S;
  1095. S -> [S]
  1096. end,
  1097. [{header, Header},
  1098. {data, [{"Status", SysState},
  1099. {"Parent", Parent},
  1100. {"Logged events", format_log_state(Module, Log)}]} |
  1101. Specific].
  1102. format_log_state(Module, Log) ->
  1103. [case Event of
  1104. {out, Msg, From, State} ->
  1105. {out, Msg, From, format_status(terminate, Module, get(), State)};
  1106. {noreply, State} ->
  1107. {noreply, format_status(terminate, Module, get(), State)};
  1108. _ -> Event
  1109. end || Event <- Log].
  1110. format_status(Opt, Module, PDict, State) ->
  1111. DefStatus =
  1112. case Opt of
  1113. terminate -> State;
  1114. _ -> [{data, [{"State", State}]}]
  1115. end,
  1116. case erlang:function_exported(Module, format_status, 2) of
  1117. true ->
  1118. case catch Module:formatStatus(Opt, [PDict, State]) of
  1119. {'EXIT', _} -> DefStatus;
  1120. Else -> Else
  1121. end;
  1122. _ ->
  1123. DefStatus
  1124. end.
  1125. %%-----------------------------------------------------------------
  1126. %% Format debug messages. Print them as the call-back module sees
  1127. %% them, not as the real erlang messages. Use trace for that.
  1128. %%-----------------------------------------------------------------
  1129. print_event(Dev, {in, Msg}, Name) ->
  1130. case Msg of
  1131. {{call, {From, _Tag}}, Call} ->
  1132. io:format(Dev, "*DBG* ~tp got call ~tp from ~tw~n",
  1133. [Name, Call, From]);
  1134. {cast, Cast} ->
  1135. io:format(Dev, "*DBG* ~tp got cast ~tp~n",
  1136. [Name, Cast]);
  1137. _ ->
  1138. io:format(Dev, "*DBG* ~tp got ~tp~n", [Name, Msg])
  1139. end;
  1140. print_event(Dev, {out, Msg, {To, _Tag}, State}, Name) ->
  1141. io:format(Dev, "*DBG* ~tp sent ~tp to ~tw, new state ~tp~n",
  1142. [Name, Msg, To, State]);
  1143. print_event(Dev, {noreply, State}, Name) ->
  1144. io:format(Dev, "*DBG* ~tp new state ~tp~n", [Name, State]);
  1145. print_event(Dev, Event, Name) ->
  1146. io:format(Dev, "*DBG* ~tp dbg ~tp~n", [Name, Event]).