各种有用的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.

971 lines
34 KiB

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