各种有用的erlang行为
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

958 行
33 KiB

4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
  1. -module(gen_emm).
  2. -compile(inline).
  3. -compile({inline_size, 128}).
  4. -include_lib("kernel/include/logger.hrl").
  5. -include("genGbh.hrl").
  6. -import(maps, [iterator/1, next/1]).
  7. -import(gen_call, [gcall/3, gcall/4, greply/2, try_greply/2]).
  8. -export([
  9. %% API for gen_emm
  10. start/0, start/1, start/2, start_link/0, start_link/1, start_link/2
  11. , start_monitor/0, start_monitor/1, start_monitor/2
  12. , stop/1, stop/3
  13. , call/3, call/4
  14. , send/3
  15. , send_request/3, wait_response/2, receive_response/2, check_response/2
  16. , info_notify/2, call_notify/2
  17. , add_epm/3, add_sup_epm/3, del_epm/3
  18. , swap_epm/3, swap_sup_epm/3
  19. , which_epm/1
  20. %% gen callbacks
  21. , init_it/6
  22. %% sys callbacks
  23. , system_continue/3
  24. , system_terminate/4
  25. , system_code_change/4
  26. , system_get_state/1
  27. , system_replace_state/2
  28. , format_status/2
  29. %% Internal callbacks
  30. , wakeupFromHib/5
  31. %% logger callback
  32. , format_log/1, format_log/2, print_event/3
  33. ]).
  34. -define(STACKTRACE(), element(2, erlang:process_info(self(), current_stacktrace))).
  35. -type epmHandler() ::
  36. atom() |
  37. {atom(), term()}.
  38. -type terminateArgs() ::
  39. term() |
  40. stop |
  41. removeEpm |
  42. {error, term()} |
  43. {stop, Reason :: term()} |
  44. {error, {'EXIT', Reason :: term()}}.
  45. -export_type([addEpmRet/0, delEpmRet/0]).
  46. -type addEpmRet() ::
  47. ok |
  48. term() |
  49. {'EXIT', term()}.
  50. -type delEpmRet() ::
  51. ok |
  52. term() |
  53. {'EXIT', term()}.
  54. -type serverName() ::
  55. {'local', atom()} |
  56. {'global', term()} |
  57. {'via', atom(), term()}.
  58. -type serverRef() ::
  59. pid() |
  60. (LocalName :: atom())|
  61. {Name :: atom(), Node :: atom()} |
  62. {'global', term()} |
  63. {'via', atom(), term()}.
  64. -type debug_flag() ::
  65. 'trace' |
  66. 'log' |
  67. 'statistics' |
  68. 'debug'|
  69. {'logfile', string()}.
  70. -type startOpt() ::
  71. {'timeout', timeout()} |
  72. {'debug', [debug_flag()]} |
  73. {'spawn_opt', [proc_lib:start_spawn_option()]} |
  74. {'hibernate_after', timeout()}.
  75. -type startRet() ::
  76. {'ok', pid()} |
  77. {'ok', {pid(), reference()}} |
  78. {'error', term()}.
  79. -type from() :: {To :: pid(), Tag :: term()}.
  80. -type requestId() :: term().
  81. -record(epmHer, {
  82. epmId = undefined :: term(),
  83. epmM :: atom(),
  84. epmSup = undefined :: 'undefined' | pid(),
  85. epmS :: term()
  86. }).
  87. -callback init(InitArgs :: term()) ->
  88. {ok, State :: term()} |
  89. {ok, State :: term(), hibernate} |
  90. {error, Reason :: term()}.
  91. -callback handleEvent(Event :: term(), State :: term()) ->
  92. kpS |
  93. removeEpm |
  94. {noreply, NewState :: term()} |
  95. {noreply, NewState :: term(), hibernate} |
  96. {swapEpm, NewState :: term(), Args1 :: term(), NewHandler :: epmHandler(), Args2 :: term()}.
  97. -callback handleCall(Request :: term(), State :: term()) ->
  98. {removeEpm, Reply :: term()} |
  99. {reply, Reply :: term()} |
  100. {reply, Reply :: term(), NewState :: term()} |
  101. {reply, Reply :: term(), NewState :: term(), hibernate} |
  102. {swapEpm, Reply :: term(), NewState :: term(), Args1 :: term(), NewHandler :: epmHandler(), Args2 :: term()}.
  103. -callback handleInfo(Info :: term(), State :: term()) ->
  104. kpS |
  105. removeEpm |
  106. {noreply, NewState :: term()} |
  107. {noreply, NewState :: term(), hibernate} |
  108. {swapEpm, NewState :: term(), Args1 :: term(), NewHandler :: epmHandler(), Args2 :: term()}.
  109. -callback terminate(Args :: terminateArgs(), State :: term()) ->
  110. term().
  111. -callback code_change(OldVsn :: (term() | {down, term()}), State :: term(), Extra :: term()) ->
  112. {ok, NewState :: term()}.
  113. -callback format_status(Opt, StatusData) -> Status when
  114. Opt :: 'normal' | 'terminate',
  115. StatusData :: [PDict | State],
  116. PDict :: [{Key :: term(), Value :: term()}],
  117. State :: term(),
  118. Status :: term().
  119. -optional_callbacks([
  120. handleInfo/2
  121. , terminate/2
  122. , code_change/3
  123. , format_status/2
  124. ]).
  125. -spec start() -> startRet().
  126. start() ->
  127. gen:start(?MODULE, nolink, ?MODULE, [], []).
  128. -spec start(ServerName :: serverName() | [startOpt()]) -> startRet().
  129. start(ServerName) when is_tuple(ServerName) ->
  130. gen:start(?MODULE, nolink, ServerName, ?MODULE, [], []);
  131. start(Opts) when is_list(Opts) ->
  132. gen:start(?MODULE, nolink, ?MODULE, [], Opts).
  133. -spec start(ServerName :: serverName(), Opts :: [startOpt()]) -> startRet().
  134. start(ServerName, Opts) ->
  135. gen:start(?MODULE, nolink, ServerName, ?MODULE, [], Opts).
  136. -spec start_link() -> startRet().
  137. start_link() ->
  138. gen:start(?MODULE, link, ?MODULE, [], []).
  139. -spec start_link(ServerName :: serverName() | [startOpt()]) -> startRet().
  140. start_link(ServerName) when is_tuple(ServerName) ->
  141. gen:start(?MODULE, link, ServerName, ?MODULE, [], []);
  142. start_link(Opts) when is_list(Opts) ->
  143. gen:start(?MODULE, link, ?MODULE, [], Opts).
  144. -spec start_link(ServerName :: serverName(), Opts :: [startOpt()]) -> startRet().
  145. start_link(ServerName, Opts) ->
  146. gen:start(?MODULE, link, ServerName, ?MODULE, [], Opts).
  147. -spec start_monitor() -> startRet().
  148. start_monitor() ->
  149. gen:start(?MODULE, monitor, ?MODULE, [], []).
  150. -spec start_monitor(ServerName :: serverName() | [startOpt()]) -> startRet().
  151. start_monitor(ServerName) when is_tuple(ServerName) ->
  152. gen:start(?MODULE, monitor, ServerName, ?MODULE, [], []);
  153. start_monitor(Opts) when is_list(Opts) ->
  154. gen:start(?MODULE, monitor, ?MODULE, [], Opts).
  155. -spec start_monitor(ServerName :: serverName(), Opts :: [startOpt()]) -> startRet().
  156. start_monitor(ServerName, Opts) ->
  157. gen:start(?MODULE, monitor, ServerName, ?MODULE, [], Opts).
  158. -spec stop(ServerRef :: serverRef()) -> 'ok'.
  159. stop(ServerRef) ->
  160. gen:stop(ServerRef).
  161. -spec stop(ServerRef :: serverRef(), Reason :: term(), Timeout :: timeout()) -> ok.
  162. stop(ServerRef, Reason, Timeout) ->
  163. gen:stop(ServerRef, Reason, Timeout).
  164. %% -spec init_it(pid(), 'self' | pid(), emgr_name(), module(), [term()], [_]) ->
  165. init_it(Starter, self, ServerRef, Mod, Args, Options) ->
  166. init_it(Starter, self(), ServerRef, Mod, Args, Options);
  167. init_it(Starter, Parent, ServerRef, _, _, Options) ->
  168. process_flag(trap_exit, true),
  169. Name = gen:name(ServerRef),
  170. Debug = gen:debug_options(Name, Options),
  171. HibernateAfterTimeout = gen:hibernate_after(Options),
  172. proc_lib:init_ack(Starter, {ok, self()}),
  173. receiveIng(Parent, Name, HibernateAfterTimeout, #{}, Debug, false).
  174. -spec add_epm(serverRef(), epmHandler(), term()) -> ok | {error, existed} | {error, term()}.
  175. add_epm(EpmSrv, EpmHandler, Args) ->
  176. epmRpc(EpmSrv, {'$addEpm', EpmHandler, Args}).
  177. -spec add_sup_epm(serverRef(), epmHandler(), term()) -> ok | {error, existed} | {error, term()}.
  178. add_sup_epm(EpmSrv, EpmHandler, Args) ->
  179. epmRpc(EpmSrv, {'$addSupEpm', EpmHandler, Args, self()}).
  180. -spec del_epm(serverRef(), epmHandler(), term()) -> ok | {error, module_not_found}.
  181. del_epm(EpmSrv, EpmHandler, Args) ->
  182. epmRpc(EpmSrv, {'$delEpm', EpmHandler, Args}).
  183. -spec swap_epm(serverRef(), {epmHandler(), term()}, {epmHandler(), term()}) -> ok | {error, existed} | {error, term()}.
  184. swap_epm(EpmSrv, {H1, A1}, {H2, A2}) ->
  185. epmRpc(EpmSrv, {'$swapEpm', H1, A1, H2, A2}).
  186. -spec swap_sup_epm(serverRef(), {epmHandler(), term()}, {epmHandler(), term()}) -> ok | {error, existed} | {error, term()}.
  187. swap_sup_epm(EpmSrv, {H1, A1}, {H2, A2}) ->
  188. epmRpc(EpmSrv, {'$swapSupEpm', H1, A1, H2, A2, self()}).
  189. -spec which_epm(serverRef()) -> [epmHandler()].
  190. which_epm(EpmSrv) ->
  191. epmRpc(EpmSrv, '$which_handlers').
  192. -spec info_notify(serverRef(), term()) -> 'ok'.
  193. info_notify(EpmSrv, Event) ->
  194. epmRequest(EpmSrv, {'$epm_info', '$infoNotify', Event}).
  195. -spec call_notify(serverRef(), term()) -> 'ok'.
  196. call_notify(EpmSrv, Event) ->
  197. epmRpc(EpmSrv, {'$syncNotify', Event}).
  198. -spec call(serverRef(), epmHandler(), term()) -> term().
  199. call(EpmSrv, EpmHandler, Query) ->
  200. epmRpc(EpmSrv, {'$epmCall', EpmHandler, Query}).
  201. -spec call(serverRef(), epmHandler(), term(), timeout()) -> term().
  202. call(EpmSrv, EpmHandler, Query, Timeout) ->
  203. epmRpc(EpmSrv, {'$epmCall', EpmHandler, Query}, Timeout).
  204. send(EpmSrv, EpmHandler, Msg) ->
  205. epmRequest(EpmSrv, {'$epm_info', EpmHandler, Msg}).
  206. -spec send_request(serverRef(), epmHandler(), term()) -> requestId().
  207. send_request(EpmSrv, EpmHandler, Query) ->
  208. gen:send_request(EpmSrv, '$epm_call', {'$epmCall', EpmHandler, Query}).
  209. -spec wait_response(RequestId :: requestId(), timeout()) -> {reply, Reply :: term()} | 'timeout' | {error, {Reason :: term(), serverRef()}}.
  210. wait_response(RequestId, Timeout) ->
  211. case gen:wait_response(RequestId, Timeout) of
  212. {reply, {error, _} = Err} -> Err;
  213. Return -> Return
  214. end.
  215. -spec receive_response(RequestId :: requestId(), timeout()) -> {reply, Reply :: term()} | 'timeout' | {error, {Reason :: term(), serverRef()}}.
  216. receive_response(RequestId, Timeout) ->
  217. case gen:receive_response(RequestId, Timeout) of
  218. {reply, {error, _} = Err} -> Err;
  219. Return -> Return
  220. end.
  221. -spec check_response(Msg :: term(), RequestId :: requestId()) ->
  222. {reply, Reply :: term()} | 'no_reply' | {error, {Reason :: term(), serverRef()}}.
  223. check_response(Msg, RequestId) ->
  224. case gen:check_response(Msg, RequestId) of
  225. {reply, {error, _} = Err} -> Err;
  226. Return -> Return
  227. end.
  228. epmRpc(EpmSrv, Cmd) ->
  229. try gcall(EpmSrv, '$epm_call', Cmd, infinity) of
  230. {ok, Reply} ->
  231. Reply
  232. catch Class:Reason ->
  233. erlang:raise(Class, {Reason, {?MODULE, call, [EpmSrv, Cmd, infinity]}}, ?STACKTRACE())
  234. end.
  235. epmRpc(EpmSrv, Cmd, Timeout) ->
  236. try gcall(EpmSrv, '$epm_call', Cmd, Timeout) of
  237. {ok, Reply} ->
  238. Reply
  239. catch Class:Reason ->
  240. erlang:raise(Class, {Reason, {?MODULE, call, [EpmSrv, Cmd, Timeout]}}, ?STACKTRACE())
  241. end.
  242. epmRequest({global, Name}, Msg) ->
  243. try global:send(Name, Msg),
  244. ok
  245. catch _:_ -> ok
  246. end;
  247. epmRequest({via, RegMod, Name}, Msg) ->
  248. try RegMod:send(Name, Msg),
  249. ok
  250. catch _:_ -> ok
  251. end;
  252. epmRequest(EpmSrv, Cmd) ->
  253. EpmSrv ! Cmd,
  254. ok.
  255. loopEntry(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, true) ->
  256. proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug]);
  257. loopEntry(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, _) ->
  258. receiveIng(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, false).
  259. wakeupFromHib(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug) ->
  260. receiveIng(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, true).
  261. receiveIng(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, IsHib) ->
  262. receive
  263. {system, From, Req} ->
  264. sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug, {ServerName, HibernateAfterTimeout, EpmHers, IsHib}, IsHib);
  265. {'EXIT', Parent, Reason} ->
  266. terminate_server(Reason, Parent, ServerName, EpmHers);
  267. {'$epm_call', From, Request} ->
  268. epmCallMsg(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, From, Request);
  269. {'$epm_info', CmdOrEmpHandler, Event} ->
  270. epmInfoMsg(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, CmdOrEmpHandler, Event);
  271. Msg ->
  272. handleMsg(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, Msg)
  273. after HibernateAfterTimeout ->
  274. proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug])
  275. end.
  276. epmCallMsg(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, From, Request) ->
  277. ?SYS_DEBUG(Debug, ServerName, {call, From, Request}),
  278. case Request of
  279. '$which_handlers' ->
  280. reply(From, maps:keys(EpmHers)),
  281. receiveIng(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, false);
  282. {'$addEpm', EpmHandler, Args} ->
  283. {Reply, NewEpmHers, IsHib} = doAddEpm(EpmHers, EpmHandler, Args, undefined),
  284. reply(From, Reply),
  285. loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, Debug, IsHib);
  286. {'$addSupEpm', EpmHandler, Args, EpmSup} ->
  287. {Reply, NewEpmHers, IsHib} = doAddSupEpm(EpmHers, EpmHandler, Args, EpmSup),
  288. reply(From, Reply),
  289. loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, Debug, IsHib);
  290. {'$delEpm', EpmHandler, Args} ->
  291. {Reply, NewEpmHers} = doDelEpm(EpmHers, EpmHandler, Args),
  292. reply(From, Reply),
  293. receiveIng(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, Debug, false);
  294. {'$swapEpm', EpmId1, Args1, EpmId2, Args2} ->
  295. {Reply, NewEpmHers, IsHib} = doSwapEpm(EpmHers, EpmId1, Args1, EpmId2, Args2),
  296. reply(From, Reply),
  297. loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, Debug, IsHib);
  298. {'$swapSupEpm', EpmId1, Args1, EpmId2, Args2, SupPid} ->
  299. {Reply, NewEpmHers, IsHib} = doSwapSupEpm(EpmHers, EpmId1, Args1, EpmId2, Args2, SupPid),
  300. reply(From, Reply),
  301. loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, Debug, IsHib);
  302. {'$syncNotify', Event} ->
  303. {NewEpmHers, IsHib} = doNotify(EpmHers, handleEvent, Event, false),
  304. reply(From, ok),
  305. loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, Debug, IsHib);
  306. {'$epmCall', EpmHandler, Query} ->
  307. case doEpmHandle(EpmHers, EpmHandler, handleCall, Query, From) of
  308. {NewEpmHers, IsHib} ->
  309. loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, Debug, IsHib);
  310. NewEpmHers ->
  311. loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, Debug, false)
  312. end
  313. end.
  314. epmInfoMsg(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, CmdOrEmpHandler, Event) ->
  315. ?SYS_DEBUG(Debug, ServerName, {info, CmdOrEmpHandler, Event}),
  316. case CmdOrEmpHandler of
  317. '$infoNotify' ->
  318. {NewEpmHers, IsHib} = doNotify(EpmHers, handleEvent, Event, false),
  319. loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, Debug, IsHib);
  320. EpmHandler ->
  321. case doEpmHandle(EpmHers, EpmHandler, handleInfo, Event, false) of
  322. {NewEpmHers, IsHib} ->
  323. loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, Debug, IsHib);
  324. NewEpmHers ->
  325. loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, Debug, false)
  326. end
  327. end.
  328. handleMsg(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, Msg) ->
  329. ?SYS_DEBUG(Debug, ServerName, {in, Msg}),
  330. case Msg of
  331. {'EXIT', From, Reason} ->
  332. NewEpmHers = epmStopOne(From, EpmHers, Reason),
  333. receiveIng(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, Debug, false);
  334. {_From, Tag, stop} ->
  335. try terminate_server(normal, Parent, ServerName, EpmHers)
  336. after
  337. reply(Tag, ok)
  338. end;
  339. {_From, Tag, get_modules} ->
  340. reply(Tag, get_modules(EpmHers)),
  341. receiveIng(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, false);
  342. {_From, Tag, which_handlers} ->
  343. reply(Tag, maps:keys(EpmHers)),
  344. receiveIng(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, false);
  345. _ ->
  346. {NewEpmHers, IsHib} = doNotify(EpmHers, handleInfo, Msg, false),
  347. loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, Debug, IsHib)
  348. end.
  349. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  350. %% EPM inner fun
  351. addNewEpm(InitRet, EpmHers, Module, EpmId, EpmSup) ->
  352. case InitRet of
  353. {ok, State} ->
  354. EpmHer = #epmHer{epmId = EpmId, epmM = Module, epmS = State, epmSup = EpmSup},
  355. {ok, EpmHers#{EpmId => EpmHer}, false};
  356. {ok, State, hibernate} ->
  357. EpmHer = #epmHer{epmId = EpmId, epmM = Module, epmS = State, epmSup = EpmSup},
  358. {ok, EpmHers#{EpmId => EpmHer}, true};
  359. Other ->
  360. {Other, EpmHers, false}
  361. end.
  362. doAddEpm(EpmHers, EpmId, Args, EpmSup) ->
  363. case EpmId of
  364. {Module, _SubId} ->
  365. case EpmHers of
  366. #{EpmId := _EpmHer} ->
  367. {{error, existed}, EpmHers, false};
  368. _ ->
  369. try Module:init(Args) of
  370. Result ->
  371. addNewEpm(Result, EpmHers, Module, EpmId, EpmSup)
  372. catch
  373. throw:Ret ->
  374. addNewEpm(Ret, EpmHers, Module, EpmId, EpmSup);
  375. C:R:S ->
  376. {{error, {C, R, S}}, EpmHers, false}
  377. end
  378. end;
  379. _ ->
  380. case EpmHers of
  381. #{EpmId := _EpmHer} ->
  382. {{error, existed}, EpmHers, false};
  383. _ ->
  384. try EpmId:init(Args) of
  385. Result ->
  386. addNewEpm(Result, EpmHers, EpmId, EpmId, EpmSup)
  387. catch
  388. throw:Ret ->
  389. addNewEpm(Ret, EpmHers, EpmId, EpmId, EpmSup);
  390. C:R:S ->
  391. {{error, {C, R, S}}, EpmHers, false}
  392. end
  393. end
  394. end.
  395. doAddSupEpm(EpmHers, EpmHandler, Args, EpmSup) ->
  396. case doAddEpm(EpmHers, EpmHandler, Args, EpmSup) of
  397. {ok, _, _} = Result ->
  398. link(EpmSup),
  399. Result;
  400. Ret ->
  401. Ret
  402. end.
  403. doSwapEpm(EpmHers, EpmId1, Args1, EpmMId, Args2) ->
  404. case EpmHers of
  405. #{EpmId1 := #epmHer{epmSup = EpmSup} = EpmHer} ->
  406. State2 = epmTerminate(EpmHer, Args1, swapped, {swapped, EpmMId, EpmSup}),
  407. NewEpmHers = maps:remove(EpmId1, EpmHers),
  408. case EpmSup of
  409. false ->
  410. doAddEpm(NewEpmHers, EpmMId, {Args2, State2}, undefined);
  411. _ ->
  412. doAddSupEpm(NewEpmHers, EpmMId, {Args2, State2}, EpmSup)
  413. end;
  414. _ ->
  415. doAddEpm(EpmHers, EpmMId, {Args2, undefined}, undefined)
  416. end.
  417. doSwapSupEpm(EpmHers, EpmId1, Args1, EpmMId, Args2, EpmSup) ->
  418. case EpmHers of
  419. #{EpmId1 := #epmHer{epmSup = OldEpmSup} = EpmHer} ->
  420. State2 = epmTerminate(EpmHer, Args1, swapped, {swapped, EpmMId, OldEpmSup}),
  421. NewEpmHers = maps:remove(EpmId1, EpmHers),
  422. doAddSupEpm(NewEpmHers, EpmMId, {Args2, State2}, EpmSup);
  423. _ ->
  424. doAddSupEpm(EpmHers, EpmMId, {Args2, undefined}, EpmSup)
  425. end.
  426. doNotify(EpmHers, Func, Event, _Form) ->
  427. allNotify(iterator(EpmHers), Func, Event, false, EpmHers, false).
  428. allNotify(Iterator, Func, Event, From, TemEpmHers, IsHib) ->
  429. case next(Iterator) of
  430. {K, _V, NextIterator} ->
  431. case doEpmHandle(TemEpmHers, K, Func, Event, From) of
  432. {NewEpmHers, NewIsHib} ->
  433. allNotify(NextIterator, Func, Event, From, NewEpmHers, IsHib orelse NewIsHib);
  434. NewEpmHers ->
  435. allNotify(NextIterator, Func, Event, From, NewEpmHers, IsHib)
  436. end;
  437. _ ->
  438. {TemEpmHers, IsHib}
  439. end.
  440. doEpmHandle(EpmHers, EpmId, Func, Event, From) ->
  441. case EpmHers of
  442. #{EpmId := #epmHer{epmM = EpmM, epmS = EpmS} = EpmHer} ->
  443. try EpmM:Func(Event, EpmS) of
  444. Result ->
  445. handleEpmCR(Result, EpmHers, EpmId, EpmHer, Event, From)
  446. catch
  447. throw:Ret ->
  448. handleEpmCR(Ret, EpmHers, EpmId, EpmHer, Event, From);
  449. Class:Reason:Strace ->
  450. epmTerminate(EpmHer, {error, {Class, Reason, Strace}}, Event, crash),
  451. maps:remove(EpmId, EpmHers)
  452. end;
  453. _ ->
  454. try_greply(From, {error, bad_module}),
  455. EpmHers
  456. end.
  457. doDelEpm(EpmHers, EpmHandler, Args) ->
  458. case EpmHers of
  459. #{EpmHandler := EpmHer} ->
  460. epmTerminate(EpmHer, Args, delete, normal),
  461. {ok, maps:remove(EpmHandler, EpmHers)};
  462. _ ->
  463. {{error, module_not_found}, EpmHers}
  464. end.
  465. %% handleEpmCallbackRet
  466. handleEpmCR(Result, EpmHers, EpmId, EpmHer, Event, From) ->
  467. case Result of
  468. kpS ->
  469. EpmHers;
  470. {noreply, NewEpmS} ->
  471. MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  472. EpmHers#{EpmId := MewEpmHer};
  473. {noreply, NewEpmS, hibernate} ->
  474. MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  475. {EpmHers#{EpmId := MewEpmHer}, true};
  476. {swapEpm, NewEpmS, Args1, EpmMId, Args2} ->
  477. #epmHer{epmSup = EpmSup} = MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  478. State = epmTerminate(MewEpmHer, Args1, swapped, {swapped, EpmMId, EpmSup}),
  479. TemEpmHers = maps:remove(EpmId, EpmHers),
  480. {_, NewEpmHers, IsHib} =
  481. case EpmSup of
  482. undefined ->
  483. doAddEpm(TemEpmHers, EpmMId, {Args2, State}, undefined);
  484. _ ->
  485. doAddSupEpm(TemEpmHers, EpmMId, {Args2, State}, EpmSup)
  486. end,
  487. {NewEpmHers, IsHib};
  488. {swapEpm, Reply, NewEpmS, Args1, EpmMId, Args2} ->
  489. reply(From, Reply),
  490. #epmHer{epmSup = EpmSup} = MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  491. State = epmTerminate(MewEpmHer, Args1, swapped, {swapped, EpmMId, EpmSup}),
  492. TemEpmHers = maps:remove(EpmId, EpmHers),
  493. {_, NewEpmHers, IsHib} =
  494. case EpmSup of
  495. undefined ->
  496. doAddEpm(TemEpmHers, EpmMId, {Args2, State}, undefined);
  497. _ ->
  498. doAddSupEpm(TemEpmHers, EpmMId, {Args2, State}, EpmSup)
  499. end,
  500. {NewEpmHers, IsHib};
  501. removeEpm ->
  502. epmTerminate(EpmHer, removeEpm, remove, normal),
  503. maps:remove(EpmId, EpmHers);
  504. {removeEpm, Reply} ->
  505. reply(From, Reply),
  506. epmTerminate(EpmHer, removeEpm, remove, normal),
  507. maps:remove(EpmId, EpmHers);
  508. {reply, Reply} ->
  509. reply(From, Reply),
  510. EpmHers;
  511. {reply, Reply, NewEpmS} ->
  512. reply(From, Reply),
  513. MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  514. EpmHers#{EpmId := MewEpmHer};
  515. {reply, Reply, NewEpmS, hibernate} ->
  516. reply(From, Reply),
  517. MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  518. {EpmHers#{EpmId := MewEpmHer}, true};
  519. Other ->
  520. epmTerminate(EpmHer, {error, {bad_ret, Other}}, Event, crash),
  521. maps:remove(EpmId, EpmHers)
  522. end.
  523. reportTerminate(EpmHer, crash, {error, Why}, LastIn, _) ->
  524. reportTerminate2(EpmHer, Why, LastIn);
  525. %% How == normal | shutdown | {swapped, NewHandler, NewSupervisor}
  526. reportTerminate(EpmHer, How, _, LastIn, _) ->
  527. reportTerminate2(EpmHer, How, LastIn).
  528. reportTerminate2(#epmHer{epmSup = EpmSup, epmId = EpmId, epmS = State} = EpmHer, Reason, LastIn) ->
  529. report_error(EpmHer, Reason, State, LastIn),
  530. case EpmSup of
  531. undefined ->
  532. ok;
  533. _ ->
  534. EpmSup ! {gen_event_EXIT, EpmId, Reason},
  535. ok
  536. end.
  537. report_error(_EpmHer, normal, _, _) -> ok;
  538. report_error(_EpmHer, shutdown, _, _) -> ok;
  539. report_error(_EpmHer, {swapped, _, _}, _, _) -> ok;
  540. report_error(#epmHer{epmId = EpmId, epmM = EpmM}, Reason, State, LastIn) ->
  541. ?LOG_ERROR(
  542. #{
  543. label => {gen_emm, epm_terminate},
  544. handler => {EpmId, EpmM},
  545. name => undefined,
  546. last_message => LastIn,
  547. state => format_status(terminate, EpmM, get(), State),
  548. reason => Reason
  549. },
  550. #{
  551. domain => [otp],
  552. report_cb => fun gen_emm:format_log/2,
  553. error_logger => #{tag => error, report_cb => fun gen_emm:format_log/1}
  554. }).
  555. epmStopAll(EpmHers) ->
  556. forStopAll(iterator(EpmHers)).
  557. forStopAll(Iterator) ->
  558. case next(Iterator) of
  559. {_K, V, NextIterator} ->
  560. epmTerminate(V, stop, stop, shutdown),
  561. case element(#epmHer.epmSup, V) of
  562. undefined ->
  563. ignore;
  564. EpmSup ->
  565. unlink(EpmSup)
  566. end,
  567. forStopAll(NextIterator);
  568. _ ->
  569. ok
  570. end.
  571. epmStopOne(ExitEmpSup, EpmHers, Reason) ->
  572. forStopOne(iterator(EpmHers), ExitEmpSup, Reason, EpmHers).
  573. forStopOne(Iterator, ExitEmpSup, Reason, TemEpmHers) ->
  574. case next(Iterator) of
  575. {K, V, NextIterator} ->
  576. case element(#epmHer.epmSup, V) =:= ExitEmpSup of
  577. true ->
  578. epmTerminate(V, {stop, Reason}, {parent_terminated, {ExitEmpSup, Reason}}, shutdown),
  579. forStopOne(NextIterator, ExitEmpSup, Reason, maps:remove(K, TemEpmHers));
  580. _ ->
  581. forStopOne(NextIterator, ExitEmpSup, Reason, TemEpmHers)
  582. end;
  583. _ ->
  584. TemEpmHers
  585. end.
  586. epmTerminate(#epmHer{epmM = EpmM, epmS = State} = EpmHer, Args, LastIn, Reason) ->
  587. case erlang:function_exported(EpmM, terminate, 2) of
  588. true ->
  589. Res = (catch EpmM:terminate(Args, State)),
  590. reportTerminate(EpmHer, Reason, Args, LastIn, Res),
  591. Res;
  592. _ ->
  593. reportTerminate(EpmHer, Reason, Args, LastIn, ok),
  594. ok
  595. end.
  596. -compile({inline, [reply/2]}).
  597. -spec reply(From :: from(), Reply :: term()) -> ok.
  598. reply(From, Reply) ->
  599. greply(From, Reply).
  600. terminate_server(Reason, _Parent, _ServerName, EpmHers) ->
  601. epmStopAll(EpmHers),
  602. exit(Reason).
  603. %%-----------------------------------------------------------------
  604. %% Callback functions for system messages handling.
  605. %%-----------------------------------------------------------------
  606. system_continue(Parent, Debug, {ServerName, HibernateAfterTimeout, EpmHers, IsHib}) ->
  607. loopEntry(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, IsHib).
  608. -spec system_terminate(_, _, _, _) -> no_return().
  609. system_terminate(Reason, Parent, _Debug, {ServerName, _HibernateAfterTimeout, EpmHers, _IsHib}) ->
  610. terminate_server(Reason, Parent, ServerName, EpmHers).
  611. %%-----------------------------------------------------------------
  612. %% Module here is sent in the system msg change_code. It specifies
  613. %% which module should be changed.
  614. %%-----------------------------------------------------------------
  615. system_code_change({ServerName, HibernateAfterTimeout, EpmHers, IsHib}, Module, OldVsn, Extra) ->
  616. NewEpmHers = forCodeChange(iterator(EpmHers), Module, OldVsn, Extra, EpmHers),
  617. {ok, {ServerName, HibernateAfterTimeout, NewEpmHers, IsHib}}.
  618. forCodeChange(Iterator, CModule, OldVsn, Extra, TemEpmHers) ->
  619. case next(Iterator) of
  620. {K, #epmHer{epmM = Module, epmS = EpmS} = V, NextIterator} when Module =:= CModule ->
  621. {ok, NewEpmS} = Module:code_change(OldVsn, EpmS, Extra),
  622. forCodeChange(NextIterator, CModule, OldVsn, Extra, TemEpmHers#{K := V#epmHer{epmS = NewEpmS}});
  623. {_, _, NextIterator} ->
  624. forCodeChange(NextIterator, CModule, OldVsn, Extra, TemEpmHers);
  625. _ ->
  626. TemEpmHers
  627. end.
  628. system_get_state({_ServerName, _HibernateAfterTimeout, EpmHers, _Hib}) ->
  629. {ok, forGetState(iterator(EpmHers), [])}.
  630. forGetState(Iterator, Acc) ->
  631. case next(Iterator) of
  632. {_K, #epmHer{epmId = EpmId, epmM = Module, epmS = EpmS}, NextIterator} ->
  633. forGetState(NextIterator, [{Module, EpmId, EpmS} | Acc]);
  634. _ ->
  635. Acc
  636. end.
  637. system_replace_state(StateFun, {ServerName, HibernateAfterTimeout, EpmHers, IsHib}) ->
  638. {NewEpmHers, NStates} = forReplaceState(iterator(EpmHers), StateFun, EpmHers, []),
  639. {ok, NStates, {ServerName, HibernateAfterTimeout, NewEpmHers, IsHib}}.
  640. forReplaceState(Iterator, StateFun, TemEpmHers, NStates) ->
  641. case next(Iterator) of
  642. {K, #epmHer{epmId = EpmId, epmM = Module, epmS = EpmS} = V, NextIterator} ->
  643. NState = {_, _, NewEpmS} = StateFun({Module, EpmId, EpmS}),
  644. forReplaceState(NextIterator, StateFun, TemEpmHers#{K := V#epmHer{epmS = NewEpmS}}, [NState | NStates]);
  645. _ ->
  646. {TemEpmHers, NStates}
  647. end.
  648. %%-----------------------------------------------------------------
  649. %% Format debug messages. Print them as the call-back module sees
  650. %% them, not as the real erlang messages. Use trace for that.
  651. %%-----------------------------------------------------------------
  652. print_event(Dev, Msg, Name) ->
  653. case Msg of
  654. {call, From, Request} ->
  655. io:format(Dev, "*DBG* ~tp got call ~tp from ~tp ~n", [Name, Request, From]);
  656. {info, CmdOrEmpHandler, Event} ->
  657. io:format(Dev, "*DBG* ~tp got info ~tp~n", [CmdOrEmpHandler, Event]);
  658. {in, Msg} ->
  659. io:format(Dev, "*DBG* ~tp got in ~tp~n", [Name, Msg]);
  660. _ ->
  661. io:format(Dev, "*DBG* ~tp : ~tp~n", [Name, Msg])
  662. end.
  663. %% format_log/1 is the report callback used by Logger handler
  664. %% error_logger only. It is kept for backwards compatibility with
  665. %% legacy error_logger event handlers. This function must always
  666. %% return {Format,Args} compatible with the arguments in this module's
  667. %% calls to error_logger prior to OTP-21.0.
  668. format_log(Report) ->
  669. Depth = error_logger:get_format_depth(),
  670. FormatOpts = #{
  671. chars_limit => unlimited,
  672. depth => Depth,
  673. single_line => false,
  674. encoding => utf8
  675. },
  676. format_log_multi(limit_report(Report, Depth), FormatOpts).
  677. limit_report(Report, unlimited) ->
  678. Report;
  679. limit_report(#{label := {gen_event, terminate},
  680. last_message := LastIn,
  681. state := State,
  682. reason := Reason} = Report,
  683. Depth) ->
  684. Report#{
  685. last_message => io_lib:limit_term(LastIn, Depth),
  686. state => io_lib:limit_term(State, Depth),
  687. reason => io_lib:limit_term(Reason, Depth)
  688. };
  689. limit_report(#{label := {gen_event, no_handle_info}, message := Msg} = Report, Depth) ->
  690. Report#{message => io_lib:limit_term(Msg, Depth)}.
  691. %% format_log/2 is the report callback for any Logger handler, except
  692. %% error_logger.
  693. format_log(Report, FormatOpts0) ->
  694. Default = #{
  695. chars_limit => unlimited,
  696. depth => unlimited,
  697. single_line => false,
  698. encoding => utf8
  699. },
  700. FormatOpts = maps:merge(Default, FormatOpts0),
  701. IoOpts =
  702. case FormatOpts of
  703. #{chars_limit := unlimited} ->
  704. [];
  705. #{chars_limit := Limit} ->
  706. [{chars_limit, Limit}]
  707. end,
  708. {Format, Args} = format_log_single(Report, FormatOpts),
  709. io_lib:format(Format, Args, IoOpts).
  710. format_log_single(#{label := {gen_event, terminate},
  711. handler := Handler,
  712. name := SName,
  713. last_message := LastIn,
  714. state := State,
  715. reason := Reason},
  716. #{single_line := true, depth := Depth} = FormatOpts) ->
  717. P = p(FormatOpts),
  718. Reason1 = fix_reason(Reason),
  719. Format1 = lists:append(["Generic event handler ", P, " crashed. "
  720. "Installed: ", P, ". Last event: ", P,
  721. ". State: ", P, ". Reason: ", P, "."]),
  722. Args1 =
  723. case Depth of
  724. unlimited ->
  725. [Handler, SName, Reason1, LastIn, State];
  726. _ ->
  727. [Handler, Depth, SName, Depth, Reason1, Depth,
  728. LastIn, Depth, State, Depth]
  729. end,
  730. {Format1, Args1};
  731. format_log_single(#{label := {gen_event, no_handle_info},
  732. module := Mod,
  733. message := Msg},
  734. #{single_line := true, depth := Depth} = FormatOpts) ->
  735. P = p(FormatOpts),
  736. Format = lists:append(["Undefined handle_info in ", P, ". Unhandled message: ", P, "."]),
  737. Args =
  738. case Depth of
  739. unlimited ->
  740. [Mod, Msg];
  741. _ ->
  742. [Mod, Depth, Msg, Depth]
  743. end,
  744. {Format, Args};
  745. format_log_single(Report, FormatOpts) ->
  746. format_log_multi(Report, FormatOpts).
  747. format_log_multi(#{label := {gen_event, terminate},
  748. handler := Handler,
  749. name := SName,
  750. last_message := LastIn,
  751. state := State,
  752. reason := Reason},
  753. #{depth := Depth} = FormatOpts) ->
  754. Reason1 = fix_reason(Reason),
  755. P = p(FormatOpts),
  756. Format =
  757. lists:append(["** gen_event handler ", P, " crashed.\n",
  758. "** Was installed in ", P, "\n",
  759. "** Last event was: ", P, "\n",
  760. "** When handler state == ", P, "\n",
  761. "** Reason == ", P, "\n"]),
  762. Args =
  763. case Depth of
  764. unlimited ->
  765. [Handler, SName, LastIn, State, Reason1];
  766. _ ->
  767. [Handler, Depth, SName, Depth, LastIn, Depth, State, Depth, Reason1, Depth]
  768. end,
  769. {Format, Args};
  770. format_log_multi(#{label := {gen_event, no_handle_info},
  771. module := Mod,
  772. message := Msg},
  773. #{depth := Depth} = FormatOpts) ->
  774. P = p(FormatOpts),
  775. Format =
  776. "** Undefined handle_info in ~p\n"
  777. "** Unhandled message: " ++ P ++ "\n",
  778. Args =
  779. case Depth of
  780. unlimited ->
  781. [Mod, Msg];
  782. _ ->
  783. [Mod, Msg, Depth]
  784. end,
  785. {Format, Args}.
  786. fix_reason({'EXIT', {undef, [{M, F, A, _L} | _] = MFAs} = Reason}) ->
  787. case code:is_loaded(M) of
  788. false ->
  789. {'module could not be loaded', MFAs};
  790. _ ->
  791. case erlang:function_exported(M, F, length(A)) of
  792. true ->
  793. Reason;
  794. _ ->
  795. {'function not exported', MFAs}
  796. end
  797. end;
  798. fix_reason({'EXIT', Reason}) ->
  799. Reason;
  800. fix_reason(Reason) ->
  801. Reason.
  802. p(#{single_line := Single, depth := Depth, encoding := Enc}) ->
  803. "~" ++ single(Single) ++ mod(Enc) ++ p(Depth);
  804. p(unlimited) ->
  805. "p";
  806. p(_Depth) ->
  807. "P".
  808. single(true) -> "0";
  809. single(false) -> "".
  810. mod(latin1) -> "";
  811. mod(_) -> "t".
  812. %% Message from the release_handler.
  813. %% The list of modules got to be a set, i.e. no duplicate elements!
  814. get_modules(EpmHers) ->
  815. allMods(iterator(EpmHers), []).
  816. allMods(Iterator, Acc) ->
  817. case next(Iterator) of
  818. {_K, V, NextIterator} ->
  819. allMods(NextIterator, [element(#epmHer.epmM, V) | Acc]);
  820. _ ->
  821. lists:usort(Acc)
  822. end.
  823. %%-----------------------------------------------------------------
  824. %% Status information
  825. %%-----------------------------------------------------------------
  826. format_status(Opt, StatusData) ->
  827. [PDict, SysState, Parent, _Debug, {ServerName, _HibernateAfterTimeout, EpmHers, _IsHib}] = StatusData,
  828. Header = gen:format_status_header("Status for gen_emm handler", ServerName),
  829. FmtMSL = allStateStatus(iterator(EpmHers), Opt, PDict, []),
  830. [{header, Header}, {data, [{"Status", SysState}, {"Parent", Parent}]}, {items, {"Installed handlers", FmtMSL}}].
  831. allStateStatus(Iterator, Opt, PDict, EpmHers) ->
  832. case next(Iterator) of
  833. {_K, #epmHer{epmM = Module, epmS = EpmS} = V, NextIterator} ->
  834. NewEpmS = format_status(Opt, Module, PDict, EpmS),
  835. allStateStatus(NextIterator, Opt, PDict, [V#epmHer{epmS = NewEpmS} | EpmHers]);
  836. _ ->
  837. EpmHers
  838. end.
  839. format_status(Opt, Mod, PDict, State) ->
  840. case erlang:function_exported(Mod, format_status, 2) of
  841. true ->
  842. Args = [PDict, State],
  843. case catch Mod:format_status(Opt, Args) of
  844. {'EXIT', _} -> State;
  845. Else -> Else
  846. end;
  847. _ ->
  848. State
  849. end.