各种有用的erlang行为
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1569 lines
52 KiB

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