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

2840 lines
122 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. -module(gen_ipc).
  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_server or gen_statem behaviour
  10. start/3, start/4, start_link/3, start_link/4
  11. , start_monitor/3, start_monitor/4
  12. , stop/1, stop/3
  13. , cast/2, send/2
  14. , abcast/2, abcast/3
  15. , call/2, call/3
  16. , send_request/2, send_request/4
  17. , wait_response/2, receive_response/2, check_response/2
  18. , wait_response/3, receive_response/3, check_response/3
  19. , reqids_new/0, reqids_size/1
  20. , reqids_add/3, reqids_to_list/1
  21. , multi_call/2, multi_call/3, multi_call/4
  22. , enter_loop/4, enter_loop/5, enter_loop/6
  23. , reply/1, reply/2
  24. %% API for gen_event behaviour
  25. , send_request/3
  26. , info_notify/2, call_notify/2
  27. , epm_call/3, epm_call/4, epm_info/3
  28. , add_epm/3, del_epm/3, add_sup_epm/3
  29. , swap_epm/3, swap_sup_epm/3
  30. , which_epm/1
  31. %% gen callbacks
  32. , init_it/6
  33. %% sys callbacks
  34. , system_continue/3
  35. , system_terminate/4
  36. , system_code_change/4
  37. , system_get_state/1
  38. , system_replace_state/2
  39. , format_status/2
  40. %% Internal callbacks
  41. , wakeupFromHib/12
  42. %% logger callback
  43. , format_log/1
  44. , format_log/2
  45. , epm_log/1
  46. , print_event/3
  47. ]).
  48. % 简写备注**********************************
  49. % isPostpone isPos
  50. % isHibernate isHib
  51. % nextEvent nextE
  52. % nextStatus nextS
  53. % keepStatus kpS
  54. % keepStatusState kpS_S
  55. % repeatStatus reS
  56. % repeatStatusState reS_S
  57. % *****************************************
  58. % %% timeout相关宏定义
  59. % -define(REL_TIMEOUT(T), ((is_integer(T) andalso (T) >= 0) orelse (T) =:= infinity)).
  60. % -define(ABS_TIMEOUT(T), (is_integer(T) orelse (T) =:= infinity)).
  61. -define(STACKTRACE(), element(2, erlang:process_info(self(), current_stacktrace))).
  62. -define(CB_FORM_ENTER, 1). %% 从enter 回调返回
  63. -define(CB_FORM_AFTER, 2). %% 从after 回调返回
  64. -define(CB_FORM_EVENT, 3). %% 从event 回调返回
  65. %%%==========================================================================
  66. %%% Interface functions.
  67. %%%==========================================================================
  68. %% gcall 发送消息来源进程格式类型
  69. -type from() :: {To :: pid(), Tag :: term()}.
  70. -type request_id() :: gen:request_id().
  71. -type request_id_collection() :: gen:request_id_collection().
  72. -type response_timeout() :: timeout() | {abs, integer()}.
  73. %% 事件类型
  74. -type eventType() :: externalEventType() | timeoutEventType() | {'onevent', Subtype :: term()}.
  75. -type externalEventType() :: {'call', From :: from()} | 'cast' | 'info'.
  76. -type timeoutEventType() :: GTimeoutName :: term() | 'eTimeout' | 'sTimeout'. %% 前面的GTimeoutName这个是通用超时标识名
  77. %% 是否捕捉信号 gen_event管理进程需要设置该参数为true
  78. -type isTrapExit() :: boolean().
  79. %% 是否允许进入enter 回调
  80. -type isEnter() :: boolean().
  81. %% 如果为 "true" 则推迟当前事件,并在状态更改时重试(=/=)
  82. -type isPos() :: boolean().
  83. %% 如果为 "true" 则使服务器休眠而不是进入接收状态
  84. -type isHib() :: boolean().
  85. %% 定时器相关
  86. -type timeouts() :: Time :: timeout() | integer().
  87. -type timeoutOption() :: {abs, Abs :: boolean()}.
  88. % gen_event模式下回调模块的标识
  89. -type epmHandler() :: atom() | {atom(), term()}.
  90. %% 在状态更改期间:
  91. %% NextStatus and NewData are set.
  92. %% 按照出现的顺序处理 actions()列表
  93. %% 这些action() 按包含列表中的出现顺序执行。设置选项的选项将覆盖任何以前的选项,因此每种类型的最后一种将获胜。
  94. %% 如果设置了enter 则进入enter回调
  95. %% 如果设置了doAfter 则进入after回调
  96. %% 如果 "postpone" 为 "true",则推迟当前事件。
  97. %% 如果设置了“超时”,则开始状态超时。 零超时事件将会插入到待处理事件的前面 先执行
  98. %% 如果有postponed 事件则 事件执行顺序为 超时添加和更新 + 零超时 + 当前事件 + 反序的Postpone事件 + LeftEvent
  99. %% 处理待处理的事件,或者如果没有待处理的事件,则服务器进入接收或休眠状态(当“hibernate”为“ true”时)
  100. -type initAction() ::
  101. {trap_exit, Bool :: isTrapExit()} | % 设置是否捕捉信息 主要用于gen_event模式下
  102. eventAction().
  103. -type eventAction() ::
  104. {'doAfter', Args :: term()} | % 设置执行某事件后是否回调 handleAfter
  105. {'isPos', Bool :: isPos()} | % 设置推迟选项
  106. {'nextE', EventType :: eventType(), EventContent :: term()} | % 插入事件作为下一个处理
  107. commonAction().
  108. -type afterAction() ::
  109. {'nextE', EventType :: eventType(), EventContent :: term()} | % 插入事件作为下一个处理
  110. commonAction().
  111. -type enterAction() ::
  112. {'isPos', false} | % 虽然enter action 不能设置postpone 但是可以取消之前event的设置
  113. commonAction().
  114. -type commonAction() ::
  115. {'isEnter', Bool :: isEnter()} |
  116. {'isHib', Bool :: isHib()} |
  117. timeoutAction() |
  118. replyAction().
  119. -type timeoutAction() ::
  120. timeoutNewAction() |
  121. timeoutCancelAction() |
  122. timeoutUpdateAction().
  123. -type timeoutNewAction() ::
  124. {'eTimeout', Time :: timeouts(), EventContent :: term()} | % Set the event_timeout option
  125. {'eTimeout', Time :: timeouts(), EventContent :: term(), Options :: ([timeoutOption()])} | % Set the event_timeout option
  126. {'sTimeout', Time :: timeouts(), EventContent :: term()} | % Set the status_timeout option
  127. {'sTimeout', Time :: timeouts(), EventContent :: term(), Options :: ([timeoutOption()])} | % Set the status_timeout option
  128. {'gTimeout', Name :: term(), Time :: timeouts(), EventContent :: term()} | % Set the generic_timeout option
  129. {'gTimeout', Name :: term(), Time :: timeouts(), EventContent :: term(), Options :: ([timeoutOption()])}. % Set the generic_timeout option
  130. -type timeoutCancelAction() ::
  131. 'c_eTimeout' | % 不可能也不需要更新此超时,因为任何其他事件都会自动取消它。
  132. 'c_sTimeout' |
  133. {'c_gTimeout', Name :: term()}.
  134. -type timeoutUpdateAction() ::
  135. {'u_eTimeout', EventContent :: term()} | % 不可能也不需要取消此超时,因为任何其他事件都会自动取消它。
  136. {'u_sTimeout', EventContent :: term()} |
  137. {'u_gTimeout', Name :: term(), EventContent :: term()}.
  138. -type actions(ActionType) ::
  139. ActionType |
  140. [ActionType, ...].
  141. -type replyAction() ::
  142. {'reply', From :: from(), Reply :: term()}.
  143. -type eventCallbackResult() ::
  144. {'reply', Reply :: term(), NewState :: term()} | % 用作gen_server模式时快速响应进入消息接收
  145. {'sreply', Reply :: term(), NextStatus :: term(), NewState :: term()} | % 用作gen_ipc模式便捷式返回reply 而不用把reply放在actions列表中
  146. {'noreply', NewState :: term()} | % 用作gen_server模式时快速响应进入消息接收
  147. {'reply', Reply :: term(), NewState :: term(), Options :: hibernate | {doAfter, Args :: term()}} | % 用作gen_server模式时快速响应进入消息接收
  148. {'sreply', Reply :: term(), NextStatus :: term(), NewState :: term(), Actions :: actions(eventAction())} | % 用作gen_ipc模式便捷式返回reply 而不用把reply放在actions列表中
  149. {'noreply', NewState :: term(), Options :: hibernate | {doAfter, Args :: term()}} | % 用作gen_server模式时快速响应进入循环
  150. {'nextS', NextStatus :: term(), NewState :: term()} | % {next_status,NextS,NewData,[]}
  151. {'nextS', NextStatus :: term(), NewState :: term(), Actions :: actions(eventAction())} | % Status transition, maybe to the same status
  152. commonCallbackResult(eventAction()).
  153. -type afterCallbackResult() ::
  154. {'nextS', NextStatus :: term(), NewState :: term()} | % {next_status,NextS,NewData,[]}
  155. {'nextS', NextStatus :: term(), NewState :: term(), Actions :: actions(afterAction())} | % Status transition, maybe to the same status
  156. {'noreply', NewState :: term()} | % 用作gen_server模式时快速响应进入消息接收
  157. {'noreply', NewState :: term(), Options :: hibernate} | % 用作gen_server模式时快速响应进入消息接收
  158. commonCallbackResult(afterAction()).
  159. -type enterCallbackResult() ::
  160. commonCallbackResult(enterAction()).
  161. -type commonCallbackResult(ActionType) ::
  162. {'kpS', NewState :: term()} | % {keep_status,NewData,[]}
  163. {'kpS', NewState :: term(), Actions :: actions(ActionType)} | % Keep status, change data
  164. 'kpS_S' | % {keep_status_and_data,[]}
  165. {'kpS_S', Actions :: [ActionType]} | % Keep status and data -> only actions
  166. {'reS', NewState :: term()} | % {repeat_status,NewData,[]}
  167. {'reS', NewState :: term(), Actions :: actions(ActionType)} | % Repeat status, change data
  168. 'reS_S' | % {repeat_status_and_data,[]}
  169. {'reS_S', Actions :: actions(ActionType)} | % Repeat status and data -> only actions
  170. 'stop' | % {stop,normal}
  171. {'stop', Reason :: term()} | % Stop the server
  172. {'stop', Reason :: term(), NewState :: term()} | % Stop the server
  173. {'stopReply', Reason :: term(), Replies :: replyAction() | [replyAction(), ...] | term()} | % Reply then stop the server
  174. {'stopReply', Reason :: term(), Replies :: replyAction() | [replyAction(), ...] | term(), NewState :: term()}. % Reply then stop the server
  175. %% 状态机的初始化功能函数
  176. %% 如果要模拟gen_server init返回定时时间 可以在Actions返回定时动作
  177. %% 如果要把改进程当做gen_event管理进程需要在actions列表包含 {trap_exit, true} 设置该进程捕捉异常
  178. -callback init(Args :: term()) ->
  179. 'ignore' |
  180. {'stop', Reason :: term()} |
  181. {'ok', State :: term()} |
  182. {'ok', Status :: term(), State :: term()} |
  183. {'ok', Status :: term(), State :: term(), Actions :: actions(initAction())}.
  184. %% 当 enter call 回调函数
  185. -callback handleEnter(OldStatus :: term(), CurStatus :: term(), State :: term()) ->
  186. enterCallbackResult().
  187. %% 当 init返回actions包含 doAfter 的时候会在 enter调用后 调用该函数 或者
  188. %% 在事件回调函数返回后 enter调用后调用该函数
  189. %% 该回调函数相当于 gen_server 的 handle_continue回调 但是在综合模式时 也可以生效
  190. -callback handleAfter(AfterArgs :: term(), Status :: term(), State :: term()) ->
  191. afterCallbackResult().
  192. %% call 所以状态的回调函数
  193. -callback handleCall(EventContent :: term(), Status :: term(), State :: term(), From :: {pid(), Tag :: term()}) ->
  194. eventCallbackResult().
  195. %% cast 回调函数
  196. -callback handleCast(EventContent :: term(), Status :: term(), State :: term()) ->
  197. eventCallbackResult().
  198. %% info 回调函数
  199. -callback handleInfo(EventContent :: term(), Status :: term(), State :: term()) ->
  200. eventCallbackResult().
  201. %% error 回调函数 守护模式下 进程捕捉到错误可以回调次函数
  202. -callback handleError(Error :: term(), State :: term()) ->
  203. eventCallbackResult().
  204. %% 内部事件 Onevent 包括actions 设置的定时器超时产生的事件 和 nextE产生的超时事件 但是不是 call cast info 回调函数 以及其他自定义定时事件 的回调函数
  205. %% 并且这里需要注意 其他erlang:start_timer生成超时事件发送的消息 不能和gen_ipc定时器关键字重合 有可能会导致一些问题
  206. -callback handleOnevent(EventType :: term(), EventContent :: term(), Status :: term(), State :: term()) ->
  207. eventCallbackResult().
  208. %% 在gen_event模式下 扩展了下面三个回调函数 考虑场景是:
  209. %% 比如游戏里的公会 有时候一个公会一个进程来管理可能开销比较高 只用一个进程来管理所以公会有可能一个进程处理不过来
  210. %% 这个时候可以考虑用gen_ipc来分组管理 一个gen_ipc进程管理 N 个公会 但是管理进程需要做一些数据保存什么 或者定时 就可能会用到下面的这些函数
  211. %% gen_event模式时 notify 有可能需要回调该管理进程的该函数
  212. -callback handleEpmEvent(EventContent :: term(), Status :: term(), State :: term()) ->
  213. eventCallbackResult().
  214. %% gen_event模式时 call请求 有可能需要回调该管理进程的该函数
  215. -callback handleEpmCall(EventContent :: term(), Status :: term(), State :: term()) ->
  216. eventCallbackResult().
  217. %% gen_event模式时 info消息 有可能需要回调该管理进程的该函数
  218. -callback handleEpmInfo(EventContent :: term(), Status :: term(), State :: term()) ->
  219. eventCallbackResult().
  220. %% 在服务器终止之前进行清理。
  221. -callback terminate(Reason :: 'normal' | 'shutdown' | {'shutdown', term()} | term(), Status :: term(), State :: term()) ->
  222. any().
  223. %% 代码更新回调函数
  224. -callback code_change(OldVsn :: term() | {'down', term()}, OldStatus :: term(), OldState :: term(), Extra :: term()) ->
  225. {ok, NewStatus :: term(), NewData :: term()} |
  226. (Reason :: term()).
  227. %% 以一种通常被精简的方式来格式化回调模块状态。
  228. %% 对于StatusOption =:= 'normal',首选返回 term 是[{data,[{"Status",FormattedStatus}]}]
  229. %% 对于StatusOption =:= 'terminate',它只是FormattedStatus
  230. -callback formatStatus(StatusOption, [PDict | term()]) ->
  231. Status :: term() when
  232. StatusOption :: 'normal' | 'terminate',
  233. PDict :: [{Key :: term(), Value :: term()}].
  234. -optional_callbacks([
  235. formatStatus/2
  236. , terminate/3
  237. , code_change/4
  238. , handleEnter/3
  239. , handleAfter/3
  240. , handleError/2
  241. , handleOnevent/4
  242. , handleEpmEvent/3
  243. , handleEpmCall/3
  244. , handleEpmInfo/3
  245. ]).
  246. -record(epmHer, {
  247. epmId = undefined :: term(),
  248. epmM :: atom(),
  249. epmSup = undefined :: 'undefined' | pid(),
  250. epmS :: term()
  251. }).
  252. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% start stop API start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  253. -type serverName() ::
  254. {'local', atom()} |
  255. {'global', GlobalName :: term()} |
  256. {'via', RegMod :: module(), Name :: term()}.
  257. -type serverRef() ::
  258. pid() |
  259. (LocalName :: atom()) |
  260. {Name :: atom(), Node :: atom()} |
  261. {'global', GlobalName :: term()} |
  262. {'via', RegMod :: module(), ViaName :: term()}.
  263. -type startOpt() ::
  264. daemon |
  265. {'timeout', Time :: timeout()} |
  266. {'spawn_opt', [proc_lib:spawn_option()]} |
  267. enterLoopOpt().
  268. -type enterLoopOpt() ::
  269. {'debug', Debugs :: [sys:debug_option()]} |
  270. {'hibernate_after', HibernateAfterTimeout :: timeout()}.
  271. -type startRet() ::
  272. 'ignore' |
  273. {'ok', pid()} |
  274. {'ok', {pid(), reference()}} |
  275. {'error', term()}.
  276. -spec start(Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet().
  277. start(Module, Args, Opts) ->
  278. gen:start(?MODULE, nolink, Module, Args, Opts).
  279. -spec start(ServerName :: serverName(), Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet().
  280. start(ServerName, Module, Args, Opts) ->
  281. gen:start(?MODULE, nolink, ServerName, Module, Args, Opts).
  282. -spec start_link(Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet().
  283. start_link(Module, Args, Opts) ->
  284. gen:start(?MODULE, link, Module, Args, Opts).
  285. -spec start_link(ServerName :: serverName(), Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet().
  286. start_link(ServerName, Module, Args, Opts) ->
  287. gen:start(?MODULE, link, ServerName, Module, Args, Opts).
  288. %% Start and monitor
  289. -spec start_monitor(Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet().
  290. start_monitor(Module, Args, Opts) ->
  291. gen:start(?MODULE, monitor, Module, Args, Opts).
  292. -spec start_monitor(ServerName :: serverName(), Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet().
  293. start_monitor(ServerName, Module, Args, Opts) ->
  294. gen:start(?MODULE, monitor, ServerName, Module, Args, Opts).
  295. -spec stop(ServerRef :: serverRef()) -> ok.
  296. stop(ServerRef) ->
  297. gen:stop(ServerRef).
  298. -spec stop(ServerRef :: serverRef(), Reason :: term(), Timeout :: timeout()) -> ok.
  299. stop(ServerRef, Reason, Timeout) ->
  300. gen:stop(ServerRef, Reason, Timeout).
  301. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% start stop API end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  302. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gen callbacks start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  303. doModuleInit(Module, Args) ->
  304. try
  305. Module:init(Args)
  306. catch
  307. throw:Ret -> Ret;
  308. Class:Reason:Stacktrace -> {'EXIT', Class, Reason, Stacktrace}
  309. end.
  310. init_it(Starter, self, ServerRef, Module, Args, Opts) ->
  311. init_it(Starter, self(), ServerRef, Module, Args, Opts);
  312. init_it(Starter, Parent, ServerRef, Module, Args, Opts) ->
  313. Name = gen:name(ServerRef),
  314. Debug = gen:debug_options(Name, Opts),
  315. GbhOpts = #gbhOpts{daemon = not lists:member(notDaemon, Opts)},
  316. HibernateAfterTimeout = gen:hibernate_after(Opts),
  317. case doModuleInit(Module, Args) of
  318. {ok, State} ->
  319. proc_lib:init_ack(Starter, {ok, self()}),
  320. loopEntry(Parent, Debug, Module, Name, GbhOpts, HibernateAfterTimeout, undefined, State, []);
  321. {ok, Status, State} ->
  322. proc_lib:init_ack(Starter, {ok, self()}),
  323. loopEntry(Parent, Debug, Module, Name, GbhOpts, HibernateAfterTimeout, Status, State, []);
  324. {ok, Status, State, Actions} ->
  325. proc_lib:init_ack(Starter, {ok, self()}),
  326. loopEntry(Parent, Debug, Module, Name, GbhOpts, HibernateAfterTimeout, Status, State, listify(Actions));
  327. {stop, Reason} ->
  328. gen:unregister_name(ServerRef),
  329. proc_lib:init_ack(Starter, {error, Reason}),
  330. exit(Reason);
  331. ignore ->
  332. gen:unregister_name(ServerRef),
  333. proc_lib:init_ack(Starter, ignore),
  334. exit(normal);
  335. {'EXIT', Class, Reason, Stacktrace} ->
  336. gen:unregister_name(ServerRef),
  337. proc_lib:init_ack(Starter, {error, Reason}),
  338. error_info(Class, Reason, Stacktrace, Parent, Name, Module, HibernateAfterTimeout, fasle, #{}, [], #{}, '$un_init', '$un_init', Debug, []),
  339. erlang:raise(Class, Reason, Stacktrace);
  340. _Ret ->
  341. gen:unregister_name(ServerRef),
  342. Error = {'init_bad_return', _Ret},
  343. proc_lib:init_ack(Starter, {error, Error}),
  344. error_info(error, Error, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, fasle, #{}, [], #{}, '$un_init', '$un_init', Debug, []),
  345. exit(Error)
  346. end.
  347. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gen callbacks end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  348. %% 进入循环 调用该进程必须使用proc_lib启动 且已经初始化状态和数据 包括注册名称
  349. %% 可以通过使用与从init / 1返回的参数相同的参数,而不是通过start / 3,4或start_link / 3,4启动状态机,而将当前由proc_lib启动的进程转换为状态机。
  350. -spec enter_loop(Module :: module(), Status :: term(), State :: term(), Opts :: [enterLoopOpt()]) -> no_return().
  351. enter_loop(Module, Status, State, Opts) ->
  352. enter_loop(Module, Status, State, Opts, self(), []).
  353. -spec enter_loop(Module :: module(), Status :: term(), State :: term(), Opts :: [enterLoopOpt()], ServerOrActions :: serverName() | pid() | actions(eventAction())) -> no_return().
  354. enter_loop(Module, Status, State, Opts, ServerOrActions) ->
  355. if
  356. is_list(ServerOrActions) ->
  357. enter_loop(Module, Status, State, Opts, self(), ServerOrActions);
  358. true ->
  359. enter_loop(Module, Status, State, Opts, ServerOrActions, [])
  360. end.
  361. -spec enter_loop(Module :: module(), Status :: term(), State :: term(), Opts :: [enterLoopOpt()], Server :: serverName() | pid(), Actions :: actions(eventAction())) -> no_return().
  362. enter_loop(Module, Status, State, Opts, ServerName, Actions) ->
  363. is_atom(Module) orelse error({atom, Module}),
  364. Parent = gen:get_parent(),
  365. Name = gen:get_proc_name(ServerName),
  366. Debug = gen:debug_options(Name, Opts),
  367. GbhOpts = #gbhOpts{daemon = not lists:member(notDaemon, Opts)},
  368. HibernateAfterTimeout = gen:hibernate_after(Opts),
  369. loopEntry(Parent, Debug, Module, Name, GbhOpts, HibernateAfterTimeout, Status, State, Actions).
  370. %% 这里的 init_it/6 和 enter_loop/5,6,7 函数汇聚
  371. loopEntry(Parent, Debug, Module, Name, GbhOpts, HibernateAfterTimeout, CurStatus, CurState, Actions) ->
  372. %% 如果该进程用于 gen_event 或者该进程需要捕捉退出信号 和 捕捉supervisor进程树的退出信息 则需要设置 process_flag(trap_exit, true) 需要在Actions返回 {trap_exit, true}
  373. MewActions =
  374. case lists:keyfind(trap_exit, 1, Actions) of
  375. false ->
  376. Actions;
  377. {trap_exit, true} ->
  378. process_flag(trap_exit, true),
  379. lists:keydelete(trap_exit, 1, Actions);
  380. _ ->
  381. lists:keydelete(trap_exit, 1, Actions)
  382. end,
  383. ?SYS_DEBUG(Debug, Name, {enter, CurStatus}),
  384. %% 强制执行{postpone,false}以确保我们的假事件被丢弃
  385. LastActions = MewActions ++ [{isPos, false}],
  386. parseEventAL(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, false, #{}, [], #{}, CurStatus, CurState, CurStatus, Debug, [{onevent, init_status}], true, LastActions, ?CB_FORM_EVENT).
  387. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% sys callbacks start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  388. system_continue(Parent, Debug, {Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, IsHib}) ->
  389. if
  390. IsHib ->
  391. proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug]);
  392. true ->
  393. receiveIng(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, false)
  394. end.
  395. system_terminate(Reason, Parent, Debug, {Parent, Name, Module, _GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, _IsHib}) ->
  396. terminate(exit, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, []).
  397. system_code_change({Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, IsHib}, _Mod, OldVsn, Extra) ->
  398. case
  399. try Module:code_change(OldVsn, CurStatus, CurState, Extra)
  400. catch
  401. throw:Result -> Result;
  402. _C:_R:_S -> {_C, _R, _S}
  403. end
  404. of
  405. {ok, NewStatus, NewState} ->
  406. {ok, {Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, NewStatus, NewState, IsHib}};
  407. Error ->
  408. Error
  409. end.
  410. system_get_state({_Parent, _Name, _Module, _GbhOpts, _HibernateAfterTimeout, _IsEnter, _EpmHers, _Postponed, _Timers, CurStatus, CurState, _IsHib}) ->
  411. {ok, {CurStatus, CurState}}.
  412. system_replace_state(StatusFun, {Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, IsHib}) ->
  413. {NewStatus, NewState} = StatusFun(CurStatus, CurState),
  414. {ok, {NewStatus, NewState}, {Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, NewStatus, NewState, IsHib}}.
  415. format_status(Opt, [PDict, SysStatus, Parent, Debug, {Parent, Name, Module, _GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, _IsHib}]) ->
  416. Header = gen:format_status_header("Status for gen_ipc", Name),
  417. Log = sys:get_log(Debug),
  418. [
  419. {header, Header},
  420. {data,
  421. [
  422. {"Status", SysStatus},
  423. {"Parent", Parent},
  424. {"Time-outs", listTimeouts(Timers)},
  425. {"Logged Events", Log},
  426. {"Postponed", Postponed}
  427. ]
  428. } |
  429. case format_status(Opt, PDict, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState) of
  430. L when is_list(L) -> L;
  431. T -> [T]
  432. end
  433. ].
  434. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% sys callbacks end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  435. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% API helpers start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  436. -spec call(ServerRef :: serverRef(), Request :: term()) -> Reply :: term().
  437. call(ServerRef, Request) ->
  438. try gcall(ServerRef, '$gen_call', Request) of
  439. {ok, Reply} ->
  440. Reply
  441. catch Class:Reason ->
  442. erlang:raise(Class, {Reason, {?MODULE, call, [ServerRef, Request]}}, ?STACKTRACE())
  443. end.
  444. -spec call(ServerRef :: serverRef(), Request :: term(), Timeout :: timeout()) -> Reply :: term().
  445. call(ServerRef, Request, Timeout) ->
  446. try gcall(ServerRef, '$gen_call', Request, Timeout) of
  447. {ok, Reply} ->
  448. Reply
  449. catch Class:Reason ->
  450. erlang:raise(Class, {Reason, {?MODULE, call, [ServerRef, Request]}}, ?STACKTRACE())
  451. end.
  452. %%% -----------------------------------------------------------------
  453. %%% Make a call to servers at several nodes.
  454. %%% Returns: {[Replies],[BadNodes]}
  455. %%% A Timeout can be given
  456. %%%
  457. %%% A middleman process is used in case late answers arrives after
  458. %%% the timeout. If they would be allowed to glog the callers message
  459. %%% queue, it would probably become confused. Late answers will
  460. %%% now arrive to the terminated middleman and so be discarded.
  461. %%% -----------------------------------------------------------------
  462. -spec multi_call(
  463. Name :: atom(),
  464. Request :: term()
  465. ) ->
  466. {Replies ::
  467. [{Node :: node(), Reply :: term()}],
  468. BadNodes :: [node()]
  469. }.
  470. %%
  471. multi_call(Name, Request)
  472. when is_atom(Name) ->
  473. multi_call([node() | nodes()], Name, Request, infinity).
  474. -spec multi_call(
  475. Nodes :: [node()],
  476. Name :: atom(),
  477. Request :: term()
  478. ) ->
  479. {Replies ::
  480. [{Node :: node(), Reply :: term()}],
  481. BadNodes :: [node()]
  482. }.
  483. %%
  484. multi_call(Nodes, Name, Request)
  485. when is_list(Nodes), is_atom(Name) ->
  486. multi_call(Nodes, Name, Request, infinity).
  487. -spec multi_call(
  488. Nodes :: [node()],
  489. Name :: atom(),
  490. Request :: term(),
  491. Timeout :: timeout()
  492. ) ->
  493. {Replies ::
  494. [{Node :: node(), Reply :: term()}],
  495. BadNodes :: [node()]
  496. }.
  497. -define(
  498. is_timeout(X), ( (X) =:= infinity orelse ( is_integer(X) andalso (X) >= 0 ) )).
  499. multi_call(Nodes, Name, Request, Timeout)
  500. when is_list(Nodes), is_atom(Name), ?is_timeout(Timeout) ->
  501. Alias = alias(),
  502. try
  503. Timer = if Timeout == infinity -> undefined;
  504. true -> erlang:start_timer(Timeout, self(), Alias)
  505. end,
  506. Reqs = mc_send(Nodes, Name, Alias, Request, Timer, []),
  507. mc_recv(Reqs, Alias, Timer, [], [])
  508. after
  509. _ = unalias(Alias)
  510. end.
  511. -dialyzer({no_improper_lists, mc_send/6}).
  512. mc_send([], _Name, _Alias, _Request, _Timer, Reqs) ->
  513. Reqs;
  514. mc_send([Node|Nodes], Name, Alias, Request, Timer, Reqs) when is_atom(Node) ->
  515. NN = {Name, Node},
  516. Mon = try
  517. erlang:monitor(process, NN, [{tag, Alias}])
  518. catch
  519. error:badarg ->
  520. %% Node not alive...
  521. M = make_ref(),
  522. Alias ! {Alias, M, process, NN, noconnection},
  523. M
  524. end,
  525. try
  526. %% We use 'noconnect' since it is no point in bringing up a new
  527. %% connection if it was not brought up by the monitor signal...
  528. _ = erlang:send(NN,
  529. {'$gen_call', {self(), [[alias|Alias]|Mon]}, Request},
  530. [noconnect]),
  531. ok
  532. catch
  533. _:_ ->
  534. ok
  535. end,
  536. mc_send(Nodes, Name, Alias, Request, Timer, [[Node|Mon]|Reqs]);
  537. mc_send(_BadNodes, _Name, Alias, _Request, Timer, Reqs) ->
  538. %% Cleanup then fail...
  539. unalias(Alias),
  540. mc_cancel_timer(Timer, Alias),
  541. _ = mc_recv_tmo(Reqs, Alias, [], []),
  542. error(badarg).
  543. mc_recv([], Alias, Timer, Replies, BadNodes) ->
  544. mc_cancel_timer(Timer, Alias),
  545. unalias(Alias),
  546. {Replies, BadNodes};
  547. mc_recv([[Node|Mon] | RestReqs] = Reqs, Alias, Timer, Replies, BadNodes) ->
  548. receive
  549. {[[alias|Alias]|Mon], Reply} ->
  550. erlang:demonitor(Mon, [flush]),
  551. mc_recv(RestReqs, Alias, Timer, [{Node,Reply}|Replies], BadNodes);
  552. {Alias, Mon, process, _, _} ->
  553. mc_recv(RestReqs, Alias, Timer, Replies, [Node|BadNodes]);
  554. {timeout, Timer, Alias} ->
  555. unalias(Alias),
  556. mc_recv_tmo(Reqs, Alias, Replies, BadNodes)
  557. end.
  558. mc_recv_tmo([], _Alias, Replies, BadNodes) ->
  559. {Replies, BadNodes};
  560. mc_recv_tmo([[Node|Mon] | RestReqs], Alias, Replies, BadNodes) ->
  561. erlang:demonitor(Mon),
  562. receive
  563. {[[alias|Alias]|Mon], Reply} ->
  564. mc_recv_tmo(RestReqs, Alias, [{Node,Reply}|Replies], BadNodes);
  565. {Alias, Mon, process, _, _} ->
  566. mc_recv_tmo(RestReqs, Alias, Replies, [Node|BadNodes])
  567. after
  568. 0 ->
  569. mc_recv_tmo(RestReqs, Alias, Replies, [Node|BadNodes])
  570. end.
  571. mc_cancel_timer(undefined, _Alias) ->
  572. ok;
  573. mc_cancel_timer(Timer, Alias) ->
  574. case erlang:cancel_timer(Timer) of
  575. false ->
  576. receive
  577. {timeout, Timer, Alias} ->
  578. ok
  579. end;
  580. _ ->
  581. ok
  582. end.
  583. -spec cast(ServerRef :: serverRef(), Msg :: term()) -> ok.
  584. cast({global, Name}, Msg) ->
  585. try global:send(Name, {'$gen_cast', Msg}),
  586. ok
  587. catch _:_ -> ok
  588. end;
  589. cast({via, RegMod, Name}, Msg) ->
  590. try RegMod:send(Name, {'$gen_cast', Msg}),
  591. ok
  592. catch _:_ -> ok
  593. end;
  594. cast({Name, Node} = Dest, Msg) when is_atom(Name), is_atom(Node) ->
  595. try erlang:send(Dest, {'$gen_cast', Msg}),
  596. ok
  597. catch _:_ -> ok
  598. end;
  599. cast(Dest, Msg) ->
  600. try erlang:send(Dest, {'$gen_cast', Msg}),
  601. ok
  602. catch _:_ -> ok
  603. end.
  604. -spec send(ServerRef :: serverRef(), Msg :: term()) -> ok.
  605. send({global, Name}, Msg) ->
  606. try global:send(Name, Msg),
  607. ok
  608. catch _:_ -> ok
  609. end;
  610. send({via, RegMod, Name}, Msg) ->
  611. try RegMod:send(Name, Msg),
  612. ok
  613. catch _:_ -> ok
  614. end;
  615. send({Name, Node} = Dest, Msg) when is_atom(Name), is_atom(Node) ->
  616. try erlang:send(Dest, Msg),
  617. ok
  618. catch _:_ -> ok
  619. end;
  620. send(Dest, Msg) ->
  621. try erlang:send(Dest, Msg),
  622. ok
  623. catch _:_ -> ok
  624. end.
  625. %% 异步广播,不返回任何内容,只是发送“ n”祈祷
  626. abcast(Name, Msg) when is_atom(Name) ->
  627. doAbcast([node() | nodes()], Name, Msg).
  628. abcast(Nodes, Name, Msg) when is_list(Nodes), is_atom(Name) ->
  629. doAbcast(Nodes, Name, Msg).
  630. doAbcast(Nodes, Name, Msg) ->
  631. [
  632. begin
  633. try erlang:send({Name, Node}, {'$gen_cast', Msg}),
  634. ok
  635. catch
  636. _:_ -> ok
  637. end
  638. end || Node <- Nodes
  639. ],
  640. ok.
  641. %% gen_event send_request/3
  642. -spec send_request(ServerRef :: serverRef(), epmHandler(), term()) -> request_id().
  643. send_request(Name, Handler, Query) ->
  644. gen:send_request(Name, self(), {'$epmCall', Handler, Query}).
  645. %% -----------------------------------------------------------------
  646. %% Send a request to a generic server and return a Key which should be
  647. %% used with wait_response/2 or check_response/2 to fetch the
  648. %% result of the request.
  649. -spec send_request(ServerRef::serverRef(), Request::term()) ->
  650. ReqId::request_id().
  651. send_request(ServerRef, Request) ->
  652. try
  653. gen:send_request(ServerRef, '$gen_call', Request)
  654. catch
  655. error:badarg ->
  656. error(badarg, [ServerRef, Request])
  657. end.
  658. -spec send_request(ServerRef::serverRef(),
  659. Request::term(),
  660. Label::term(),
  661. ReqIdCollection::request_id_collection()) ->
  662. NewReqIdCollection::request_id_collection().
  663. send_request(ServerRef, Request, Label, ReqIdCol) ->
  664. try
  665. gen:send_request(ServerRef, '$gen_call', Request, Label, ReqIdCol)
  666. catch
  667. error:badarg ->
  668. error(badarg, [ServerRef, Request, Label, ReqIdCol])
  669. end.
  670. -spec wait_response(ReqId, WaitTime) -> Result when
  671. ReqId :: request_id(),
  672. WaitTime :: response_timeout(),
  673. Response :: {reply, Reply::term()}
  674. | {error, {Reason::term(), serverRef()}},
  675. Result :: Response | 'timeout'.
  676. wait_response(ReqId, WaitTime) ->
  677. try
  678. gen:wait_response(ReqId, WaitTime)
  679. catch
  680. error:badarg ->
  681. error(badarg, [ReqId, WaitTime])
  682. end.
  683. -spec wait_response(ReqIdCollection, WaitTime, Delete) -> Result when
  684. ReqIdCollection :: request_id_collection(),
  685. WaitTime :: response_timeout(),
  686. Delete :: boolean(),
  687. Response :: {reply, Reply::term()} |
  688. {error, {Reason::term(), serverRef()}},
  689. Result :: {Response,
  690. Label::term(),
  691. NewReqIdCollection::request_id_collection()} |
  692. 'no_request' |
  693. 'timeout'.
  694. wait_response(ReqIdCol, WaitTime, Delete) ->
  695. try
  696. gen:wait_response(ReqIdCol, WaitTime, Delete)
  697. catch
  698. error:badarg ->
  699. error(badarg, [ReqIdCol, WaitTime, Delete])
  700. end.
  701. -spec receive_response(ReqId, Timeout) -> Result when
  702. ReqId :: request_id(),
  703. Timeout :: response_timeout(),
  704. Response :: {reply, Reply::term()} |
  705. {error, {Reason::term(), serverRef()}},
  706. Result :: Response | 'timeout'.
  707. receive_response(ReqId, Timeout) ->
  708. try
  709. gen:receive_response(ReqId, Timeout)
  710. catch
  711. error:badarg ->
  712. error(badarg, [ReqId, Timeout])
  713. end.
  714. -spec receive_response(ReqIdCollection, Timeout, Delete) -> Result when
  715. ReqIdCollection :: request_id_collection(),
  716. Timeout :: response_timeout(),
  717. Delete :: boolean(),
  718. Response :: {reply, Reply::term()} |
  719. {error, {Reason::term(), serverRef()}},
  720. Result :: {Response,
  721. Label::term(),
  722. NewReqIdCollection::request_id_collection()} |
  723. 'no_request' |
  724. 'timeout'.
  725. receive_response(ReqIdCol, Timeout, Delete) ->
  726. try
  727. gen:receive_response(ReqIdCol, Timeout, Delete)
  728. catch
  729. error:badarg ->
  730. error(badarg, [ReqIdCol, Timeout, Delete])
  731. end.
  732. -spec check_response(Msg, ReqId) -> Result when
  733. Msg :: term(),
  734. ReqId :: request_id(),
  735. Response :: {reply, Reply::term()} |
  736. {error, {Reason::term(), serverRef()}},
  737. Result :: Response | 'no_reply'.
  738. check_response(Msg, ReqId) ->
  739. try
  740. gen:check_response(Msg, ReqId)
  741. catch
  742. error:badarg ->
  743. error(badarg, [Msg, ReqId])
  744. end.
  745. -spec check_response(Msg, ReqIdCollection, Delete) -> Result when
  746. Msg :: term(),
  747. ReqIdCollection :: request_id_collection(),
  748. Delete :: boolean(),
  749. Response :: {reply, Reply::term()} |
  750. {error, {Reason::term(), serverRef()}},
  751. Result :: {Response,
  752. Label::term(),
  753. NewReqIdCollection::request_id_collection()} |
  754. 'no_request' |
  755. 'no_reply'.
  756. check_response(Msg, ReqIdCol, Delete) ->
  757. try
  758. gen:check_response(Msg, ReqIdCol, Delete)
  759. catch
  760. error:badarg ->
  761. error(badarg, [Msg, ReqIdCol, Delete])
  762. end.
  763. -spec reqids_new() ->
  764. NewReqIdCollection::request_id_collection().
  765. reqids_new() ->
  766. gen:reqids_new().
  767. -spec reqids_size(ReqIdCollection::request_id_collection()) ->
  768. non_neg_integer().
  769. reqids_size(ReqIdCollection) ->
  770. try
  771. gen:reqids_size(ReqIdCollection)
  772. catch
  773. error:badarg -> error(badarg, [ReqIdCollection])
  774. end.
  775. -spec reqids_add(ReqId::request_id(), Label::term(),
  776. ReqIdCollection::request_id_collection()) ->
  777. NewReqIdCollection::request_id_collection().
  778. reqids_add(ReqId, Label, ReqIdCollection) ->
  779. try
  780. gen:reqids_add(ReqId, Label, ReqIdCollection)
  781. catch
  782. error:badarg -> error(badarg, [ReqId, Label, ReqIdCollection])
  783. end.
  784. -spec reqids_to_list(ReqIdCollection::request_id_collection()) ->
  785. [{ReqId::request_id(), Label::term()}].
  786. reqids_to_list(ReqIdCollection) ->
  787. try
  788. gen:reqids_to_list(ReqIdCollection)
  789. catch
  790. error:badarg -> error(badarg, [ReqIdCollection])
  791. end.
  792. %% Reply from a status machine callback to whom awaits in call/2
  793. -spec reply([replyAction(), ...] | replyAction()) -> ok.
  794. reply({reply, {To, Tag}, Reply}) ->
  795. try To ! {Tag, Reply},
  796. ok
  797. catch _:_ ->
  798. ok
  799. end;
  800. reply(Replies) when is_list(Replies) ->
  801. [greply(From, Reply) || {reply, From, Reply} <- Replies],
  802. ok.
  803. -compile({inline, [reply/2]}).
  804. -spec reply(From :: from(), Reply :: term()) -> ok.
  805. reply(From, Reply) ->
  806. greply(From, Reply).
  807. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% API helpers end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  808. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gen_event start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  809. epmRequest({global, Name}, Msg) ->
  810. try global:send(Name, Msg),
  811. ok
  812. catch _:_ -> ok
  813. end;
  814. epmRequest({via, RegMod, Name}, Msg) ->
  815. try RegMod:send(Name, Msg),
  816. ok
  817. catch _:_ -> ok
  818. end;
  819. epmRequest(EpmSrv, Cmd) ->
  820. EpmSrv ! Cmd,
  821. ok.
  822. -spec epm_info(serverRef(), epmHandler(), term()) -> term().
  823. epm_info(EpmSrv, EpmHandler, Msg) ->
  824. epmRequest(EpmSrv, {'$epm_info', EpmHandler, Msg}).
  825. -spec info_notify(serverRef(), term()) -> 'ok'.
  826. info_notify(EpmSrv, Event) ->
  827. epmRequest(EpmSrv, {'$epm_info', '$infoNotify', Event}).
  828. epmRpc(EpmSrv, Cmd) ->
  829. try gcall(EpmSrv, '$epm_call', Cmd, infinity) of
  830. {ok, Reply} ->
  831. Reply
  832. catch Class:Reason ->
  833. erlang:raise(Class, {Reason, {?MODULE, call, [EpmSrv, Cmd, infinity]}}, ?STACKTRACE())
  834. end.
  835. epmRpc(EpmSrv, Cmd, Timeout) ->
  836. try gcall(EpmSrv, '$epm_call', Cmd, Timeout) of
  837. {ok, Reply} ->
  838. Reply
  839. catch Class:Reason ->
  840. erlang:raise(Class, {Reason, {?MODULE, call, [EpmSrv, Cmd, Timeout]}}, ?STACKTRACE())
  841. end.
  842. -spec call_notify(serverRef(), term()) -> 'ok'.
  843. call_notify(EpmSrv, Event) ->
  844. epmRpc(EpmSrv, {'$syncNotify', Event}).
  845. -spec epm_call(serverRef(), epmHandler(), term()) -> term().
  846. epm_call(EpmSrv, EpmHandler, Query) ->
  847. epmRpc(EpmSrv, {'$epmCall', EpmHandler, Query}).
  848. -spec epm_call(serverRef(), epmHandler(), term(), timeout()) -> term().
  849. epm_call(EpmSrv, EpmHandler, Query, Timeout) ->
  850. epmRpc(EpmSrv, {'$epmCall', EpmHandler, Query}, Timeout).
  851. -spec add_epm(serverRef(), epmHandler(), term()) -> term().
  852. add_epm(EpmSrv, EpmHandler, Args) ->
  853. epmRpc(EpmSrv, {'$addEpm', EpmHandler, Args}).
  854. -spec add_sup_epm(serverRef(), epmHandler(), term()) -> term().
  855. add_sup_epm(EpmSrv, EpmHandler, Args) ->
  856. epmRpc(EpmSrv, {'$addSupEpm', EpmHandler, Args, self()}).
  857. -spec del_epm(serverRef(), epmHandler(), term()) -> term().
  858. del_epm(EpmSrv, EpmHandler, Args) ->
  859. epmRpc(EpmSrv, {'$delEpm', EpmHandler, Args}).
  860. -spec swap_epm(serverRef(), {epmHandler(), term()}, {epmHandler(), term()}) -> 'ok' | {'error', term()}.
  861. swap_epm(EpmSrv, {H1, A1}, {H2, A2}) ->
  862. epmRpc(EpmSrv, {'$swapEpm', H1, A1, H2, A2}).
  863. -spec swap_sup_epm(serverRef(), {epmHandler(), term()}, {epmHandler(), term()}) -> 'ok' | {'error', term()}.
  864. swap_sup_epm(EpmSrv, {H1, A1}, {H2, A2}) ->
  865. epmRpc(EpmSrv, {'$swapSupEpm', H1, A1, H2, A2, self()}).
  866. -spec which_epm(serverRef()) -> [epmHandler()].
  867. which_epm(EpmSrv) ->
  868. epmRpc(EpmSrv, '$which_handlers').
  869. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  870. %% EPM inner fun
  871. addNewEpm(InitRet, EpmHers, Module, EpmId, EpmSup) ->
  872. case InitRet of
  873. {ok, State} ->
  874. EpmHer = #epmHer{epmId = EpmId, epmM = Module, epmS = State, epmSup = EpmSup},
  875. {ok, EpmHers#{EpmId => EpmHer}, false};
  876. {ok, State, hibernate} ->
  877. EpmHer = #epmHer{epmId = EpmId, epmM = Module, epmS = State, epmSup = EpmSup},
  878. {ok, EpmHers#{EpmId => EpmHer}, true};
  879. Other ->
  880. {Other, EpmHers, false}
  881. end.
  882. doAddEpm(EpmHers, {Module, _SubId} = EpmId, Args, EpmSup) ->
  883. case EpmHers of
  884. #{EpmId := _EpmHer} ->
  885. {{error, existed}, EpmHers, false};
  886. _ ->
  887. try Module:init(Args) of
  888. Result ->
  889. addNewEpm(Result, EpmHers, Module, EpmId, EpmSup)
  890. catch
  891. throw:Ret ->
  892. addNewEpm(Ret, EpmHers, Module, EpmId, EpmSup);
  893. C:R:S ->
  894. {{error, {C, R, S}}, EpmHers, false}
  895. end
  896. end;
  897. doAddEpm(EpmHers, Module, Args, EpmSup) ->
  898. case EpmHers of
  899. #{Module := _EpmHer} ->
  900. {{error, existed}, EpmHers, false};
  901. _ ->
  902. try Module:init(Args) of
  903. Result ->
  904. addNewEpm(Result, EpmHers, Module, Module, EpmSup)
  905. catch
  906. throw:Ret ->
  907. addNewEpm(Ret, EpmHers, Module, Module, EpmSup);
  908. C:R:S ->
  909. {{error, {C, R, S}}, EpmHers, false}
  910. end
  911. end.
  912. doAddSupEpm(EpmHers, EpmHandler, Args, EpmSup) ->
  913. case doAddEpm(EpmHers, EpmHandler, Args, EpmSup) of
  914. {ok, _, _} = Result ->
  915. link(EpmSup),
  916. Result;
  917. Ret ->
  918. Ret
  919. end.
  920. doSwapEpm(EpmHers, EpmId1, Args1, EpmMId, Args2) ->
  921. case EpmHers of
  922. #{EpmId1 := #epmHer{epmSup = EpmSup} = EpmHer} ->
  923. State2 = epmTerminate(EpmHer, Args1, swapped, {swapped, EpmMId, EpmSup}),
  924. NewEpmHers = maps:remove(EpmId1, EpmHers),
  925. case EpmSup of
  926. false ->
  927. doAddEpm(NewEpmHers, EpmMId, {Args2, State2}, undefined);
  928. _ ->
  929. doAddSupEpm(NewEpmHers, EpmMId, {Args2, State2}, EpmSup)
  930. end;
  931. undefined ->
  932. doAddEpm(EpmHers, EpmMId, {Args2, undefined}, undefined)
  933. end.
  934. doSwapSupEpm(EpmHers, EpmId1, Args1, EpmMId, Args2, EpmSup) ->
  935. case EpmHers of
  936. #{EpmId1 := EpmHer} ->
  937. State2 = epmTerminate(EpmHer, Args1, swapped, {swapped, EpmMId, EpmSup}),
  938. NewEpmHers = maps:remove(EpmId1, EpmHers),
  939. doAddSupEpm(NewEpmHers, EpmMId, {Args2, State2}, EpmSup);
  940. undefined ->
  941. doAddSupEpm(EpmHers, EpmMId, {Args2, undefined}, EpmSup)
  942. end.
  943. doNotify(EpmHers, Func, Event, _Form) ->
  944. allNotify(iterator(EpmHers), Func, Event, false, EpmHers, false).
  945. allNotify(Iterator, Func, Event, From, TemEpmHers, IsHib) ->
  946. case next(Iterator) of
  947. {K, _V, NextIterator} ->
  948. {NewEpmHers, NewIsHib} = doEpmHandle(TemEpmHers, K, Func, Event, From),
  949. allNotify(NextIterator, Func, Event, From, NewEpmHers, IsHib orelse NewIsHib);
  950. _ ->
  951. {TemEpmHers, IsHib}
  952. end.
  953. doEpmHandle(EpmHers, EpmHandler, Func, Event, From) ->
  954. case EpmHers of
  955. #{EpmHandler := #epmHer{epmM = EpmM, epmS = EpmS} = EpmHer} ->
  956. try EpmM:Func(Event, EpmS) of
  957. Result ->
  958. handleEpmCR(Result, EpmHers, EpmHer, Event, From)
  959. catch
  960. throw:Ret ->
  961. handleEpmCR(Ret, EpmHers, EpmHer, Event, From);
  962. C:R:S ->
  963. epmTerminate(EpmHer, {error, {C, R, S}}, Event, crash),
  964. NewEpmHers = maps:remove(EpmHandler, EpmHers),
  965. {NewEpmHers, false}
  966. end;
  967. _ ->
  968. try_greply(From, {error, bad_module}),
  969. {EpmHers, false}
  970. end.
  971. doDelEpm(EpmHers, EpmHandler, Args) ->
  972. case EpmHers of
  973. #{EpmHandler := EpmHer} ->
  974. epmTerminate(EpmHer, Args, delete, normal),
  975. {ok, maps:remove(EpmHandler, EpmHers)};
  976. undefined ->
  977. {{error, module_not_found}, EpmHers}
  978. end.
  979. epmTerminate(#epmHer{epmM = EpmM, epmS = State} = EpmHer, Args, LastIn, Reason) ->
  980. case erlang:function_exported(EpmM, terminate, 2) of
  981. true ->
  982. Res = (catch EpmM:terminate(Args, State)),
  983. reportTerminate(EpmHer, Reason, Args, LastIn, Res),
  984. Res;
  985. false ->
  986. reportTerminate(EpmHer, Reason, Args, LastIn, ok),
  987. ok
  988. end.
  989. reportTerminate(EpmHer, crash, {error, Why}, LastIn, _) ->
  990. reportTerminate2(EpmHer, Why, LastIn);
  991. %% How == normal | shutdown | {swapped, NewHandler, NewSupervisor}
  992. reportTerminate(EpmHer, How, _, LastIn, _) ->
  993. reportTerminate2(EpmHer, How, LastIn).
  994. reportTerminate2(#epmHer{epmSup = EpmSup, epmId = EpmId, epmS = State} = EpmHer, Reason, LastIn) ->
  995. report_error(EpmHer, Reason, State, LastIn),
  996. case EpmSup of
  997. undefined ->
  998. ok;
  999. _ ->
  1000. EpmSup ! {gen_event_EXIT, EpmId, Reason},
  1001. ok
  1002. end.
  1003. report_error(_EpmHer, normal, _, _) -> ok;
  1004. report_error(_EpmHer, shutdown, _, _) -> ok;
  1005. report_error(_EpmHer, {swapped, _, _}, _, _) -> ok;
  1006. report_error(#epmHer{epmId = EpmId, epmM = EpmM}, Reason, State, LastIn) ->
  1007. ?LOG_ERROR(
  1008. #{
  1009. label => {gen_ipc, epm_terminate},
  1010. handler => {EpmId, EpmM},
  1011. name => undefined,
  1012. last_message => LastIn,
  1013. state => State,
  1014. reason => Reason
  1015. },
  1016. #{
  1017. domain => [otp],
  1018. report_cb => fun gen_ipc:epm_log/1,
  1019. error_logger => #{tag => error}
  1020. }).
  1021. epm_log(#{label := {gen_ipc, epm_terminate}, handler := Handler, name := SName, last_message := LastIn, state := State, reason := Reason}) ->
  1022. Reason1 =
  1023. case Reason of
  1024. {'EXIT', {undef, [{M, F, A, L} | MFAs]}} ->
  1025. case code:is_loaded(M) of
  1026. false ->
  1027. {'module could not be loaded', [{M, F, A, L} | MFAs]};
  1028. _ ->
  1029. case erlang:function_exported(M, F, length(A)) of
  1030. true ->
  1031. {undef, [{M, F, A, L} | MFAs]};
  1032. false ->
  1033. {'function not exported', [{M, F, A, L} | MFAs]}
  1034. end
  1035. end;
  1036. {'EXIT', Why} ->
  1037. Why;
  1038. _ ->
  1039. Reason
  1040. end,
  1041. {"** gen_ipc emp handler ~p crashed.~n"
  1042. "** Was installed in ~tp~n"
  1043. "** Last event was: ~tp~n"
  1044. "** When handler state == ~tp~n"
  1045. "** Reason == ~tp~n", [Handler, SName, LastIn, State, Reason1]}.
  1046. epmStopAll(EpmHers) ->
  1047. allStop(iterator(EpmHers)).
  1048. allStop(Iterator) ->
  1049. case next(Iterator) of
  1050. {_K, V, NextIterator} ->
  1051. epmTerminate(V, stop, 'receive', shutdown),
  1052. case element(#epmHer.epmSup, V) of
  1053. undefined ->
  1054. ignore;
  1055. EpmSup ->
  1056. unlink(EpmSup)
  1057. end,
  1058. allStop(NextIterator);
  1059. none ->
  1060. ok
  1061. end.
  1062. epmStopOne(ExitEmpSup, EpmHers) ->
  1063. forStopOne(iterator(EpmHers), ExitEmpSup, EpmHers).
  1064. forStopOne(Iterator, ExitEmpSup, TemEpmHers) ->
  1065. case next(Iterator) of
  1066. {K, V, NextIterator} ->
  1067. case element(#epmHer.epmSup, V) =:= ExitEmpSup of
  1068. true ->
  1069. epmTerminate(V, stop, 'receive', shutdown),
  1070. forStopOne(NextIterator, ExitEmpSup, maps:remove(K, TemEpmHers));
  1071. _ ->
  1072. forStopOne(NextIterator, ExitEmpSup, TemEpmHers)
  1073. end;
  1074. none ->
  1075. TemEpmHers
  1076. end.
  1077. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gen_event end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1078. listify(Item) when is_list(Item) ->
  1079. Item;
  1080. listify(Item) ->
  1081. [Item].
  1082. %%%==========================================================================
  1083. %%% Internal callbacks
  1084. wakeupFromHib(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug) ->
  1085. %% 这是一条新消息,唤醒了我们,因此我们必须立即收到它
  1086. receiveIng(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, true).
  1087. %%%==========================================================================
  1088. %% Entry point for system_continue/3
  1089. reLoopEntry(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, IsHib) ->
  1090. if
  1091. IsHib ->
  1092. proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug]);
  1093. true ->
  1094. receiveIng(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, false)
  1095. end.
  1096. %% 接收新的消息
  1097. receiveIng(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, IsHib) ->
  1098. receive
  1099. Msg ->
  1100. case Msg of
  1101. {'$gen_call', From, Request} ->
  1102. matchCallMsg(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, From, Request);
  1103. {'$gen_cast', Cast} ->
  1104. matchCastMsg(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, Cast);
  1105. {timeout, TimerRef, TimeoutType} ->
  1106. case Timers of
  1107. #{TimeoutType := {TimerRef, TimeoutMsg}} ->
  1108. NewTimers = maps:remove(TimeoutType, Timers),
  1109. matchTimeoutMsg(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, NewTimers, CurStatus, CurState, Debug, TimeoutType, TimeoutMsg);
  1110. _ ->
  1111. matchInfoMsg(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, Msg)
  1112. end;
  1113. {system, PidFrom, Request} ->
  1114. %% 不返回但尾递归调用 system_continue/3
  1115. sys:handle_system_msg(Request, PidFrom, Parent, ?MODULE, Debug, {Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, IsHib}, IsHib);
  1116. {'EXIT', PidFrom, Reason} ->
  1117. case Parent =:= PidFrom of
  1118. true ->
  1119. terminate(exit, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, []);
  1120. _ ->
  1121. NewEpmHers = epmStopOne(PidFrom, EpmHers),
  1122. matchInfoMsg(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, NewEpmHers, Postponed, Timers, CurStatus, CurState, Debug, Msg)
  1123. end;
  1124. {'$epm_call', From, Request} ->
  1125. matchEpmCallMsg(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, From, Request);
  1126. {'$epm_info', CmdOrEmpHandler, Event} ->
  1127. matchEpmInfoMsg(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, CmdOrEmpHandler, Event);
  1128. _ ->
  1129. matchInfoMsg(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, Msg)
  1130. end
  1131. after
  1132. HibernateAfterTimeout ->
  1133. proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug])
  1134. end.
  1135. matchCallMsg(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, From, Request) ->
  1136. CurEvent = {{call, From}, Request},
  1137. ?SYS_DEBUG(Debug, Name, {in, CurEvent, CurStatus}),
  1138. try Module:handleCall(Request, CurStatus, CurState, From) of
  1139. Result ->
  1140. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, [CurEvent], Result, ?CB_FORM_EVENT, From)
  1141. catch
  1142. throw:Result ->
  1143. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, [CurEvent], Result, ?CB_FORM_EVENT, From);
  1144. Class:Reason:Strace ->
  1145. try_greply(From, {error, {inner_error, {Class, Reason, Strace}}}),
  1146. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, [CurEvent], Class, Reason, Strace)
  1147. end.
  1148. matchCastMsg(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, Cast) ->
  1149. CurEvent = {cast, Cast},
  1150. ?SYS_DEBUG(Debug, Name, {in, CurEvent, CurStatus}),
  1151. try Module:handleCast(Cast, CurStatus, CurState) of
  1152. Result ->
  1153. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, [CurEvent], Result, ?CB_FORM_EVENT, false)
  1154. catch
  1155. throw:Result ->
  1156. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, [CurEvent], Result, ?CB_FORM_EVENT, false);
  1157. Class:Reason:Strace ->
  1158. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, [CurEvent], Class, Reason, Strace)
  1159. end.
  1160. matchInfoMsg(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, Msg) ->
  1161. CurEvent = {info, Msg},
  1162. ?SYS_DEBUG(Debug, Name, {in, CurEvent, CurStatus}),
  1163. try Module:handleInfo(Msg, CurStatus, CurState) of
  1164. Result ->
  1165. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, [CurEvent], Result, ?CB_FORM_EVENT, false)
  1166. catch
  1167. throw:Result ->
  1168. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, [CurEvent], Result, ?CB_FORM_EVENT, false);
  1169. Class:Reason:Strace ->
  1170. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, [CurEvent], Class, Reason, Strace)
  1171. end.
  1172. matchTimeoutMsg(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, TimeoutType, TimeoutMsg) ->
  1173. CurEvent = {TimeoutType, TimeoutMsg},
  1174. ?SYS_DEBUG(Debug, Name, {in, CurEvent, CurStatus}),
  1175. try Module:handleOnevent(TimeoutType, TimeoutMsg, CurStatus, CurState) of
  1176. Result ->
  1177. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, [CurEvent], Result, ?CB_FORM_EVENT, false)
  1178. catch
  1179. throw:Result ->
  1180. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, [CurEvent], Result, ?CB_FORM_EVENT, false);
  1181. Class:Reason:Strace ->
  1182. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, [CurEvent], Class, Reason, Strace)
  1183. end.
  1184. matchEpmCallMsg(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, From, Request) ->
  1185. ?SYS_DEBUG(Debug, Name, {in, Request, CurStatus}),
  1186. case Request of
  1187. '$which_handlers' ->
  1188. reply(From, EpmHers);
  1189. {'$addEpm', EpmHandler, Args} ->
  1190. {Reply, NewEpmHers, IsHib} = doAddEpm(EpmHers, EpmHandler, Args, undefined),
  1191. reply(From, Reply),
  1192. reLoopEntry(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, NewEpmHers, Postponed, Timers, CurStatus, CurState, Debug, IsHib);
  1193. {'$addSupEpm', EpmHandler, Args, EpmSup} ->
  1194. {Reply, NewEpmHers, IsHib} = doAddSupEpm(EpmHers, EpmHandler, Args, EpmSup),
  1195. reply(From, Reply),
  1196. reLoopEntry(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, NewEpmHers, Postponed, Timers, CurStatus, CurState, Debug, IsHib);
  1197. {'$delEpm', EpmHandler, Args} ->
  1198. {Reply, NewEpmHers} = doDelEpm(EpmHers, EpmHandler, Args),
  1199. reply(From, Reply),
  1200. receiveIng(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, NewEpmHers, Postponed, Timers, CurStatus, CurState, Debug, false);
  1201. {'$swapEpm', EpmId1, Args1, EpmId2, Args2} ->
  1202. {Reply, NewEpmHers, IsHib} = doSwapEpm(EpmHers, EpmId1, Args1, EpmId2, Args2),
  1203. reply(From, Reply),
  1204. reLoopEntry(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, NewEpmHers, Postponed, Timers, CurStatus, CurState, Debug, IsHib);
  1205. {'$swapSupEpm', EpmId1, Args1, EpmId2, Args2, SupPid} ->
  1206. {Reply, NewEpmHers, IsHib} = doSwapSupEpm(EpmHers, EpmId1, Args1, EpmId2, Args2, SupPid),
  1207. reply(From, Reply),
  1208. reLoopEntry(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, NewEpmHers, Postponed, Timers, CurStatus, CurState, Debug, IsHib);
  1209. {'$syncNotify', Event} ->
  1210. {NewEpmHers, IsHib} = doNotify(EpmHers, handleEvent, Event, false),
  1211. reply(From, ok),
  1212. startEpmCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, NewEpmHers, Postponed, Timers, CurStatus, CurState, Debug, handleEpmEvent, Request, IsHib);
  1213. {'$epmCall', EpmHandler, Query} ->
  1214. {NewEpmHers, IsHib} = doEpmHandle(EpmHers, EpmHandler, handleCall, Query, From),
  1215. startEpmCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, NewEpmHers, Postponed, Timers, CurStatus, CurState, Debug, handleEpmCall, Request, IsHib)
  1216. end.
  1217. matchEpmInfoMsg(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, CmdOrEmpHandler, Event) ->
  1218. ?SYS_DEBUG(Debug, Name, {in, {CmdOrEmpHandler, Event}, CurStatus}),
  1219. case CmdOrEmpHandler of
  1220. '$infoNotify' ->
  1221. {NewEpmHers, IsHib} = doNotify(EpmHers, handleEvent, Event, false),
  1222. startEpmCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, NewEpmHers, Postponed, Timers, CurStatus, CurState, Debug, handleEpmEvent, Event, IsHib);
  1223. EpmHandler ->
  1224. {NewEpmHers, IsHib} = doEpmHandle(EpmHers, EpmHandler, handleInfo, Event, false),
  1225. startEpmCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, NewEpmHers, Postponed, Timers, CurStatus, CurState, Debug, handleEpmInfo, Event, IsHib)
  1226. end.
  1227. startEpmCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, CallbackFun, Event, IsHib) ->
  1228. case erlang:function_exported(Module, CallbackFun, 3) of
  1229. true ->
  1230. ?SYS_DEBUG(Debug, Name, {in, Event, CurStatus}),
  1231. try Module:CallbackFun(Event, CurStatus, CurState) of
  1232. Result ->
  1233. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, [Event], Result, ?CB_FORM_EVENT, false)
  1234. catch
  1235. throw:Ret ->
  1236. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, [Event], Ret, ?CB_FORM_EVENT, false);
  1237. Class:Reason:Strace ->
  1238. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, [Event], Class, Reason, Strace)
  1239. end;
  1240. _ ->
  1241. reLoopEntry(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, IsHib)
  1242. end.
  1243. startEnterCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, PrevStatus, CurState, CurStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter) ->
  1244. try Module:handleEnter(PrevStatus, CurStatus, CurState) of
  1245. Result ->
  1246. handleEnterCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, PrevStatus, CurState, CurStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter, Result)
  1247. catch
  1248. throw:Result ->
  1249. handleEnterCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, PrevStatus, CurState, CurStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter, Result);
  1250. Class:Reason:Strace ->
  1251. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Class, Reason, Strace)
  1252. end.
  1253. startAfterCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Args) ->
  1254. try Module:handleAfter(Args, CurStatus, CurState) of
  1255. Result ->
  1256. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Result, ?CB_FORM_AFTER, false)
  1257. catch
  1258. throw:Result ->
  1259. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Result, ?CB_FORM_AFTER, false);
  1260. Class:Reason:Strace ->
  1261. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, {doAfter, Args}, Class, Reason, Strace)
  1262. end.
  1263. startEventCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, {Type, Content}) ->
  1264. case Type of
  1265. 'cast' ->
  1266. try Module:handleCast(Content, CurStatus, CurState) of
  1267. Result ->
  1268. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Result, ?CB_FORM_EVENT, false)
  1269. catch
  1270. throw:Ret ->
  1271. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Ret, ?CB_FORM_EVENT, false);
  1272. Class:Reason:Strace ->
  1273. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, {Type, Content}, Class, Reason, Strace)
  1274. end;
  1275. 'info' ->
  1276. try Module:handleInfo(Content, CurStatus, CurState) of
  1277. Result ->
  1278. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Result, ?CB_FORM_EVENT, false)
  1279. catch
  1280. throw:Ret ->
  1281. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Ret, ?CB_FORM_EVENT, false);
  1282. Class:Reason:Strace ->
  1283. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, {Type, Content}, Class, Reason, Strace)
  1284. end;
  1285. {'call', From} ->
  1286. try Module:handleCall(Content, CurStatus, CurState, From) of
  1287. Result ->
  1288. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Result, ?CB_FORM_EVENT, From)
  1289. catch
  1290. throw:Ret ->
  1291. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Ret, ?CB_FORM_EVENT, From);
  1292. Class:Reason:Strace ->
  1293. try_greply(From, {error, {inner_error, {Class, Reason, Strace}}}),
  1294. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, {Type, Content}, Class, Reason, Strace)
  1295. end;
  1296. _ ->
  1297. try Module:handleOnevent(Type, Content, CurStatus, CurState) of
  1298. Result ->
  1299. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Result, ?CB_FORM_EVENT, false)
  1300. catch
  1301. throw:Ret ->
  1302. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Ret, ?CB_FORM_EVENT, false);
  1303. Class:Reason:Strace ->
  1304. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, {Type, Content}, Class, Reason, Strace)
  1305. end
  1306. end.
  1307. %% handleEpmCallbackRet
  1308. handleEpmCR(Result, EpmHers, #epmHer{epmId = EpmId} = EpmHer, Event, From) ->
  1309. case Result of
  1310. kpS ->
  1311. {EpmHers, false};
  1312. {noreply, NewEpmS} ->
  1313. MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  1314. {EpmHers#{EpmId := MewEpmHer}, false};
  1315. {noreply, NewEpmS, hibernate} ->
  1316. MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  1317. {EpmHers#{EpmId := MewEpmHer}, true};
  1318. {swapEpm, NewEpmS, Args1, EpmMId, Args2} ->
  1319. #epmHer{epmId = OldEpmMId, epmSup = EpmSup} = MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  1320. State = epmTerminate(MewEpmHer, Args1, swapped, {swapped, OldEpmMId, EpmSup}),
  1321. TemEpmHers = maps:remove(EpmId, EpmHers),
  1322. {_, NewEpmHers, IsHib} =
  1323. case EpmSup of
  1324. undefined ->
  1325. doAddEpm(TemEpmHers, EpmMId, {Args2, State}, undefined);
  1326. _ ->
  1327. doAddSupEpm(TemEpmHers, EpmMId, {Args2, State}, EpmSup)
  1328. end,
  1329. {NewEpmHers, IsHib};
  1330. {swapEpm, Reply, NewEpmS, Args1, EpmMId, Args2} ->
  1331. reply(From, Reply),
  1332. #epmHer{epmId = OldEpmMId, epmSup = EpmSup} = MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  1333. State = epmTerminate(MewEpmHer, Args1, swapped, {swapped, OldEpmMId, EpmSup}),
  1334. TemEpmHers = maps:remove(EpmId, EpmHers),
  1335. {_, NewEpmHers, IsHib} =
  1336. case EpmSup of
  1337. undefined ->
  1338. doAddEpm(TemEpmHers, EpmMId, {Args2, State}, undefined);
  1339. _ ->
  1340. doAddSupEpm(TemEpmHers, EpmMId, {Args2, State}, EpmSup)
  1341. end,
  1342. {NewEpmHers, IsHib};
  1343. removeEpm ->
  1344. epmTerminate(EpmHer, removeEpm, remove, normal),
  1345. {maps:remove(EpmId, EpmHers), false};
  1346. {removeEpm, Reply} ->
  1347. reply(From, Reply),
  1348. epmTerminate(EpmHer, removeEpm, remove, normal),
  1349. {maps:remove(EpmId, EpmHers), false};
  1350. {reply, Reply} ->
  1351. reply(From, Reply),
  1352. {EpmHers, false};
  1353. {reply, Reply, NewEpmS} ->
  1354. reply(From, Reply),
  1355. MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  1356. {EpmHers#{EpmId := MewEpmHer}, false};
  1357. {reply, Reply, NewEpmS, hibernate} ->
  1358. reply(From, Reply),
  1359. MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  1360. {EpmHers#{EpmId := MewEpmHer}, true};
  1361. Other ->
  1362. epmTerminate(EpmHer, {error, Other}, Event, crash),
  1363. {maps:remove(EpmId, EpmHers), false}
  1364. end.
  1365. %% handleEnterCallbackRet
  1366. handleEnterCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, PrevStatus, CurState, CurStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter, Result) ->
  1367. case Result of
  1368. {kpS, NewState} ->
  1369. dealEnterCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, PrevStatus, NewState, CurStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter, false);
  1370. {kpS, NewState, Actions} ->
  1371. parseEnterAL(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, PrevStatus, NewState, CurStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter, false, listify(Actions));
  1372. kpS_S ->
  1373. dealEnterCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, PrevStatus, CurState, CurStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter, false);
  1374. {kpS_S, Actions} ->
  1375. parseEnterAL(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, PrevStatus, CurState, CurStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter, false, listify(Actions));
  1376. {reS, NewState} ->
  1377. dealEnterCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, PrevStatus, NewState, CurStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter, true);
  1378. {reS, NewState, Actions} ->
  1379. parseEnterAL(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, PrevStatus, NewState, CurStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter, true, listify(Actions));
  1380. reS_S ->
  1381. dealEnterCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, PrevStatus, CurState, CurStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter, true);
  1382. {reS_S, Actions} ->
  1383. parseEnterAL(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, PrevStatus, CurState, CurStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter, true, listify(Actions));
  1384. stop ->
  1385. terminate(exit, normal, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents);
  1386. {stop, Reason} ->
  1387. terminate(exit, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents);
  1388. {stop, Reason, NewState} ->
  1389. terminate(exit, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, Debug, LeftEvents);
  1390. {stopReply, Reason, Replies} ->
  1391. ?SYS_DEBUG(Debug, Name, {out, Replies}),
  1392. try
  1393. terminate(exit, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents)
  1394. after
  1395. case Replies of
  1396. {reply, RFrom, Reply} ->
  1397. reply(RFrom, Reply);
  1398. _ ->
  1399. [reply(RFrom, Reply) || {reply, RFrom, Reply} <- Replies],
  1400. ok
  1401. end
  1402. end;
  1403. {stopReply, Reason, Replies, NewState} ->
  1404. ?SYS_DEBUG(Debug, Name, {out, Replies}),
  1405. try
  1406. terminate(exit, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, Debug, LeftEvents)
  1407. after
  1408. case Replies of
  1409. {reply, RFrom, Reply} ->
  1410. reply(RFrom, Reply);
  1411. _ ->
  1412. [reply(RFrom, Reply) || {reply, RFrom, Reply} <- Replies],
  1413. ok
  1414. end
  1415. end;
  1416. _ ->
  1417. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, error, {bad_handleEnterCR, Result}, ?STACKTRACE())
  1418. end.
  1419. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Result, CallbackForm, From) ->
  1420. case Result of
  1421. {noreply, NewState} ->
  1422. receiveIng(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, Debug, false);
  1423. {noreply, NewState, Option} ->
  1424. case Option of
  1425. hibernate ->
  1426. reLoopEntry(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, Debug, true);
  1427. {doAfter, Args} ->
  1428. startAfterCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, Debug, [], Args);
  1429. _Ret ->
  1430. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, error, {bad_noreply, _Ret}, ?STACKTRACE())
  1431. end;
  1432. {reply, Reply, NewState} ->
  1433. reply(From, Reply),
  1434. ?SYS_DEBUG(Debug, Name, {out, Reply, From}),
  1435. receiveIng(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, Debug, false);
  1436. {reply, Reply, NewState, Option} ->
  1437. reply(From, Reply),
  1438. ?SYS_DEBUG(Debug, Name, {out, Reply, From}),
  1439. case Option of
  1440. hibernate ->
  1441. reLoopEntry(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, Debug, true);
  1442. {doAfter, Args} ->
  1443. startAfterCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, Debug, [], Args);
  1444. _Ret ->
  1445. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, error, {bad_reply, _Ret}, ?STACKTRACE())
  1446. end;
  1447. {sreply, Reply, NewStatus, NewState} ->
  1448. reply(From, Reply),
  1449. ?SYS_DEBUG(Debug, Name, {out, Reply, From}),
  1450. dealEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, NewStatus, Debug, LeftEvents, NewStatus =/= CurStatus);
  1451. {sreply, Reply, NewStatus, NewState, Actions} ->
  1452. reply(From, Reply),
  1453. ?SYS_DEBUG(Debug, Name, {out, Reply, From}),
  1454. parseEventAL(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, NewStatus, Debug, LeftEvents, NewStatus =/= CurStatus, listify(Actions), CallbackForm);
  1455. {nextS, NewStatus, NewState} ->
  1456. dealEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, NewStatus, Debug, LeftEvents, NewStatus =/= CurStatus);
  1457. {nextS, NewStatus, NewState, Actions} ->
  1458. parseEventAL(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, NewStatus, Debug, LeftEvents, NewStatus =/= CurStatus, listify(Actions), CallbackForm);
  1459. {kpS, NewState} ->
  1460. dealEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, CurStatus, Debug, LeftEvents, false);
  1461. {kpS, NewState, Actions} ->
  1462. parseEventAL(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, CurStatus, Debug, LeftEvents, false, listify(Actions), CallbackForm);
  1463. kpS_S ->
  1464. dealEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, CurStatus, Debug, LeftEvents, false);
  1465. {kpS_S, Actions} ->
  1466. parseEventAL(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, CurStatus, Debug, LeftEvents, false, listify(Actions), CallbackForm);
  1467. {reS, NewState} ->
  1468. dealEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, CurStatus, Debug, LeftEvents, true);
  1469. {reS, NewState, Actions} ->
  1470. parseEventAL(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, CurStatus, Debug, LeftEvents, true, listify(Actions), CallbackForm);
  1471. reS_S ->
  1472. dealEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, CurStatus, Debug, LeftEvents, true);
  1473. {reS_S, Actions} ->
  1474. parseEventAL(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, CurStatus, Debug, LeftEvents, true, listify(Actions), CallbackForm);
  1475. stop ->
  1476. terminate(exit, normal, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents);
  1477. {stop, Reason} ->
  1478. terminate(exit, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents);
  1479. {stop, Reason, NewState} ->
  1480. terminate(exit, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, Debug, LeftEvents);
  1481. {stopReply, Reason, Replies} ->
  1482. ?SYS_DEBUG(Debug, Name, {out, Replies}),
  1483. try
  1484. terminate(exit, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents)
  1485. after
  1486. case Replies of
  1487. {reply, RFrom, Reply} ->
  1488. reply(RFrom, Reply);
  1489. _ when is_list(Replies) ->
  1490. [reply(RFrom, Reply) || {reply, RFrom, Reply} <- Replies],
  1491. ok;
  1492. _ ->
  1493. _ = reply(From, Replies)
  1494. end
  1495. end;
  1496. {stopReply, Reason, Replies, NewState} ->
  1497. ?SYS_DEBUG(Debug, Name, {out, Replies}),
  1498. try
  1499. terminate(exit, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, NewState, Debug, LeftEvents)
  1500. after
  1501. case Replies of
  1502. {reply, RFrom, Reply} ->
  1503. _ = reply(RFrom, Reply);
  1504. _ when is_list(Replies) ->
  1505. [reply(RFrom, Reply) || {reply, RFrom, Reply} <- Replies],
  1506. ok;
  1507. _ ->
  1508. _ = reply(From, Replies)
  1509. end
  1510. end;
  1511. _ ->
  1512. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, error, {bad_handleEventCR, Result}, ?STACKTRACE())
  1513. end.
  1514. dealEnterCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter, IsCallEnter) ->
  1515. NewTimers = cancelESTimeout(CurStatus =:= NewStatus, Timers),
  1516. case IsEnter andalso IsCallEnter of
  1517. true ->
  1518. startEnterCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, NewTimers, CurStatus, CurState, NewStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter);
  1519. false ->
  1520. performTransitions(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, NewTimers, CurStatus, CurState, NewStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter)
  1521. end.
  1522. %% dealEventCallbackRet
  1523. dealEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewStatus, Debug, LeftEvents, IsCallEnter) ->
  1524. NewTimers = cancelESTimeout(CurStatus =:= NewStatus, Timers),
  1525. case IsEnter andalso IsCallEnter of
  1526. true ->
  1527. startEnterCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, NewTimers, CurStatus, CurState, NewStatus, Debug, LeftEvents, [], false, false, false);
  1528. false ->
  1529. performTransitions(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, NewTimers, CurStatus, CurState, NewStatus, Debug, LeftEvents, [], false, false, false)
  1530. end.
  1531. %% 处理enter callback 动作列表
  1532. %% parseEnterActionsList
  1533. parseEnterAL(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewStatus, Debug, LeftEvents, NextEs, IsPos, IsCallEnter, IsHib, DoAfter, Actions) ->
  1534. NewTimers = cancelESTimeout(CurStatus =:= NewStatus, Timers),
  1535. %% enter 调用不能改成状态 actions 不能返回 IsPos = true 但是可以取消之前的推迟 设置IsPos = false 不能设置 doafter 不能插入事件
  1536. case Actions of
  1537. [] ->
  1538. case IsEnter andalso IsCallEnter of
  1539. true ->
  1540. startEnterCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, NewTimers, CurStatus, CurState, NewStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter);
  1541. _ ->
  1542. performTransitions(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, NewTimers, CurStatus, CurState, NewStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter)
  1543. end;
  1544. _ ->
  1545. case doParseAL(Actions, ?CB_FORM_ENTER, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs) of
  1546. {error, ErrorContent} ->
  1547. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, Actions, error, ErrorContent, ?STACKTRACE());
  1548. {NewIsEnter, NNewTimers, Debug, NewIsPos, NewIsHib, DoAfter, NewNextEs} ->
  1549. case NewIsEnter andalso IsCallEnter of
  1550. true ->
  1551. startEnterCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, NewIsEnter, EpmHers, Postponed, NNewTimers, CurStatus, CurState, NewStatus, Debug, LeftEvents, NewNextEs, NewIsPos, NewIsHib, DoAfter);
  1552. _ ->
  1553. performTransitions(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, NewIsEnter, EpmHers, Postponed, NNewTimers, CurStatus, CurState, NewStatus, Debug, LeftEvents, NewNextEs, NewIsPos, NewIsHib, DoAfter)
  1554. end
  1555. end
  1556. end.
  1557. %% 处理非 enter 或者after callback 返回的动作列表
  1558. %% parseEventActionsList
  1559. parseEventAL(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewStatus, Debug, LeftEvents, IsCallEnter, Actions, CallbackForm) ->
  1560. NewTimers = cancelESTimeout(CurStatus =:= NewStatus, Timers),
  1561. case Actions of
  1562. [] ->
  1563. case IsEnter andalso IsCallEnter of
  1564. true ->
  1565. startEnterCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, NewTimers, CurStatus, CurState, NewStatus, Debug, LeftEvents, [], false, false, false);
  1566. _ ->
  1567. performTransitions(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, NewTimers, CurStatus, CurState, NewStatus, Debug, LeftEvents, [], false, false, false)
  1568. end;
  1569. _ ->
  1570. case doParseAL(Actions, CallbackForm, Name, IsEnter, NewTimers, Debug, false, false, false, []) of
  1571. {error, ErrorContent} ->
  1572. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, Actions, error, ErrorContent, ?STACKTRACE());
  1573. {NewIsEnter, NNewTimers, Debug, NewIsPos, NewIsHib, MewDoAfter, NewNextEs} ->
  1574. case NewIsEnter andalso IsCallEnter of
  1575. true ->
  1576. startEnterCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, NNewTimers, CurStatus, CurState, NewStatus, Debug, LeftEvents, NewNextEs, NewIsPos, NewIsHib, MewDoAfter);
  1577. _ ->
  1578. performTransitions(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, NNewTimers, CurStatus, CurState, NewStatus, Debug, LeftEvents, NewNextEs, NewIsPos, NewIsHib, MewDoAfter)
  1579. end
  1580. end
  1581. end.
  1582. %% loopParseActionsList
  1583. doParseAL([], _CallbackForm, _Name, IsEnter, Times, Debug, IsPos, IsHib, DoAfter, NextEs) ->
  1584. {IsEnter, Times, Debug, IsPos, IsHib, DoAfter, NextEs};
  1585. doParseAL([OneAction | LeftActions], CallbackForm, Name, IsEnter, Timers, Debug, IsPos, IsHib, DoAfter, NextEs) ->
  1586. case OneAction of
  1587. {reply, From, Reply} ->
  1588. reply(From, Reply),
  1589. ?SYS_DEBUG(Debug, Name, {out, Reply, From}),
  1590. doParseAL(LeftActions, CallbackForm, Name, IsEnter, Timers, Debug, IsPos, IsHib, DoAfter, NextEs);
  1591. {eTimeout, Time, TimeoutMsg} ->
  1592. case Time of
  1593. infinity ->
  1594. NewTimers = doCancelTimer(eTimeout, Timers),
  1595. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs);
  1596. _ ->
  1597. TimerRef = erlang:start_timer(Time, self(), eTimeout),
  1598. ?SYS_DEBUG(Debug, Name, {start_timer, {eTimeout, Time, TimeoutMsg, []}}),
  1599. NewTimers = doRegisterTimer(eTimeout, TimerRef, TimeoutMsg, Timers),
  1600. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs)
  1601. end;
  1602. {sTimeout, Time, TimeoutMsg} ->
  1603. case Time of
  1604. infinity ->
  1605. NewTimers = doCancelTimer(sTimeout, Timers),
  1606. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs);
  1607. _ ->
  1608. TimerRef = erlang:start_timer(Time, self(), sTimeout),
  1609. ?SYS_DEBUG(Debug, Name, {start_timer, {sTimeout, Time, TimeoutMsg, []}}),
  1610. NewTimers = doRegisterTimer(sTimeout, TimerRef, TimeoutMsg, Timers),
  1611. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs)
  1612. end;
  1613. {gTimeout, TimeoutName, Time, TimeoutMsg} ->
  1614. case Time of
  1615. infinity ->
  1616. NewTimers = doCancelTimer(TimeoutName, Timers),
  1617. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs);
  1618. _ ->
  1619. TimerRef = erlang:start_timer(Time, self(), TimeoutName),
  1620. ?SYS_DEBUG(Debug, Name, {start_timer, {TimeoutName, Time, TimeoutMsg, []}}),
  1621. NewTimers = doRegisterTimer(TimeoutName, TimerRef, TimeoutMsg, Timers),
  1622. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs)
  1623. end;
  1624. {eTimeout, Time, TimeoutMsg, Options} ->
  1625. case Time of
  1626. infinity ->
  1627. NewTimers = doCancelTimer(eTimeout, Timers),
  1628. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs);
  1629. _ ->
  1630. TimerRef = erlang:start_timer(Time, self(), eTimeout, Options),
  1631. ?SYS_DEBUG(Debug, Name, {start_timer, {eTimeout, Time, TimeoutMsg, Options}}),
  1632. NewTimers = doRegisterTimer(eTimeout, TimerRef, TimeoutMsg, Timers),
  1633. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs)
  1634. end;
  1635. {sTimeout, Time, TimeoutMsg, Options} ->
  1636. case Time of
  1637. infinity ->
  1638. NewTimers = doCancelTimer(sTimeout, Timers),
  1639. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs);
  1640. _ ->
  1641. TimerRef = erlang:start_timer(Time, self(), sTimeout, Options),
  1642. ?SYS_DEBUG(Debug, Name, {start_timer, {sTimeout, Time, TimeoutMsg, Options}}),
  1643. NewTimers = doRegisterTimer(sTimeout, TimerRef, TimeoutMsg, Timers),
  1644. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs)
  1645. end;
  1646. {gTimeout, TimeoutName, Time, TimeoutMsg, Options} ->
  1647. case Time of
  1648. infinity ->
  1649. NewTimers = doCancelTimer(TimeoutName, Timers),
  1650. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs);
  1651. _ ->
  1652. TimerRef = erlang:start_timer(Time, self(), TimeoutName, Options),
  1653. ?SYS_DEBUG(Debug, Name, {start_timer, {TimeoutName, Time, TimeoutMsg, Options}}),
  1654. NewTimers = doRegisterTimer(TimeoutName, TimerRef, TimeoutMsg, Timers),
  1655. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs)
  1656. end;
  1657. {u_eTimeout, NewTimeoutMsg} ->
  1658. NewTimers = doUpdateTimer(eTimeout, NewTimeoutMsg, Timers),
  1659. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs);
  1660. {u_sTimeout, NewTimeoutMsg} ->
  1661. NewTimers = doUpdateTimer(sTimeout, NewTimeoutMsg, Timers),
  1662. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs);
  1663. {u_gTimeout, TimeoutName, NewTimeoutMsg} ->
  1664. NewTimers = doUpdateTimer(TimeoutName, NewTimeoutMsg, Timers),
  1665. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs);
  1666. c_eTimeout ->
  1667. NewTimers = doCancelTimer(eTimeout, Timers),
  1668. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs);
  1669. c_sTimeout ->
  1670. NewTimers = doCancelTimer(sTimeout, Timers),
  1671. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs);
  1672. {c_gTimeout, TimeoutName} ->
  1673. NewTimers = doCancelTimer(TimeoutName, Timers),
  1674. doParseAL(LeftActions, CallbackForm, Name, IsEnter, NewTimers, Debug, IsPos, IsHib, DoAfter, NextEs);
  1675. {isEnter, NewIsEnter} ->
  1676. ?SYS_DEBUG(Debug, Name, {change_isEnter, NewIsEnter}),
  1677. doParseAL(LeftActions, CallbackForm, Name, Timers, NewIsEnter, Debug, IsPos, IsHib, DoAfter, NextEs);
  1678. {isHib, NewIsHib} ->
  1679. doParseAL(LeftActions, CallbackForm, Name, IsEnter, Timers, Debug, IsPos, NewIsHib, DoAfter, NextEs);
  1680. {isPos, NewIsPos} when (not NewIsPos orelse CallbackForm == ?CB_FORM_EVENT) ->
  1681. doParseAL(LeftActions, CallbackForm, Name, IsEnter, Timers, Debug, NewIsPos, IsHib, DoAfter, NextEs);
  1682. {doAfter, Args} when CallbackForm == ?CB_FORM_EVENT ->
  1683. doParseAL(LeftActions, CallbackForm, Name, IsEnter, Timers, Debug, IsPos, IsHib, {true, Args}, NextEs);
  1684. {nextE, Type, Content} when CallbackForm == ?CB_FORM_EVENT orelse CallbackForm == ?CB_FORM_AFTER ->
  1685. %% 处理next_event动作
  1686. doParseAL(LeftActions, CallbackForm, Name, IsEnter, Timers, Debug, IsPos, IsHib, DoAfter, [{Type, Content} | NextEs]);
  1687. _ ->
  1688. {error, {bad_ActionType, OneAction}}
  1689. end.
  1690. % checkTimeOptions({TimeoutType, Time, TimeoutMsg, Options} = NewTV) ->
  1691. % case Options of
  1692. % [{abs, true}] when ?ABS_TIMEOUT(Time) ->
  1693. % NewTV;
  1694. % [{abs, false}] when ?REL_TIMEOUT(Time) ->
  1695. % {TimeoutType, Time, TimeoutMsg};
  1696. % [] when ?REL_TIMEOUT(Time) ->
  1697. % {TimeoutType, Time, TimeoutMsg};
  1698. % _ ->
  1699. % %% 如果将来 start_timer opt扩展了 这里的代码也要修改
  1700. % error_timeout_opt
  1701. % end.
  1702. %% 进行状态转换
  1703. performTransitions(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewStatus, Debug, AllLeftEvents, NextEs, IsPos, IsHib, DoAfter) ->
  1704. %% 已收集所有选项,并缓冲next_events。执行实际状态转换。如果推迟则将当前事件移至推迟
  1705. %% 此时 NextEs的顺序与最开始出现的顺序相反. 后面执行的顺序 当前新增事件 + 反序的Postpone事件 + LeftEvents
  1706. case AllLeftEvents of
  1707. [] ->
  1708. CurEvent = undefined,
  1709. LeftEvents = [];
  1710. _ ->
  1711. [CurEvent | LeftEvents] = AllLeftEvents
  1712. end,
  1713. ?SYS_DEBUG(Debug, Name, case IsPos of true -> {postpone, CurEvent, CurStatus, NewStatus}; _ -> {consume, CurEvent, CurStatus, NewStatus} end),
  1714. if
  1715. CurStatus =:= NewStatus ->
  1716. %% Cancel event timeout
  1717. if
  1718. IsPos ->
  1719. LastLeftEvents =
  1720. case NextEs of
  1721. [] ->
  1722. LeftEvents;
  1723. [Es1] ->
  1724. [Es1 | LeftEvents];
  1725. [Es2, Es1] ->
  1726. [Es1, Es2 | LeftEvents];
  1727. _ ->
  1728. lists:reverse(NextEs, LeftEvents)
  1729. end,
  1730. performEvents(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, [CurEvent | Postponed], Timers, NewStatus, CurState, Debug, LastLeftEvents, IsHib, DoAfter);
  1731. true ->
  1732. LastLeftEvents =
  1733. case NextEs of
  1734. [] ->
  1735. LeftEvents;
  1736. [Es1] ->
  1737. [Es1 | LeftEvents];
  1738. [Es2, Es1] ->
  1739. [Es1, Es2 | LeftEvents];
  1740. _ ->
  1741. lists:reverse(NextEs, LeftEvents)
  1742. end,
  1743. performEvents(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, NewStatus, CurState, Debug, LastLeftEvents, IsHib, DoAfter)
  1744. end;
  1745. true ->
  1746. %% 状态发生改变 重试推迟的事件
  1747. if
  1748. IsPos ->
  1749. NewLeftEvents =
  1750. case Postponed of
  1751. [] ->
  1752. [CurEvent | LeftEvents];
  1753. [E1] ->
  1754. [E1, CurEvent | LeftEvents];
  1755. [E2, E1] ->
  1756. [E1, E2, CurEvent | LeftEvents];
  1757. _ ->
  1758. lists:reverse(Postponed, [CurEvent | LeftEvents])
  1759. end,
  1760. LastLeftEvents =
  1761. case NextEs of
  1762. [] ->
  1763. NewLeftEvents;
  1764. [Es1] ->
  1765. [Es1 | NewLeftEvents];
  1766. [Es2, Es1] ->
  1767. [Es1, Es2 | NewLeftEvents];
  1768. _ ->
  1769. lists:reverse(NextEs, NewLeftEvents)
  1770. end,
  1771. performEvents(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, [], Timers, NewStatus, CurState, Debug, LastLeftEvents, IsHib, DoAfter);
  1772. true ->
  1773. NewLeftEvents =
  1774. case Postponed of
  1775. [] ->
  1776. LeftEvents;
  1777. [E1] ->
  1778. [E1 | LeftEvents];
  1779. [E2, E1] ->
  1780. [E1, E2 | LeftEvents];
  1781. _ ->
  1782. lists:reverse(Postponed, LeftEvents)
  1783. end,
  1784. LastLeftEvents =
  1785. case NextEs of
  1786. [] ->
  1787. NewLeftEvents;
  1788. [Es1] ->
  1789. [Es1 | NewLeftEvents];
  1790. [Es2, Es1] ->
  1791. [Es1, Es2 | NewLeftEvents];
  1792. _ ->
  1793. lists:reverse(NextEs, NewLeftEvents)
  1794. end,
  1795. performEvents(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, [], Timers, NewStatus, CurState, Debug, LastLeftEvents, IsHib, DoAfter)
  1796. end
  1797. end.
  1798. %% 状态转换已完成,如果有排队事件,则继续循环,否则获取新事件
  1799. performEvents(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, IsHib, DoAfter) ->
  1800. % io:format("loop_done: status_data = ~p ~n postponed = ~p LeftEvents = ~p ~n timers = ~p.~n", [S#status.status_data,,S#status.postponed,LeftEvents,S#status.timers]),
  1801. case DoAfter of
  1802. {true, Args} ->
  1803. %% 这里 IsHib设置会被丢弃 按照gen_server中的设计 continue 和 hiernate是互斥的
  1804. startAfterCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Args);
  1805. _ ->
  1806. case LeftEvents of
  1807. [] ->
  1808. reLoopEntry(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, IsHib);
  1809. [Event | _Events] ->
  1810. %% 循环直到没有排队事件
  1811. if
  1812. IsHib ->
  1813. %% _ = garbage_collect(),
  1814. erts_internal:garbage_collect(major);
  1815. true ->
  1816. ignore
  1817. end,
  1818. startEventCall(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Event)
  1819. end
  1820. end.
  1821. %% 取消事件超时 和 状态超时
  1822. cancelESTimeout(true, Timers) ->
  1823. %% Cancel event timeout
  1824. case Timers of
  1825. #{eTimeout := {TimerRef, _TimeoutMsg}} ->
  1826. cancelTimer(eTimeout, TimerRef, Timers);
  1827. _ ->
  1828. Timers
  1829. end;
  1830. cancelESTimeout(false, Timers) ->
  1831. %% 取消 status and event timeout
  1832. case Timers of
  1833. #{sTimeout := {STimerRef, _STimeoutMsg}} ->
  1834. TemTimer = cancelTimer(sTimeout, STimerRef, Timers),
  1835. case TemTimer of
  1836. #{eTimeout := {ETimerRef, _ETimeoutMsg}} ->
  1837. cancelTimer(eTimeout, ETimerRef, TemTimer);
  1838. _ ->
  1839. TemTimer
  1840. end;
  1841. _ ->
  1842. case Timers of
  1843. #{eTimeout := {ETimerRef, _ETimeoutMsg}} ->
  1844. cancelTimer(eTimeout, ETimerRef, Timers);
  1845. _ ->
  1846. Timers
  1847. end
  1848. end.
  1849. doRegisterTimer(TimeoutType, NewTimerRef, TimeoutMsg, Timers) ->
  1850. case Timers of
  1851. #{TimeoutType := {OldTimerRef, _OldTimeMsg}} ->
  1852. justCancelTimer(TimeoutType, OldTimerRef),
  1853. Timers#{TimeoutType := {NewTimerRef, TimeoutMsg}};
  1854. _ ->
  1855. Timers#{TimeoutType => {NewTimerRef, TimeoutMsg}}
  1856. end.
  1857. doCancelTimer(TimeoutType, Timers) ->
  1858. case Timers of
  1859. #{TimeoutType := {TimerRef, _TimeoutMsg}} ->
  1860. cancelTimer(TimeoutType, TimerRef, Timers);
  1861. _ ->
  1862. Timers
  1863. end.
  1864. doUpdateTimer(TimeoutType, Timers, TimeoutMsg) ->
  1865. case Timers of
  1866. #{TimeoutType := {TimerRef, _OldTimeoutMsg}} ->
  1867. Timers#{TimeoutType := {TimerRef, TimeoutMsg}};
  1868. _ ->
  1869. Timers
  1870. end.
  1871. justCancelTimer(TimeoutType, TimerRef) ->
  1872. case erlang:cancel_timer(TimerRef) of
  1873. false ->
  1874. %% 找不到计时器,我们还没有看到超时消息
  1875. receive
  1876. {timeout, TimerRef, TimeoutType} ->
  1877. %% 丢弃该超时消息
  1878. ok
  1879. after 0 ->
  1880. ok
  1881. end;
  1882. _ ->
  1883. %% Timer 已经运行了
  1884. ok
  1885. end.
  1886. cancelTimer(TimeoutType, TimerRef, Timers) ->
  1887. case erlang:cancel_timer(TimerRef) of
  1888. false ->
  1889. %% 找不到计时器,我们还没有看到超时消息
  1890. receive
  1891. {timeout, TimerRef, TimeoutType} ->
  1892. %% 丢弃该超时消息
  1893. ok
  1894. after 0 ->
  1895. ok
  1896. end;
  1897. _ ->
  1898. %% Timer 已经运行了
  1899. ok
  1900. end,
  1901. maps:remove(TimeoutType, Timers).
  1902. %% 排队立即超时事件(超时0事件)
  1903. %% 自事件超时0起,事件得到特殊处理
  1904. %% 任何收到的事件都会取消事件超时,
  1905. %% 因此,如果在事件超时0事件之前存在入队事件-事件超时被取消,因此没有事件。
  1906. %% 其他(status_timeout和{timeout,Name})超时0个事件
  1907. %% 在事件计时器超时0事件之后发生的事件被认为是
  1908. %% 属于在事件计时器之后启动的计时器
  1909. %% 已触发超时0事件,因此它们不会取消事件计时器。
  1910. %% mergeTimeoutEvents([], _Status, _CycleData, Debug, Events) ->
  1911. %% {Events, Debug};
  1912. %% mergeTimeoutEvents([{eTimeout, _} = TimeoutEvent | TimeoutEvents], Status, CycleData, Debug, []) ->
  1913. %% %% 由于队列中没有其他事件,因此添加该事件零超时事件
  1914. %% ?SYS_DEBUG(Debug, CycleData, {insert_timeout, TimeoutEvent, Status}),
  1915. %% mergeTimeoutEvents(TimeoutEvents, Status, CycleData, Debug, [TimeoutEvent]);
  1916. %% mergeTimeoutEvents([{eTimeout, _} | TimeoutEvents], Status, CycleData, Debug, Events) ->
  1917. %% %% 忽略,因为队列中还有其他事件,因此它们取消了事件超时0。
  1918. %% mergeTimeoutEvents(TimeoutEvents, Status, CycleData, Debug, Events);
  1919. %% mergeTimeoutEvents([TimeoutEvent | TimeoutEvents], Status, CycleData, Debug, Events) ->
  1920. %% %% Just prepend all others
  1921. %% ?SYS_DEBUG(Debug, CycleData, {insert_timeout, TimeoutEvent, Status}),
  1922. %% mergeTimeoutEvents(TimeoutEvents, Status, CycleData, Debug, [TimeoutEvent | Events]).
  1923. %% Return a list of all pending timeouts
  1924. listTimeouts(Timers) ->
  1925. {maps:size(Timers), allTimer(iterator(Timers), [])}.
  1926. allTimer(Iterator, Acc) ->
  1927. case next(Iterator) of
  1928. {TimeoutType, {_TimerRef, TimeoutMsg}, NextIterator} ->
  1929. allTimer(NextIterator, [{TimeoutType, TimeoutMsg} | Acc]);
  1930. none ->
  1931. Acc
  1932. end.
  1933. %%---------------------------------------------------------------------------
  1934. innerError(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, MsgEvent, Class, Reason, Stacktrace) ->
  1935. case GbhOpts of
  1936. #gbhOpts{daemon = true} ->
  1937. error_msg({innerError, {Class, Reason, Stacktrace}}, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, MsgEvent),
  1938. case erlang:function_exported(Module, handleError, 2) of
  1939. true ->
  1940. try Module:handleError({Class, Reason, Stacktrace}, CurState) of
  1941. Result ->
  1942. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, [MsgEvent], Result, ?CB_FORM_EVENT, false)
  1943. catch
  1944. throw:Result ->
  1945. handleEventCR(Parent, Name, Module, GbhOpts, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, [MsgEvent], Result, ?CB_FORM_EVENT, false);
  1946. IClass:IReason:IStrace ->
  1947. error_msg({handleError, {IClass, IReason, IStrace}}, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, {Class, Reason, Stacktrace}),
  1948. kpS
  1949. end;
  1950. false ->
  1951. kpS
  1952. end;
  1953. _ ->
  1954. terminate(Class, Reason, Stacktrace, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, MsgEvent)
  1955. end.
  1956. terminate(Class, Reason, Stacktrace, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents) ->
  1957. epmStopAll(EpmHers),
  1958. %% 这里停止所有的epm 但是并没有更新 epmHers为#{} 目前感觉没必要清理掉
  1959. case erlang:function_exported(Module, terminate, 3) of
  1960. true ->
  1961. try Module:terminate(Reason, CurStatus, CurState) of
  1962. _ -> ok
  1963. catch
  1964. throw:_ -> ok;
  1965. Class:Reason:Strace ->
  1966. error_info(Class, Reason, Strace, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents),
  1967. erlang:raise(Class, Reason, Strace)
  1968. end;
  1969. false ->
  1970. ok
  1971. end,
  1972. case Reason of
  1973. normal ->
  1974. ?SYS_DEBUG(Debug, Name, {terminate, Reason, CurStatus});
  1975. shutdown ->
  1976. ?SYS_DEBUG(Debug, Name, {terminate, Reason, CurStatus});
  1977. {shutdown, _} ->
  1978. ?SYS_DEBUG(Debug, Name, {terminate, Reason, CurStatus});
  1979. _ ->
  1980. error_info(Class, Reason, Stacktrace, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents)
  1981. end,
  1982. case Stacktrace of
  1983. [] ->
  1984. erlang:Class(Reason);
  1985. _ ->
  1986. erlang:raise(Class, Reason, Stacktrace)
  1987. end.
  1988. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% debug 日志 Start%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1989. error_info(Class, Reason, Stacktrace, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents) ->
  1990. Log = sys:get_log(Debug),
  1991. ?LOG_ERROR(
  1992. #{
  1993. label => {gen_ipc, terminate},
  1994. name => Name,
  1995. module => Module,
  1996. queue => LeftEvents,
  1997. postponed => Postponed,
  1998. isEnter => IsEnter,
  1999. status => format_status(terminate, get(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState),
  2000. timeouts => listTimeouts(Timers),
  2001. log => Log,
  2002. reason => {Class, Reason, Stacktrace},
  2003. client_info => cliStacktrace(LeftEvents)
  2004. },
  2005. #{
  2006. domain => [otp],
  2007. report_cb => fun gen_ipc:format_log/2,
  2008. error_logger => #{tag => error, report_cb => fun gen_ipc:format_log/1}}).
  2009. error_msg(Reason, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents) ->
  2010. Log = sys:get_log(Debug),
  2011. ?LOG_ERROR(
  2012. #{
  2013. label => {gen_ipc, inner_error},
  2014. name => Name,
  2015. module => Module,
  2016. queue => LeftEvents,
  2017. postponed => Postponed,
  2018. isEnter => IsEnter,
  2019. status => format_status(inner_error, get(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState),
  2020. timeouts => listTimeouts(Timers),
  2021. log => Log,
  2022. reason => Reason,
  2023. client_info => cliStacktrace(LeftEvents)
  2024. },
  2025. #{
  2026. domain => [otp],
  2027. report_cb => fun gen_ipc:format_log/2,
  2028. error_logger => #{tag => error, report_cb => fun gen_ipc:format_log/1}}).
  2029. cliStacktrace([]) ->
  2030. undefined;
  2031. cliStacktrace([{{call, {Pid, _Tag}}, _Req} | _]) when is_pid(Pid) ->
  2032. if
  2033. node(Pid) =:= node() ->
  2034. case process_info(Pid, [current_stacktrace, registered_name]) of
  2035. undefined ->
  2036. {Pid, dead};
  2037. [{current_stacktrace, Stacktrace}, {registered_name, []}] ->
  2038. {Pid, {Pid, Stacktrace}};
  2039. [{current_stacktrace, Stacktrace}, {registered_name, Name}] ->
  2040. {Pid, {Name, Stacktrace}}
  2041. end;
  2042. true ->
  2043. {Pid, remote}
  2044. end;
  2045. cliStacktrace([_ | _]) ->
  2046. undefined;
  2047. cliStacktrace(_) ->
  2048. undefined.
  2049. %% format_log/1 is the report callback used by Logger handler
  2050. %% error_logger only. It is kept for backwards compatibility with
  2051. %% legacy error_logger event handlers. This function must always
  2052. %% return {Format,Args} compatible with the arguments in this module's
  2053. %% calls to error_logger prior to OTP-21.0.
  2054. format_log(Report) ->
  2055. Depth = error_logger:get_format_depth(),
  2056. FormatOpts = #{
  2057. chars_limit => unlimited,
  2058. depth => Depth,
  2059. single_line => false,
  2060. encoding => utf8
  2061. },
  2062. format_log_multi(limit_report(Report, Depth), FormatOpts).
  2063. limit_report(Report, unlimited) ->
  2064. Report;
  2065. limit_report(
  2066. #{
  2067. label := {gen_ipc, terminate},
  2068. queue := Q,
  2069. postponed := Postponed,
  2070. module := Module,
  2071. status := FmtData,
  2072. timeouts := Timeouts,
  2073. log := Log,
  2074. reason := {Class, Reason, Stacktrace},
  2075. client_info := ClientInfo
  2076. } = Report,
  2077. Depth) ->
  2078. Report#{
  2079. queue =>
  2080. case Q of
  2081. [Event | Events] ->
  2082. [io_lib:limit_term(Event, Depth) | io_lib:limit_term(Events, Depth)];
  2083. _ ->
  2084. []
  2085. end,
  2086. postponed =>
  2087. case Postponed of
  2088. [] -> [];
  2089. _ -> io_lib:limit_term(Postponed, Depth)
  2090. end,
  2091. modules => io_lib:limit_term(Module, Depth),
  2092. status => io_lib:limit_term(FmtData, Depth),
  2093. timeouts =>
  2094. case Timeouts of
  2095. {0, _} -> Timeouts;
  2096. _ -> io_lib:limit_term(Timeouts, Depth)
  2097. end,
  2098. log =>
  2099. case Log of
  2100. [] -> [];
  2101. _ -> [io_lib:limit_term(T, Depth) || T <- Log]
  2102. end,
  2103. reason =>
  2104. {Class, io_lib:limit_term(Reason, Depth), io_lib:limit_term(Stacktrace, Depth)},
  2105. client_info => limit_client_info(ClientInfo, Depth)
  2106. };
  2107. limit_report(
  2108. #{
  2109. label := {gen_ipc, inner_error},
  2110. queue := Q,
  2111. postponed := Postponed,
  2112. module := Module,
  2113. status := FmtData,
  2114. timeouts := Timeouts,
  2115. log := Log,
  2116. reason := {Class, Reason, Stacktrace},
  2117. client_info := ClientInfo
  2118. } = Report,
  2119. Depth) ->
  2120. Report#{
  2121. queue =>
  2122. case Q of
  2123. [Event | Events] ->
  2124. [io_lib:limit_term(Event, Depth) | io_lib:limit_term(Events, Depth)];
  2125. _ ->
  2126. []
  2127. end,
  2128. postponed =>
  2129. case Postponed of
  2130. [] -> [];
  2131. _ -> io_lib:limit_term(Postponed, Depth)
  2132. end,
  2133. modules => io_lib:limit_term(Module, Depth),
  2134. status => io_lib:limit_term(FmtData, Depth),
  2135. timeouts =>
  2136. case Timeouts of
  2137. {0, _} -> Timeouts;
  2138. _ -> io_lib:limit_term(Timeouts, Depth)
  2139. end,
  2140. log =>
  2141. case Log of
  2142. [] -> [];
  2143. _ -> [io_lib:limit_term(T, Depth) || T <- Log]
  2144. end,
  2145. reason =>
  2146. {Class, io_lib:limit_term(Reason, Depth), io_lib:limit_term(Stacktrace, Depth)},
  2147. client_info => limit_client_info(ClientInfo, Depth)
  2148. }.
  2149. limit_client_info({Pid, {Name, Stacktrace}}, Depth) ->
  2150. {Pid, {Name, io_lib:limit_term(Stacktrace, Depth)}};
  2151. limit_client_info(Client, _Depth) ->
  2152. Client.
  2153. %% format_log/2 is the report callback for any Logger handler, except
  2154. %% error_logger.
  2155. format_log(Report, FormatOpts0) ->
  2156. Default = #{
  2157. chars_limit => unlimited,
  2158. depth => unlimited,
  2159. single_line => false,
  2160. encoding => utf8
  2161. },
  2162. FormatOpts = maps:merge(Default, FormatOpts0),
  2163. IoOpts =
  2164. case FormatOpts of
  2165. #{chars_limit := unlimited} -> [];
  2166. #{chars_limit := Limit} -> [{chars_limit, Limit}]
  2167. end,
  2168. {Format, Args} = format_log_single(Report, FormatOpts),
  2169. io_lib:format(Format, Args, IoOpts).
  2170. format_log_single(
  2171. #{
  2172. label := {gen_ipc, terminate},
  2173. name := Name,
  2174. queue := Q,
  2175. %% postponed
  2176. %% isEnter
  2177. status := FmtData,
  2178. %% timeouts
  2179. log := Log,
  2180. reason := {Class, Reason, Stacktrace},
  2181. client_info := ClientInfo
  2182. },
  2183. #{single_line := true, depth := Depth} = FormatOpts) ->
  2184. P = p(FormatOpts),
  2185. {FixedReason, FixedStacktrace} = fix_reason(Class, Reason, Stacktrace),
  2186. {ClientFmt, ClientArgs} = format_client_log_single(ClientInfo, P, Depth),
  2187. Format =
  2188. lists:append(
  2189. ["State machine ", P, " terminating. Reason: ", P,
  2190. case FixedStacktrace of
  2191. [] -> "";
  2192. _ -> ". Stack: " ++ P
  2193. end,
  2194. case Q of
  2195. [] -> "";
  2196. _ -> ". Last event: " ++ P
  2197. end,
  2198. ". State: ", P,
  2199. case Log of
  2200. [] -> "";
  2201. _ -> ". Log: " ++ P
  2202. end,
  2203. "."]
  2204. ),
  2205. Args0 =
  2206. [Name, FixedReason] ++
  2207. case FixedStacktrace of
  2208. [] -> [];
  2209. _ -> [FixedStacktrace]
  2210. end ++
  2211. case Q of
  2212. [] -> [];
  2213. [Event | _] -> [Event]
  2214. end ++
  2215. [FmtData] ++
  2216. case Log of
  2217. [] -> [];
  2218. _ -> [Log]
  2219. end,
  2220. Args =
  2221. case Depth of
  2222. unlimited ->
  2223. Args0;
  2224. _ ->
  2225. lists:flatmap(fun(A) -> [A, Depth] end, Args0)
  2226. end,
  2227. {Format ++ ClientFmt, Args ++ ClientArgs};
  2228. format_log_single(
  2229. #{
  2230. label := {gen_ipc, inner_error},
  2231. name := Name,
  2232. queue := Q,
  2233. %% postponed
  2234. %% isEnter
  2235. status := FmtData,
  2236. %% timeouts
  2237. log := Log,
  2238. reason := {Class, Reason, Stacktrace},
  2239. client_info := ClientInfo
  2240. },
  2241. #{single_line := true, depth := Depth} = FormatOpts) ->
  2242. P = p(FormatOpts),
  2243. {FixedReason, FixedStacktrace} = fix_reason(Class, Reason, Stacktrace),
  2244. {ClientFmt, ClientArgs} = format_client_log_single(ClientInfo, P, Depth),
  2245. Format =
  2246. lists:append(
  2247. ["State machine ", P, " inner_error. Reason: ", P,
  2248. case FixedStacktrace of
  2249. [] -> "";
  2250. _ -> ". Stack: " ++ P
  2251. end,
  2252. case Q of
  2253. [] -> "";
  2254. _ -> ". Last event: " ++ P
  2255. end,
  2256. ". State: ", P,
  2257. case Log of
  2258. [] -> "";
  2259. _ -> ". Log: " ++ P
  2260. end,
  2261. "."]
  2262. ),
  2263. Args0 =
  2264. [Name, FixedReason] ++
  2265. case FixedStacktrace of
  2266. [] -> [];
  2267. _ -> [FixedStacktrace]
  2268. end ++
  2269. case Q of
  2270. [] -> [];
  2271. [Event | _] -> [Event]
  2272. end ++
  2273. [FmtData] ++
  2274. case Log of
  2275. [] -> [];
  2276. _ -> [Log]
  2277. end,
  2278. Args =
  2279. case Depth of
  2280. unlimited ->
  2281. Args0;
  2282. _ ->
  2283. lists:flatmap(fun(A) -> [A, Depth] end, Args0)
  2284. end,
  2285. {Format ++ ClientFmt, Args ++ ClientArgs};
  2286. format_log_single(Report, FormatOpts) ->
  2287. format_log_multi(Report, FormatOpts).
  2288. format_log_multi(
  2289. #{
  2290. label := {gen_ipc, terminate},
  2291. name := Name,
  2292. queue := Q,
  2293. postponed := Postponed,
  2294. module := Module,
  2295. isEnter := StateEnter,
  2296. status := FmtData,
  2297. timeouts := Timeouts,
  2298. log := Log,
  2299. reason := {Class, Reason, Stacktrace},
  2300. client_info := ClientInfo
  2301. },
  2302. #{depth := Depth} = FormatOpts) ->
  2303. P = p(FormatOpts),
  2304. {FixedReason, FixedStacktrace} = fix_reason(Class, Reason, Stacktrace),
  2305. {ClientFmt, ClientArgs} = format_client_log(ClientInfo, P, Depth),
  2306. CBMode =
  2307. case StateEnter of
  2308. true ->
  2309. [Module, 'isEnter=true'];
  2310. false ->
  2311. Module
  2312. end,
  2313. Format =
  2314. lists:append(
  2315. ["** gen_ipc State machine ", P, " inner_error~n",
  2316. case Q of
  2317. [] -> "";
  2318. _ -> "** Last event = " ++ P ++ "~n"
  2319. end,
  2320. "** When server status = ", P, "~n",
  2321. "** Reason for termination = ", P, ":", P, "~n",
  2322. "** Callback modules = ", P, "~n",
  2323. "** Callback mode = ", P, "~n",
  2324. case Q of
  2325. [_, _ | _] -> "** Queued = " ++ P ++ "~n";
  2326. _ -> ""
  2327. end,
  2328. case Postponed of
  2329. [] -> "";
  2330. _ -> "** Postponed = " ++ P ++ "~n"
  2331. end,
  2332. case FixedStacktrace of
  2333. [] -> "";
  2334. _ -> "** Stacktrace =~n** " ++ P ++ "~n"
  2335. end,
  2336. case Timeouts of
  2337. {0, _} -> "";
  2338. _ -> "** Time-outs: " ++ P ++ "~n"
  2339. end,
  2340. case Log of
  2341. [] -> "";
  2342. _ -> "** Log =~n** " ++ P ++ "~n"
  2343. end]),
  2344. Args0 =
  2345. [Name |
  2346. case Q of
  2347. [] -> [];
  2348. [Event | _] -> [Event]
  2349. end] ++
  2350. [FmtData,
  2351. Class, FixedReason,
  2352. Module,
  2353. CBMode] ++
  2354. case Q of
  2355. [_ | [_ | _] = Events] -> [Events];
  2356. _ -> []
  2357. end ++
  2358. case Postponed of
  2359. [] -> [];
  2360. _ -> [Postponed]
  2361. end ++
  2362. case FixedStacktrace of
  2363. [] -> [];
  2364. _ -> [FixedStacktrace]
  2365. end ++
  2366. case Timeouts of
  2367. {0, _} -> [];
  2368. _ -> [Timeouts]
  2369. end ++
  2370. case Log of
  2371. [] -> [];
  2372. _ -> [Log]
  2373. end,
  2374. Args =
  2375. case Depth of
  2376. unlimited ->
  2377. Args0;
  2378. _ ->
  2379. lists:flatmap(fun(A) -> [A, Depth] end, Args0)
  2380. end,
  2381. {Format ++ ClientFmt, Args ++ ClientArgs};
  2382. format_log_multi(
  2383. #{
  2384. label := {gen_ipc, terminate},
  2385. name := Name,
  2386. queue := Q,
  2387. postponed := Postponed,
  2388. module := Module,
  2389. isEnter := StateEnter,
  2390. status := FmtData,
  2391. timeouts := Timeouts,
  2392. log := Log,
  2393. reason := {Class, Reason, Stacktrace},
  2394. client_info := ClientInfo
  2395. },
  2396. #{depth := Depth} = FormatOpts) ->
  2397. P = p(FormatOpts),
  2398. {FixedReason, FixedStacktrace} = fix_reason(Class, Reason, Stacktrace),
  2399. {ClientFmt, ClientArgs} = format_client_log(ClientInfo, P, Depth),
  2400. CBMode =
  2401. case StateEnter of
  2402. true ->
  2403. [Module, 'isEnter=true'];
  2404. false ->
  2405. Module
  2406. end,
  2407. Format =
  2408. lists:append(
  2409. ["** gen_ipc State machine ", P, " terminating~n",
  2410. case Q of
  2411. [] -> "";
  2412. _ -> "** Last event = " ++ P ++ "~n"
  2413. end,
  2414. "** When server status = ", P, "~n",
  2415. "** Reason for termination = ", P, ":", P, "~n",
  2416. "** Callback modules = ", P, "~n",
  2417. "** Callback mode = ", P, "~n",
  2418. case Q of
  2419. [_, _ | _] -> "** Queued = " ++ P ++ "~n";
  2420. _ -> ""
  2421. end,
  2422. case Postponed of
  2423. [] -> "";
  2424. _ -> "** Postponed = " ++ P ++ "~n"
  2425. end,
  2426. case FixedStacktrace of
  2427. [] -> "";
  2428. _ -> "** Stacktrace =~n** " ++ P ++ "~n"
  2429. end,
  2430. case Timeouts of
  2431. {0, _} -> "";
  2432. _ -> "** Time-outs: " ++ P ++ "~n"
  2433. end,
  2434. case Log of
  2435. [] -> "";
  2436. _ -> "** Log =~n** " ++ P ++ "~n"
  2437. end]),
  2438. Args0 =
  2439. [Name |
  2440. case Q of
  2441. [] -> [];
  2442. [Event | _] -> [Event]
  2443. end] ++
  2444. [FmtData,
  2445. Class, FixedReason,
  2446. Module,
  2447. CBMode] ++
  2448. case Q of
  2449. [_ | [_ | _] = Events] -> [Events];
  2450. _ -> []
  2451. end ++
  2452. case Postponed of
  2453. [] -> [];
  2454. _ -> [Postponed]
  2455. end ++
  2456. case FixedStacktrace of
  2457. [] -> [];
  2458. _ -> [FixedStacktrace]
  2459. end ++
  2460. case Timeouts of
  2461. {0, _} -> [];
  2462. _ -> [Timeouts]
  2463. end ++
  2464. case Log of
  2465. [] -> [];
  2466. _ -> [Log]
  2467. end,
  2468. Args =
  2469. case Depth of
  2470. unlimited ->
  2471. Args0;
  2472. _ ->
  2473. lists:flatmap(fun(A) -> [A, Depth] end, Args0)
  2474. end,
  2475. {Format ++ ClientFmt, Args ++ ClientArgs}.
  2476. fix_reason(Class, Reason, Stacktrace) ->
  2477. case Stacktrace of
  2478. [{M, F, Args, _} | ST]
  2479. when Class =:= error, Reason =:= undef ->
  2480. case code:is_loaded(M) of
  2481. false ->
  2482. {{'module could not be loaded', M}, ST};
  2483. _ ->
  2484. Arity =
  2485. if
  2486. is_list(Args) ->
  2487. length(Args);
  2488. is_integer(Args) ->
  2489. Args
  2490. end,
  2491. case erlang:function_exported(M, F, Arity) of
  2492. true ->
  2493. {Reason, Stacktrace};
  2494. false ->
  2495. {{'function not exported', {M, F, Arity}}, ST}
  2496. end
  2497. end;
  2498. _ -> {Reason, Stacktrace}
  2499. end.
  2500. format_client_log_single(undefined, _, _) ->
  2501. {"", []};
  2502. format_client_log_single({Pid, dead}, _, _) ->
  2503. {" Client ~0p is dead.", [Pid]};
  2504. format_client_log_single({Pid, remote}, _, _) ->
  2505. {" Client ~0p is remote on node ~0p.", [Pid, node(Pid)]};
  2506. format_client_log_single({_Pid, {Name, Stacktrace0}}, P, Depth) ->
  2507. %% Minimize the stacktrace a bit for single line reports. This is
  2508. %% hopefully enough to point out the position.
  2509. Stacktrace = lists:sublist(Stacktrace0, 4),
  2510. Format = lists:append([" Client ", P, " stacktrace: ", P, "."]),
  2511. Args =
  2512. case Depth of
  2513. unlimited ->
  2514. [Name, Stacktrace];
  2515. _ ->
  2516. [Name, Depth, Stacktrace, Depth]
  2517. end,
  2518. {Format, Args}.
  2519. format_client_log(undefined, _, _) ->
  2520. {"", []};
  2521. format_client_log({Pid, dead}, _, _) ->
  2522. {"** Client ~p is dead~n", [Pid]};
  2523. format_client_log({Pid, remote}, _, _) ->
  2524. {"** Client ~p is remote on node ~p~n", [Pid, node(Pid)]};
  2525. format_client_log({_Pid, {Name, Stacktrace}}, P, Depth) ->
  2526. Format = lists:append(["** Client ", P, " stacktrace~n** ", P, "~n"]),
  2527. Args =
  2528. case Depth of
  2529. unlimited ->
  2530. [Name, Stacktrace];
  2531. _ ->
  2532. [Name, Depth, Stacktrace, Depth]
  2533. end,
  2534. {Format, Args}.
  2535. p(#{single_line := Single, depth := Depth, encoding := Enc}) ->
  2536. "~" ++ single(Single) ++ mod(Enc) ++ p(Depth);
  2537. p(unlimited) ->
  2538. "p";
  2539. p(_Depth) ->
  2540. "P".
  2541. single(true) -> "0";
  2542. single(false) -> "".
  2543. mod(latin1) -> "";
  2544. mod(_) -> "t".
  2545. %% Call Module:format_status/2 or return a default value
  2546. format_status(Opt, PDict, _Parent, _Name, Module, _HibernateAfterTimeout, _IsEnter, _EpmHers, _Postponed, _Timers, CurStatus, CurState) ->
  2547. case erlang:function_exported(Module, formatStatus, 2) of
  2548. true ->
  2549. try Module:formatStatus(Opt, [PDict, CurStatus, CurState])
  2550. catch
  2551. throw:Result -> Result;
  2552. _:_ ->
  2553. format_status_default(Opt, {{CurStatus, CurState}, atom_to_list(Module) ++ ":formatStatus/2 crashed"})
  2554. end;
  2555. false ->
  2556. format_status_default(Opt, {CurStatus, CurState})
  2557. end.
  2558. %% The default Module:format_status/3
  2559. format_status_default(Opt, State_Data) ->
  2560. case Opt of
  2561. terminate ->
  2562. State_Data;
  2563. _ ->
  2564. [{data, [{"State", State_Data}]}]
  2565. end.
  2566. print_event(Dev, SystemEvent, Name) ->
  2567. case SystemEvent of
  2568. {in, Event, Status} ->
  2569. io:format(
  2570. Dev, "*DBG* ~tp receive ~ts in Status ~tp~n",
  2571. [Name, event_string(Event), Status]);
  2572. {code_change, Event, Status} ->
  2573. io:format(
  2574. Dev, "*DBG* ~tp receive ~ts after code change in Status ~tp~n",
  2575. [Name, event_string(Event), Status]);
  2576. {out, Reply, {To, _Tag}} ->
  2577. io:format(
  2578. Dev, "*DBG* ~tp send ~tp to ~tw~n",
  2579. [Name, Reply, To]);
  2580. {out, Replys} ->
  2581. io:format(
  2582. Dev, "*DBG* ~tp sends to: ~tp~n",
  2583. [Name, Replys]);
  2584. {enter, Status} ->
  2585. io:format(
  2586. Dev, "*DBG* ~tp enter in Status ~tp~n",
  2587. [Name, Status]);
  2588. {start_timer, Action} ->
  2589. io:format(
  2590. Dev, "*DBG* ~tp start_timer ~tp ~n",
  2591. [Name, Action]);
  2592. {insert_timeout, Event, Status} ->
  2593. io:format(
  2594. Dev, "*DBG* ~tp insert_timeout ~tp in Status ~tp~n",
  2595. [Name, Event, Status]);
  2596. {terminate, Reason, Status} ->
  2597. io:format(
  2598. Dev, "*DBG* ~tp terminate ~tp in Status ~tp~n",
  2599. [Name, Reason, Status]);
  2600. {change_isEnter, IsEnter} ->
  2601. io:format(
  2602. Dev, "*DBG* ~tp change_isEnter to ~tp ~n",
  2603. [Name, IsEnter]);
  2604. {Tag, Event, Status, NextStatus}
  2605. when Tag =:= postpone; Tag =:= consume ->
  2606. StateString =
  2607. case NextStatus of
  2608. Status ->
  2609. io_lib:format("~tp", [Status]);
  2610. _ ->
  2611. io_lib:format("~tp => ~tp", [Status, NextStatus])
  2612. end,
  2613. io:format(
  2614. Dev, "*DBG* ~tp ~tw ~ts in state ~ts~n",
  2615. [Name, Tag, event_string(Event), StateString]);
  2616. _NotMatch ->
  2617. io:format(
  2618. Dev, "*DBG* ~tp NotMatch ~tp ~n",
  2619. [Name, _NotMatch])
  2620. end.
  2621. event_string(Event) ->
  2622. case Event of
  2623. {{call, {Pid, _Tag}}, Request} ->
  2624. io_lib:format("call ~tp from ~tw", [Request, Pid]);
  2625. {EventType, EventContent} ->
  2626. io_lib:format("~tw ~tp", [EventType, EventContent])
  2627. end.
  2628. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% debug 日志 End %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%