各种有用的erlang行为
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

2155 líneas
92 KiB

hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
hace 5 años
  1. -module(gen_ipc).
  2. -include_lib("kernel/include/logger.hrl").
  3. -export([
  4. %% API for gen_server or gen_statem behaviour
  5. start/3, start/4, start_link/3, start_link/4
  6. , stop/1, stop/3
  7. , cast/2
  8. , abcast/2, abcast/3
  9. , call/2, call/3
  10. , multi_call/2, multi_call/3, multi_call/4
  11. , enter_loop/4, enter_loop/5, enter_loop/6
  12. , reply/1, reply/2
  13. %% API for gen_event behaviour
  14. , infoNotify/2, callNotify/2
  15. , epmCall/3, epmCall/4, epmInfo/3
  16. , addEpm/3, addSupEpm/3, whichEpm/1
  17. , deleteEpm/3, swapEpm/3, swapSupEpm/3
  18. %% gen callbacks
  19. , init_it/6
  20. %% sys callbacks
  21. , system_continue/3
  22. , system_terminate/4
  23. , system_code_change/4
  24. , system_get_state/1
  25. , system_replace_state/2
  26. , format_status/2
  27. %% Internal callbacks
  28. , wakeup_from_hibernate/5
  29. %% logger callback
  30. , format_log/1
  31. , epm_log/1
  32. ]).
  33. %% 进程字典的宏定义
  34. -define(PD_PARENT, '$pd_parent').
  35. -define(PD_PRO_NAME, '$pd_proname').
  36. -define(PD_EPM_FLAG, '$pd_epmFlag').
  37. -define(PD_EPM_LIST, '$pd_epmList').
  38. %% timeout相关宏定义
  39. -define(REL_TIMEOUT(T), ((is_integer(T) andalso (T) >= 0) orelse (T) =:= infinity)).
  40. -define(ABS_TIMEOUT(T), (is_integer(T) orelse (T) =:= infinity)).
  41. -define(STACKTRACE(), element(2, erlang:process_info(self(), current_stacktrace))).
  42. -define(CB_FORM_ENTER, 1). %% 从enter 回调返回
  43. -define(CB_FORM_AFTER, 2). %% 从after 回调返回
  44. -define(CB_FORM_EVENT, 3). %% 从event 回调返回
  45. %% debug 调试相关宏定义
  46. -define(NOT_DEBUG, []).
  47. -define(SYS_DEBUG(Debug, SystemEvent),
  48. case Debug of
  49. ?NOT_DEBUG ->
  50. Debug;
  51. _ ->
  52. sys:handle_debug(Debug, fun print_event/3, getProName(), SystemEvent)
  53. end).
  54. %%%==========================================================================
  55. %%% Interface functions.
  56. %%%==========================================================================
  57. %% gen:call 发送消息来源进程格式类型
  58. -type from() :: {To :: pid(), Tag :: term()}.
  59. %% 事件类型
  60. -type eventType() :: externalEventType() | timeoutEventType() | {'onevent', Subtype :: term()}.
  61. -type externalEventType() :: {'call', From :: from()} | 'cast' | 'info'.
  62. -type timeoutEventType() :: 'eTimeout' | 'sTimeout' | {'gTimeout', Name :: term()}.
  63. %% 是否改进程捕捉信号 gen_event管理进程需要设置该参数为true
  64. -type isTrapExit() :: boolean().
  65. %% 是否允许进入enter 回调
  66. -type isEnter() :: boolean().
  67. %% 如果为 "true" 则推迟当前事件,并在状态更改时重试(=/=)
  68. -type isPostpone() :: boolean().
  69. %% 如果为 "true" 则使服务器休眠而不是进入接收状态
  70. -type isHibernate() :: boolean().
  71. %% 定时器相关
  72. -type timeouts() :: Time :: timeout() | integer().
  73. -type timeoutOption() :: {abs, Abs :: boolean()}.
  74. % gen_event模式下回调模块的Key
  75. -type epmHandler() :: atom() | {atom(), term()}.
  76. %% 在状态更改期间:
  77. %% NextStatus and NewData are set.
  78. %% 按照出现的顺序处理 actions()列表
  79. %% 这些action() 按包含列表中的出现顺序执行。设置选项的选项将覆盖任何以前的选项,因此每种类型的最后一种将获胜。
  80. %% 如果设置了enter 则进入enter回调
  81. %% 如果设置了doAfter 则进入after回调
  82. %% 如果 "postpone" 为 "true",则推迟当前事件。
  83. %% 如果设置了“超时”,则开始状态超时。 零超时事件将会插入到待处理事件的前面 先执行
  84. %% 如果有postponed 事件则 事件执行顺序为 超时添加和更新 + 零超时 + 当前事件 + 反序的Postpone事件 + LeftEvent
  85. %% 处理待处理的事件,或者如果没有待处理的事件,则服务器进入接收或休眠状态(当“hibernate”为“ true”时)
  86. -type initAction() ::
  87. {trap_exit, Bool :: isTrapExit()} | % 设置是否捕捉信息 主要用于gen_event模式下
  88. eventAction().
  89. -type eventAction() ::
  90. {'doAfter', Args :: term()} | % 设置执行某事件后是否回调 handleAfter
  91. {'isPostpone', Bool :: isPostpone()} | % 设置推迟选项
  92. {'nextEvent', EventType :: eventType(), EventContent :: term()} | % 插入事件作为下一个处理
  93. commonAction().
  94. -type afterAction() ::
  95. {'nextEvent', EventType :: eventType(), EventContent :: term()} | % 插入事件作为下一个处理
  96. commonAction().
  97. -type enterAction() ::
  98. {'isPostpone', false} | % 虽然enter action 不能设置postpone 但是可以取消之前event的设置
  99. commonAction().
  100. -type commonAction() ::
  101. {'isEnter', Bool :: isEnter()} |
  102. {'isHibernate', Bool :: isHibernate()} |
  103. timeoutAction() |
  104. replyAction().
  105. -type timeoutAction() ::
  106. timeoutNewAction() |
  107. timeoutCancelAction() |
  108. timeoutUpdateAction().
  109. -type timeoutNewAction() ::
  110. {'eTimeout', Time :: timeouts(), EventContent :: term()} | % Set the event_timeout option
  111. {'eTimeout', Time :: timeouts(), EventContent :: term(), Options :: ([timeoutOption()])} | % Set the generic_timeout option
  112. {{'gTimeout', Name :: term()}, Time :: timeouts(), EventContent :: term()} | % Set the generic_timeout option
  113. {{'gTimeout', Name :: term()}, Time :: timeouts(), EventContent :: term(), Options :: ([timeoutOption()])} | % Set the status_timeout option
  114. {'sTimeout', Time :: timeouts(), EventContent :: term()} | % Set the status_timeout option
  115. {'sTimeout', Time :: timeouts(), EventContent :: term(), Options :: ([timeoutOption()])}.
  116. -type timeoutCancelAction() ::
  117. 'c_eTimeout' |
  118. {'c_gTimeout', Name :: term()} |
  119. 'c_sTimeout'.
  120. -type timeoutUpdateAction() ::
  121. {'u_eTimeout', EventContent :: term()} |
  122. {{'u_gTimeout', Name :: term()}, EventContent :: term()} |
  123. {'u_sTimeout', EventContent :: term()}.
  124. -type replyAction() ::
  125. {'reply', From :: from(), Reply :: term()}.
  126. -type eventCallbackResult() ::
  127. {'reply', Reply :: term(), NewState :: term()} | % 用作gen_server模式时快速响应进入消息接收
  128. {'noreply', NewState :: term()} | % 用作gen_server模式时快速响应进入消息接收
  129. {'reply', Reply :: term(), NewState :: term(), Options :: hibernate | {doAfter, Args}} | % 用作gen_server模式时快速响应进入消息接收
  130. {'noreply', NewState :: term(), Options :: hibernate | {doAfter, Args}} | % 用作gen_server模式时快速响应进入循环
  131. {'nextStatus', NextStatus :: term(), NewState :: term()} | % {next_status,NextStatus,NewData,[]}
  132. {'nextStatus', NextStatus :: term(), NewState :: term(), Actions :: [eventAction(), ...]} | % Status transition, maybe to the same status
  133. commonCallbackResult(eventAction()).
  134. -type afterCallbackResult() ::
  135. {'nextStatus', NextStatus :: term(), NewState :: term()} | % {next_status,NextStatus,NewData,[]}
  136. {'nextStatus', NextStatus :: term(), NewState :: term(), Actions :: [afterAction(), ...]} | % Status transition, maybe to the same status
  137. {'noreply', NewState :: term()} | % 用作gen_server模式时快速响应进入消息接收
  138. {'noreply', NewState :: term(), Options :: hibernate} | % 用作gen_server模式时快速响应进入消息接收
  139. commonCallbackResult(afterAction()).
  140. -type enterCallbackResult() ::
  141. commonCallbackResult(enterAction()).
  142. -type commonCallbackResult(ActionType) ::
  143. {'keepStatus', NewState :: term()} | % {keep_status,NewData,[]}
  144. {'keepStatus', NewState :: term(), Actions :: [ActionType]} | % Keep status, change data
  145. 'keepStatusState' | % {keep_status_and_data,[]}
  146. {'keepStatusState', Actions :: [ActionType]} | % Keep status and data -> only actions
  147. {'repeatStatus', NewState :: term()} | % {repeat_status,NewData,[]}
  148. {'repeatStatus', NewState :: term(), Actions :: [ActionType]} | % Repeat status, change data
  149. 'repeatStatusState' | % {repeat_status_and_data,[]}
  150. {'repeatStatusState', Actions :: [ActionType]} | % Repeat status and data -> only actions
  151. 'stop' | % {stop,normal}
  152. {'stop', Reason :: term()} | % Stop the server
  153. {'stop', Reason :: term(), NewState :: term()} | % Stop the server
  154. {'stopReply', Reason :: term(), Replies :: [replyAction(), ...]} | % Reply then stop the server
  155. {'stopReply', Reason :: term(), Replies :: [replyAction(), ...], NewState :: term()}. % Reply then stop the server
  156. %% 状态机的初始化功能函数
  157. %% 如果要模拟gen_server init返回定时时间 可以在Actions返回定时动作
  158. %% 如果要把改进程当做gen_event管理进程需要在actions列表包含 {trap_exit, true} 设置该进程捕捉异常
  159. -callback init(Args :: term()) ->
  160. 'ignore' |
  161. {'stop', Reason :: term()} |
  162. {'ok', State :: term()} |
  163. {'ok', Status :: term(), State :: term()} |
  164. {'ok', Status :: term(), State :: term(), Actions :: [initAction(), ...]}.
  165. %% 当 enter call 回调函数
  166. -callback handleEnter(OldStatus :: term(), CurStatus :: term(), State :: term()) ->
  167. enterCallbackResult().
  168. %% 当 init返回actions包含 doAfter 的时候会在 enter调用后 调用该函数 或者
  169. %% 在事件回调函数返回后 enter调用后调用该函数
  170. %% 该回调函数相当于 gen_server 的 handle_continue回调 但是在综合模式时 也可以生效
  171. -callback handleAfter(AfterArgs :: term(), Status :: term(), State :: term()) ->
  172. afterCallbackResult().
  173. %% call 所以状态的回调函数
  174. -callback handleCall(EventContent :: term(), From :: {pid(), Tag :: term()}, Status :: term(), State :: term()) ->
  175. eventCallbackResult().
  176. %% cast 回调函数
  177. -callback handleCast(EventContent :: term(), Status :: term(), State :: term()) ->
  178. eventCallbackResult().
  179. %% info 回调函数
  180. -callback handleInfo(EventContent :: term(), Status :: term(), State :: term()) ->
  181. eventCallbackResult().
  182. %% 内部事件 Onevent 包括actions 设置的定时器超时产生的事件 和 nextEvent产生的超时事件 但是不是 call cast info 回调函数 以及其他自定义定时事件 的回调函数
  183. %% 并且这里需要注意 其他erlang:start_timer生成超时事件发送的消息 不能和gen_ipc定时器关键字重合 有可能会导致一些问题
  184. -callback handleOnevent(EventType :: term(), EventContent :: term(), Status :: term(), State :: term()) ->
  185. eventCallbackResult().
  186. %% 在gen_event模式下 扩展了下面三个回调函数 考虑场景是:
  187. %% 比如游戏里的公会 有时候一个公会一个进程来管理可能开销比较高 只用一个进程来管理所以公会有可能一个进程处理不过来
  188. %% 这个时候可以考虑用gen_ipc来分组管理 一个gen_ipc进程管理 N 个公会 但是管理进程需要做一些数据保存什么 或者定时 就可能会用到下面的这些函数
  189. %% gen_event模式时 notify 有可能需要回调该管理进程的该函数
  190. -callback handleEpmEvent(EventContent :: term(), Status :: term(), State :: term()) ->
  191. eventCallbackResult().
  192. %% gen_event模式时 call请求 有可能需要回调该管理进程的该函数
  193. -callback handleEpmCall(EventContent :: term(), Status :: term(), State :: term()) ->
  194. eventCallbackResult().
  195. %% gen_event模式时 info消息 有可能需要回调该管理进程的该函数
  196. -callback handleEpmInfo(EventContent :: term(), Status :: term(), State :: term()) ->
  197. eventCallbackResult().
  198. %% 在服务器终止之前进行清理。
  199. -callback terminate(Reason :: 'normal' | 'shutdown' | {'shutdown', term()} | term(), Status :: term(), State :: term()) ->
  200. any().
  201. %% 代码更新回调函数
  202. -callback code_change(OldVsn :: term() | {'down', term()}, OldStatus :: term(), OldState :: term(), Extra :: term()) ->
  203. {ok, NewStatus :: term(), NewData :: term()} |
  204. (Reason :: term()).
  205. %% 以一种通常被精简的方式来格式化回调模块状态。
  206. %% 对于StatusOption =:= 'normal',首选返回 term 是[{data,[{"Status",FormattedStatus}]}]
  207. %% 对于StatusOption =:= 'terminate',它只是FormattedStatus
  208. -callback formatStatus(StatusOption, [PDict | term()]) ->
  209. Status :: term() when
  210. StatusOption :: 'normal' | 'terminate',
  211. PDict :: [{Key :: term(), Value :: term()}].
  212. -optional_callbacks([
  213. formatStatus/2
  214. , terminate/3
  215. , code_change/4
  216. , handleEnter/3
  217. , handleAfter/3
  218. , handleOnevent/4
  219. , handleEpmEvent/3
  220. , handleEpmCall/3
  221. , handleEpmInfo/3
  222. ]).
  223. -record(cycleData, {
  224. module :: atom()
  225. , isEnter = false :: boolean()
  226. , hibernateAfter = infinity :: timeout()
  227. , postponed = [] :: [{eventType(), term()}]
  228. , timers = #{} :: #{TimeoutType :: timeoutEventType() => {TimerRef :: reference(), TimeoutMsg :: term()}}
  229. }).
  230. -record(epmHer, {
  231. epmM :: atom(),
  232. epmId = false,
  233. epmS :: term(),
  234. epmSup = false :: 'false' | pid()}).
  235. -compile({inline, [isEventType/1]}).
  236. isEventType(Type) ->
  237. case Type of
  238. {'call', {_Pid, _Ref}} -> true;
  239. 'cast' -> true;
  240. 'info' -> true;
  241. {'onevent', _SubType} -> true;
  242. 'eTimeout' -> true;
  243. 'sTimeout' -> true;
  244. {'gTimeout', _Name} -> true;
  245. _ ->
  246. false
  247. end.
  248. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% start stop API start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  249. -type serverName() ::
  250. {'local', atom()} |
  251. {'global', GlobalName :: term()} |
  252. {'via', RegMod :: module(), Name :: term()}.
  253. -type serverRef() ::
  254. pid() |
  255. (LocalName :: atom()) |
  256. {Name :: atom(), Node :: atom()} |
  257. {'global', GlobalName :: term()} |
  258. {'via', RegMod :: module(), ViaName :: term()}.
  259. -type startOpt() ::
  260. {'timeout', Time :: timeout()} |
  261. {'spawn_opt', [proc_lib:spawn_option()]} |
  262. enterLoopOpt().
  263. -type enterLoopOpt() ::
  264. {'debug', Debugs :: [sys:debug_option()]} |
  265. {'hibernate_after', HibernateAfterTimeout :: timeout()}.
  266. -type startRet() ::
  267. 'ignore' |
  268. {'ok', pid()} |
  269. {'error', term()}.
  270. -spec start(Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet().
  271. start(Module, Args, Opts) ->
  272. gen:start(?MODULE, nolink, Module, Args, Opts).
  273. -spec start(ServerName :: serverName(), Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet().
  274. start(ServerName, Module, Args, Opts) ->
  275. gen:start(?MODULE, nolink, ServerName, Module, Args, Opts).
  276. -spec start_link(Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet().
  277. start_link(Module, Args, Opts) ->
  278. gen:start(?MODULE, link, Module, Args, Opts).
  279. -spec start_link(ServerName :: serverName(), Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet().
  280. start_link(ServerName, Module, Args, Opts) ->
  281. gen:start(?MODULE, link, ServerName, Module, Args, Opts).
  282. -spec stop(ServerRef :: serverRef()) -> ok.
  283. stop(ServerRef) ->
  284. gen:stop(ServerRef).
  285. -spec stop(ServerRef :: serverRef(), Reason :: term(), Timeout :: timeout()) -> ok.
  286. stop(ServerRef, Reason, Timeout) ->
  287. gen:stop(ServerRef, Reason, Timeout).
  288. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% start stop API end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  289. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gen callbacks start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  290. doModuleInit(Module, Args) ->
  291. try
  292. Module:init(Args)
  293. catch
  294. throw:Ret -> Ret;
  295. Class:Reason:Stacktrace -> {'EXIT', Class, Reason, Stacktrace}
  296. end.
  297. init_it(Starter, self, ServerRef, Module, Args, Opts) ->
  298. init_it(Starter, self(), ServerRef, Module, Args, Opts);
  299. init_it(Starter, Parent, ServerRef, Module, Args, Opts) ->
  300. Name = gen:name(ServerRef),
  301. Debug = gen:debug_options(Name, Opts),
  302. HibernateAfterTimeout = gen:hibernate_after(Opts),
  303. case doModuleInit(Module, Args) of
  304. {ok, State} ->
  305. proc_lib:init_ack(Starter, {ok, self()}),
  306. loopEntry(Parent, Debug, Module, Name, HibernateAfterTimeout, undefined, State, []);
  307. {ok, Status, State} ->
  308. proc_lib:init_ack(Starter, {ok, self()}),
  309. loopEntry(Parent, Debug, Module, Name, HibernateAfterTimeout, Status, State, []);
  310. {ok, Status, State, Actions} ->
  311. proc_lib:init_ack(Starter, {ok, self()}),
  312. loopEntry(Parent, Debug, Module, Name, HibernateAfterTimeout, Status, State, Actions);
  313. {stop, Reason} ->
  314. gen:unregister_name(ServerRef),
  315. proc_lib:init_ack(Starter, {error, Reason}),
  316. exit(Reason);
  317. ignore ->
  318. gen:unregister_name(ServerRef),
  319. proc_lib:init_ack(Starter, ignore),
  320. exit(normal);
  321. {'EXIT', Class, Reason, Stacktrace} ->
  322. gen:unregister_name(ServerRef),
  323. proc_lib:init_ack(Starter, {error, Reason}),
  324. error_info(Class, Reason, Stacktrace, #cycleData{module = Module}, 'Sun_init', '$un_init', Debug, []),
  325. erlang:raise(Class, Reason, Stacktrace);
  326. _Ret ->
  327. gen:unregister_name(ServerRef),
  328. Error = {badReturnFrom_doModuleInit, _Ret},
  329. proc_lib:init_ack(Starter, {error, Error}),
  330. error_info(error, Error, ?STACKTRACE(), #cycleData{module = Module}, '$un_init', '$un_init', Debug, []),
  331. exit(Error)
  332. end.
  333. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gen callbacks end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  334. %% 进入循环 调用该进程必须使用proc_lib启动 且已经初始化状态和数据 包括注册名称
  335. -spec enter_loop(Module :: module(), Status :: term(), State :: term(), Opts :: [enterLoopOpt()]) -> no_return().
  336. enter_loop(Module, Status, State, Opts) ->
  337. enter_loop(Module, Status, State, Opts, self(), []).
  338. -spec enter_loop(Module :: module(), Status :: term(), State :: term(), Opts :: [enterLoopOpt()], ServerOrActions :: serverName() | pid() | [eventAction()]) -> no_return().
  339. enter_loop(Module, Status, State, Opts, ServerOrActions) ->
  340. if
  341. is_list(ServerOrActions) ->
  342. enter_loop(Module, Opts, Status, State, self(), ServerOrActions);
  343. true ->
  344. enter_loop(Module, Opts, Status, State, ServerOrActions, [])
  345. end.
  346. -spec enter_loop(Module :: module(), Status :: term(), State :: term(), Opts :: [enterLoopOpt()], Server :: serverName() | pid(), Actions :: [eventAction()]) -> no_return().
  347. enter_loop(Module, Status, State, Opts, ServerName, Actions) ->
  348. is_atom(Module) orelse error({atom, Module}),
  349. Parent = gen:get_parent(),
  350. Name = gen:get_proc_name(ServerName),
  351. Debug = gen:debug_options(Name, Opts),
  352. HibernateAfterTimeout = gen:hibernate_after(Opts),
  353. loopEntry(Parent, Debug, Module, Name, HibernateAfterTimeout, Status, State, Actions).
  354. %% 这里的 init_it/6 和 enter_loop/5,6,7 函数汇聚
  355. loopEntry(Parent, Debug, Module, Name, HibernateAfterTimeout, CurStatus, CurState, Actions) ->
  356. setParent(Parent),
  357. setProName(Name),
  358. %% 如果该进程用于 gen_event 则需要设置 process_flag(trap_exit, true) 需要在Actions返回 {trap_exit, true}
  359. MewActions =
  360. case lists:keyfind(trap_exit, 1, Actions) of
  361. false ->
  362. Actions;
  363. {trap_exit, true} ->
  364. process_flag(trap_exit, true),
  365. lists:keydelete(trap_exit, 1, Actions);
  366. _ ->
  367. lists:keydelete(trap_exit, 1, Actions)
  368. end,
  369. CycleData = #cycleData{module = Module, hibernateAfter = HibernateAfterTimeout},
  370. NewDebug = ?SYS_DEBUG(Debug, {enter, CurStatus}),
  371. %% 强制执行{postpone,false}以确保我们的假事件被丢弃
  372. LastActions = MewActions ++ [{isPostpone, false}],
  373. parseEventActionsList(CycleData, CurStatus, CurState, CurStatus, NewDebug, [{onevent, init_status}], true, LastActions, ?CB_FORM_EVENT).
  374. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% sys callbacks start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  375. system_continue(Parent, Debug, {CycleData, CurStatus, CurState, IsHibernate}) ->
  376. updateParent(Parent),
  377. if
  378. IsHibernate ->
  379. proc_lib:hibernate(?MODULE, wakeup_from_hibernate, [CycleData, CurStatus, CurState, Debug, IsHibernate]);
  380. true ->
  381. receiveMsgWait(CycleData, CurStatus, CurState, Debug, IsHibernate)
  382. end.
  383. system_terminate(Reason, Parent, Debug, {CycleData, CurStatus, CurState, _IsHibernate}) ->
  384. updateParent(Parent),
  385. terminate(exit, Reason, ?STACKTRACE(), CycleData, CurStatus, CurState, Debug, []).
  386. system_code_change({#cycleData{module = Module} = CycleData, CurStatus, CurState, IsHibernate}, _Mod, OldVsn, Extra) ->
  387. case
  388. try Module:code_change(OldVsn, CurStatus, CurState, Extra)
  389. catch
  390. throw:Result -> Result
  391. end
  392. of
  393. {ok, NewStatus, NewState} ->
  394. {ok, {CycleData, NewStatus, NewState, IsHibernate}};
  395. Error ->
  396. Error
  397. end.
  398. system_get_state({_CycleData, CurStatus, CurState, _IsHibernate}) ->
  399. {ok, {CurStatus, CurState}}.
  400. system_replace_state(StatusFun, {CycleData, CurStatus, CurState, IsHibernate}) ->
  401. {NewStatus, NewState} = StatusFun(CurStatus, CurState),
  402. {ok, {NewStatus, NewState}, {CycleData, NewStatus, NewState, IsHibernate}}.
  403. format_status(Opt, [PDict, SysStatus, Parent, Debug, {#cycleData{timers = Timers, postponed = Postponed} = CycleData, CurStatus, CurState, _IsHibernate}]) ->
  404. Header = gen:format_status_header("Status for status machine", getProName()),
  405. updateParent(Parent),
  406. Log = sys:get_log(Debug),
  407. [
  408. {header, Header},
  409. {data,
  410. [
  411. {"Status", SysStatus},
  412. {"Parent", Parent},
  413. {"Time-outs", list_timeouts(Timers)},
  414. {"Logged Events", Log},
  415. {"Postponed", Postponed}
  416. ]
  417. } |
  418. case format_status(Opt, PDict, CycleData, CurStatus, CurState) of
  419. L when is_list(L) -> L;
  420. T -> [T]
  421. end
  422. ].
  423. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% sys callbacks end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  424. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% API helpers start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  425. -spec call(ServerRef :: serverRef(), Request :: term()) -> Reply :: term().
  426. call(ServerRef, Request) ->
  427. try gen:call(ServerRef, '$gen_call', Request) of
  428. {ok, Reply} ->
  429. Reply
  430. catch
  431. Class:Reason:Stacktrace ->
  432. erlang:raise(Class, {Reason, {?MODULE, call, [ServerRef, Request]}}, Stacktrace)
  433. end.
  434. -spec call(ServerRef :: serverRef(), Request :: term(), Timeout :: timeout() |{'cleanTimeout', T :: timeout()} | {'dirtyTimeout', T :: timeout()}) -> Reply :: term().
  435. call(ServerRef, Request, infinity) ->
  436. try gen:call(ServerRef, '$gen_call', Request, infinity) of
  437. {ok, Reply} ->
  438. Reply
  439. catch
  440. Class:Reason:Stacktrace ->
  441. erlang:raise(Class, {Reason, {?MODULE, call, [ServerRef, Request, infinity]}}, Stacktrace)
  442. end;
  443. call(ServerRef, Request, {dirtyTimeout, T} = Timeout) ->
  444. try gen:call(ServerRef, '$gen_call', Request, T) of
  445. {ok, Reply} ->
  446. Reply
  447. catch
  448. Class:Reason:Stacktrace ->
  449. erlang:raise(Class, {Reason, {?MODULE, call, [ServerRef, Request, Timeout]}}, Stacktrace)
  450. end;
  451. call(ServerRef, Request, {cleanTimeout, T} = Timeout) ->
  452. callClean(ServerRef, Request, Timeout, T);
  453. call(ServerRef, Request, {_, _} = Timeout) ->
  454. erlang:error(badarg, [ServerRef, Request, Timeout]);
  455. call(ServerRef, Request, Timeout) ->
  456. callClean(ServerRef, Request, Timeout, Timeout).
  457. callClean(ServerRef, Request, Timeout, T) ->
  458. %% 通过代理过程呼叫服务器以躲避任何较晚的答复
  459. Ref = make_ref(),
  460. Self = self(),
  461. Pid = spawn(
  462. fun() ->
  463. Self !
  464. try gen:call(ServerRef, '$gen_call', Request, T) of
  465. Result ->
  466. {Ref, Result}
  467. catch Class:Reason:Stacktrace ->
  468. {Ref, Class, Reason, Stacktrace}
  469. end
  470. end),
  471. Mref = monitor(process, Pid),
  472. receive
  473. {Ref, Result} ->
  474. demonitor(Mref, [flush]),
  475. case Result of
  476. {ok, Reply} ->
  477. Reply
  478. end;
  479. {Ref, Class, Reason, Stacktrace} ->
  480. demonitor(Mref, [flush]),
  481. erlang:raise(Class, {Reason, {?MODULE, call, [ServerRef, Request, Timeout]}}, Stacktrace);
  482. {'DOWN', Mref, _, _, Reason} ->
  483. %% 从理论上讲,有可能在try-of和!之间杀死代理进程。因此,在这种情况下
  484. exit(Reason)
  485. end.
  486. multi_call(Name, Request) when is_atom(Name) ->
  487. do_multi_call([node() | nodes()], Name, Request, infinity).
  488. multi_call(Nodes, Name, Request) when is_list(Nodes), is_atom(Name) ->
  489. do_multi_call(Nodes, Name, Request, infinity).
  490. multi_call(Nodes, Name, Request, infinity) ->
  491. do_multi_call(Nodes, Name, Request, infinity);
  492. multi_call(Nodes, Name, Request, Timeout) when is_list(Nodes), is_atom(Name), is_integer(Timeout), Timeout >= 0 ->
  493. do_multi_call(Nodes, Name, Request, Timeout).
  494. do_multi_call(Nodes, Name, Request, infinity) ->
  495. Tag = make_ref(),
  496. Monitors = send_nodes(Nodes, Name, Tag, Request, []),
  497. rec_nodes(Tag, Monitors, Name, undefined);
  498. do_multi_call(Nodes, Name, Request, Timeout) ->
  499. Tag = make_ref(),
  500. Caller = self(),
  501. Receiver = spawn(
  502. fun() ->
  503. process_flag(trap_exit, true),
  504. Mref = erlang:monitor(process, Caller),
  505. receive
  506. {Caller, Tag} ->
  507. Monitors = send_nodes(Nodes, Name, Tag, Request, []),
  508. TimerId = erlang:start_timer(Timeout, self(), ok),
  509. Result = rec_nodes(Tag, Monitors, Name, TimerId),
  510. exit({self(), Tag, Result});
  511. {'DOWN', Mref, _, _, _} ->
  512. exit(normal)
  513. end
  514. end
  515. ),
  516. Mref = erlang:monitor(process, Receiver),
  517. Receiver ! {self(), Tag},
  518. receive
  519. {'DOWN', Mref, _, _, {Receiver, Tag, Result}} ->
  520. Result;
  521. {'DOWN', Mref, _, _, Reason} ->
  522. exit(Reason)
  523. end.
  524. send_nodes([Node | Tail], Name, Tag, Request, Monitors) when is_atom(Node) ->
  525. Monitor = start_monitor(Node, Name),
  526. catch {Name, Node} ! {'$gen_call', {self(), {Tag, Node}}, Request},
  527. send_nodes(Tail, Name, Tag, Request, [Monitor | Monitors]);
  528. send_nodes([_Node | Tail], Name, Tag, Request, Monitors) ->
  529. send_nodes(Tail, Name, Tag, Request, Monitors);
  530. send_nodes([], _Name, _Tag, _Req, Monitors) ->
  531. Monitors.
  532. rec_nodes(Tag, Nodes, Name, TimerId) ->
  533. rec_nodes(Tag, Nodes, Name, [], [], 2000, TimerId).
  534. rec_nodes(Tag, [{N, R} | Tail], Name, BadNodes, Replies, Time, TimerId) ->
  535. receive
  536. {'DOWN', R, _, _, _} ->
  537. rec_nodes(Tag, Tail, Name, [N | BadNodes], Replies, Time, TimerId);
  538. {{Tag, N}, Reply} ->
  539. erlang:demonitor(R, [flush]),
  540. rec_nodes(Tag, Tail, Name, BadNodes,
  541. [{N, Reply} | Replies], Time, TimerId);
  542. {timeout, TimerId, _} ->
  543. erlang:demonitor(R, [flush]),
  544. rec_nodes_rest(Tag, Tail, Name, [N | BadNodes], Replies)
  545. end;
  546. rec_nodes(Tag, [N | Tail], Name, BadNodes, Replies, Time, TimerId) ->
  547. receive
  548. {nodedown, N} ->
  549. monitor_node(N, false),
  550. rec_nodes(Tag, Tail, Name, [N | BadNodes], Replies, 2000, TimerId);
  551. {{Tag, N}, Reply} ->
  552. receive {nodedown, N} -> ok after 0 -> ok end,
  553. monitor_node(N, false),
  554. rec_nodes(Tag, Tail, Name, BadNodes,
  555. [{N, Reply} | Replies], 2000, TimerId);
  556. {timeout, TimerId, _} ->
  557. receive {nodedown, N} -> ok after 0 -> ok end,
  558. monitor_node(N, false),
  559. rec_nodes_rest(Tag, Tail, Name, [N | BadNodes], Replies)
  560. after Time ->
  561. case rpc:call(N, erlang, whereis, [Name]) of
  562. Pid when is_pid(Pid) ->
  563. rec_nodes(Tag, [N | Tail], Name, BadNodes,
  564. Replies, infinity, TimerId);
  565. _ ->
  566. receive {nodedown, N} -> ok after 0 -> ok end,
  567. monitor_node(N, false),
  568. rec_nodes(Tag, Tail, Name, [N | BadNodes],
  569. Replies, 2000, TimerId)
  570. end
  571. end;
  572. rec_nodes(_, [], _, BadNodes, Replies, _, TimerId) ->
  573. case catch erlang:cancel_timer(TimerId) of
  574. false ->
  575. receive
  576. {timeout, TimerId, _} -> ok
  577. after 0 ->
  578. ok
  579. end;
  580. _ ->
  581. ok
  582. end,
  583. {Replies, BadNodes}.
  584. rec_nodes_rest(Tag, [{N, R} | Tail], Name, BadNodes, Replies) ->
  585. receive
  586. {'DOWN', R, _, _, _} ->
  587. rec_nodes_rest(Tag, Tail, Name, [N | BadNodes], Replies);
  588. {{Tag, N}, Reply} ->
  589. erlang:demonitor(R, [flush]),
  590. rec_nodes_rest(Tag, Tail, Name, BadNodes, [{N, Reply} | Replies])
  591. after 0 ->
  592. erlang:demonitor(R, [flush]),
  593. rec_nodes_rest(Tag, Tail, Name, [N | BadNodes], Replies)
  594. end;
  595. rec_nodes_rest(Tag, [N | Tail], Name, BadNodes, Replies) ->
  596. receive
  597. {nodedown, N} ->
  598. monitor_node(N, false),
  599. rec_nodes_rest(Tag, Tail, Name, [N | BadNodes], Replies);
  600. {{Tag, N}, Reply} ->
  601. receive {nodedown, N} -> ok after 0 -> ok end,
  602. monitor_node(N, false),
  603. rec_nodes_rest(Tag, Tail, Name, BadNodes, [{N, Reply} | Replies])
  604. after 0 ->
  605. receive {nodedown, N} -> ok after 0 -> ok end,
  606. monitor_node(N, false),
  607. rec_nodes_rest(Tag, Tail, Name, [N | BadNodes], Replies)
  608. end;
  609. rec_nodes_rest(_Tag, [], _Name, BadNodes, Replies) ->
  610. {Replies, BadNodes}.
  611. start_monitor(Node, Name) when is_atom(Node), is_atom(Name) ->
  612. if node() =:= nonode@nohost, Node =/= nonode@nohost ->
  613. Ref = make_ref(),
  614. self() ! {'DOWN', Ref, process, {Name, Node}, noconnection},
  615. {Node, Ref};
  616. true ->
  617. case catch erlang:monitor(process, {Name, Node}) of
  618. {'EXIT', _} ->
  619. monitor_node(Node, true),
  620. Node;
  621. Ref when is_reference(Ref) ->
  622. {Node, Ref}
  623. end
  624. end.
  625. -spec cast(ServerRef :: serverRef(), Msg :: term()) -> ok.
  626. cast({global, Name}, Msg) ->
  627. try global:send(Name, {'$gen_cast', Msg}) of
  628. _ -> ok
  629. catch
  630. _:_ -> ok
  631. end;
  632. cast({via, RegMod, Name}, Msg) ->
  633. try RegMod:send(Name, {'$gen_cast', Msg}) of
  634. _ -> ok
  635. catch
  636. _:_ -> ok
  637. end;
  638. cast({Name, Node} = Dest, Msg) when is_atom(Name), is_atom(Node) ->
  639. try erlang:send(Dest, {'$gen_cast', Msg})
  640. catch
  641. error:_ -> ok
  642. end;
  643. cast(Dest, Msg) ->
  644. try erlang:send(Dest, {'$gen_cast', Msg})
  645. catch
  646. error:_ -> ok
  647. end.
  648. %% 异步广播,不返回任何内容,只是发送“ n”祈祷
  649. abcast(Name, Msg) when is_atom(Name) ->
  650. doAbcast([node() | nodes()], Name, Msg).
  651. abcast(Nodes, Name, Msg) when is_list(Nodes), is_atom(Name) ->
  652. doAbcast(Nodes, Name, Msg).
  653. doAbcast([Node | Nodes], Name, Msg) when is_atom(Node) ->
  654. try erlang:send({Name, Node}, {'$gen_cast', Msg})
  655. catch
  656. error:_ -> ok
  657. end,
  658. doAbcast(Nodes, Name, Msg);
  659. doAbcast([], _, _) -> abcast.
  660. %% Reply from a status machine callback to whom awaits in call/2
  661. -spec reply([replyAction()] | replyAction()) -> ok.
  662. reply({reply, From, Reply}) ->
  663. reply(From, Reply);
  664. reply(Replies) when is_list(Replies) ->
  665. replies(Replies).
  666. replies([{reply, From, Reply} | Replies]) ->
  667. reply(From, Reply),
  668. replies(Replies);
  669. replies([]) ->
  670. ok.
  671. -compile({inline, [reply/2]}).
  672. -spec reply(From :: from(), Reply :: term()) -> ok.
  673. reply({To, Tag}, Reply) ->
  674. Msg = {Tag, Reply},
  675. try To ! Msg of
  676. _ ->
  677. ok
  678. catch
  679. _:_ -> ok
  680. end.
  681. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% API helpers end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  682. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gen_event start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  683. epmRequest({global, Name}, Msg) ->
  684. try global:send(Name, Msg) of
  685. _ -> ok
  686. catch
  687. _:_ -> ok
  688. end;
  689. epmRequest({via, RegMod, Name}, Msg) ->
  690. try RegMod:send(Name, Msg) of
  691. _ -> ok
  692. catch
  693. _:_ -> ok
  694. end;
  695. epmRequest(EpmSrv, Cmd) ->
  696. EpmSrv ! Cmd,
  697. ok.
  698. -spec epmInfo(serverRef(), epmHandler(), term()) -> term().
  699. epmInfo(EpmSrv, EpmHandler, Msg) ->
  700. epmRequest(EpmSrv, {'$epm_info', EpmHandler, Msg}).
  701. -spec infoNotify(serverRef(), term()) -> 'ok'.
  702. infoNotify(EpmSrv, Event) ->
  703. epmRequest(EpmSrv, {'$epm_info', '$infoNotify', Event}).
  704. epmRpc(EpmSrv, Cmd) ->
  705. try gen:call(EpmSrv, '$epm_call', Cmd, infinity) of
  706. {ok, Reply} ->
  707. Reply
  708. catch
  709. Class:Reason:Stacktrace ->
  710. erlang:raise(Class, {Reason, {?MODULE, call, [EpmSrv, Cmd, infinity]}}, Stacktrace)
  711. end.
  712. epmRpc(EpmSrv, Cmd, Timeout) ->
  713. try gen:call(EpmSrv, '$epm_call', Cmd, Timeout) of
  714. {ok, Reply} ->
  715. Reply
  716. catch
  717. Class:Reason:Stacktrace ->
  718. erlang:raise(Class, {Reason, {?MODULE, call, [EpmSrv, Cmd, Timeout]}}, Stacktrace)
  719. end.
  720. -spec callNotify(serverRef(), term()) -> 'ok'.
  721. callNotify(EpmSrv, Event) ->
  722. epmRpc(EpmSrv, {'$syncNotify', Event}).
  723. -spec epmCall(serverRef(), epmHandler(), term()) -> term().
  724. epmCall(EpmSrv, EpmHandler, Query) ->
  725. epmRpc(EpmSrv, {'$epmCall', EpmHandler, Query}).
  726. -spec epmCall(serverRef(), epmHandler(), term(), timeout()) -> term().
  727. epmCall(EpmSrv, EpmHandler, Query, Timeout) ->
  728. epmRpc(EpmSrv, {'$epmCall', EpmHandler, Query}, Timeout).
  729. -spec addEpm(serverRef(), epmHandler(), term()) -> term().
  730. addEpm(EpmSrv, EpmHandler, Args) ->
  731. epmRpc(EpmSrv, {'$addEpm', EpmHandler, Args}).
  732. -spec addSupEpm(serverRef(), epmHandler(), term()) -> term().
  733. addSupEpm(EpmSrv, EpmHandler, Args) ->
  734. epmRpc(EpmSrv, {'$addSupEpm', EpmHandler, Args}).
  735. -spec deleteEpm(serverRef(), epmHandler(), term()) -> term().
  736. deleteEpm(EpmSrv, EpmHandler, Args) ->
  737. epmRpc(EpmSrv, {'$deleteEpm', EpmHandler, Args}).
  738. -spec swapEpm(serverRef(), {epmHandler(), term()}, {epmHandler(), term()}) -> 'ok' | {'error', term()}.
  739. swapEpm(EpmSrv, {H1, A1}, {H2, A2}) ->
  740. epmRpc(EpmSrv, {'$swapEpm', H1, A1, H2, A2}).
  741. -spec swapSupEpm(serverRef(), {epmHandler(), term()}, {epmHandler(), term()}) -> 'ok' | {'error', term()}.
  742. swapSupEpm(EpmSrv, {H1, A1}, {H2, A2}) ->
  743. epmRpc(EpmSrv, {'$swapSupEpm', H1, A1, H2, A2, self()}).
  744. -spec whichEpm(serverRef()) -> [epmHandler()].
  745. whichEpm(EpmSrv) ->
  746. epmRpc(EpmSrv, '$which_handlers').
  747. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  748. %% EPM inner fun
  749. addNewEpm(InitRet, Module, EpmId, EpmSup) ->
  750. case InitRet of
  751. {ok, State} ->
  752. EpmHer = #epmHer{epmM = Module, epmId = EpmId, epmS = State},
  753. OldList = getEpmList(),
  754. setEpmHer(EpmHer),
  755. setEpmList([{EpmId, Module, EpmSup} | OldList]),
  756. {ok, false};
  757. {ok, State, hibernate} ->
  758. EpmHer = #epmHer{epmM = Module, epmId = EpmId, epmS = State},
  759. OldList = getEpmList(),
  760. setEpmHer(EpmHer),
  761. setEpmList([{EpmId, Module, EpmSup} | OldList]),
  762. {ok, true};
  763. Other ->
  764. {Other, false}
  765. end.
  766. doAddEpm({Module, EpmId}, Args, EpmSup) ->
  767. case getEpmHer(EpmId) of
  768. undefined ->
  769. try Module:init(Args) of
  770. Result ->
  771. addNewEpm(Result, Module, EpmId, EpmSup)
  772. catch
  773. throw:Ret ->
  774. addNewEpm(Ret, Module, EpmId, EpmSup);
  775. C:R:T ->
  776. {{C, R, T}, false}
  777. end;
  778. _ ->
  779. {existed, false}
  780. end;
  781. doAddEpm(Module, Args, EpmSup) ->
  782. case getEpmHer(Module) of
  783. undefined ->
  784. try Module:init(Args) of
  785. Result ->
  786. addNewEpm(Result, Module, Module, EpmSup)
  787. catch
  788. throw:Ret ->
  789. addNewEpm(Ret, Module, Module, EpmSup);
  790. C:R:T ->
  791. {{C, R, T}, false}
  792. end;
  793. _ ->
  794. {existed, false}
  795. end.
  796. doAddSupEpm(Module, Args, EpmSup) ->
  797. case doAddEpm(Module, Args, EpmSup) of
  798. {ok, _} = Result ->
  799. link(EpmSup),
  800. Result;
  801. Ret ->
  802. Ret
  803. end.
  804. doSwapEpm(EpmId1, Args1, EpmMId, Args2) ->
  805. case getEpmHer(EpmId1) of
  806. undefined ->
  807. doAddEpm(EpmMId, {Args2, undefined}, false);
  808. #epmHer{epmSup = EpmSup} = EpmHer ->
  809. State2 = epmTerminate(EpmHer, Args1, swapped, {swapped, EpmMId, EpmSup}),
  810. case EpmSup of
  811. false ->
  812. doAddEpm(EpmMId, {Args2, State2}, false);
  813. _ ->
  814. doAddSupEpm(EpmMId, {Args2, State2}, EpmSup)
  815. end
  816. end.
  817. doSwapSupEpm(EpmId1, Args1, EpmMId, Args2, EpmSup) ->
  818. case getEpmHer(EpmId1) of
  819. undefined ->
  820. doAddSupEpm(EpmMId, {Args2, undefined}, EpmSup);
  821. EpmHer ->
  822. State2 = epmTerminate(EpmHer, Args1, swapped, {swapped, EpmMId, EpmSup}),
  823. doAddSupEpm(EpmMId, {Args2, State2}, EpmSup)
  824. end.
  825. doNotify([{EpmId, _EmpM} | T], Event, Func, IsHib) ->
  826. case doEpmHandle(getEpmHer(EpmId), Func, Event, false) of
  827. ok ->
  828. doNotify(T, Event, Func, IsHib);
  829. hibernate ->
  830. doNotify(T, Event, Func, true);
  831. _Other ->
  832. doNotify(T, Event, Func, IsHib)
  833. end;
  834. doNotify([], _Event, _Func, IsHib) ->
  835. IsHib.
  836. doEpmHandle(#epmHer{epmM = EpmM, epmS = EpmS} = EpmHer, Func, Event, From) ->
  837. try EpmM:Func(Event, EpmS) of
  838. Result ->
  839. handleEpmCallbackRet(Result, EpmHer, Event, From)
  840. catch
  841. throw:Ret ->
  842. handleEpmCallbackRet(Ret, EpmHer, Event, From);
  843. C:R:S ->
  844. epmTerminate(EpmHer, {error, {C, R, S}}, Event, crash)
  845. end;
  846. doEpmHandle(undefined, _Func, _Event, _From) ->
  847. no_epm.
  848. doDeleteEpm(EpmId, Args) ->
  849. case getEpmHer(EpmId) of
  850. undefined ->
  851. {error, module_not_found};
  852. EpmHer ->
  853. epmTerminate(EpmHer, Args, delete, normal)
  854. end.
  855. proTerminate(#epmHer{epmM = EpmM, epmS = State} = EpmHer, Args, LastIn, Reason) ->
  856. case erlang:function_exported(EpmM, terminate, 2) of
  857. true ->
  858. Res = (catch EpmM:terminate(Args, State)),
  859. reportTerminate(EpmHer, Reason, Args, LastIn, Res),
  860. Res;
  861. false ->
  862. reportTerminate(EpmHer, Reason, Args, LastIn, ok),
  863. ok
  864. end.
  865. epmTerminate(#epmHer{epmM = EpmM, epmId = EpmId, epmS = State} = EpmHer, Args, LastIn, Reason) ->
  866. %% 删除列表的数据
  867. OldList = getEpmList(),
  868. NewList = lists:keydelete(EpmId, 1, OldList),
  869. setEpmList(NewList),
  870. %% 删除进程字典中的数据
  871. delEpmHer(EpmId),
  872. case erlang:function_exported(EpmM, terminate, 2) of
  873. true ->
  874. Res = (catch EpmM:terminate(Args, State)),
  875. reportTerminate(EpmHer, Reason, Args, LastIn, Res),
  876. Res;
  877. false ->
  878. reportTerminate(EpmHer, Reason, Args, LastIn, ok),
  879. ok
  880. end.
  881. reportTerminate(EpmHer, crash, {error, Why}, LastIn, _) ->
  882. reportTerminate2(EpmHer, Why, LastIn);
  883. %% How == normal | shutdown | {swapped, NewHandler, NewSupervisor}
  884. reportTerminate(EpmHer, How, _, LastIn, _) ->
  885. reportTerminate2(EpmHer, How, LastIn).
  886. reportTerminate2(#epmHer{epmSup = EpmSup, epmId = EpmId, epmS = State} = EpmHer, Reason, LastIn) ->
  887. report_error(EpmHer, Reason, State, LastIn),
  888. case EpmSup of
  889. false ->
  890. ok;
  891. _ ->
  892. EpmSup ! {gen_event_EXIT, EpmId, Reason},
  893. ok
  894. end.
  895. report_error(_EpmHer, normal, _, _) -> ok;
  896. report_error(_EpmHer, shutdown, _, _) -> ok;
  897. report_error(_EpmHer, {swapped, _, _}, _, _) -> ok;
  898. report_error(#epmHer{epmM = EpmM, epmId = EpmId}, Reason, State, LastIn) ->
  899. ?LOG_ERROR(
  900. #{
  901. label=>{gen_ipc, epm_terminate},
  902. handler => {EpmId, EpmM},
  903. name => getProName(),
  904. last_message => LastIn,
  905. state=> format_status(terminate, [EpmM, get(), State]),
  906. reason => Reason
  907. },
  908. #{
  909. domain => [otp],
  910. report_cb => fun gen_ipc:epm_log/1,
  911. error_logger => #{tag => error}
  912. }).
  913. epm_log(#{label := {gen_ipc, epm_terminate}, handler := Handler, name := SName, last_message := LastIn, state := State, reason := Reason}) ->
  914. Reason1 =
  915. case Reason of
  916. {'EXIT', {undef, [{M, F, A, L} | MFAs]}} ->
  917. case code:is_loaded(M) of
  918. false ->
  919. {'module could not be loaded', [{M, F, A, L} | MFAs]};
  920. _ ->
  921. case erlang:function_exported(M, F, length(A)) of
  922. true ->
  923. {undef, [{M, F, A, L} | MFAs]};
  924. false ->
  925. {'function not exported', [{M, F, A, L} | MFAs]}
  926. end
  927. end;
  928. {'EXIT', Why} ->
  929. Why;
  930. _ ->
  931. Reason
  932. end,
  933. {"** gen_ipc emp handler ~p crashed.~n"
  934. "** Was installed in ~tp~n"
  935. "** Last event was: ~tp~n"
  936. "** When handler state == ~tp~n"
  937. "** Reason == ~tp~n", [Handler, SName, LastIn, State, Reason1]};
  938. epm_log(#{label := {gen_ipc, no_handle_info}, module := Mod, message := Msg}) ->
  939. {"** Undefined handle_info in ~tp~n"
  940. "** Unhandled message: ~tp~n", [Mod, Msg]}.
  941. epmStopAll() ->
  942. EpmList = getEpmList(),
  943. [
  944. begin
  945. proTerminate(getEpmHer(EpmId), stop, 'receive', shutdown),
  946. case EpmSup =/= false of
  947. true ->
  948. unlink(EpmSup);
  949. _ ->
  950. ignore
  951. end
  952. end || {EpmId, _EpmM, EpmSup} <- EpmList
  953. ].
  954. epmStopOne(ExitEmpSup) ->
  955. EpmList = getEpmList(),
  956. [epmTerminate(getEpmHer(EpmId), stop, 'receive', shutdown) || {EpmId, _EpmM, EpmSup} <- EpmList, ExitEmpSup =:= EpmSup].
  957. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gen_event end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  958. %% 仅在#params.parent不同时更新。今天,这应该是不可能的(OTP-22.0),但是,例如,如果有人在新的sys调用中实现了更改服务器父服务器,则可能发生这种情况。
  959. -compile({inline, updateParent/1}).
  960. updateParent(Parent) ->
  961. setProName(Parent).
  962. %%%==========================================================================
  963. %%% Internal callbacks
  964. wakeup_from_hibernate(CycleData, CurStatus, CurState, Debug, IsHibernate) ->
  965. %% 这是一条新消息,唤醒了我们,因此我们必须立即收到它
  966. receiveMsgWait(CycleData, CurStatus, CurState, Debug, IsHibernate).
  967. %%%==========================================================================
  968. %% Entry point for system_continue/3
  969. reLoopEntry(CycleData, CurStatus, CurState, Debug, IsHibernate) ->
  970. if
  971. IsHibernate ->
  972. proc_lib:hibernate(?MODULE, wakeup_from_hibernate, [CycleData, CurStatus, CurState, Debug, IsHibernate]);
  973. true ->
  974. receiveMsgWait(CycleData, CurStatus, CurState, Debug, IsHibernate)
  975. end.
  976. %% 接收新的消息
  977. receiveMsgWait(#cycleData{hibernateAfter = HibernateAfterTimeout} = CycleData, CurStatus, CurState, Debug, IsHibernate) ->
  978. receive
  979. Msg ->
  980. case Msg of
  981. {'$gen_call', From, Request} ->
  982. matchCallMsg(CycleData, CurStatus, CurState, Debug, {{call, From}, Request});
  983. {'$gen_cast', Cast} ->
  984. matchCastMsg(CycleData, CurStatus, CurState, Debug, {cast, Cast});
  985. {timeout, TimerRef, TimeoutType} ->
  986. case element(#cycleData.timers, CycleData) of
  987. #{TimeoutType := {TimerRef, TimeoutMsg}} = Timers ->
  988. NewTimer = maps:remove(TimeoutType, Timers),
  989. NewCycleData = setelement(#cycleData.timers, CycleData, NewTimer),
  990. matchTimeoutMsg(NewCycleData, CurStatus, CurState, Debug, {TimeoutType, TimeoutMsg});
  991. #{} ->
  992. matchInfoMsg(CycleData, CurStatus, CurState, Debug, {info, Msg})
  993. end;
  994. {system, PidFrom, Request} ->
  995. %% 不返回但尾递归调用 system_continue/3
  996. sys:handle_system_msg(Request, PidFrom, getParent(), ?MODULE, Debug, {CycleData, CurStatus, CurState, IsHibernate});
  997. {'EXIT', PidFrom, Reason} ->
  998. case getParent() of
  999. PidFrom ->
  1000. terminate(exit, Reason, ?STACKTRACE(), CycleData, CurStatus, CurState, Debug, []);
  1001. _ ->
  1002. epmStopOne(PidFrom),
  1003. matchInfoMsg(CycleData, CurStatus, CurState, Debug, {info, Msg})
  1004. end;
  1005. {'$epm_call', From, Request} ->
  1006. matchEpmCallMsg(CycleData, CurStatus, CurState, Debug, From, Request);
  1007. {'$epm_info', CmdOrEmpHandler, Event} ->
  1008. matchEpmInfoMsg(CycleData, CurStatus, CurState, Debug, CmdOrEmpHandler, Event);
  1009. _ ->
  1010. matchInfoMsg(CycleData, CurStatus, CurState, Debug, {info, Msg})
  1011. end
  1012. after
  1013. HibernateAfterTimeout ->
  1014. proc_lib:hibernate(?MODULE, wakeup_from_hibernate, [CycleData, CurStatus, CurState, Debug, IsHibernate])
  1015. end.
  1016. matchCallMsg(#cycleData{module = Module} = CycleData, CurStatus, CurState, Debug, {{call, From}, Request} = Event) ->
  1017. NewDebug = ?SYS_DEBUG(Debug, {in, Event, CurStatus}),
  1018. try Module:handleCall(Request, From, CurStatus, CurState) of
  1019. Result ->
  1020. handleEventCallbackRet(CycleData, CurStatus, CurState, NewDebug, [Event], Result, ?CB_FORM_EVENT, From)
  1021. catch
  1022. throw:Result ->
  1023. handleEventCallbackRet(CycleData, CurStatus, CurState, NewDebug, [Event], Result, ?CB_FORM_EVENT, From);
  1024. Class:Reason:Stacktrace ->
  1025. terminate(Class, Reason, Stacktrace, CycleData, CurStatus, CurState, NewDebug, [Event])
  1026. end.
  1027. matchCastMsg(#cycleData{module = Module} = CycleData, CurStatus, CurState, Debug, {cast, Cast} = Event) ->
  1028. NewDebug = ?SYS_DEBUG(Debug, {in, Event, CurStatus}),
  1029. try Module:handleCast(Cast, CurStatus, CurState) of
  1030. Result ->
  1031. handleEventCallbackRet(CycleData, CurStatus, CurState, NewDebug, [Event], Result, ?CB_FORM_EVENT, false)
  1032. catch
  1033. throw:Result ->
  1034. handleEventCallbackRet(CycleData, CurStatus, CurState, NewDebug, [Event], Result, ?CB_FORM_EVENT, false);
  1035. Class:Reason:Stacktrace ->
  1036. terminate(Class, Reason, Stacktrace, CycleData, CurStatus, CurState, NewDebug, [Event])
  1037. end.
  1038. matchInfoMsg(#cycleData{module = Module} = CycleData, CurStatus, CurState, Debug, {info, Msg} = Event) ->
  1039. NewDebug = ?SYS_DEBUG(Debug, {in, Event, CurStatus}),
  1040. try Module:handleInfo(Msg, CurStatus, CurState) of
  1041. Result ->
  1042. handleEventCallbackRet(CycleData, CurStatus, CurState, NewDebug, [Event], Result, ?CB_FORM_EVENT, false)
  1043. catch
  1044. throw:Result ->
  1045. handleEventCallbackRet(CycleData, CurStatus, CurState, NewDebug, [Event], Result, ?CB_FORM_EVENT, false);
  1046. Class:Reason:Stacktrace ->
  1047. terminate(Class, Reason, Stacktrace, CycleData, CurStatus, CurState, NewDebug, [Event])
  1048. end.
  1049. matchTimeoutMsg(#cycleData{module = Module} = CycleData, CurStatus, CurState, Debug, {TimeoutType, TimeoutMsg} = Event) ->
  1050. NewDebug = ?SYS_DEBUG(Debug, {in, Event, CurStatus}),
  1051. try Module:handleOnevent(TimeoutType, TimeoutMsg, CurStatus, CurState) of
  1052. Result ->
  1053. handleEventCallbackRet(CycleData, CurStatus, CurState, NewDebug, [Event], Result, ?CB_FORM_EVENT, false)
  1054. catch
  1055. throw:Result ->
  1056. handleEventCallbackRet(CycleData, CurStatus, CurState, NewDebug, [Event], Result, ?CB_FORM_EVENT, false);
  1057. Class:Reason:Stacktrace ->
  1058. terminate(Class, Reason, Stacktrace, CycleData, CurStatus, CurState, NewDebug, [Event])
  1059. end.
  1060. matchEpmCallMsg(CycleData, CurStatus, CurState, Debug, From, Request) ->
  1061. NewDebug = ?SYS_DEBUG(Debug, {in, Request, CurStatus}),
  1062. case Request of
  1063. '$which_handlers' ->
  1064. reply(From, getEpmList());
  1065. {'$addEpm', EpmHandler, Args} ->
  1066. {Reply, IsHib} = doAddEpm(EpmHandler, Args, false),
  1067. reply(From, Reply),
  1068. reLoopEntry(CycleData, CurStatus, CurState, NewDebug, IsHib);
  1069. {'$addSupEpm', EpmHandler, Args, EpmSup} ->
  1070. {Reply, IsHib} = doAddSupEpm(EpmHandler, Args, EpmSup),
  1071. reply(From, Reply),
  1072. reLoopEntry(CycleData, CurStatus, CurState, NewDebug, IsHib);
  1073. {'$deleteEpm', EpmHandler, Args} ->
  1074. Reply = doDeleteEpm(EpmHandler, Args),
  1075. reply(From, Reply),
  1076. receiveMsgWait(CycleData, CurStatus, CurState, NewDebug, false);
  1077. {'$swapEpm', EpmId1, Args1, EpmId2, Args2} ->
  1078. {Reply, IsHib} = doSwapEpm(EpmId1, Args1, EpmId2, Args2),
  1079. reply(From, Reply),
  1080. reLoopEntry(CycleData, CurStatus, CurState, NewDebug, IsHib);
  1081. {'$swapSupEpm', EpmId1, Args1, EpmId2, Args2, SupPid} ->
  1082. {Reply, IsHib} = doSwapSupEpm(EpmId1, Args1, EpmId2, Args2, SupPid),
  1083. reply(From, Reply),
  1084. reLoopEntry(CycleData, CurStatus, CurState, NewDebug, IsHib);
  1085. {'$syncNotify', Event} ->
  1086. IsHib = doNotify(getEpmList(), Event, handleEvent, false),
  1087. reply(From, ok),
  1088. startEpmCall(CycleData, CurStatus, CurState, NewDebug, handleEpmEvent, Request, IsHib);
  1089. {'$epmCall', EpmHandler, Query} ->
  1090. IsHib = doEpmHandle(getEpmHer(EpmHandler), handleCall, Query, From),
  1091. startEpmCall(CycleData, CurStatus, CurState, Debug, handleEpmCall, Request, IsHib)
  1092. end.
  1093. matchEpmInfoMsg(CycleData, CurStatus, CurState, Debug, CmdOrEmpHandler, Event) ->
  1094. case CmdOrEmpHandler of
  1095. '$infoNotify' ->
  1096. IsHib = doNotify(getEpmList(), Event, handleEvent, false),
  1097. startEpmCall(CycleData, CurStatus, CurState, Debug, handleEpmEvent, Event, IsHib);
  1098. EpmHandler ->
  1099. IsHib = doEpmHandle(getEpmHer(EpmHandler), Event, handleInfo, false),
  1100. startEpmCall(CycleData, CurStatus, CurState, Debug, handleEpmInfo, Event, IsHib)
  1101. end.
  1102. startEpmCall(#cycleData{module = Module} = CycleData, CurStatus, CurState, Debug, CallbackFun, Event, IsHib) ->
  1103. case erlang:function_exported(Module, CallbackFun, 3) of
  1104. true ->
  1105. NewDebug = ?SYS_DEBUG(Debug, {in, Event, CurStatus}),
  1106. try Module:CallbackFun(Event, CurStatus, CurState) of
  1107. Result ->
  1108. handleEventCallbackRet(CycleData, CurStatus, CurState, NewDebug, [Event], Result, ?CB_FORM_EVENT, false)
  1109. catch
  1110. throw:Ret ->
  1111. handleEventCallbackRet(CycleData, CurStatus, CurState, NewDebug, [Event], Ret, ?CB_FORM_EVENT, false);
  1112. Class:Reason:Stacktrace ->
  1113. terminate(Class, Reason, Stacktrace, CycleData, CurStatus, CurState, NewDebug, [Event])
  1114. end;
  1115. _ ->
  1116. receiveMsgWait(CycleData, CurStatus, CurState, Debug, IsHib)
  1117. end.
  1118. startEnterCall(#cycleData{module = Module} = CycleData, PrevStatus, CurState, CurStatus, Debug, LeftEvents, Timeouts, NextEvents, IsPostpone, IsHibernate, DoAfter) ->
  1119. try Module:handleEnter(PrevStatus, CurStatus, CurState) of
  1120. Result ->
  1121. handleEnterCallbackRet(CycleData, PrevStatus, CurState, CurStatus, Debug, LeftEvents, Timeouts, NextEvents, IsPostpone, IsHibernate, DoAfter, Result)
  1122. catch
  1123. throw:Result ->
  1124. handleEnterCallbackRet(CycleData, PrevStatus, CurState, CurStatus, Debug, LeftEvents, Timeouts, NextEvents, IsPostpone, IsHibernate, DoAfter, Result);
  1125. Class:Reason:Stacktrace ->
  1126. terminate(Class, Reason, Stacktrace, CycleData, Debug, CurStatus, CurState, LeftEvents)
  1127. end.
  1128. startAfterCall(#cycleData{module = Module} = CycleData, CurStatus, CurState, Debug, LeftEvents, Args) ->
  1129. try Module:handleAfter(Args, CurStatus, CurState) of
  1130. Result ->
  1131. handleEventCallbackRet(CycleData, CurStatus, CurState, Debug, LeftEvents, Result, ?CB_FORM_AFTER, false)
  1132. catch
  1133. throw:Result ->
  1134. handleEventCallbackRet(CycleData, CurStatus, CurState, Debug, LeftEvents, Result, ?CB_FORM_AFTER, false);
  1135. Class:Reason:Stacktrace ->
  1136. terminate(Class, Reason, Stacktrace, CycleData, CurStatus, CurState, Debug, LeftEvents)
  1137. end.
  1138. startEventCall(#cycleData{module = Module} = CycleData, CurStatus, CurState, Debug, LeftEvents, {Type, Content}) ->
  1139. case Type of
  1140. 'cast' ->
  1141. try Module:handleCast(Content, CurStatus, CurState) of
  1142. Result ->
  1143. handleEventCallbackRet(CycleData, CurStatus, CurState, Debug, LeftEvents, Result, ?CB_FORM_EVENT, false)
  1144. catch
  1145. throw:Ret ->
  1146. handleEventCallbackRet(CycleData, CurStatus, CurState, Debug, LeftEvents, Ret, ?CB_FORM_EVENT, false);
  1147. Class:Reason:Stacktrace ->
  1148. terminate(Class, Reason, Stacktrace, CycleData, CurStatus, CurState, Debug, LeftEvents)
  1149. end;
  1150. 'info' ->
  1151. try Module:handleInfo(Content, CurStatus, CurState) of
  1152. Result ->
  1153. handleEventCallbackRet(CycleData, CurStatus, CurState, Debug, LeftEvents, Result, ?CB_FORM_EVENT, false)
  1154. catch
  1155. throw:Ret ->
  1156. handleEventCallbackRet(CycleData, CurStatus, CurState, Debug, LeftEvents, Ret, ?CB_FORM_EVENT, false);
  1157. Class:Reason:Stacktrace ->
  1158. terminate(Class, Reason, Stacktrace, CycleData, CurStatus, CurState, Debug, LeftEvents)
  1159. end;
  1160. {'call', From} ->
  1161. try Module:handleCall(Content, CurStatus, CurState) of
  1162. Result ->
  1163. handleEventCallbackRet(CycleData, CurStatus, CurState, Debug, LeftEvents, Result, ?CB_FORM_EVENT, From)
  1164. catch
  1165. throw:Ret ->
  1166. handleEventCallbackRet(CycleData, CurStatus, CurState, Debug, LeftEvents, Ret, ?CB_FORM_EVENT, From);
  1167. Class:Reason:Stacktrace ->
  1168. terminate(Class, Reason, Stacktrace, CycleData, CurStatus, CurState, Debug, LeftEvents)
  1169. end;
  1170. _ ->
  1171. try Module:handleOnevent(Content, CurStatus, CurState) of
  1172. Result ->
  1173. handleEventCallbackRet(CycleData, CurStatus, CurState, Debug, LeftEvents, Result, ?CB_FORM_EVENT, false)
  1174. catch
  1175. throw:Ret ->
  1176. handleEventCallbackRet(CycleData, CurStatus, CurState, Debug, LeftEvents, Ret, ?CB_FORM_EVENT, false);
  1177. Class:Reason:Stacktrace ->
  1178. terminate(Class, Reason, Stacktrace, CycleData, CurStatus, CurState, Debug, LeftEvents)
  1179. end
  1180. end.
  1181. handleEpmCallbackRet(Result, EpmHer, Event, From) ->
  1182. case Result of
  1183. ok ->
  1184. ok;
  1185. {ok, NewEpmS} ->
  1186. MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  1187. setEpmHer(MewEpmHer),
  1188. ok;
  1189. {ok, NewEpmS, hibernate} ->
  1190. MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  1191. setEpmHer(MewEpmHer),
  1192. hibernate;
  1193. {swapEpm, NewEpmS, Args1, EpmMId, Args2} ->
  1194. #epmHer{epmId = OldEpmMId, epmSup = EpmSup} = MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  1195. State = epmTerminate(MewEpmHer, Args1, swapped, {swapped, OldEpmMId, EpmSup}),
  1196. case EpmSup of
  1197. false ->
  1198. doAddEpm(EpmMId, {Args2, State}, false);
  1199. _ ->
  1200. doAddSupEpm(EpmMId, {Args2, State}, EpmSup)
  1201. end,
  1202. ok;
  1203. {swapEpm, Reply, NewEpmS, Args1, EpmMId, Args2} ->
  1204. reply(From, Reply),
  1205. #epmHer{epmId = OldEpmMId, epmSup = EpmSup} = MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  1206. State = epmTerminate(MewEpmHer, Args1, swapped, {swapped, OldEpmMId, EpmSup}),
  1207. case EpmSup of
  1208. false ->
  1209. doAddEpm(EpmMId, {Args2, State}, false);
  1210. _ ->
  1211. doAddSupEpm(EpmMId, {Args2, State}, EpmSup)
  1212. end,
  1213. ok;
  1214. removeEpm ->
  1215. epmTerminate(EpmHer, removeEpm, remove, normal),
  1216. ok;
  1217. {removeEpm, Reply} ->
  1218. reply(From, Reply),
  1219. epmTerminate(EpmHer, removeEpm, remove, normal),
  1220. ok;
  1221. {reply, Reply} ->
  1222. reply(From, Reply),
  1223. ok;
  1224. {reply, Reply, NewEpmS} ->
  1225. reply(From, Reply),
  1226. MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  1227. setEpmHer(MewEpmHer),
  1228. ok;
  1229. {reply, Reply, NewEpmS, hibernate} ->
  1230. reply(From, Reply),
  1231. MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
  1232. setEpmHer(MewEpmHer),
  1233. hibernate;
  1234. Other ->
  1235. epmTerminate(EpmHer, {error, Other}, Event, crash),
  1236. ok
  1237. end.
  1238. handleEnterCallbackRet(CycleData, PrevStatus, CurState, CurStatus, Debug, LeftEvents, Timeouts, NextEvents, IsPostpone, IsHibernate, DoAfter, Result) ->
  1239. case Result of
  1240. {keepStatus, NewState} ->
  1241. dealEnterCallbackRet(CycleData, PrevStatus, NewState, CurStatus, Debug, LeftEvents, Timeouts, NextEvents, IsPostpone, IsHibernate, DoAfter, false);
  1242. {keepStatus, NewState, Actions} ->
  1243. parseEnterActionsList(CycleData, PrevStatus, NewState, CurStatus, Debug, LeftEvents, Timeouts, NextEvents, IsPostpone, IsHibernate, DoAfter, false, Actions);
  1244. keepStatusData ->
  1245. dealEnterCallbackRet(CycleData, PrevStatus, CurState, CurStatus, Debug, LeftEvents, Timeouts, NextEvents, IsPostpone, IsHibernate, DoAfter, false);
  1246. {keepStatusData, Actions} ->
  1247. parseEnterActionsList(CycleData, PrevStatus, CurState, CurStatus, Debug, LeftEvents, Timeouts, NextEvents, IsPostpone, IsHibernate, DoAfter, false, Actions);
  1248. {repeatStatus, NewState} ->
  1249. dealEnterCallbackRet(CycleData, PrevStatus, NewState, CurStatus, Debug, LeftEvents, Timeouts, NextEvents, IsPostpone, IsHibernate, DoAfter, true);
  1250. {repeatStatus, NewState, Actions} ->
  1251. parseEnterActionsList(CycleData, PrevStatus, NewState, CurStatus, Debug, LeftEvents, Timeouts, NextEvents, IsPostpone, IsHibernate, DoAfter, true, Actions);
  1252. repeatStatusData ->
  1253. dealEnterCallbackRet(CycleData, PrevStatus, CurState, CurStatus, Debug, LeftEvents, Timeouts, NextEvents, IsPostpone, IsHibernate, DoAfter, true);
  1254. {repeatStatusData, Actions} ->
  1255. parseEnterActionsList(CycleData, PrevStatus, CurState, CurStatus, Debug, LeftEvents, Timeouts, NextEvents, IsPostpone, IsHibernate, DoAfter, true, Actions);
  1256. stop ->
  1257. terminate(exit, normal, ?STACKTRACE(), CycleData, CurStatus, CurState, Debug, LeftEvents);
  1258. {stop, Reason} ->
  1259. terminate(exit, Reason, ?STACKTRACE(), CycleData, CurStatus, CurState, Debug, LeftEvents);
  1260. {stop, Reason, NewState} ->
  1261. terminate(exit, Reason, ?STACKTRACE(), CycleData, CurStatus, NewState, Debug, LeftEvents);
  1262. {stopReply, Reason, Replies} ->
  1263. replyThenTerminate(exit, Reason, ?STACKTRACE(), CycleData, CurStatus, CurState, Debug, LeftEvents, Replies);
  1264. {stopReply, Reason, Replies, NewState} ->
  1265. replyThenTerminate(exit, Reason, ?STACKTRACE(), CycleData, CurStatus, NewState, Debug, LeftEvents, Replies);
  1266. _ ->
  1267. terminate(error, {badReturnFrom_EnterFunction, Result}, ?STACKTRACE(), CycleData, CurStatus, CurState, Debug, LeftEvents)
  1268. end.
  1269. handleEventCallbackRet(CycleData, CurStatus, CurState, Debug, LeftEvents, Result, CallbackForm, From) ->
  1270. case Result of
  1271. {noreply, NewState} ->
  1272. receiveMsgWait(CycleData, CurStatus, NewState, Debug, false);
  1273. {noreply, NewState, Option} ->
  1274. case Option of
  1275. hibernate ->
  1276. reLoopEntry(CycleData, CurStatus, NewState, Debug, true);
  1277. {doAfter, Args} ->
  1278. startAfterCall(CycleData, CurStatus, NewState, Debug, [], Args);
  1279. _Ret ->
  1280. terminate(error, {bad_reply_option, _Ret}, ?STACKTRACE(), CycleData, CurStatus, NewState, Debug, [])
  1281. end;
  1282. {nextStatus, NewStatus, NewState} ->
  1283. dealEventCallbackRet(CycleData, CurStatus, NewState, NewStatus, Debug, LeftEvents, NewStatus =/= CurStatus);
  1284. {nextStatus, NewStatus, NewState, Actions} ->
  1285. parseEventActionsList(CycleData, CurStatus, NewState, NewStatus, Debug, LeftEvents, NewStatus =/= CurStatus, Actions, CallbackForm);
  1286. {keepStatus, NewState} ->
  1287. dealEventCallbackRet(CycleData, CurStatus, NewState, CurStatus, Debug, LeftEvents, false);
  1288. {keepStatus, NewState, Actions} ->
  1289. parseEventActionsList(CycleData, CurStatus, NewState, CurStatus, Debug, LeftEvents, false, Actions, CallbackForm);
  1290. keepStatusData ->
  1291. dealEventCallbackRet(CycleData, CurStatus, CurState, CurStatus, Debug, LeftEvents, false);
  1292. {keepStatusData, Actions} ->
  1293. parseEventActionsList(CycleData, CurStatus, CurState, CurStatus, Debug, LeftEvents, false, Actions, CallbackForm);
  1294. {repeatStatus, NewState} ->
  1295. dealEventCallbackRet(CycleData, CurStatus, NewState, CurStatus, Debug, LeftEvents, true);
  1296. {repeatStatus, NewState, Actions} ->
  1297. parseEventActionsList(CycleData, CurStatus, NewState, CurStatus, Debug, LeftEvents, true, Actions, CallbackForm);
  1298. repeatStatusData ->
  1299. dealEventCallbackRet(CycleData, CurStatus, CurState, CurStatus, Debug, LeftEvents, true);
  1300. {repeatStatusData, Actions} ->
  1301. parseEventActionsList(CycleData, CurStatus, CurState, CurStatus, Debug, LeftEvents, true, Actions, CallbackForm);
  1302. stop ->
  1303. terminate(exit, normal, ?STACKTRACE(), CycleData, CurStatus, CurState, Debug, LeftEvents);
  1304. {stop, Reason} ->
  1305. terminate(exit, Reason, ?STACKTRACE(), CycleData, CurStatus, CurState, Debug, LeftEvents);
  1306. {stop, Reason, NewState} ->
  1307. terminate(exit, Reason, ?STACKTRACE(), CycleData, CurStatus, NewState, Debug, LeftEvents);
  1308. {stopReply, Reason, Replies} ->
  1309. replyThenTerminate(exit, Reason, ?STACKTRACE(), CycleData, CurStatus, CurState, Debug, LeftEvents, Replies);
  1310. {stopReply, Reason, Replies, NewState} ->
  1311. replyThenTerminate(exit, Reason, ?STACKTRACE(), CycleData, CurStatus, NewState, Debug, LeftEvents, Replies);
  1312. {reply, Reply, NewState} when CallbackForm == ?CB_FORM_EVENT ->
  1313. reply(From, Reply),
  1314. NewDebug = ?SYS_DEBUG(Debug, {out, Reply, From}),
  1315. receiveMsgWait(CycleData, CurStatus, NewState, NewDebug, false);
  1316. {reply, Reply, NewState, Option} when CallbackForm == ?CB_FORM_EVENT ->
  1317. reply(From, Reply),
  1318. NewDebug = ?SYS_DEBUG(Debug, {out, Reply, From}),
  1319. case Option of
  1320. hibernate ->
  1321. reLoopEntry(CycleData, CurStatus, NewState, NewDebug, true);
  1322. {doAfter, Args} ->
  1323. startAfterCall(CycleData, CurStatus, NewState, NewDebug, [], Args);
  1324. _Ret ->
  1325. terminate(error, {bad_reply_option, _Ret}, ?STACKTRACE(), CycleData, CurStatus, NewState, Debug, [])
  1326. end;
  1327. _ ->
  1328. terminate(error, {bad_return_from_status_function, Result}, ?STACKTRACE(), CycleData, CurStatus, CurState, Debug, LeftEvents)
  1329. end.
  1330. -compile({inline, [dealEnterCallbackRet/12]}).
  1331. dealEnterCallbackRet(#cycleData{isEnter = IsEnter} = CycleData, CurStatus, CurState, NewStatus, Debug, LeftEvents, Timeouts, NextEvents, IsPostpone, IsHibernate, DoAfter, IsCallEnter) ->
  1332. case IsEnter andalso IsCallEnter of
  1333. true ->
  1334. startEnterCall(CycleData, CurStatus, CurState, NewStatus, Debug, LeftEvents, Timeouts, NextEvents, IsPostpone, IsHibernate, DoAfter);
  1335. false ->
  1336. performTransitions(CycleData, CurStatus, CurState, NewStatus, Debug, LeftEvents, Timeouts, NextEvents, IsPostpone, IsHibernate, DoAfter)
  1337. end.
  1338. -compile({inline, [dealEventCallbackRet/7]}).
  1339. dealEventCallbackRet(#cycleData{isEnter = IsEnter} = CycleData, CurStatus, CurState, NewStatus, Debug, LeftEvents, IsCallEnter) ->
  1340. case IsEnter andalso IsCallEnter of
  1341. true ->
  1342. startEnterCall(CycleData, CurStatus, CurState, NewStatus, Debug, LeftEvents, [], [], false, false, false);
  1343. false ->
  1344. performTransitions(CycleData, CurStatus, CurState, NewStatus, Debug, LeftEvents, [], [], false, false, false)
  1345. end.
  1346. %% 处理enter callback 动作列表
  1347. parseEnterActionsList(CycleData, CurStatus, CurState, NewStatus, Debug, LeftEvents, Timeouts, NextEvents, IsPostpone, IsCallEnter, IsHibernate, DoAfter, Actions) ->
  1348. %% enter 调用不能改成状态 actions 不能返回 IsPostpone = true 但是可以取消之前的推迟 设置IsPostpone = false 不能设置 doafter 不能插入事件
  1349. case loopParseActionsList(Actions, ?CB_FORM_ENTER, CycleData, Debug, IsPostpone, IsHibernate, DoAfter, Timeouts, NextEvents) of
  1350. {error, ErrorContent} ->
  1351. terminate(error, ErrorContent, ?STACKTRACE(), CycleData, CurStatus, CurState, Debug, []);
  1352. {NewCycleData, NewDebug, NewIsPostpone, NewIsHibernate, DoAfter, NewTimeouts, NextEvents} ->
  1353. case IsCallEnter andalso element(#cycleData.isEnter, NewCycleData) of
  1354. true ->
  1355. startEnterCall(NewCycleData, CurStatus, CurState, NewStatus, NewDebug, LeftEvents, NewTimeouts, NextEvents, NewIsPostpone, NewIsHibernate, DoAfter);
  1356. _ ->
  1357. performTransitions(NewCycleData, CurStatus, CurState, NewStatus, NewDebug, LeftEvents, NewTimeouts, NextEvents, NewIsPostpone, NewIsHibernate, DoAfter)
  1358. end
  1359. end.
  1360. %% 处理非 enter 或者after callback 返回的动作列表
  1361. parseEventActionsList(CycleData, CurStatus, CurState, NewStatus, Debug, LeftEvents, IsCallEnter, Actions, CallbackForm) ->
  1362. case loopParseActionsList(Actions, CallbackForm, CycleData, Debug, false, false, false, [], []) of
  1363. {error, ErrorContent} ->
  1364. terminate(error, ErrorContent, ?STACKTRACE(), CycleData, CurStatus, CurState, Debug, []);
  1365. {NewCycleData, NewDebug, NewIsPostpone, NewIsHibernate, MewDoAfter, NewTimeouts, NewNextEvents} ->
  1366. case IsCallEnter andalso element(#cycleData.isEnter, NewCycleData) of
  1367. true ->
  1368. startEnterCall(NewCycleData, CurStatus, CurState, NewStatus, NewDebug, LeftEvents, NewTimeouts, NewNextEvents, NewIsPostpone, NewIsHibernate, MewDoAfter);
  1369. _ ->
  1370. performTransitions(NewCycleData, CurStatus, CurState, NewStatus, NewDebug, LeftEvents, NewTimeouts, NewNextEvents, NewIsPostpone, NewIsHibernate, MewDoAfter)
  1371. end
  1372. end.
  1373. loopParseActionsList([], _CallbackForm, CycleData, Debug, IsPostpone, IsHibernate, DoAfter, Timeouts, NextEvents) ->
  1374. {CycleData, Debug, IsPostpone, IsHibernate, DoAfter, Timeouts, NextEvents};
  1375. loopParseActionsList([OneAction | LeftActions], CallbackForm, CycleData, Debug, IsPostpone, IsHibernate, DoAfter, Timeouts, NextEvents) ->
  1376. case OneAction of
  1377. {reply, From, Reply} ->
  1378. reply(From, Reply),
  1379. NewDebug = ?SYS_DEBUG(Debug, {out, Reply, From}),
  1380. loopParseActionsList(LeftActions, CallbackForm, CycleData, NewDebug, IsPostpone, IsHibernate, DoAfter, Timeouts, NextEvents);
  1381. {eTimeout, _Time, _TimeoutMsg, _Options} = ENewTVOpt ->
  1382. case checkTimeOptions(ENewTVOpt) of
  1383. error_timeout_opt ->
  1384. {error, {bad_eTimeout_action, ENewTVOpt}};
  1385. RetTV ->
  1386. loopParseActionsList(LeftActions, CallbackForm, CycleData, Debug, IsPostpone, IsHibernate, DoAfter, [RetTV | Timeouts], NextEvents)
  1387. end;
  1388. {sTimeout, _Time, _TimeoutMsg, _Options} = SNewTVOpt ->
  1389. case checkTimeOptions(SNewTVOpt) of
  1390. error_timeout_opt ->
  1391. {error, {bad_sTimeout_action, SNewTVOpt}};
  1392. RetTV ->
  1393. loopParseActionsList(LeftActions, CallbackForm, CycleData, Debug, IsPostpone, IsHibernate, DoAfter, [RetTV | Timeouts], NextEvents)
  1394. end;
  1395. {{gTimeout, _Name}, _Time, _TimeoutMsg, _Options} = GNewTVOpt ->
  1396. case checkTimeOptions(GNewTVOpt) of
  1397. error_timeout_opt ->
  1398. {error, {bad_gTimeout_action, GNewTVOpt}};
  1399. RetTV ->
  1400. loopParseActionsList(LeftActions, CallbackForm, CycleData, Debug, IsPostpone, IsHibernate, DoAfter, [RetTV | Timeouts], NextEvents)
  1401. end;
  1402. {u_eTimeout, _TimeoutMsg} = UENewTV ->
  1403. loopParseActionsList(LeftActions, CallbackForm, CycleData, Debug, IsPostpone, IsHibernate, DoAfter, [UENewTV | Timeouts], NextEvents);
  1404. {u_sTimeout, _TimeoutMsg} = USNewTV ->
  1405. loopParseActionsList(LeftActions, CallbackForm, CycleData, Debug, IsPostpone, IsHibernate, DoAfter, [USNewTV | Timeouts], NextEvents);
  1406. {{u_gTimeout, _Name}, _TimeoutMsg} = UGNewTV ->
  1407. loopParseActionsList(LeftActions, CallbackForm, CycleData, Debug, IsPostpone, IsHibernate, DoAfter, [UGNewTV | Timeouts], NextEvents);
  1408. c_eTimeout ->
  1409. loopParseActionsList(LeftActions, CallbackForm, CycleData, Debug, IsPostpone, IsHibernate, DoAfter, [c_eTimeout | Timeouts], NextEvents);
  1410. c_sTimeout ->
  1411. loopParseActionsList(LeftActions, CallbackForm, CycleData, Debug, IsPostpone, IsHibernate, DoAfter, [c_sTimeout | Timeouts], NextEvents);
  1412. {c_gTimeout, _Name} = CGNewTV ->
  1413. loopParseActionsList(LeftActions, CallbackForm, CycleData, Debug, IsPostpone, IsHibernate, DoAfter, [CGNewTV | Timeouts], NextEvents);
  1414. {isEnter, IsEnter} when is_boolean(IsEnter) ->
  1415. NewCycleData =
  1416. case element(#cycleData.isEnter, CycleData) of
  1417. IsEnter ->
  1418. CycleData;
  1419. _ ->
  1420. setelement(#cycleData.isEnter, CycleData, IsEnter)
  1421. end,
  1422. loopParseActionsList(LeftActions, CallbackForm, NewCycleData, Debug, IsPostpone, IsHibernate, DoAfter, Timeouts, NextEvents);
  1423. {isHibernate, NewIsHibernate} when is_boolean(NewIsHibernate) ->
  1424. loopParseActionsList(LeftActions, CallbackForm, CycleData, Debug, IsPostpone, NewIsHibernate, DoAfter, Timeouts, NextEvents);
  1425. {isPostpone, NewIsPostpone} when is_boolean(NewIsPostpone) andalso (not NewIsPostpone orelse CallbackForm == ?CB_FORM_EVENT) ->
  1426. loopParseActionsList(LeftActions, CallbackForm, CycleData, Debug, NewIsPostpone, IsHibernate, DoAfter, Timeouts, NextEvents);
  1427. {doAfter, Args} when CallbackForm == ?CB_FORM_EVENT ->
  1428. loopParseActionsList(LeftActions, CallbackForm, CycleData, Debug, IsPostpone, IsHibernate, {true, Args}, Timeouts, NextEvents);
  1429. {eTimeout, Time, _TimeoutMsg} = ENewTV when ?REL_TIMEOUT(Time) ->
  1430. loopParseActionsList(LeftActions, CallbackForm, CycleData, Debug, IsPostpone, IsHibernate, DoAfter, [ENewTV | Timeouts], NextEvents);
  1431. {sTimeout, Time, _TimeoutMsg} = SNewTV when ?REL_TIMEOUT(Time) ->
  1432. loopParseActionsList(LeftActions, CallbackForm, CycleData, Debug, IsPostpone, IsHibernate, DoAfter, [SNewTV | Timeouts], NextEvents);
  1433. {{gTimeout, _Name}, Time, _TimeoutMsg} = GNewTV when ?REL_TIMEOUT(Time) ->
  1434. loopParseActionsList(LeftActions, CallbackForm, CycleData, Debug, IsPostpone, IsHibernate, DoAfter, [GNewTV | Timeouts], NextEvents);
  1435. {nextEvent, Type, Content} when CallbackForm == ?CB_FORM_EVENT orelse CallbackForm == ?CB_FORM_AFTER ->
  1436. %% 处理next_event动作
  1437. case isEventType(Type) of
  1438. true ->
  1439. loopParseActionsList(LeftActions, CallbackForm, CycleData, Debug, IsPostpone, IsHibernate, DoAfter, Timeouts, [{Type, Content} | NextEvents]);
  1440. _ ->
  1441. {error, {bad_next_event, Type, Content}}
  1442. end;
  1443. _ActRet ->
  1444. {error, {bad_action_type, _ActRet}}
  1445. end.
  1446. checkTimeOptions({TimeoutType, Time, TimeoutMsg, Options} = NewTV) ->
  1447. case Options of
  1448. [{abs, true}] when ?ABS_TIMEOUT(Time) ->
  1449. NewTV;
  1450. [{abs, false}] when ?REL_TIMEOUT(Time) ->
  1451. {TimeoutType, Time, TimeoutMsg};
  1452. [] when ?REL_TIMEOUT(Time) ->
  1453. {TimeoutType, Time, TimeoutMsg};
  1454. _ ->
  1455. %% 如果将来 start_timer opt扩展了 这里的代码也要修改
  1456. error_timeout_opt
  1457. end.
  1458. %% 进行状态转换
  1459. performTransitions(#cycleData{postponed = Postponed, timers = Timers} = CycleData, CurStatus, CurState, NewStatus, Debug, [Event | LeftEvents], Timeouts, NextEvents, IsPostpone, IsHibernate, DoAfter) ->
  1460. %% 已收集所有选项,并缓冲next_events。执行实际状态转换。如果推迟则将当前事件移至推迟
  1461. %% 此时 Timeouts, NextEvents的顺序与最开始出现的顺序相反. 后面执行的顺序 超时添加和更新 + 零超时 + 当前事件 + 反序的Postpone事件 + LeftEvent %% TODO 测试验证
  1462. NewDebug = ?SYS_DEBUG(Debug, case IsPostpone of true -> {postpone, Event, CurStatus, NewStatus}; _ -> {consume, Event, NewStatus, NewStatus} end),
  1463. if
  1464. CurStatus =:= NewStatus ->
  1465. %% Cancel event timeout
  1466. LastTimers =
  1467. case Timers of
  1468. #{eTimeout := {TimerRef, _TimeoutMsg}} ->
  1469. cancelTimer(eTimeout, TimerRef, Timers);
  1470. _ ->
  1471. Timers
  1472. end,
  1473. if
  1474. IsPostpone ->
  1475. NewCycleData = setelement(#cycleData.postponed, CycleData, [Event | Postponed]),
  1476. performTimeouts(NewCycleData, NewStatus, CurState, NewDebug, LeftEvents, Timeouts, NextEvents, LastTimers, IsHibernate, DoAfter);
  1477. true ->
  1478. performTimeouts(CycleData, NewStatus, CurState, NewDebug, LeftEvents, Timeouts, NextEvents, LastTimers, IsHibernate, DoAfter)
  1479. end;
  1480. true ->
  1481. %% 取消 status and event timeout
  1482. LastTimers =
  1483. case Timers of
  1484. #{sTimeout := {STimerRef, _STimeoutMsg}} ->
  1485. TemTimer = cancelTimer(sTimeout, STimerRef, Timers),
  1486. case TemTimer of
  1487. #{eTimeout := {ETimerRef, _ETimeoutMsg}} ->
  1488. cancelTimer(eTimeout, ETimerRef, TemTimer);
  1489. _ ->
  1490. TemTimer
  1491. end;
  1492. _ ->
  1493. case Timers of
  1494. #{eTimeout := {ETimerRef, _ETimeoutMsg}} ->
  1495. cancelTimer(eTimeout, ETimerRef, Timers);
  1496. _ ->
  1497. Timers
  1498. end
  1499. end,
  1500. NewCycleData = setelement(#cycleData.postponed, CycleData, []),
  1501. %% 状态发生改变 重试推迟的事件
  1502. if
  1503. IsPostpone ->
  1504. NewLeftEvents =
  1505. case Postponed of
  1506. [] ->
  1507. [Event | LeftEvents];
  1508. [E1] ->
  1509. [E1, Event | LeftEvents];
  1510. [E2, E1] ->
  1511. [E1, E2, Event | LeftEvents];
  1512. _ ->
  1513. lists:reverse(Postponed, [Event | LeftEvents])
  1514. end,
  1515. performTimeouts(NewCycleData, NewStatus, CurState, NewDebug, NewLeftEvents, Timeouts, NextEvents, LastTimers, IsHibernate, DoAfter);
  1516. true ->
  1517. NewLeftEvents =
  1518. case Postponed of
  1519. [] ->
  1520. LeftEvents;
  1521. [E1] ->
  1522. [E1 | LeftEvents];
  1523. [E2, E1] ->
  1524. [E1, E2 | LeftEvents];
  1525. _ ->
  1526. lists:reverse(Postponed, LeftEvents)
  1527. end,
  1528. performTimeouts(NewCycleData, NewStatus, CurState, NewDebug, NewLeftEvents, Timeouts, NextEvents, LastTimers, IsHibernate, DoAfter)
  1529. end
  1530. end.
  1531. %% 通过超时和插入事件的处理继续状态转换
  1532. performTimeouts(#cycleData{timers = OldTimer} = CycleData, CurStatus, CurState, Debug, LeftEvents, Timeouts, NextEvents, CurTimers, IsHibernate, DoAfter) ->
  1533. TemLastEvents =
  1534. case NextEvents of
  1535. [] ->
  1536. LeftEvents;
  1537. [E1] ->
  1538. [E1 | LeftEvents];
  1539. [E2, E1] ->
  1540. [E1, E2 | LeftEvents];
  1541. _ ->
  1542. lists:reverse(NextEvents, LeftEvents)
  1543. end,
  1544. case Timeouts of
  1545. [] ->
  1546. case OldTimer =:= CurTimers of
  1547. true ->
  1548. performEvents(CycleData, CurStatus, CurState, Debug, TemLastEvents, IsHibernate, DoAfter);
  1549. _ ->
  1550. NewCycleData = setelement(#cycleData.timers, CycleData, CurTimers),
  1551. performEvents(NewCycleData, CurStatus, CurState, Debug, TemLastEvents, IsHibernate, DoAfter)
  1552. end;
  1553. _ ->
  1554. %% 下面执行 loopTimeoutList 时 列表顺序跟最开始的是发的
  1555. {NewTimers, TimeoutEvents, NewDebug} = loopTimeoutsList(lists:reverse(Timeouts), CurTimers, [], Debug),
  1556. case TimeoutEvents of
  1557. [] ->
  1558. case OldTimer =:= NewTimers of
  1559. true ->
  1560. performEvents(CycleData, CurStatus, CurState, NewDebug, TemLastEvents, IsHibernate, DoAfter);
  1561. _ ->
  1562. NewCycleData = setelement(#cycleData.timers, CycleData, NewTimers),
  1563. performEvents(NewCycleData, CurStatus, CurState, NewDebug, TemLastEvents, IsHibernate, DoAfter)
  1564. end;
  1565. _ ->
  1566. {LastEvents, LastDebug} = mergeTimeoutEvents(TimeoutEvents, CurStatus, NewDebug, TemLastEvents),
  1567. case OldTimer =:= NewTimers of
  1568. true ->
  1569. performEvents(CycleData, CurStatus, CurState, LastDebug, LastEvents, IsHibernate, DoAfter);
  1570. _ ->
  1571. NewCycleData = setelement(#cycleData.timers, CycleData, NewTimers),
  1572. performEvents(NewCycleData, CurStatus, CurState, LastDebug, LastEvents, IsHibernate, DoAfter)
  1573. end
  1574. end
  1575. end.
  1576. loopTimeoutsList([], Timers, TimeoutEvents, Debug) ->
  1577. {Timers, TimeoutEvents, Debug};
  1578. loopTimeoutsList([OneTimeout | LeftTimeouts], Timers, TimeoutEvents, Debug) ->
  1579. case OneTimeout of
  1580. {TimeoutType, Time, TimeoutMsg, Options} ->
  1581. case Time of
  1582. infinity ->
  1583. NewTimers = doCancelTimer(TimeoutType, Timers),
  1584. loopTimeoutsList(LeftTimeouts, NewTimers, TimeoutEvents, Debug);
  1585. 0 when Options =:= [] ->
  1586. NewTimers = doCancelTimer(TimeoutType, Timers),
  1587. loopTimeoutsList(LeftTimeouts, NewTimers, [{TimeoutType, TimeoutMsg} | TimeoutEvents], Debug);
  1588. _ ->
  1589. TimerRef = erlang:start_timer(Time, self(), TimeoutType, Options),
  1590. NewDebug = ?SYS_DEBUG(Debug, {start_timer, {TimeoutType, Time, TimeoutMsg, Options}}),
  1591. NewTimers = doRegisterTimer(TimeoutType, TimerRef, TimeoutMsg, Timers),
  1592. loopTimeoutsList(LeftTimeouts, NewTimers, TimeoutEvents, NewDebug)
  1593. end;
  1594. {TimeoutType, Time, TimeoutMsg} ->
  1595. case Time of
  1596. infinity ->
  1597. NewTimers = doCancelTimer(TimeoutType, Timers),
  1598. loopTimeoutsList(LeftTimeouts, NewTimers, TimeoutEvents, Debug);
  1599. 0 ->
  1600. NewTimers = doCancelTimer(TimeoutType, Timers),
  1601. loopTimeoutsList(LeftTimeouts, NewTimers, [{TimeoutType, TimeoutMsg} | TimeoutEvents], Debug);
  1602. _ ->
  1603. TimerRef = erlang:start_timer(Time, self(), TimeoutType),
  1604. NewDebug = ?SYS_DEBUG(Debug, {start_timer, {TimeoutType, Time, TimeoutMsg, []}}),
  1605. NewTimers = doRegisterTimer(TimeoutType, TimerRef, TimeoutMsg, Timers),
  1606. loopTimeoutsList(LeftTimeouts, NewTimers, TimeoutEvents, NewDebug)
  1607. end;
  1608. {UpdateTimeoutType, NewTimeoutMsg} ->
  1609. NewTimers = doUpdateTimer(UpdateTimeoutType, NewTimeoutMsg, Timers),
  1610. loopTimeoutsList(LeftTimeouts, NewTimers, TimeoutEvents, Debug);
  1611. CancelTimeoutType ->
  1612. NewTimers = doCancelTimer(CancelTimeoutType, Timers),
  1613. loopTimeoutsList(LeftTimeouts, NewTimers, TimeoutEvents, Debug)
  1614. end.
  1615. doRegisterTimer(TimeoutType, NewTimerRef, TimeoutMsg, Timers) ->
  1616. case Timers of
  1617. #{TimeoutType := {OldTimerRef, _OldTimeMsg}} ->
  1618. TemTimers = cancelTimer(TimeoutType, OldTimerRef, Timers),
  1619. TemTimers#{TimeoutType => {NewTimerRef, TimeoutMsg}};
  1620. _ ->
  1621. Timers#{TimeoutType => {NewTimerRef, TimeoutMsg}}
  1622. end.
  1623. doCancelTimer(TimeoutType, Timers) ->
  1624. case Timers of
  1625. #{TimeoutType := {TimerRef, _TimeoutMsg}} ->
  1626. cancelTimer(TimeoutType, TimerRef, Timers);
  1627. _ ->
  1628. Timers
  1629. end.
  1630. doUpdateTimer(TimeoutType, Timers, TimeoutMsg) ->
  1631. case Timers of
  1632. #{TimeoutType := {TimerRef, _OldTimeoutMsg}} ->
  1633. Timers#{TimeoutType := {TimerRef, TimeoutMsg}};
  1634. _ ->
  1635. Timers
  1636. end.
  1637. -compile({inline, [cancelTimer/3]}).
  1638. cancelTimer(TimeoutType, TimerRef, Timers) ->
  1639. case erlang:cancel_timer(TimerRef) of
  1640. false ->
  1641. %% 找不到计时器,我们还没有看到超时消息
  1642. receive
  1643. {TimeoutType, TimerRef, _Msg} ->
  1644. %% 丢弃该超时消息
  1645. ok
  1646. end;
  1647. _ ->
  1648. %% Timer 已经运行了
  1649. ok
  1650. end,
  1651. maps:remove(TimeoutType, Timers).
  1652. %% 排队立即超时事件(超时0事件)
  1653. %% 自事件超时0起,事件得到特殊处理
  1654. %% 任何收到的事件都会取消事件超时,
  1655. %% 因此,如果在事件超时0事件之前存在入队事件-事件超时被取消,因此没有事件。
  1656. %% 其他(status_timeout和{timeout,Name})超时0个事件
  1657. %% 在事件计时器超时0事件之后发生的事件被认为是
  1658. %% 属于在事件计时器之后启动的计时器
  1659. %% 已触发超时0事件,因此它们不会取消事件计时器。
  1660. mergeTimeoutEvents([], _Status, Debug, Events) ->
  1661. {Events, Debug};
  1662. mergeTimeoutEvents([{eTimeout, _} = TimeoutEvent | TimeoutEvents], Status, Debug, []) ->
  1663. %% 由于队列中没有其他事件,因此添加该事件零超时事件
  1664. NewDebug = ?SYS_DEBUG(Debug, {insert_timeout, TimeoutEvent, Status}),
  1665. mergeTimeoutEvents(TimeoutEvents, Status, NewDebug, [TimeoutEvent]);
  1666. mergeTimeoutEvents([{eTimeout, _} | TimeoutEvents], Status, Debug, Events) ->
  1667. %% 忽略,因为队列中还有其他事件,因此它们取消了事件超时0。
  1668. mergeTimeoutEvents(TimeoutEvents, Status, Debug, Events);
  1669. mergeTimeoutEvents([TimeoutEvent | TimeoutEvents], Status, Debug, Events) ->
  1670. %% Just prepend all others
  1671. NewDebug = ?SYS_DEBUG(Debug, {insert_timeout, TimeoutEvent, Status}),
  1672. mergeTimeoutEvents(TimeoutEvents, Status, NewDebug, [TimeoutEvent | Events]).
  1673. %% Return a list of all pending timeouts
  1674. list_timeouts(Timers) ->
  1675. {maps:size(Timers),
  1676. maps:fold(
  1677. fun(TimeoutType, {_TimerRef, TimeoutMsg}, Acc) ->
  1678. [{TimeoutType, TimeoutMsg} | Acc]
  1679. end, [], Timers)}.
  1680. %%---------------------------------------------------------------------------
  1681. %% 状态转换已完成,如果有排队事件,则继续循环,否则获取新事件
  1682. performEvents(CycleData, CurStatus, CurState, Debug, LeftEvents, IsHibernate, DoAfter) ->
  1683. % 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]),
  1684. case DoAfter of
  1685. {true, Args} ->
  1686. %% 这里 IsHibernate设置会被丢弃 按照gen_server中的设计 continue 和 hiernate是互斥的
  1687. startAfterCall(CycleData, CurStatus, CurState, Debug, LeftEvents, Args);
  1688. _ ->
  1689. case LeftEvents of
  1690. [] ->
  1691. reLoopEntry(CycleData, CurStatus, CurState, Debug, IsHibernate);
  1692. [Event | _Events] ->
  1693. %% 循环直到没有排队事件
  1694. if
  1695. IsHibernate ->
  1696. %% _ = garbage_collect(),
  1697. erts_internal:garbage_collect(major);
  1698. true ->
  1699. ignore
  1700. end,
  1701. startEventCall(CycleData, CurStatus, CurState, Debug, LeftEvents, Event)
  1702. end
  1703. end.
  1704. doReplies([], Debug) ->
  1705. Debug;
  1706. doReplies([{reply, From, Reply} | Replies], Debug) ->
  1707. reply(From, Reply),
  1708. NewDebug = ?SYS_DEBUG(Debug, {out, Reply, From}),
  1709. doReplies(Replies, NewDebug);
  1710. doReplies([OneReply | _Replies], Debug) ->
  1711. {bad_reply_action, OneReply, Debug}.
  1712. replyThenTerminate(Class, Reason, Stacktrace, CycleData, CurStatus, CurState, Debug, LeftEvents, Replies) ->
  1713. case doReplies(Replies, Debug) of
  1714. {bad_reply_action, OneReply, Debug} ->
  1715. terminate(error, {bad_reply_action, OneReply}, ?STACKTRACE(), CycleData, CurStatus, CurState, Debug, LeftEvents);
  1716. NewDebug ->
  1717. terminate(Class, Reason, Stacktrace, CycleData, CurStatus, CurState, NewDebug, LeftEvents)
  1718. end.
  1719. terminate(Class, Reason, Stacktrace, #cycleData{module = Module} = CycleData, CurStatus, CurState, Debug, LeftEvents) ->
  1720. epmStopAll(),
  1721. case erlang:function_exported(Module, terminate, 3) of
  1722. true ->
  1723. try Module:terminate(Reason, CurStatus, CurState) of
  1724. _ -> ok
  1725. catch
  1726. throw:_ -> ok;
  1727. C:R:ST ->
  1728. error_info(C, R, ST, CycleData, CurStatus, CurState, Debug, LeftEvents),
  1729. erlang:raise(C, R, ST)
  1730. end;
  1731. false ->
  1732. ok
  1733. end,
  1734. case Reason of
  1735. normal ->
  1736. ?SYS_DEBUG(Debug, {terminate, Reason, CurStatus});
  1737. shutdown ->
  1738. ?SYS_DEBUG(Debug, {terminate, Reason, CurStatus});
  1739. {shutdown, _} ->
  1740. ?SYS_DEBUG(Debug, {terminate, Reason, CurStatus});
  1741. _ ->
  1742. error_info(Class, Reason, Stacktrace, CycleData, CurStatus, CurState, Debug, LeftEvents)
  1743. end,
  1744. case Stacktrace of
  1745. [] ->
  1746. erlang:Class(Reason);
  1747. _ ->
  1748. erlang:raise(Class, Reason, Stacktrace)
  1749. end.
  1750. error_info(Class, Reason, Stacktrace, #cycleData{isEnter = IsEnter, postponed = Postponed, timers = Timers} = CycleData, CurStatus, CurState, Debug, LeftEvents) ->
  1751. Log = sys:get_log(Debug),
  1752. ?LOG_ERROR(
  1753. #{
  1754. label => {gen_ipc, terminate},
  1755. name => getProName(),
  1756. queue => LeftEvents,
  1757. postponed => Postponed,
  1758. isEnter => IsEnter,
  1759. status => format_status(terminate, get(), CycleData, CurStatus, CurState),
  1760. timeouts => list_timeouts(Timers),
  1761. log => Log,
  1762. reason => {Class, Reason, Stacktrace},
  1763. client_info => clientStacktrace(LeftEvents)
  1764. },
  1765. #{
  1766. domain => [otp],
  1767. report_cb => fun gen_ipc:format_log/1,
  1768. error_logger => #{tag => error}}
  1769. ).
  1770. clientStacktrace([]) ->
  1771. undefined;
  1772. clientStacktrace([{{call, {Pid, _Tag}}, _Req} | _]) when is_pid(Pid) ->
  1773. if
  1774. node(Pid) =:= node() ->
  1775. case process_info(Pid, [current_stacktrace, registered_name]) of
  1776. undefined ->
  1777. {Pid, dead};
  1778. [{current_stacktrace, Stacktrace}, {registered_name, []}] ->
  1779. {Pid, {Pid, Stacktrace}};
  1780. [{current_stacktrace, Stacktrace}, {registered_name, Name}] ->
  1781. {Pid, {Name, Stacktrace}}
  1782. end;
  1783. true ->
  1784. {Pid, remote}
  1785. end;
  1786. clientStacktrace([_ | _]) ->
  1787. undefined.
  1788. format_log(#{label:={gen_statusm, terminate},
  1789. name:=Name,
  1790. queue:=LeftEvents,
  1791. postponed:=Postponed,
  1792. callback_mode:=CallbackMode,
  1793. status_enter:=StatusEnter,
  1794. status:=FmtData,
  1795. timeouts:=Timeouts,
  1796. log:=Log,
  1797. reason:={Class, Reason, Stacktrace},
  1798. client_info:=ClientInfo}) ->
  1799. {FixedReason, FixedStacktrace} =
  1800. case Stacktrace of
  1801. [{M, F, Args, _} | ST]
  1802. when Class =:= error, Reason =:= undef ->
  1803. case code:is_loaded(M) of
  1804. false ->
  1805. {{'module could not be loaded', M}, ST};
  1806. _ ->
  1807. Arity =
  1808. if
  1809. is_list(Args) ->
  1810. length(Args);
  1811. is_integer(Args) ->
  1812. Args
  1813. end,
  1814. case erlang:function_exported(M, F, Arity) of
  1815. true ->
  1816. {Reason, Stacktrace};
  1817. false ->
  1818. {{'function not exported', {M, F, Arity}}, ST}
  1819. end
  1820. end;
  1821. _ -> {Reason, Stacktrace}
  1822. end,
  1823. {ClientFmt, ClientArgs} = format_client_log(ClientInfo),
  1824. CBMode =
  1825. case StatusEnter of
  1826. true ->
  1827. [CallbackMode, status_enter];
  1828. false ->
  1829. CallbackMode
  1830. end,
  1831. {"** Status machine ~tp terminating~n" ++
  1832. case LeftEvents of
  1833. [] -> "";
  1834. _ -> "** Last event = ~tp~n"
  1835. end ++
  1836. "** When server status = ~tp~n" ++
  1837. "** Reason for termination = ~w:~tp~n" ++
  1838. "** Callback mode = ~p~n" ++
  1839. case LeftEvents of
  1840. [_, _ | _] -> "** Queued = ~tp~n";
  1841. _ -> ""
  1842. end ++
  1843. case Postponed of
  1844. [] -> "";
  1845. _ -> "** Postponed = ~tp~n"
  1846. end ++
  1847. case FixedStacktrace of
  1848. [] -> "";
  1849. _ -> "** Stacktrace =~n** ~tp~n"
  1850. end ++
  1851. case Timeouts of
  1852. {0, _} -> "";
  1853. _ -> "** Time-outs: ~p~n"
  1854. end ++
  1855. case Log of
  1856. [] -> "";
  1857. _ -> "** Log =~n** ~tp~n"
  1858. end ++ ClientFmt,
  1859. [Name |
  1860. case LeftEvents of
  1861. [] -> [];
  1862. [Event | _] -> [error_logger:limit_term(Event)]
  1863. end] ++
  1864. [error_logger:limit_term(FmtData),
  1865. Class, error_logger:limit_term(FixedReason),
  1866. CBMode] ++
  1867. case LeftEvents of
  1868. [_ | [_ | _] = Events] -> [error_logger:limit_term(Events)];
  1869. _ -> []
  1870. end ++
  1871. case Postponed of
  1872. [] -> [];
  1873. _ -> [error_logger:limit_term(Postponed)]
  1874. end ++
  1875. case FixedStacktrace of
  1876. [] -> [];
  1877. _ -> [error_logger:limit_term(FixedStacktrace)]
  1878. end ++
  1879. case Timeouts of
  1880. {0, _} -> [];
  1881. _ -> [error_logger:limit_term(Timeouts)]
  1882. end ++
  1883. case Log of
  1884. [] -> [];
  1885. _ -> [[error_logger:limit_term(T) || T <- Log]]
  1886. end ++ ClientArgs}.
  1887. format_client_log(undefined) ->
  1888. {"", []};
  1889. format_client_log({Pid, dead}) ->
  1890. {"** Client ~p is dead~n", [Pid]};
  1891. format_client_log({Pid, remote}) ->
  1892. {"** Client ~p is remote on node ~p~n", [Pid, node(Pid)]};
  1893. format_client_log({_Pid, {Name, Stacktrace}}) ->
  1894. {"** Client ~tp stacktrace~n"
  1895. "** ~tp~n",
  1896. [Name, error_logger:limit_term(Stacktrace)]}.
  1897. %% Call Module:format_status/2 or return a default value
  1898. format_status(Opt, PDict, #cycleData{module = Module}, CurStatus, CurState) ->
  1899. case erlang:function_exported(Module, format_status, 2) of
  1900. true ->
  1901. try Module:formatStatus(Opt, [PDict, CurStatus, CurState])
  1902. catch
  1903. throw:Result ->
  1904. Result;
  1905. _:_ ->
  1906. format_status_default(Opt, {CurStatus, atom_to_list(Module) ++ ":format_status/2 crashed"})
  1907. end;
  1908. false ->
  1909. format_status_default(Opt, {CurStatus, CurState})
  1910. end.
  1911. %% The default Module:format_status/3
  1912. format_status_default(Opt, Status_State) ->
  1913. case Opt of
  1914. terminate ->
  1915. Status_State;
  1916. _ ->
  1917. [{data, [{"Status", Status_State}]}]
  1918. end.
  1919. %%---------------------------------------------------------------------------
  1920. %% Format debug messages. Print them as the call-back module sees
  1921. %% them, not as the real erlang messages. Use trace for that.
  1922. %%--------------------------------------------------------------------------
  1923. print_event(Dev, SystemEvent, Name) ->
  1924. case SystemEvent of
  1925. {in, Event, Status} ->
  1926. io:format(Dev, "*DBG* ~tp receive ~ts in status ~tp~n", [Name, event_string(Event), Status]);
  1927. {code_change, Event, Status} ->
  1928. io:format(Dev, "*DBG* ~tp receive ~ts after code change in status ~tp~n", [Name, event_string(Event), Status]);
  1929. {out, Reply, {To, _Tag}} ->
  1930. io:format(Dev, "*DBG* ~tp send ~tp to ~tw~n", [Name, Reply, To]);
  1931. {enter, Status} ->
  1932. io:format(Dev, "*DBG* ~tp enter in status ~tp~n", [Name, Status]);
  1933. {start_timer, Action, Status} ->
  1934. io:format(Dev, "*DBG* ~tp start_timer ~tp in status ~tp~n", [Name, Action, Status]);
  1935. {insert_timeout, Event, Status} ->
  1936. io:format(Dev, "*DBG* ~tp insert_timeout ~tp in status ~tp~n", [Name, Event, Status]);
  1937. {terminate, Reason, Status} ->
  1938. io:format(Dev, "*DBG* ~tp terminate ~tp in status ~tp~n", [Name, Reason, Status]);
  1939. {Tag, Event, Status, NextStatus}
  1940. when Tag =:= postpone; Tag =:= consume ->
  1941. StatusString =
  1942. case NextStatus of
  1943. Status ->
  1944. io_lib:format("~tp", [Status]);
  1945. _ ->
  1946. io_lib:format("~tp => ~tp", [Status, NextStatus])
  1947. end,
  1948. io:format(Dev, "*DBG* ~tp ~tw ~ts in status ~ts~n", [Name, Tag, event_string(Event), StatusString])
  1949. end.
  1950. event_string(Event) ->
  1951. case Event of
  1952. {{call, {Pid, _Tag}}, Request} ->
  1953. io_lib:format("call ~tp from ~tw", [Request, Pid]);
  1954. {EventType, EventContent} ->
  1955. io_lib:format("~tw ~tp", [EventType, EventContent])
  1956. end.
  1957. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 进程字典操作函数 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1958. setParent(Parent) ->
  1959. erlang:put(?PD_PARENT, Parent).
  1960. getParent() ->
  1961. erlang:get(?PD_PARENT).
  1962. setProName(Name) ->
  1963. erlang:put(?PD_PRO_NAME, Name).
  1964. getProName() ->
  1965. erlang:get(?PD_PRO_NAME).
  1966. setEpmList(EpmList) ->
  1967. erlang:put(?PD_EPM_LIST, EpmList).
  1968. getEpmList() ->
  1969. case erlang:get(?PD_EPM_LIST) of
  1970. undefined ->
  1971. [];
  1972. RetList ->
  1973. RetList
  1974. end.
  1975. delEpmHer(#epmHer{epmId = EpmId}) ->
  1976. erlang:erase({?PD_EPM_FLAG, EpmId}).
  1977. setEpmHer(#epmHer{epmId = EpmId} = EpmHer) ->
  1978. erlang:put({?PD_EPM_FLAG, EpmId}, EpmHer).
  1979. getEpmHer(EpmId) ->
  1980. erlang:get({?PD_EPM_FLAG, EpmId}).
  1981. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%