各种有用的erlang行为
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

964 regels
33 KiB

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