From b82cfe6594b159a24009dd52bf94d9e6361350cb Mon Sep 17 00:00:00 2001 From: SisMaker <1713699517@qq.com> Date: Mon, 14 Feb 2022 18:24:45 +0800 Subject: [PATCH] =?UTF-8?q?ft:=20call=20M=20F=20A=20=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gen_apu.erl | 1874 ++++++++++++++++++++++++----------------------- 1 file changed, 974 insertions(+), 900 deletions(-) diff --git a/src/gen_apu.erl b/src/gen_apu.erl index 6991e39..6072892 100644 --- a/src/gen_apu.erl +++ b/src/gen_apu.erl @@ -6,33 +6,34 @@ -include_lib("kernel/include/logger.hrl"). -export([ - %% API for gen_apu - start/3, start/4, start_link/3, start_link/4 - , start_monitor/3, start_monitor/4 - , stop/1, stop/3 - , call/2, call/3 - , send_request/2, wait_response/2, receive_response/2, check_response/2 - , cast/2, send/2, reply/1, reply/2 - , abcast/2, abcast/3 - , multi_call/2, multi_call/3, multi_call/4 - , enter_loop/3, enter_loop/4, enter_loop/5 - - %% gen callbacks - , init_it/6 - - %% sys callbacks - , system_continue/3 - , system_terminate/4 - , system_code_change/4 - , system_get_state/1 - , system_replace_state/2 - , format_status/2 - - %% Internal callbacks - , wakeupFromHib/8 - - %% logger callback - , format_log/1, format_log/2 + %% API for gen_apu + start/3, start/4, start_link/3, start_link/4 + , start_monitor/3, start_monitor/4 + , stop/1, stop/3 + , call/2, call/3 + , clfn/4, clfn/5, clfs/4, clfs/5, csfn/4, csfs/4 + , send_request/2, wait_response/2, receive_response/2, check_response/2 + , cast/2, send/2, reply/1, reply/2 + , abcast/2, abcast/3 + , multi_call/2, multi_call/3, multi_call/4 + , enter_loop/3, enter_loop/4, enter_loop/5 + + %% gen callbacks + , init_it/6 + + %% sys callbacks + , system_continue/3 + , system_terminate/4 + , system_code_change/4 + , system_get_state/1 + , system_replace_state/2 + , format_status/2 + + %% Internal callbacks + , wakeupFromHib/8 + + %% logger callback + , format_log/1, format_log/2 ]). @@ -41,52 +42,52 @@ %% debug 调试相关宏定义 -define(NOT_DEBUG, []). -define(SYS_DEBUG(Debug, Name, Msg), - case Debug of - ?NOT_DEBUG -> - Debug; - _ -> - sys:handle_debug(Debug, fun print_event/3, Name, Msg) - end). + case Debug of + ?NOT_DEBUG -> + Debug; + _ -> + sys:handle_debug(Debug, fun print_event/3, Name, Msg) + end). -type serverName() :: - {'local', atom()} | - {'global', GlobalName :: term()} | - {'via', RegMod :: module(), Name :: term()}. +{'local', atom()} | +{'global', GlobalName :: term()} | +{'via', RegMod :: module(), Name :: term()}. -type serverRef() :: - pid() - | (LocalName :: atom()) - | {Name :: atom(), Node :: atom()} - | {'global', GlobalName :: term()} - | {'via', RegMod :: module(), ViaName :: term()}. +pid() +| (LocalName :: atom()) +| {Name :: atom(), Node :: atom()} +| {'global', GlobalName :: term()} +| {'via', RegMod :: module(), ViaName :: term()}. -type startOpt() :: - {'timeout', Time :: timeout()} | - {'spawn_opt', [proc_lib:spawn_option()]} | - enterLoopOpt(). +{'timeout', Time :: timeout()} | +{'spawn_opt', [proc_lib:spawn_option()]} | +enterLoopOpt(). -type enterLoopOpt() :: - {'debug', Debugs :: [sys:debug_option()]} | - {'hibernate_after', HibernateAfterTimeout :: timeout()}. +{'debug', Debugs :: [sys:debug_option()]} | +{'hibernate_after', HibernateAfterTimeout :: timeout()}. -type startRet() :: - 'ignore' | - {'ok', pid()} | - {'ok', {pid(), reference()}} | - {'error', term()}. +'ignore' | +{'ok', pid()} | +{'ok', {pid(), reference()}} | +{'error', term()}. -type action() :: - timeout() | - hibernate | - {'doAfter', Args :: term()} | - {'nTimeout', Name :: term(), Time :: timeouts(), TimeoutMsg :: term()} | - {'nTimeout', Name :: term(), Time :: timeouts(), TimeoutMsg :: term(), Options :: ([timeoutOption()])} | - {'uTimeout', Name :: term(), TimeoutMsg :: term()} | - {'cTimeout', Name :: term()}. +timeout() | +hibernate | +{'doAfter', Args :: term()} | +{'nTimeout', Name :: term(), Time :: timeouts(), TimeoutMsg :: term()} | +{'nTimeout', Name :: term(), Time :: timeouts(), TimeoutMsg :: term(), Options :: ([timeoutOption()])} | +{'uTimeout', Name :: term(), TimeoutMsg :: term()} | +{'cTimeout', Name :: term()}. -type actions() :: - action() | - [action(), ...]. +action() | +[action(), ...]. -type timeouts() :: Time :: timeout() | integer(). -type timeoutOption() :: {abs, Abs :: boolean()}. @@ -97,147 +98,147 @@ -type requestId() :: term(). -type replyAction() :: - {'reply', From :: from(), Reply :: term()}. +{'reply', From :: from(), Reply :: term()}. -callback init(Args :: term()) -> - {ok, State :: term()} | - {ok, State :: term(), Actions :: actions()} | - {stop, Reason :: term()} | - ignore. + {ok, State :: term()} | + {ok, State :: term(), Actions :: actions()} | + {stop, Reason :: term()} | + ignore. %% call 消息的返回 -export_type([handleCallRet/0]). -type handleCallRet() :: - kpS | - {reply, Reply :: term()} | - {reply, Reply :: term(), NewState :: term()} | - {reply, Reply :: term(), NewState :: term(), Actions :: actions()} | - {noreply, NewState :: term()} | - {noreply, NewState :: term(), Actions :: actions()} | - {stop, Reason :: term(), NewState :: term()} | - {stopReply, Reason :: term(), Reply :: term(), NewState :: term()}. +kpS | +{reply, Reply :: term()} | +{reply, Reply :: term(), NewState :: term()} | +{reply, Reply :: term(), NewState :: term(), Actions :: actions()} | +{noreply, NewState :: term()} | +{noreply, NewState :: term(), Actions :: actions()} | +{stop, Reason :: term(), NewState :: term()} | +{stopReply, Reason :: term(), Reply :: term(), NewState :: term()}. %% cast 消息的返回 -export_type([handleCastRet/0]). -type handleCastRet() :: - kpS | - {noreply, NewState :: term()} | - {noreply, NewState :: term(), Actions :: actions()} | - {stop, Reason :: term(), NewState :: term()}. +kpS | +{noreply, NewState :: term()} | +{noreply, NewState :: term(), Actions :: actions()} | +{stop, Reason :: term(), NewState :: term()}. -callback handleInfo(Info :: timeout | term(), State :: term()) -> - kpS | - {noreply, NewState :: term()} | - {noreply, NewState :: term(), Actions :: actions()} | - {stop, Reason :: term(), NewState :: term()}. + kpS | + {noreply, NewState :: term()} | + {noreply, NewState :: term(), Actions :: actions()} | + {stop, Reason :: term(), NewState :: term()}. -callback handleAfter(Info :: term(), State :: term()) -> - kpS | - {noreply, NewState :: term()} | - {noreply, NewState :: term(), Actions :: actions()} | - {stop, Reason :: term(), NewState :: term()}. + kpS | + {noreply, NewState :: term()} | + {noreply, NewState :: term(), Actions :: actions()} | + {stop, Reason :: term(), NewState :: term()}. -callback terminate(Reason :: (normal | shutdown | {shutdown, term()} |term()), State :: term()) -> - term(). + term(). -callback code_change(OldVsn :: (term() | {down, term()}), State :: term(), Extra :: term()) -> - {ok, NewState :: term()} | {error, Reason :: term()}. + {ok, NewState :: term()} | {error, Reason :: term()}. -callback formatStatus(Opt, StatusData) -> Status when - Opt :: 'normal' | 'terminate', - StatusData :: [PDict | State], - PDict :: [{Key :: term(), Value :: term()}], - State :: term(), - Status :: term(). + Opt :: 'normal' | 'terminate', + StatusData :: [PDict | State], + PDict :: [{Key :: term(), Value :: term()}], + State :: term(), + Status :: term(). -optional_callbacks([ - handleAfter/2 - , handleInfo/2 - , terminate/2 - , code_change/3 - , formatStatus/2 +handleAfter/2 +, handleInfo/2 +, terminate/2 +, code_change/3 +, formatStatus/2 ]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% start stop API start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -spec start(Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet(). start(Module, Args, Options) -> - gen:start(?MODULE, nolink, Module, Args, Options). + gen:start(?MODULE, nolink, Module, Args, Options). -spec start(ServerName :: serverName(), Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet(). start(ServerName, Module, Args, Options) -> - gen:start(?MODULE, nolink, ServerName, Module, Args, Options). + gen:start(?MODULE, nolink, ServerName, Module, Args, Options). -spec start_link(Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet(). start_link(Module, Args, Options) -> - gen:start(?MODULE, link, Module, Args, Options). + gen:start(?MODULE, link, Module, Args, Options). -spec start_link(ServerName :: serverName(), Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet(). start_link(ServerName, Module, Args, Options) -> - gen:start(?MODULE, link, ServerName, Module, Args, Options). + gen:start(?MODULE, link, ServerName, Module, Args, Options). -spec start_monitor(Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet(). start_monitor(Module, Args, Options) -> - gen:start(?MODULE, monitor, Module, Args, Options). + gen:start(?MODULE, monitor, Module, Args, Options). -spec start_monitor(ServerName :: serverName(), Module :: module(), Args :: term(), Opts :: [startOpt()]) -> startRet(). start_monitor(ServerName, Module, Args, Options) -> - gen:start(?MODULE, monitor, ServerName, Module, Args, Options). + gen:start(?MODULE, monitor, ServerName, Module, Args, Options). %%停止通用服务器并等待其终止。如果服务器位于另一个节点上,则将监视该节点。 -spec stop(ServerRef :: serverRef()) -> ok. stop(ServerRef) -> - gen:stop(ServerRef). + gen:stop(ServerRef). -spec stop(ServerRef :: serverRef(), Reason :: term(), Timeout :: timeout()) -> ok. stop(ServerRef, Reason, Timeout) -> - gen:stop(ServerRef, Reason, Timeout). + gen:stop(ServerRef, Reason, Timeout). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% start stop API end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gen callbacks start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% doModuleInit(Module, Args) -> - try - Module:init(Args) - catch - throw:Ret -> Ret; - Class:Reason:Strace -> {'EXIT', Class, Reason, Strace} - end. + try + Module:init(Args) + catch + throw:Ret -> Ret; + Class:Reason:Strace -> {'EXIT', Class, Reason, Strace} + end. init_it(Starter, self, ServerRef, Module, Args, Options) -> - init_it(Starter, self(), ServerRef, Module, Args, Options); + init_it(Starter, self(), ServerRef, Module, Args, Options); init_it(Starter, Parent, ServerRef, Module, Args, Options) -> - Name = gen:name(ServerRef), - Debug = gen:debug_options(Name, Options), - HibernateAfterTimeout = gen:hibernate_after(Options), - - case doModuleInit(Module, Args) of - {ok, State} -> - proc_lib:init_ack(Starter, {ok, self()}), - receiveIng(Parent, Name, Module, HibernateAfterTimeout, Debug, #{}, State, false); - {ok, State, Actions} -> - proc_lib:init_ack(Starter, {ok, self()}), - loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, #{}, State, listify(Actions)); - {stop, Reason} -> - % 为了保持一致性,我们必须确保在 - % %%父进程收到有关失败的通知之前,必须先注销%%注册名称(如果有)。 - % %%(否则,如果父进程立即%%再次尝试启动该进程,则其父进程可能会收到%already_started错误)。 - gen:unregister_name(ServerRef), - proc_lib:init_ack(Starter, {error, Reason}), - exit(Reason); - ignore -> - gen:unregister_name(ServerRef), - proc_lib:init_ack(Starter, ignore), - exit(normal); - {'EXIT', Class, Reason, Stacktrace} -> - gen:unregister_name(ServerRef), - proc_lib:init_ack(Starter, {error, terminate_reason(Class, Reason, Stacktrace)}), - erlang:raise(Class, Reason, Stacktrace); - _Ret -> - Error = {bad_return_value, _Ret}, - proc_lib:init_ack(Starter, {error, Error}), - exit(Error) - end. + Name = gen:name(ServerRef), + Debug = gen:debug_options(Name, Options), + HibernateAfterTimeout = gen:hibernate_after(Options), + + case doModuleInit(Module, Args) of + {ok, State} -> + proc_lib:init_ack(Starter, {ok, self()}), + receiveIng(Parent, Name, Module, HibernateAfterTimeout, Debug, #{}, State, false); + {ok, State, Actions} -> + proc_lib:init_ack(Starter, {ok, self()}), + loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, #{}, State, listify(Actions)); + {stop, Reason} -> + % 为了保持一致性,我们必须确保在 + % %%父进程收到有关失败的通知之前,必须先注销%%注册名称(如果有)。 + % %%(否则,如果父进程立即%%再次尝试启动该进程,则其父进程可能会收到%already_started错误)。 + gen:unregister_name(ServerRef), + proc_lib:init_ack(Starter, {error, Reason}), + exit(Reason); + ignore -> + gen:unregister_name(ServerRef), + proc_lib:init_ack(Starter, ignore), + exit(normal); + {'EXIT', Class, Reason, Stacktrace} -> + gen:unregister_name(ServerRef), + proc_lib:init_ack(Starter, {error, terminate_reason(Class, Reason, Stacktrace)}), + erlang:raise(Class, Reason, Stacktrace); + _Ret -> + Error = {bad_return_value, _Ret}, + proc_lib:init_ack(Starter, {error, Error}), + exit(Error) + end. %%----------------------------------------------------------------- @@ -253,77 +254,77 @@ init_it(Starter, Parent, ServerRef, Module, Args, Options) -> %%----------------------------------------------------------------- -spec enter_loop(Module :: module(), State :: term(), Opts :: [enterLoopOpt()]) -> no_return(). enter_loop(Module, State, Opts) -> - enter_loop(Module, State, Opts, self(), infinity). + enter_loop(Module, State, Opts, self(), infinity). -spec enter_loop(Module :: module(), State :: term(), Opts :: [enterLoopOpt()], serverName() | pid()) -> no_return(). enter_loop(Module, State, Opts, ServerName) -> - enter_loop(Module, State, Opts, ServerName, infinity). + enter_loop(Module, State, Opts, ServerName, infinity). -spec enter_loop(Module :: module(), State :: term(), Opts :: [enterLoopOpt()], Server :: serverName() | pid(), Actions :: actions()) -> no_return(). enter_loop(Module, State, Opts, ServerName, Actions) -> - Name = gen:get_proc_name(ServerName), - Parent = gen:get_parent(), - Debug = gen:debug_options(Name, Opts), - HibernateAfterTimeout = gen:hibernate_after(Opts), - loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, #{}, State, listify(Actions)). + Name = gen:get_proc_name(ServerName), + Parent = gen:get_parent(), + Debug = gen:debug_options(Name, Opts), + HibernateAfterTimeout = gen:hibernate_after(Opts), + loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, #{}, State, listify(Actions)). %%% Internal callbacks wakeupFromHib(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, IsHib) -> - %% 这是一条新消息,唤醒了我们,因此我们必须立即收到它 - receiveIng(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, IsHib). + %% 这是一条新消息,唤醒了我们,因此我们必须立即收到它 + receiveIng(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, IsHib). loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, Actions) -> - case doParseAL(Actions, Name, Debug, false, false, Timers) of - {error, ErrorContent} -> - terminate(error, ErrorContent, ?STACKTRACE(), Name, Module, Debug, Timers, CurState, []); - {NewDebug, IsHib, DoAfter, NewTimers} -> - case DoAfter of - {doAfter, Args} -> - doAfterCall(Parent, Name, Module, HibernateAfterTimeout, NewDebug, NewTimers, CurState, listHib(IsHib), Args); - _ -> - case IsHib of - true -> - proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, Name, Module, HibernateAfterTimeout, NewDebug, NewTimers, CurState, IsHib]); - _ -> - receiveIng(Parent, Name, Module, HibernateAfterTimeout, NewDebug, NewTimers, CurState, false) - end - end - end. + case doParseAL(Actions, Name, Debug, false, false, Timers) of + {error, ErrorContent} -> + terminate(error, ErrorContent, ?STACKTRACE(), Name, Module, Debug, Timers, CurState, []); + {NewDebug, IsHib, DoAfter, NewTimers} -> + case DoAfter of + {doAfter, Args} -> + doAfterCall(Parent, Name, Module, HibernateAfterTimeout, NewDebug, NewTimers, CurState, listHib(IsHib), Args); + _ -> + case IsHib of + true -> + proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, Name, Module, HibernateAfterTimeout, NewDebug, NewTimers, CurState, IsHib]); + _ -> + receiveIng(Parent, Name, Module, HibernateAfterTimeout, NewDebug, NewTimers, CurState, false) + end + end + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% sys callbacks start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%----------------------------------------------------------------- %% Callback functions for system messages handling. %%----------------------------------------------------------------- system_continue(Parent, Debug, {Name, Module, HibernateAfterTimeout, Timers, CurState, IsHib}) -> - case IsHib of - true -> - proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, IsHib]); - _ -> - receiveIng(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, IsHib) - end. + case IsHib of + true -> + proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, IsHib]); + _ -> + receiveIng(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, IsHib) + end. -spec system_terminate(_, _, _, [_]) -> no_return(). system_terminate(Reason, _Parent, Debug, {Name, Module, _HibernateAfterTimeout, Timers, CurState, _IsHib}) -> - terminate(exit, Reason, ?STACKTRACE(), Name, Module, Debug, Timers, CurState, []). + terminate(exit, Reason, ?STACKTRACE(), Name, Module, Debug, Timers, CurState, []). system_code_change({Name, Module, HibernateAfterTimeout, Timers, CurState, IsHib}, _Module, OldVsn, Extra) -> - case - try Module:code_change(OldVsn, CurState, Extra) - catch - throw:Result -> Result; - _C:_R -> {_R, _R} - end - of - {ok, NewState} -> {ok, {Name, Module, HibernateAfterTimeout, Timers, NewState, IsHib}}; - Error -> Error - end. + case + try Module:code_change(OldVsn, CurState, Extra) + catch + throw:Result -> Result; + _C:_R -> {_R, _R} + end + of + {ok, NewState} -> {ok, {Name, Module, HibernateAfterTimeout, Timers, NewState, IsHib}}; + Error -> Error + end. system_get_state({_Name, _Module, _HibernateAfterTimeout, _Timers, CurState, _IsHib}) -> - {ok, CurState}. + {ok, CurState}. system_replace_state(StateFun, {Name, Module, HibernateAfterTimeout, Timers, CurState, IsHib}) -> - NewState = StateFun(CurState), - {ok, NewState, {Name, Module, HibernateAfterTimeout, Timers, NewState, IsHib}}. + NewState = StateFun(CurState), + {ok, NewState, {Name, Module, HibernateAfterTimeout, Timers, NewState, IsHib}}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% sys callbacks end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% API helpers start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -335,21 +336,90 @@ system_replace_state(StateFun, {Name, Module, HibernateAfterTimeout, Timers, Cur %% is handled here (? Shall we do that here (or rely on timeouts) ?). -spec call(ServerRef :: serverRef(), Request :: term()) -> Reply :: term(). call(ServerRef, Request) -> - try gen_call:call(ServerRef, '$gen_call', Request) of - {ok, Reply} -> - Reply - catch Class:Reason -> - erlang:raise(Class, {Reason, {?MODULE, call, [ServerRef, Request]}}, ?STACKTRACE()) - end. + try gen_call:call(ServerRef, '$gen_call', Request) of + {ok, Reply} -> + Reply + catch Class:Reason -> + erlang:raise(Class, {Reason, {?MODULE, call, [ServerRef, Request]}}, ?STACKTRACE()) + end. -spec call(ServerRef :: serverRef(), Request :: term(), Timeout :: timeout()) -> Reply :: term(). call(ServerRef, Request, Timeout) -> - try gen_call:call(ServerRef, '$gen_call', Request, Timeout) of - {ok, Reply} -> - Reply - catch Class:Reason -> - erlang:raise(Class, {Reason, {?MODULE, call, [ServerRef, Request]}}, ?STACKTRACE()) - end. + try gen_call:call(ServerRef, '$gen_call', Request, Timeout) of + {ok, Reply} -> + Reply + catch Class:Reason -> + erlang:raise(Class, {Reason, {?MODULE, call, [ServerRef, Request]}}, ?STACKTRACE()) + end. + +clfn(ServerRef, M, F, A) -> + try gen_call:call(ServerRef, '$gen_clfn', {M, F, A}) of + {ok, Reply} -> + Reply + catch Class:Reason -> + erlang:raise(Class, {Reason, {?MODULE, clfn, [ServerRef, {M, F, A}]}}, ?STACKTRACE()) + end. + +clfn(ServerRef, M, F, A, Timeout) -> + try gen_call:call(ServerRef, '$gen_clfn', {M, F, A}, Timeout) of + {ok, Reply} -> + Reply + catch Class:Reason -> + erlang:raise(Class, {Reason, {?MODULE, clfn, [ServerRef, {M, F, A}]}}, ?STACKTRACE()) + end. + +clfs(ServerRef, M, F, A) -> + try gen_call:call(ServerRef, '$gen_clfs', {M, F, A}) of + {ok, Reply} -> + Reply + catch Class:Reason -> + erlang:raise(Class, {Reason, {?MODULE, clfs, [ServerRef, {M, F, A}]}}, ?STACKTRACE()) + end. + +clfs(ServerRef, M, F, A, Timeout) -> + try gen_call:call(ServerRef, '$gen_clfs', {M, F, A}, Timeout) of + {ok, Reply} -> + Reply + catch Class:Reason -> + erlang:raise(Class, {Reason, {?MODULE, clfs, [ServerRef, {M, F, A}]}}, ?STACKTRACE()) + end. + +csfs(ServerRef, M, F, A) -> + csfs(ServerRef, {'$gen_csfs', {M, F, A}}). + +-spec csfn(ServerRef :: serverRef(), Msg :: term()) -> ok. +csfn({global, Name}, M, F, A) -> + try global:send(Name, {'$gen_csfn', {M, F, A}}), + ok + catch _:_ -> ok + end; +csfn({via, RegMod, Name}, M, F, A) -> + try RegMod:send(Name, {'$gen_csfn', {M, F, A}}), + ok + catch _:_ -> ok + end; +csfn(Dest, M, F, A) -> + try erlang:send(Dest, {'$gen_csfn', {M, F, A}}), + ok + catch _:_ -> ok + end. + +-spec csfs(ServerRef :: serverRef(), Msg :: term()) -> ok. +csfs({global, Name}, M, F, A) -> + try global:send(Name, {'$gen_csfs', {M, F, A}}), + ok + catch _:_ -> ok + end; +csfs({via, RegMod, Name}, M, F, A) -> + try RegMod:send(Name, {'$gen_csfs', {M, F, A}}), + ok + catch _:_ -> ok + end; +csfs(Dest, M, F, A) -> + try erlang:send(Dest, {'$gen_csfs', {M, F, A}}), + ok + catch _:_ -> ok + end. %%% ----------------------------------------------------------------- %%% Make a call to servers at several nodes. @@ -363,109 +433,109 @@ call(ServerRef, Request, Timeout) -> %%% ----------------------------------------------------------------- multi_call(Name, Request) when is_atom(Name) -> - do_multi_call([node() | nodes()], Name, Request, infinity). + do_multi_call([node() | nodes()], Name, Request, infinity). multi_call(Nodes, Name, Request) when is_list(Nodes), is_atom(Name) -> - do_multi_call(Nodes, Name, Request, infinity). + do_multi_call(Nodes, Name, Request, infinity). multi_call(Nodes, Name, Request, infinity) -> - do_multi_call(Nodes, Name, Request, infinity); + do_multi_call(Nodes, Name, Request, infinity); multi_call(Nodes, Name, Request, Timeout) when is_list(Nodes), is_atom(Name), is_integer(Timeout), Timeout >= 0 -> - do_multi_call(Nodes, Name, Request, Timeout). + do_multi_call(Nodes, Name, Request, Timeout). do_multi_call([Node], Name, Req, infinity) when Node =:= node() -> - % Special case when multi_call is used with local node only. - % In that case we can leverage the benefit of recv_mark optimisation - % existing in simple gen_call:call. - try gen_call:call(Name, '$gen_call', Req, infinity) of - {ok, Res} -> {[{Node, Res}], []} - catch exit:_ -> - {[], [Node]} - end; + % Special case when multi_call is used with local node only. + % In that case we can leverage the benefit of recv_mark optimisation + % existing in simple gen_call:call. + try gen_call:call(Name, '$gen_call', Req, infinity) of + {ok, Res} -> {[{Node, Res}], []} + catch exit:_ -> + {[], [Node]} + end; do_multi_call(Nodes, Name, Request, infinity) -> - Tag = make_ref(), - Monitors = send_nodes(Nodes, Name, Tag, Request), - rec_nodes(Tag, Monitors, Name, undefined); + Tag = make_ref(), + Monitors = send_nodes(Nodes, Name, Tag, Request), + rec_nodes(Tag, Monitors, Name, undefined); do_multi_call(Nodes, Name, Request, Timeout) -> - Tag = make_ref(), - Caller = self(), - Receiver = spawn( - fun() -> - process_flag(trap_exit, true), - Mref = erlang:monitor(process, Caller), - receive - {Caller, Tag} -> - Monitors = send_nodes(Nodes, Name, Tag, Request), - TimerId = erlang:start_timer(Timeout, self(), ok), - Result = rec_nodes(Tag, Monitors, Name, TimerId), - exit({self(), Tag, Result}); - {'DOWN', Mref, _, _, _} -> - exit(normal) - end - end - ), - Mref = erlang:monitor(process, Receiver), - Receiver ! {self(), Tag}, - receive - {'DOWN', Mref, _, _, {Receiver, Tag, Result}} -> - Result; - {'DOWN', Mref, _, _, Reason} -> - exit(Reason) - end. + Tag = make_ref(), + Caller = self(), + Receiver = spawn( + fun() -> + process_flag(trap_exit, true), + Mref = erlang:monitor(process, Caller), + receive + {Caller, Tag} -> + Monitors = send_nodes(Nodes, Name, Tag, Request), + TimerId = erlang:start_timer(Timeout, self(), ok), + Result = rec_nodes(Tag, Monitors, Name, TimerId), + exit({self(), Tag, Result}); + {'DOWN', Mref, _, _, _} -> + exit(normal) + end + end + ), + Mref = erlang:monitor(process, Receiver), + Receiver ! {self(), Tag}, + receive + {'DOWN', Mref, _, _, {Receiver, Tag, Result}} -> + Result; + {'DOWN', Mref, _, _, Reason} -> + exit(Reason) + end. -spec cast(ServerRef :: serverRef(), Msg :: term()) -> ok. cast({global, Name}, Msg) -> - try global:send(Name, {'$gen_cast', Msg}), - ok - catch _:_ -> ok - end; + try global:send(Name, {'$gen_cast', Msg}), + ok + catch _:_ -> ok + end; cast({via, RegMod, Name}, Msg) -> - try RegMod:send(Name, {'$gen_cast', Msg}), - ok - catch _:_ -> ok - end; + try RegMod:send(Name, {'$gen_cast', Msg}), + ok + catch _:_ -> ok + end; cast(Dest, Msg) -> - try erlang:send(Dest, {'$gen_cast', Msg}), - ok - catch _:_ -> ok - end. + try erlang:send(Dest, {'$gen_cast', Msg}), + ok + catch _:_ -> ok + end. -spec send(ServerRef :: serverRef(), Msg :: term()) -> ok. send({global, Name}, Msg) -> - try global:send(Name, Msg), - ok - catch _:_ -> ok - end; + try global:send(Name, Msg), + ok + catch _:_ -> ok + end; send({via, RegMod, Name}, Msg) -> - try RegMod:send(Name, Msg), - ok - catch _:_ -> ok - end; + try RegMod:send(Name, Msg), + ok + catch _:_ -> ok + end; send(Dest, Msg) -> - try erlang:send(Dest, Msg), - ok - catch _:_ -> ok - end. + try erlang:send(Dest, Msg), + ok + catch _:_ -> ok + end. %% 异步广播,不返回任何内容,只是发送“ n”祈祷 abcast(Name, Msg) when is_atom(Name) -> - doAbcast([node() | nodes()], Name, Msg). + doAbcast([node() | nodes()], Name, Msg). abcast(Nodes, Name, Msg) when is_list(Nodes), is_atom(Name) -> - doAbcast(Nodes, Name, Msg). + doAbcast(Nodes, Name, Msg). doAbcast(Nodes, Name, Msg) -> - [ - begin - try erlang:send({Name, Node}, {'$gen_cast', Msg}), - ok - catch - _:_ -> ok - end - end || Node <- Nodes - ], - ok. + [ + begin + try erlang:send({Name, Node}, {'$gen_cast', Msg}), + ok + catch + _:_ -> ok + end + end || Node <- Nodes + ], + ok. %% ----------------------------------------------------------------- %% Send a reply to the client. @@ -473,33 +543,33 @@ doAbcast(Nodes, Name, Msg) -> %% Reply from a status machine callback to whom awaits in call/2 -spec reply([replyAction(), ...] | replyAction()) -> ok. reply({reply, {To, Tag}, Reply}) -> - try To ! {Tag, Reply}, - ok - catch _:_ -> - ok - end; + try To ! {Tag, Reply}, + ok + catch _:_ -> + ok + end; reply(Replies) when is_list(Replies) -> - [ - begin - try To ! {Tag, Reply}, - ok - catch _:_ -> - ok - end - end || {reply, {To, Tag}, Reply} <- Replies - ], - ok. + [ + begin + try To ! {Tag, Reply}, + ok + catch _:_ -> + ok + end + end || {reply, {To, Tag}, Reply} <- Replies + ], + ok. -spec reply(From :: from(), Reply :: term()) -> ok. reply({_To, [alias | Alias] = Tag}, Reply) -> - Alias ! {Tag, Reply}, - ok; + Alias ! {Tag, Reply}, + ok; reply({To, Tag}, Reply) -> - try To ! {Tag, Reply}, - ok - catch _:_ -> - ok - end. + try To ! {Tag, Reply}, + ok + catch _:_ -> + ok + end. %% ----------------------------------------------------------------- %% Send a request to a generic server and return a Key which should be @@ -508,33 +578,33 @@ reply({To, Tag}, Reply) -> -spec send_request(Name :: serverRef(), Request :: term()) -> requestId(). send_request(Name, Request) -> - gen:send_request(Name, '$gen_call', Request). + gen:send_request(Name, '$gen_call', Request). -spec wait_response(RequestId :: requestId(), timeout()) -> - {reply, Reply :: term()} | 'timeout' | {error, {Reason :: term(), serverRef()}}. + {reply, Reply :: term()} | 'timeout' | {error, {Reason :: term(), serverRef()}}. wait_response(RequestId, Timeout) -> - gen:wait_response(RequestId, Timeout). + gen:wait_response(RequestId, Timeout). -spec receive_response(RequestId :: requestId(), timeout()) -> {reply, Reply :: term()} | 'timeout' | {error, {Reason :: term(), serverRef()}}. receive_response(RequestId, Timeout) -> - gen:receive_response(RequestId, Timeout). + gen:receive_response(RequestId, Timeout). -spec check_response(Msg :: term(), RequestId :: requestId()) -> - {reply, Reply :: term()} | 'no_reply' | {error, {Reason :: term(), serverRef()}}. + {reply, Reply :: term()} | 'no_reply' | {error, {Reason :: term(), serverRef()}}. check_response(Msg, RequestId) -> - gen:check_response(Msg, RequestId). + gen:check_response(Msg, RequestId). send_nodes(Nodes, Name, Tag, Request) -> - [ - begin - Monitor = start_monitor(Node, Name), - try {Name, Node} ! {'$gen_call', {self(), {Tag, Node}}, Request}, - ok - catch _:_ -> ok - end, - Monitor - end || Node <- Nodes, is_atom(Node) - ]. + [ + begin + Monitor = start_monitor(Node, Name), + try {Name, Node} ! {'$gen_call', {self(), {Tag, Node}}, Request}, + ok + catch _:_ -> ok + end, + Monitor + end || Node <- Nodes, is_atom(Node) + ]. %% Against old nodes: %% If no reply has been delivered within 2 secs. (per node) check that @@ -544,358 +614,362 @@ send_nodes(Nodes, Name, Tag, Request) -> %% Wait for reply, server 'DOWN', or timeout from TimerId. rec_nodes(Tag, Nodes, Name, TimerId) -> - rec_nodes(Tag, Nodes, Name, [], [], 2000, TimerId). + rec_nodes(Tag, Nodes, Name, [], [], 2000, TimerId). rec_nodes(Tag, [{N, R} | Tail], Name, Badnodes, Replies, Time, TimerId) -> - receive - {'DOWN', R, _, _, _} -> - rec_nodes(Tag, Tail, Name, [N | Badnodes], Replies, Time, TimerId); - {{Tag, N}, Reply} -> %% Tag is bound !!! - erlang:demonitor(R, [flush]), - rec_nodes(Tag, Tail, Name, Badnodes, - [{N, Reply} | Replies], Time, TimerId); - {timeout, TimerId, _} -> - erlang:demonitor(R, [flush]), - %% Collect all replies that already have arrived - rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies) - end; + receive + {'DOWN', R, _, _, _} -> + rec_nodes(Tag, Tail, Name, [N | Badnodes], Replies, Time, TimerId); + {{Tag, N}, Reply} -> %% Tag is bound !!! + erlang:demonitor(R, [flush]), + rec_nodes(Tag, Tail, Name, Badnodes, + [{N, Reply} | Replies], Time, TimerId); + {timeout, TimerId, _} -> + erlang:demonitor(R, [flush]), + %% Collect all replies that already have arrived + rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies) + end; rec_nodes(Tag, [N | Tail], Name, Badnodes, Replies, Time, TimerId) -> - %% R6 node - receive - {nodedown, N} -> - monitor_node(N, false), - rec_nodes(Tag, Tail, Name, [N | Badnodes], Replies, 2000, TimerId); - {{Tag, N}, Reply} -> %% Tag is bound !!! - receive {nodedown, N} -> ok after 0 -> ok end, - monitor_node(N, false), - rec_nodes(Tag, Tail, Name, Badnodes, - [{N, Reply} | Replies], 2000, TimerId); - {timeout, TimerId, _} -> - receive {nodedown, N} -> ok after 0 -> ok end, - monitor_node(N, false), - %% Collect all replies that already have arrived - rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies) - after Time -> - case erpc:call(N, erlang, whereis, [Name]) of - Pid when is_pid(Pid) -> % It exists try again. - rec_nodes(Tag, [N | Tail], Name, Badnodes, - Replies, infinity, TimerId); - _ -> % badnode - receive {nodedown, N} -> ok after 0 -> ok end, - monitor_node(N, false), - rec_nodes(Tag, Tail, Name, [N | Badnodes], - Replies, 2000, TimerId) - end - end; + %% R6 node + receive + {nodedown, N} -> + monitor_node(N, false), + rec_nodes(Tag, Tail, Name, [N | Badnodes], Replies, 2000, TimerId); + {{Tag, N}, Reply} -> %% Tag is bound !!! + receive {nodedown, N} -> ok after 0 -> ok end, + monitor_node(N, false), + rec_nodes(Tag, Tail, Name, Badnodes, + [{N, Reply} | Replies], 2000, TimerId); + {timeout, TimerId, _} -> + receive {nodedown, N} -> ok after 0 -> ok end, + monitor_node(N, false), + %% Collect all replies that already have arrived + rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies) + after Time -> + case erpc:call(N, erlang, whereis, [Name]) of + Pid when is_pid(Pid) -> % It exists try again. + rec_nodes(Tag, [N | Tail], Name, Badnodes, + Replies, infinity, TimerId); + _ -> % badnode + receive {nodedown, N} -> ok after 0 -> ok end, + monitor_node(N, false), + rec_nodes(Tag, Tail, Name, [N | Badnodes], + Replies, 2000, TimerId) + end + end; rec_nodes(_, [], _, Badnodes, Replies, _, TimerId) -> - case catch erlang:cancel_timer(TimerId) of - false -> % It has already sent it's message - receive - {timeout, TimerId, _} -> ok - after 0 -> - ok - end; - _ -> % Timer was cancelled, or TimerId was 'undefined' - ok - end, - {Replies, Badnodes}. + case catch erlang:cancel_timer(TimerId) of + false -> % It has already sent it's message + receive + {timeout, TimerId, _} -> ok + after 0 -> + ok + end; + _ -> % Timer was cancelled, or TimerId was 'undefined' + ok + end, + {Replies, Badnodes}. %% Collect all replies that already have arrived rec_nodes_rest(Tag, [{N, R} | Tail], Name, Badnodes, Replies) -> - receive - {'DOWN', R, _, _, _} -> - rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies); - {{Tag, N}, Reply} -> %% Tag is bound !!! - erlang:demonitor(R, [flush]), - rec_nodes_rest(Tag, Tail, Name, Badnodes, [{N, Reply} | Replies]) - after 0 -> - erlang:demonitor(R, [flush]), - rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies) - end; + receive + {'DOWN', R, _, _, _} -> + rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies); + {{Tag, N}, Reply} -> %% Tag is bound !!! + erlang:demonitor(R, [flush]), + rec_nodes_rest(Tag, Tail, Name, Badnodes, [{N, Reply} | Replies]) + after 0 -> + erlang:demonitor(R, [flush]), + rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies) + end; rec_nodes_rest(Tag, [N | Tail], Name, Badnodes, Replies) -> - %% R6 node - receive - {nodedown, N} -> - monitor_node(N, false), - rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies); - {{Tag, N}, Reply} -> %% Tag is bound !!! - receive {nodedown, N} -> ok after 0 -> ok end, - monitor_node(N, false), - rec_nodes_rest(Tag, Tail, Name, Badnodes, [{N, Reply} | Replies]) - after 0 -> - receive {nodedown, N} -> ok after 0 -> ok end, - monitor_node(N, false), - rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies) - end; + %% R6 node + receive + {nodedown, N} -> + monitor_node(N, false), + rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies); + {{Tag, N}, Reply} -> %% Tag is bound !!! + receive {nodedown, N} -> ok after 0 -> ok end, + monitor_node(N, false), + rec_nodes_rest(Tag, Tail, Name, Badnodes, [{N, Reply} | Replies]) + after 0 -> + receive {nodedown, N} -> ok after 0 -> ok end, + monitor_node(N, false), + rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies) + end; rec_nodes_rest(_Tag, [], _Name, Badnodes, Replies) -> - {Replies, Badnodes}. + {Replies, Badnodes}. start_monitor(Node, Name) when is_atom(Node), is_atom(Name) -> - if node() =:= nonode@nohost, Node =/= nonode@nohost -> - Ref = make_ref(), - self() ! {'DOWN', Ref, process, {Name, Node}, noconnection}, - {Node, Ref}; - true -> - case catch erlang:monitor(process, {Name, Node}) of - {'EXIT', _} -> - %% Remote node is R6 - monitor_node(Node, true), - Node; - Ref when is_reference(Ref) -> - {Node, Ref} - end - end. + if node() =:= nonode@nohost, Node =/= nonode@nohost -> + Ref = make_ref(), + self() ! {'DOWN', Ref, process, {Name, Node}, noconnection}, + {Node, Ref}; + true -> + case catch erlang:monitor(process, {Name, Node}) of + {'EXIT', _} -> + %% Remote node is R6 + monitor_node(Node, true), + Node; + Ref when is_reference(Ref) -> + {Node, Ref} + end + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% API helpers end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% receiveIng(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, IsHib) -> - receive - Msg -> - case Msg of - {'$gen_call', From, Request} -> - matchCallMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, From, Request); + receive + Msg -> + case Msg of + {'$gen_call', From, Request} -> + matchCallMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, From, Request); + {'$gen_cast', Cast} -> + matchCastMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, Cast); + {'$gen_cast', Cast} -> matchCastMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, Cast); - {timeout, TimerRef, TimeoutName} -> - case Timers of - #{TimeoutName := {TimerRef, TimeoutMsg}} -> - NewTimer = maps:remove(TimeoutName, Timers), - matchInfoMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, NewTimer, CurState, TimeoutMsg); - _ -> - matchInfoMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, Msg) - end; - {system, PidFrom, Request} -> - %% 不返回但尾递归调用 system_continue/3 - sys:handle_system_msg(Request, PidFrom, Parent, ?MODULE, Debug, {Name, Module, HibernateAfterTimeout, Timers, CurState, IsHib}, IsHib); - {'EXIT', Parent, Reason} -> - terminate(exit, Reason, ?STACKTRACE(), Name, Module, Debug, Timers, CurState, Msg); - _ -> - matchInfoMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, Msg) - end - after HibernateAfterTimeout -> - proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState]) - end. + + {timeout, TimerRef, TimeoutName} -> + case Timers of + #{TimeoutName := {TimerRef, TimeoutMsg}} -> + NewTimer = maps:remove(TimeoutName, Timers), + matchInfoMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, NewTimer, CurState, TimeoutMsg); + _ -> + matchInfoMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, Msg) + end; + {system, PidFrom, Request} -> + %% 不返回但尾递归调用 system_continue/3 + sys:handle_system_msg(Request, PidFrom, Parent, ?MODULE, Debug, {Name, Module, HibernateAfterTimeout, Timers, CurState, IsHib}, IsHib); + {'EXIT', Parent, Reason} -> + terminate(exit, Reason, ?STACKTRACE(), Name, Module, Debug, Timers, CurState, Msg); + _ -> + matchInfoMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, Msg) + end + after HibernateAfterTimeout -> + proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState]) + end. matchCallMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, From, Request) -> - NewDebug = ?SYS_DEBUG(Debug, Name, {in, {{call, From}, Request}}), - try - case is_tuple(Request) of - true -> - FunName = element(1, Request), - Module:FunName(Request, CurState, From); - _ -> - Module:Request(Request, CurState, From) - end - of - Result -> - handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, From) - catch - throw:Result -> - handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, From); - Class:Reason:Strace -> - terminate(Class, Reason, Strace, Name, Module, NewDebug, Timers, CurState, {{call, From}, Request}) - end. + NewDebug = ?SYS_DEBUG(Debug, Name, {in, {{call, From}, Request}}), + try + case is_tuple(Request) of + true -> + FunName = element(1, Request), + Module:FunName(Request, CurState, From); + _ -> + Module:Request(Request, CurState, From) + end + of + Result -> + handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, From) + catch + throw:Result -> + handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, From); + Class:Reason:Strace -> + terminate(Class, Reason, Strace, Name, Module, NewDebug, Timers, CurState, {{call, From}, Request}) + end. matchCastMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, Cast) -> - NewDebug = ?SYS_DEBUG(Debug, Name, {in, {cast, Cast}}), - try - case is_tuple(Cast) of - true -> - FunName = element(1, Cast), - Module:FunName(Cast, CurState); - _ -> - Module:Cast(Cast, CurState) - end - of - Result -> - handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, false) - catch - throw:Result -> - handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, false); - Class:Reason:Strace -> - terminate(Class, Reason, Strace, Name, Module, NewDebug, Timers, CurState, {cast, Cast}) - end. + NewDebug = ?SYS_DEBUG(Debug, Name, {in, {cast, Cast}}), + try + case is_tuple(Cast) of + true -> + FunName = element(1, Cast), + Module:FunName(Cast, CurState); + _ -> + Module:Cast(Cast, CurState) + end + of + Result -> + handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, false) + catch + throw:Result -> + handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, false); + Class:Reason:Strace -> + terminate(Class, Reason, Strace, Name, Module, NewDebug, Timers, CurState, {cast, Cast}) + end. matchInfoMsg(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, Msg) -> - NewDebug = ?SYS_DEBUG(Debug, Name, {in, {info, Msg}}), - try Module:handleInfo(Msg, CurState) of - Result -> - handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, false) - catch - throw:Result -> - handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, false); - Class:Reason:Strace -> - terminate(Class, Reason, Strace, Name, Module, NewDebug, Timers, CurState, {info, Msg}) - end. + NewDebug = ?SYS_DEBUG(Debug, Name, {in, {info, Msg}}), + try Module:handleInfo(Msg, CurState) of + Result -> + handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, false) + catch + throw:Result -> + handleCR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, Result, false); + Class:Reason:Strace -> + terminate(Class, Reason, Strace, Name, Module, NewDebug, Timers, CurState, {info, Msg}) + end. doAfterCall(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, LeftAction, Args) -> - NewDebug = ?SYS_DEBUG(Debug, Name, {in, {doAfter, Args}}), - try Module:handleAfter(Args, CurState) of - Result -> - handleAR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, LeftAction, Result) - catch - throw:Result -> - handleAR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, LeftAction, Result); - Class:Reason:Strace -> - terminate(Class, Reason, Strace, Name, Module, NewDebug, Timers, CurState, {doAfter, Args}) - end. + NewDebug = ?SYS_DEBUG(Debug, Name, {in, {doAfter, Args}}), + try Module:handleAfter(Args, CurState) of + Result -> + handleAR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, LeftAction, Result) + catch + throw:Result -> + handleAR(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, LeftAction, Result); + Class:Reason:Strace -> + terminate(Class, Reason, Strace, Name, Module, NewDebug, Timers, CurState, {doAfter, Args}) + end. handleCR(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, Result, From) -> - case Result of - kpS -> - receiveIng(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, false); - {reply, Reply} -> - reply(From, Reply), - NewDebug = ?SYS_DEBUG(Debug, Name, {out, Reply, From, CurState}), - receiveIng(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, false); - {noreply, NewState} -> - receiveIng(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, NewState, false); - {reply, Reply, NewState} -> - reply(From, Reply), - NewDebug = ?SYS_DEBUG(Debug, Name, {out, Reply, From, NewState}), - receiveIng(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, NewState, false); - {noreply, NewState, Actions} -> - loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, NewState, listify(Actions)); - {stop, Reason, NewState} -> - terminate(exit, Reason, ?STACKTRACE(), Name, Module, Debug, Timers, NewState, {return, stop}); - {reply, Reply, NewState, Actions} -> - reply(From, Reply), - NewDebug = ?SYS_DEBUG(Debug, Name, {out, Reply, From, NewState}), - loopEntry(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, NewState, listify(Actions)); - {stopReply, Reason, Reply, NewState} -> - NewDebug = ?SYS_DEBUG(Debug, Name, {out, Reply, From, NewState}), - try - terminate(exit, Reason, ?STACKTRACE(), Name, Module, NewDebug, Timers, NewState, {return, stop_reply}) - after - _ = reply(From, Reply) - end - end. + case Result of + kpS -> + receiveIng(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, false); + {reply, Reply} -> + reply(From, Reply), + NewDebug = ?SYS_DEBUG(Debug, Name, {out, Reply, From, CurState}), + receiveIng(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, CurState, false); + {noreply, NewState} -> + receiveIng(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, NewState, false); + {reply, Reply, NewState} -> + reply(From, Reply), + NewDebug = ?SYS_DEBUG(Debug, Name, {out, Reply, From, NewState}), + receiveIng(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, NewState, false); + {noreply, NewState, Actions} -> + loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, NewState, listify(Actions)); + {stop, Reason, NewState} -> + terminate(exit, Reason, ?STACKTRACE(), Name, Module, Debug, Timers, NewState, {return, stop}); + {reply, Reply, NewState, Actions} -> + reply(From, Reply), + NewDebug = ?SYS_DEBUG(Debug, Name, {out, Reply, From, NewState}), + loopEntry(Parent, Name, Module, HibernateAfterTimeout, NewDebug, Timers, NewState, listify(Actions)); + {stopReply, Reason, Reply, NewState} -> + NewDebug = ?SYS_DEBUG(Debug, Name, {out, Reply, From, NewState}), + try + terminate(exit, Reason, ?STACKTRACE(), Name, Module, NewDebug, Timers, NewState, {return, stop_reply}) + after + _ = reply(From, Reply) + end + end. handleAR(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, LeftAction, Result) -> - case Result of - kpS -> - loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, LeftAction); - {noreply, NewState} -> - loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, NewState, LeftAction); - {noreply, NewState, Actions} -> - loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, NewState, listify(Actions) ++ LeftAction); - {stop, Reason, NewState} -> - terminate(exit, Reason, ?STACKTRACE(), Name, Module, Debug, Timers, NewState, {return, stop_reply}) - end. + case Result of + kpS -> + loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, CurState, LeftAction); + {noreply, NewState} -> + loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, NewState, LeftAction); + {noreply, NewState, Actions} -> + loopEntry(Parent, Name, Module, HibernateAfterTimeout, Debug, Timers, NewState, listify(Actions) ++ LeftAction); + {stop, Reason, NewState} -> + terminate(exit, Reason, ?STACKTRACE(), Name, Module, Debug, Timers, NewState, {return, stop_reply}) + end. %% loopParseActionsList doParseAL([], _Name, Debug, IsHib, DoAfter, Timers) -> - {Debug, IsHib, DoAfter, Timers}; + {Debug, IsHib, DoAfter, Timers}; doParseAL([OneAction | LeftActions], Name, Debug, IsHib, DoAfter, Timers) -> - case OneAction of - hibernate -> - doParseAL(LeftActions, Name, Debug, true, DoAfter, Timers); - {'doAfter', _Args} -> - doParseAL(LeftActions, Name, Debug, IsHib, OneAction, Timers); - {'nTimeout', TimeoutName, Time, TimeoutMsg, Options} -> - case Time of - infinity -> - NewTimers = doCancelTimer(TimeoutName, Timers), - doParseAL(LeftActions, Name, Debug, IsHib, DoAfter, NewTimers); - _ -> - TimerRef = erlang:start_timer(Time, self(), TimeoutName, Options), - NewDebug = ?SYS_DEBUG(Debug, Name, {start_timer, {TimeoutName, Time, TimeoutMsg, Options}}), - NewTimers = doRegisterTimer(TimeoutName, TimerRef, TimeoutMsg, Timers), - doParseAL(LeftActions, Name, NewDebug, IsHib, DoAfter, NewTimers) - end; - {'nTimeout', TimeoutName, Time, TimeoutMsg} -> - case Time of - infinity -> - NewTimers = doCancelTimer(TimeoutName, Timers), - doParseAL(LeftActions, Name, Debug, IsHib, DoAfter, NewTimers); - _ -> - TimerRef = erlang:start_timer(Time, self(), TimeoutName), - NewDebug = ?SYS_DEBUG(Debug, Name, {start_timer, {TimeoutName, Time, TimeoutMsg, []}}), - NewTimers = doRegisterTimer(TimeoutName, TimerRef, TimeoutMsg, Timers), - doParseAL(LeftActions, Name, NewDebug, IsHib, DoAfter, NewTimers) - end; - {'uTimeout', TimeoutName, NewTimeoutMsg} -> - NewTimers = doUpdateTimer(TimeoutName, NewTimeoutMsg, Timers), - doParseAL(LeftActions, Name, Debug, IsHib, DoAfter, NewTimers); - {'cTimeout', TimeoutName} -> - NewTimers = doCancelTimer(TimeoutName, Timers), - doParseAL(LeftActions, Name, Debug, IsHib, DoAfter, NewTimers); - infinity -> - doParseAL(LeftActions, Name, Debug, IsHib, DoAfter, Timers); - Timeout when is_integer(Timeout) -> - erlang:send_after(Timeout, self(), timeout), - NewDebug = ?SYS_DEBUG(Debug, Name, {start_timer, {timeout, Timeout, timeout, []}}), - doParseAL(LeftActions, Name, NewDebug, IsHib, DoAfter, Timers); - _ -> - {error, {bad_ActionType, OneAction}} - end. + case OneAction of + hibernate -> + doParseAL(LeftActions, Name, Debug, true, DoAfter, Timers); + {'doAfter', _Args} -> + doParseAL(LeftActions, Name, Debug, IsHib, OneAction, Timers); + {'nTimeout', TimeoutName, Time, TimeoutMsg, Options} -> + case Time of + infinity -> + NewTimers = doCancelTimer(TimeoutName, Timers), + doParseAL(LeftActions, Name, Debug, IsHib, DoAfter, NewTimers); + _ -> + TimerRef = erlang:start_timer(Time, self(), TimeoutName, Options), + NewDebug = ?SYS_DEBUG(Debug, Name, {start_timer, {TimeoutName, Time, TimeoutMsg, Options}}), + NewTimers = doRegisterTimer(TimeoutName, TimerRef, TimeoutMsg, Timers), + doParseAL(LeftActions, Name, NewDebug, IsHib, DoAfter, NewTimers) + end; + {'nTimeout', TimeoutName, Time, TimeoutMsg} -> + case Time of + infinity -> + NewTimers = doCancelTimer(TimeoutName, Timers), + doParseAL(LeftActions, Name, Debug, IsHib, DoAfter, NewTimers); + _ -> + TimerRef = erlang:start_timer(Time, self(), TimeoutName), + NewDebug = ?SYS_DEBUG(Debug, Name, {start_timer, {TimeoutName, Time, TimeoutMsg, []}}), + NewTimers = doRegisterTimer(TimeoutName, TimerRef, TimeoutMsg, Timers), + doParseAL(LeftActions, Name, NewDebug, IsHib, DoAfter, NewTimers) + end; + {'uTimeout', TimeoutName, NewTimeoutMsg} -> + NewTimers = doUpdateTimer(TimeoutName, NewTimeoutMsg, Timers), + doParseAL(LeftActions, Name, Debug, IsHib, DoAfter, NewTimers); + {'cTimeout', TimeoutName} -> + NewTimers = doCancelTimer(TimeoutName, Timers), + doParseAL(LeftActions, Name, Debug, IsHib, DoAfter, NewTimers); + infinity -> + doParseAL(LeftActions, Name, Debug, IsHib, DoAfter, Timers); + Timeout when is_integer(Timeout) -> + erlang:send_after(Timeout, self(), timeout), + NewDebug = ?SYS_DEBUG(Debug, Name, {start_timer, {timeout, Timeout, timeout, []}}), + doParseAL(LeftActions, Name, NewDebug, IsHib, DoAfter, Timers); + _ -> + {error, {bad_ActionType, OneAction}} + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% timer deal start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% doRegisterTimer(TimeoutType, NewTimerRef, TimeoutMsg, Timers) -> - case Timers of - #{TimeoutType := {OldTimerRef, _OldTimeMsg}} -> - justCancelTimer(TimeoutType, OldTimerRef), - Timers#{TimeoutType := {NewTimerRef, TimeoutMsg}}; - _ -> - Timers#{TimeoutType => {NewTimerRef, TimeoutMsg}} - end. + case Timers of + #{TimeoutType := {OldTimerRef, _OldTimeMsg}} -> + justCancelTimer(TimeoutType, OldTimerRef), + Timers#{TimeoutType := {NewTimerRef, TimeoutMsg}}; + _ -> + Timers#{TimeoutType => {NewTimerRef, TimeoutMsg}} + end. doCancelTimer(TimeoutType, Timers) -> - case Timers of - #{TimeoutType := {TimerRef, _TimeoutMsg}} -> - cancelTimer(TimeoutType, TimerRef, Timers); - _ -> - Timers - end. + case Timers of + #{TimeoutType := {TimerRef, _TimeoutMsg}} -> + cancelTimer(TimeoutType, TimerRef, Timers); + _ -> + Timers + end. doUpdateTimer(TimeoutType, Timers, TimeoutMsg) -> - case Timers of - #{TimeoutType := {TimerRef, _OldTimeoutMsg}} -> - Timers#{TimeoutType := {TimerRef, TimeoutMsg}}; - _ -> - Timers - end. + case Timers of + #{TimeoutType := {TimerRef, _OldTimeoutMsg}} -> + Timers#{TimeoutType := {TimerRef, TimeoutMsg}}; + _ -> + Timers + end. justCancelTimer(TimeoutType, TimerRef) -> - case erlang:cancel_timer(TimerRef) of - false -> - %% 找不到计时器,我们还没有看到超时消息 - receive - {timeout, TimerRef, TimeoutType} -> - %% 丢弃该超时消息 - ok - after 0 -> - ok - end; - _ -> - %% Timer 已经运行了 - ok - end. + case erlang:cancel_timer(TimerRef) of + false -> + %% 找不到计时器,我们还没有看到超时消息 + receive + {timeout, TimerRef, TimeoutType} -> + %% 丢弃该超时消息 + ok + after 0 -> + ok + end; + _ -> + %% Timer 已经运行了 + ok + end. cancelTimer(TimeoutType, TimerRef, Timers) -> - case erlang:cancel_timer(TimerRef) of - false -> % 找不到计时器,我们还没有看到超时消息 - receive - {timeout, TimerRef, TimeoutType} -> - ok % 丢弃该超时消息 - after 0 -> - ok - end; - _ -> - ok % Timer 已经运行了 - end, - maps:remove(TimeoutType, Timers). + case erlang:cancel_timer(TimerRef) of + false -> % 找不到计时器,我们还没有看到超时消息 + receive + {timeout, TimerRef, TimeoutType} -> + ok % 丢弃该超时消息 + after 0 -> + ok + end; + _ -> + ok % Timer 已经运行了 + end, + maps:remove(TimeoutType, Timers). listify(Item) when is_list(Item) -> - Item; + Item; listify(Item) -> - [Item]. + [Item]. listHib(false) -> - []; + []; listHib(_) -> - [hibernate]. + [hibernate]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% timer deal end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -916,81 +990,81 @@ listHib(_) -> %%% for exits. %%% --------------------------------------------------- terminate(Class, Reason, Stacktrace, Name, Module, Debug, _Timers, CurState, MsgEvent) -> - Reply = try_terminate(Module, terminate_reason(Class, Reason, Stacktrace), CurState), - case Reply of - {'EXIT', C, R, S} -> - error_info({R, S}, Name, undefined, MsgEvent, Module, Debug, CurState), - erlang:raise(C, R, S); - _ -> - case {Class, Reason} of - {exit, normal} -> ok; - {exit, shutdown} -> ok; - {exit, {shutdown, _}} -> ok; - _ -> - error_info(Reason, Name, undefined, MsgEvent, Module, Debug, CurState) - end - end, - case Stacktrace of - [] -> - erlang:Class(Reason); - _ -> - erlang:raise(Class, Reason, Stacktrace) - end. + Reply = try_terminate(Module, terminate_reason(Class, Reason, Stacktrace), CurState), + case Reply of + {'EXIT', C, R, S} -> + error_info({R, S}, Name, undefined, MsgEvent, Module, Debug, CurState), + erlang:raise(C, R, S); + _ -> + case {Class, Reason} of + {exit, normal} -> ok; + {exit, shutdown} -> ok; + {exit, {shutdown, _}} -> ok; + _ -> + error_info(Reason, Name, undefined, MsgEvent, Module, Debug, CurState) + end + end, + case Stacktrace of + [] -> + erlang:Class(Reason); + _ -> + erlang:raise(Class, Reason, Stacktrace) + end. try_terminate(Mod, Reason, State) -> - case erlang:function_exported(Mod, terminate, 2) of - true -> - try - {ok, Mod:terminate(Reason, State)} - catch - throw:R -> - {ok, R}; - Class:R -> - {'EXIT', Class, R, ?STACKTRACE()} - end; - false -> - {ok, ok} - end. + case erlang:function_exported(Mod, terminate, 2) of + true -> + try + {ok, Mod:terminate(Reason, State)} + catch + throw:R -> + {ok, R}; + Class:R -> + {'EXIT', Class, R, ?STACKTRACE()} + end; + false -> + {ok, ok} + end. terminate_reason(error, Reason, Stacktrace) -> {Reason, Stacktrace}; terminate_reason(exit, Reason, _Stacktrace) -> Reason. error_info(_Reason, application_controller, _From, _Msg, _Mod, _State, _Debug) -> - %% OTP-5811 Don't send an error report if it's the system process - %% application_controller which is terminating - let init take care - %% of it instead - ok; + %% OTP-5811 Don't send an error report if it's the system process + %% application_controller which is terminating - let init take care + %% of it instead + ok; error_info(Reason, Name, From, Msg, Module, Debug, State) -> - Log = sys:get_log(Debug), - ?LOG_ERROR(#{label => {gen_apu, terminate}, - name => Name, - last_message => Msg, - state => format_status(terminate, Module, get(), State), - log => format_log_state(Module, Log), - reason => Reason, - client_info => client_stacktrace(From)}, - #{ - domain => [otp], - report_cb => fun gen_apu:format_log/2, - error_logger => #{tag => error, report_cb => fun gen_apu:format_log/1} - }), - ok. + Log = sys:get_log(Debug), + ?LOG_ERROR(#{label => {gen_apu, terminate}, + name => Name, + last_message => Msg, + state => format_status(terminate, Module, get(), State), + log => format_log_state(Module, Log), + reason => Reason, + client_info => client_stacktrace(From)}, + #{ + domain => [otp], + report_cb => fun gen_apu:format_log/2, + error_logger => #{tag => error, report_cb => fun gen_apu:format_log/1} + }), + ok. client_stacktrace(undefined) -> - undefined; + undefined; client_stacktrace({From, _Tag}) -> - client_stacktrace(From); + client_stacktrace(From); client_stacktrace(From) when is_pid(From), node(From) =:= node() -> - case process_info(From, [current_stacktrace, registered_name]) of - undefined -> - {From, dead}; - [{current_stacktrace, Stacktrace}, {registered_name, []}] -> - {From, {From, Stacktrace}}; - [{current_stacktrace, Stacktrace}, {registered_name, Name}] -> - {From, {Name, Stacktrace}} - end; + case process_info(From, [current_stacktrace, registered_name]) of + undefined -> + {From, dead}; + [{current_stacktrace, Stacktrace}, {registered_name, []}] -> + {From, {From, Stacktrace}}; + [{current_stacktrace, Stacktrace}, {registered_name, Name}] -> + {From, {Name, Stacktrace}} + end; client_stacktrace(From) when is_pid(From) -> - {From, remote}. + {From, remote}. %% format_log/1 is the report callback used by Logger handler @@ -999,221 +1073,221 @@ client_stacktrace(From) when is_pid(From) -> %% return {Format,Args} compatible with the arguments in this module's %% calls to error_logger prior to OTP-21.0. format_log(Report) -> - Depth = error_logger:get_format_depth(), - FormatOpts = #{chars_limit => unlimited, - depth => Depth, - single_line => false, - encoding => utf8}, - format_log_multi(limit_report(Report, Depth), FormatOpts). + Depth = error_logger:get_format_depth(), + FormatOpts = #{chars_limit => unlimited, + depth => Depth, + single_line => false, + encoding => utf8}, + format_log_multi(limit_report(Report, Depth), FormatOpts). limit_report(Report, unlimited) -> - Report; + Report; limit_report(#{label := {gen_apu, terminate}, - last_message := Msg, - state := State, - log := Log, - reason := Reason, - client_info := Client} = Report, - Depth) -> - Report#{ - last_message => io_lib:limit_term(Msg, Depth), - state => io_lib:limit_term(State, Depth), - log => [io_lib:limit_term(L, Depth) || L <- Log], - reason => io_lib:limit_term(Reason, Depth), - client_info => limit_client_report(Client, Depth) - }; + last_message := Msg, + state := State, + log := Log, + reason := Reason, + client_info := Client} = Report, + Depth) -> + Report#{ + last_message => io_lib:limit_term(Msg, Depth), + state => io_lib:limit_term(State, Depth), + log => [io_lib:limit_term(L, Depth) || L <- Log], + reason => io_lib:limit_term(Reason, Depth), + client_info => limit_client_report(Client, Depth) + }; limit_report(#{label := {gen_apu, no_handle_info}, - message := Msg} = Report, Depth) -> - Report#{message => io_lib:limit_term(Msg, Depth)}. + message := Msg} = Report, Depth) -> + Report#{message => io_lib:limit_term(Msg, Depth)}. limit_client_report({From, {Name, Stacktrace}}, Depth) -> - {From, {Name, io_lib:limit_term(Stacktrace, Depth)}}; + {From, {Name, io_lib:limit_term(Stacktrace, Depth)}}; limit_client_report(Client, _) -> - Client. + Client. %% format_log/2 is the report callback for any Logger handler, except %% error_logger. format_log(Report, FormatOpts0) -> - Default = #{chars_limit => unlimited, - depth => unlimited, - single_line => false, - encoding => utf8}, - FormatOpts = maps:merge(Default, FormatOpts0), - IoOpts = - case FormatOpts of - #{chars_limit := unlimited} -> - []; - #{chars_limit := Limit} -> - [{chars_limit, Limit}] - end, - {Format, Args} = format_log_single(Report, FormatOpts), - io_lib:format(Format, Args, IoOpts). + Default = #{chars_limit => unlimited, + depth => unlimited, + single_line => false, + encoding => utf8}, + FormatOpts = maps:merge(Default, FormatOpts0), + IoOpts = + case FormatOpts of + #{chars_limit := unlimited} -> + []; + #{chars_limit := Limit} -> + [{chars_limit, Limit}] + end, + {Format, Args} = format_log_single(Report, FormatOpts), + io_lib:format(Format, Args, IoOpts). format_log_single(#{label := {gen_apu, terminate}, - name := Name, - last_message := Msg, - state := State, - log := Log, - reason := Reason, - client_info := Client}, - #{single_line := true, depth := Depth} = FormatOpts) -> - P = p(FormatOpts), - Format1 = lists:append(["Generic server ", P, " terminating. Reason: ", P, - ". Last message: ", P, ". State: ", P, "."]), - {ServerLogFormat, ServerLogArgs} = format_server_log_single(Log, FormatOpts), - {ClientLogFormat, ClientLogArgs} = format_client_log_single(Client, FormatOpts), - - Args1 = - case Depth of - unlimited -> - [Name, fix_reason(Reason), Msg, State]; - _ -> - [Name, Depth, fix_reason(Reason), Depth, Msg, Depth, State, Depth] - end, - {Format1 ++ ServerLogFormat ++ ClientLogFormat, - Args1 ++ ServerLogArgs ++ ClientLogArgs}; + name := Name, + last_message := Msg, + state := State, + log := Log, + reason := Reason, + client_info := Client}, + #{single_line := true, depth := Depth} = FormatOpts) -> + P = p(FormatOpts), + Format1 = lists:append(["Generic server ", P, " terminating. Reason: ", P, + ". Last message: ", P, ". State: ", P, "."]), + {ServerLogFormat, ServerLogArgs} = format_server_log_single(Log, FormatOpts), + {ClientLogFormat, ClientLogArgs} = format_client_log_single(Client, FormatOpts), + + Args1 = + case Depth of + unlimited -> + [Name, fix_reason(Reason), Msg, State]; + _ -> + [Name, Depth, fix_reason(Reason), Depth, Msg, Depth, State, Depth] + end, + {Format1 ++ ServerLogFormat ++ ClientLogFormat, + Args1 ++ ServerLogArgs ++ ClientLogArgs}; format_log_single(#{label := {gen_apu, no_handle_info}, - module := Module, - message := Msg}, - #{single_line := true, depth := Depth} = FormatOpts) -> - P = p(FormatOpts), - Format = lists:append(["Undefined handle_info in ", P, - ". Unhandled message: ", P, "."]), - Args = - case Depth of - unlimited -> - [Module, Msg]; - _ -> - [Module, Depth, Msg, Depth] - end, - {Format, Args}; + module := Module, + message := Msg}, + #{single_line := true, depth := Depth} = FormatOpts) -> + P = p(FormatOpts), + Format = lists:append(["Undefined handle_info in ", P, + ". Unhandled message: ", P, "."]), + Args = + case Depth of + unlimited -> + [Module, Msg]; + _ -> + [Module, Depth, Msg, Depth] + end, + {Format, Args}; format_log_single(Report, FormatOpts) -> - format_log_multi(Report, FormatOpts). + format_log_multi(Report, FormatOpts). format_log_multi(#{label := {gen_apu, terminate}, - name := Name, - last_message := Msg, - state := State, - log := Log, - reason := Reason, - client_info := Client}, - #{depth := Depth} = FormatOpts) -> - Reason1 = fix_reason(Reason), - {ClientFmt, ClientArgs} = format_client_log(Client, FormatOpts), - P = p(FormatOpts), - Format = - lists:append( - ["** Generic server ", P, " terminating \n" - "** Last message in was ", P, "~n" - "** When Server state == ", P, "~n" - "** Reason for termination ==~n** ", P, "~n"] ++ - case Log of - [] -> []; - _ -> ["** Log ==~n** [" | - lists:join(",~n ", lists:duplicate(length(Log), P))] ++ - ["]~n"] - end) ++ ClientFmt, - Args = - case Depth of - unlimited -> + name := Name, + last_message := Msg, + state := State, + log := Log, + reason := Reason, + client_info := Client}, + #{depth := Depth} = FormatOpts) -> + Reason1 = fix_reason(Reason), + {ClientFmt, ClientArgs} = format_client_log(Client, FormatOpts), + P = p(FormatOpts), + Format = + lists:append( + ["** Generic server ", P, " terminating \n" + "** Last message in was ", P, "~n" + "** When Server state == ", P, "~n" + "** Reason for termination ==~n** ", P, "~n"] ++ + case Log of + [] -> []; + _ -> ["** Log ==~n** [" | + lists:join(",~n ", lists:duplicate(length(Log), P))] ++ + ["]~n"] + end) ++ ClientFmt, + Args = + case Depth of + unlimited -> [Name, Msg, State, Reason1] ++ Log ++ ClientArgs; - _ -> - [Name, Depth, Msg, Depth, State, Depth, Reason1, Depth] ++ - case Log of - [] -> []; - _ -> lists:flatmap(fun(L) -> [L, Depth] end, Log) - end ++ ClientArgs - end, - {Format, Args}; + _ -> + [Name, Depth, Msg, Depth, State, Depth, Reason1, Depth] ++ + case Log of + [] -> []; + _ -> lists:flatmap(fun(L) -> [L, Depth] end, Log) + end ++ ClientArgs + end, + {Format, Args}; format_log_multi(#{label := {gen_apu, no_handle_info}, - module := Module, - message := Msg}, - #{depth := Depth} = FormatOpts) -> - P = p(FormatOpts), - Format = - "** Undefined handle_info in ~p~n" - "** Unhandled message: " ++ P ++ "~n", - Args = - case Depth of - unlimited -> - [Module, Msg]; - _ -> - [Module, Msg, Depth] - end, - {Format, Args}. + module := Module, + message := Msg}, + #{depth := Depth} = FormatOpts) -> + P = p(FormatOpts), + Format = + "** Undefined handle_info in ~p~n" + "** Unhandled message: " ++ P ++ "~n", + Args = + case Depth of + unlimited -> + [Module, Msg]; + _ -> + [Module, Msg, Depth] + end, + {Format, Args}. fix_reason({undef, [{M, F, A, L} | MFAs]} = Reason) -> - case code:is_loaded(M) of - false -> - {'module could not be loaded', [{M, F, A, L} | MFAs]}; - _ -> - case erlang:function_exported(M, F, length(A)) of - true -> - Reason; - false -> - {'function not exported', [{M, F, A, L} | MFAs]} - end - end; + case code:is_loaded(M) of + false -> + {'module could not be loaded', [{M, F, A, L} | MFAs]}; + _ -> + case erlang:function_exported(M, F, length(A)) of + true -> + Reason; + false -> + {'function not exported', [{M, F, A, L} | MFAs]} + end + end; fix_reason(Reason) -> - Reason. + Reason. format_server_log_single([], _) -> - {"", []}; + {"", []}; format_server_log_single(Log, FormatOpts) -> - Args = - case maps:get(depth, FormatOpts) of - unlimited -> - [Log]; - Depth -> - [Log, Depth] - end, - {" Log: " ++ p(FormatOpts), Args}. + Args = + case maps:get(depth, FormatOpts) of + unlimited -> + [Log]; + Depth -> + [Log, Depth] + end, + {" Log: " ++ p(FormatOpts), Args}. format_client_log_single(undefined, _) -> - {"", []}; + {"", []}; format_client_log_single({From, dead}, _) -> - {" Client ~0p is dead.", [From]}; + {" Client ~0p is dead.", [From]}; format_client_log_single({From, remote}, _) -> - {" Client ~0p is remote on node ~0p.", [From, node(From)]}; + {" Client ~0p is remote on node ~0p.", [From, node(From)]}; format_client_log_single({_From, {Name, Stacktrace0}}, FormatOpts) -> - P = p(FormatOpts), - %% Minimize the stacktrace a bit for single line reports. This is - %% hopefully enough to point out the position. - Stacktrace = lists:sublist(Stacktrace0, 4), - Args = - case maps:get(depth, FormatOpts) of - unlimited -> - [Name, Stacktrace]; - Depth -> - [Name, Depth, Stacktrace, Depth] - end, - {" Client " ++ P ++ " stacktrace: " ++ P ++ ".", Args}. + P = p(FormatOpts), + %% Minimize the stacktrace a bit for single line reports. This is + %% hopefully enough to point out the position. + Stacktrace = lists:sublist(Stacktrace0, 4), + Args = + case maps:get(depth, FormatOpts) of + unlimited -> + [Name, Stacktrace]; + Depth -> + [Name, Depth, Stacktrace, Depth] + end, + {" Client " ++ P ++ " stacktrace: " ++ P ++ ".", Args}. format_client_log(undefined, _) -> - {"", []}; + {"", []}; format_client_log({From, dead}, _) -> - {"** Client ~p is dead~n", [From]}; + {"** Client ~p is dead~n", [From]}; format_client_log({From, remote}, _) -> - {"** Client ~p is remote on node ~p~n", [From, node(From)]}; + {"** Client ~p is remote on node ~p~n", [From, node(From)]}; format_client_log({_From, {Name, Stacktrace}}, FormatOpts) -> - P = p(FormatOpts), - Format = lists:append(["** Client ", P, " stacktrace~n", - "** ", P, "~n"]), - Args = - case maps:get(depth, FormatOpts) of - unlimited -> - [Name, Stacktrace]; - Depth -> - [Name, Depth, Stacktrace, Depth] - end, - {Format, Args}. + P = p(FormatOpts), + Format = lists:append(["** Client ", P, " stacktrace~n", + "** ", P, "~n"]), + Args = + case maps:get(depth, FormatOpts) of + unlimited -> + [Name, Stacktrace]; + Depth -> + [Name, Depth, Stacktrace, Depth] + end, + {Format, Args}. p(#{single_line := Single, depth := Depth, encoding := Enc}) -> - "~" ++ single(Single) ++ mod(Enc) ++ p(Depth); + "~" ++ single(Single) ++ mod(Enc) ++ p(Depth); p(unlimited) -> - "p"; + "p"; p(_Depth) -> - "P". + "P". single(true) -> "0"; single(false) -> "". @@ -1225,64 +1299,64 @@ mod(_) -> "t". %% Status information %%----------------------------------------------------------------- format_status(Opt, StatusData) -> - [PDict, SysState, Parent, Debug, {Name, Module, _HibernateAfterTimeout, _Timers, CurState, _IsHib}] = StatusData, - Header = gen:format_status_header("Status for generic server", Name), - Log = sys:get_log(Debug), - Specific = - case format_status(Opt, Module, PDict, CurState) of - S when is_list(S) -> S; - S -> [S] - end, - [{header, Header}, - {data, [{"Status", SysState}, - {"Parent", Parent}, - {"Logged events", format_log_state(Module, Log)}]} | - Specific]. + [PDict, SysState, Parent, Debug, {Name, Module, _HibernateAfterTimeout, _Timers, CurState, _IsHib}] = StatusData, + Header = gen:format_status_header("Status for generic server", Name), + Log = sys:get_log(Debug), + Specific = + case format_status(Opt, Module, PDict, CurState) of + S when is_list(S) -> S; + S -> [S] + end, + [{header, Header}, + {data, [{"Status", SysState}, + {"Parent", Parent}, + {"Logged events", format_log_state(Module, Log)}]} | + Specific]. format_log_state(Module, Log) -> - [case Event of - {out, Msg, From, State} -> - {out, Msg, From, format_status(terminate, Module, get(), State)}; - {noreply, State} -> - {noreply, format_status(terminate, Module, get(), State)}; - _ -> Event - end || Event <- Log]. + [case Event of + {out, Msg, From, State} -> + {out, Msg, From, format_status(terminate, Module, get(), State)}; + {noreply, State} -> + {noreply, format_status(terminate, Module, get(), State)}; + _ -> Event + end || Event <- Log]. format_status(Opt, Module, PDict, State) -> - DefStatus = - case Opt of - terminate -> State; - _ -> [{data, [{"State", State}]}] - end, - case erlang:function_exported(Module, format_status, 2) of - true -> - case catch Module:formatStatus(Opt, [PDict, State]) of - {'EXIT', _} -> DefStatus; - Else -> Else - end; - _ -> - DefStatus - end. + DefStatus = + case Opt of + terminate -> State; + _ -> [{data, [{"State", State}]}] + end, + case erlang:function_exported(Module, format_status, 2) of + true -> + case catch Module:formatStatus(Opt, [PDict, State]) of + {'EXIT', _} -> DefStatus; + Else -> Else + end; + _ -> + DefStatus + end. %%----------------------------------------------------------------- %% Format debug messages. Print them as the call-back module sees %% them, not as the real erlang messages. Use trace for that. %%----------------------------------------------------------------- print_event(Dev, {in, Msg}, Name) -> - case Msg of - {{call, {From, _Tag}}, Call} -> - io:format(Dev, "*DBG* ~tp got call ~tp from ~tw~n", - [Name, Call, From]); - {cast, Cast} -> - io:format(Dev, "*DBG* ~tp got cast ~tp~n", - [Name, Cast]); - _ -> - io:format(Dev, "*DBG* ~tp got ~tp~n", [Name, Msg]) - end; + case Msg of + {{call, {From, _Tag}}, Call} -> + io:format(Dev, "*DBG* ~tp got call ~tp from ~tw~n", + [Name, Call, From]); + {cast, Cast} -> + io:format(Dev, "*DBG* ~tp got cast ~tp~n", + [Name, Cast]); + _ -> + io:format(Dev, "*DBG* ~tp got ~tp~n", [Name, Msg]) + end; print_event(Dev, {out, Msg, {To, _Tag}, State}, Name) -> - io:format(Dev, "*DBG* ~tp sent ~tp to ~tw, new state ~tp~n", - [Name, Msg, To, State]); + io:format(Dev, "*DBG* ~tp sent ~tp to ~tw, new state ~tp~n", + [Name, Msg, To, State]); print_event(Dev, {noreply, State}, Name) -> - io:format(Dev, "*DBG* ~tp new state ~tp~n", [Name, State]); + io:format(Dev, "*DBG* ~tp new state ~tp~n", [Name, State]); print_event(Dev, Event, Name) -> - io:format(Dev, "*DBG* ~tp dbg ~tp~n", [Name, Event]). \ No newline at end of file + io:format(Dev, "*DBG* ~tp dbg ~tp~n", [Name, Event]). \ No newline at end of file