Selaa lähdekoodia

gen_srv修改

master
AICells 4 vuotta sitten
vanhempi
commit
884e208e2e
1 muutettua tiedostoa jossa 162 lisäystä ja 118 poistoa
  1. +162
    -118
      src/gen_srv.erl

+ 162
- 118
src/gen_srv.erl Näytä tiedosto

@ -29,7 +29,7 @@
, format_status/2
%% Internal callbacks
, wakeupFromHib/6
, wakeupFromHib/8
%% logger callback
, format_log/1, format_log/2
@ -97,66 +97,69 @@
Status :: term().
-optional_callbacks([
handleCall/3
, handleCast/2
, handleInfo/2
, handleAfter/2
, terminate/2
, code_change/3
, formatStatus/2
handleCall/3
, handleCast/2
, handleInfo/2
, handleAfter/2
, terminate/2
, code_change/3
, formatStatus/2
]).
-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 requestId() :: 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()} |
timeoutAction().
timeout() |
hibernate |
{'doAfter', Args :: term()} |
timeoutAction().
-type timeoutAction() ::
timeoutNewAction() |
timeoutCancelAction() |
timeoutUpdateAction().
timeoutNewAction() |
timeoutCancelAction() |
timeoutUpdateAction().
-type timeoutNewAction() ::
{'nTimeout', Name :: term(), Time :: timeouts(), EventContent :: term()} |
{'nTimeout', Name :: term(), Time :: timeouts(), EventContent :: term(), Options :: ([timeoutOption()])}.
{'nTimeout', Name :: term(), Time :: timeouts(), TimeoutMsg :: term()} |
{'nTimeout', Name :: term(), Time :: timeouts(), TimeoutMsg :: term(), Options :: ([timeoutOption()])}.
-type timeoutUpdateAction() ::
{'uTimeout', Name :: term(), EventContent :: term()}.
{'uTimeout', Name :: term(), TimeoutMsg :: term()}.
-type timeoutCancelAction() ::
{'cTimeout', Name :: term()}.
{'cTimeout', Name :: term()}.
-type timer() :: #{TimeoutName :: atom() => {TimerRef :: reference(), TimeoutMsg :: term()}}.
-type timeouts() :: Time :: timeout() | integer().
-type timeoutOption() :: {abs, Abs :: boolean()}.
%% -type timer() :: #{TimeoutName :: atom() => {TimerRef :: reference(), TimeoutMsg :: term()}}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% start stop API start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -471,26 +474,30 @@ rec_nodes_rest(_Tag, [], _Name, Badnodes, Replies) ->
%%-----------------------------------------------------------------
%% Callback functions for system messages handling.
%%-----------------------------------------------------------------
system_continue(Parent, Debug, [Name, State, Module, Time, HibernateAfterTimeout]) ->
receiveIng(Time, Parent, Name, State, Module, HibernateAfterTimeout, Debug).
system_continue(Parent, Debug, [Name, Module, HibernateAfterTimeout, CurState, Timers, IsHib]) ->
case IsHib of
true ->
proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, Name, Module, HibernateAfterTimeout, CurState, Debug, Timers, IsHib]);
_ ->
receiveIng(Parent, Name, Module, HibernateAfterTimeout, CurState, Debug, Timers, IsHib)
end.
-spec system_terminate(_, _, _, [_]) -> no_return().
system_terminate(Reason, _Parent, Debug, [Name, Module, _HibernateAfterTimeout, CurState, Timers, _IsHib]) ->
terminate(exit, Reason, ?STACKTRACE(), Name, Module, CurState, Debug, Timers, []).
system_terminate(Reason, _Parent, Debug, [Name, State, Module, _Time, _HibernateAfterTimeout]) ->
terminate(Reason, ?STACKTRACE(), Name, undefined, [], Module, State, Debug).
system_code_change([Name, State, Module, Time, HibernateAfterTimeout], _Module, OldVsn, Extra) ->
case catch Module:code_change(OldVsn, State, Extra) of
{ok, NewState} -> {ok, [Name, NewState, Module, Time, HibernateAfterTimeout]};
system_code_change([Name, Module, HibernateAfterTimeout, CurState, Timers, IsHib], _Module, OldVsn, Extra) ->
case catch Module:code_change(OldVsn, CurState, Extra) of
{ok, NewState} -> {ok, [Name, Module, HibernateAfterTimeout, NewState, Timers, IsHib]};
Else -> Else
end.
system_get_state([_Name, State, _Mod, _Time, _HibernateAfterTimeout]) ->
{ok, State}.
system_get_state([_Name, _Module, _HibernateAfterTimeout, CurState, _Timers, _IsHib]) ->
{ok, CurState}.
system_replace_state(StateFun, [Name, State, Module, Time, HibernateAfterTimeout]) ->
NState = StateFun(State),
{ok, NState, [Name, NState, Module, Time, HibernateAfterTimeout]}.
system_replace_state(StateFun, [Name, Module, HibernateAfterTimeout, CurState, Timers, IsHib]) ->
NewState = StateFun(CurState),
{ok, NewState, [Name, Module, HibernateAfterTimeout, NewState, Timers, IsHib]}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% sys callbacks end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
start_monitor(Node, Name) when is_atom(Node), is_atom(Name) ->
@ -582,7 +589,28 @@ enter_loop(Module, State, Opts, ServerName, Action) ->
HibernateAfterTimeout = gen:hibernate_after(Opts),
loopEntry(Parent, Name, Module, HibernateAfterTimeout, State, Debug, #{}, listify(Action)).
loopEntry(Parent, Name, State, Module, HibernateAfterTimeout, Debug, Timers, Action) ->
%%% Internal callbacks
wakeupFromHib(Parent, Name, Module, HibernateAfterTimeout, CurState, Debug, Timers, IsHib) ->
%%
receiveIng(Parent, Name, Module, HibernateAfterTimeout, CurState, Debug, Timers, IsHib).
loopEntry(Parent, Name, Module, HibernateAfterTimeout, CurState, Debug, Timers, Actions) ->
case doParseAL(Actions, Name, Debug, false, false, Timers) of
{error, ErrorContent} ->
terminate(error, ErrorContent, ?STACKTRACE(), Name, Module, CurState, Debug, Timers, []);
{NewDebug, IsHib, DoAfter, NewTimers} ->
case DoAfter of
{doAfter, Args} ->
doAfterCall(Parent, Name, Module, HibernateAfterTimeout, CurState, NewDebug, NewTimers, listHib(IsHib), Args);
_ ->
case IsHib of
true ->
proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, Name, Module, HibernateAfterTimeout, CurState, NewDebug, NewTimers, IsHib]);
_ ->
receiveIng(Parent, Name, Module, HibernateAfterTimeout, CurState, NewDebug, NewTimers, false)
end
end
end,
ok.
receiveIng(Parent, Name, Module, HibernateAfterTimeout, CurState, Debug, Timers, IsHib) ->
@ -603,15 +631,15 @@ receiveIng(Parent, Name, Module, HibernateAfterTimeout, CurState, Debug, Timers,
end;
{system, PidFrom, Request} ->
%% system_continue/3
sys:handle_system_msg(Request, PidFrom, Parent, ?MODULE, Debug, [Name, Module, HibernateAfterTimeout, CurState, Timers], IsHib);
sys:handle_system_msg(Request, PidFrom, Parent, ?MODULE, Debug, [Name, Module, HibernateAfterTimeout, CurState, Timers, IsHib], IsHib);
{'EXIT', Parent, Reason} ->
terminate(Reason, Reason, ?STACKTRACE(), Name, Module, CurState, Debug, Timers, Msg);
terminate(Reason, Reason, ?STACKTRACE(), Name, Module, CurState, Debug, Timers, Msg);
_ ->
matchInfoMsg(Parent, Name, Module, HibernateAfterTimeout, CurState, Debug, Timers, Msg)
end
after HibernateAfterTimeout ->
proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, Name, Module, HibernateAfterTimeout,CurState, Debug, Timers])
proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, Name, Module, HibernateAfterTimeout, CurState, Debug, Timers])
end.
matchCallMsg(Parent, Name, Module, HibernateAfterTimeout, CurState, Debug, Timers, From, Request) ->
@ -676,7 +704,7 @@ handleCR(Parent, Name, Module, HibernateAfterTimeout, CurState, Debug, Timers, R
reply(From, Reply),
NewDebug = ?SYS_DEBUG(Debug, Name, {out, Reply, From, NewState}),
receiveIng(Parent, Name, Module, HibernateAfterTimeout, NewState, NewDebug, Timers, false);
{noreply, NewState , Action } ->
{noreply, NewState, Action} ->
loopEntry(Parent, Name, Module, HibernateAfterTimeout, NewState, Debug, Timers, listify(Action));
{stop, Reason, NewState} ->
terminate(exit, Reason, ?STACKTRACE(), Name, Module, NewState, Debug, Timers, {return, stop});
@ -687,7 +715,7 @@ handleCR(Parent, Name, Module, HibernateAfterTimeout, CurState, Debug, Timers, R
{stop, Reason, Reply, NewState} ->
reply(From, Reply),
NewDebug = ?SYS_DEBUG(Debug, Name, {out, Reply, From, NewState}),
terminate(exit, Reason, ?STACKTRACE(), Name, Module, NewState, Debug, Timers, {return, stop_reply})
terminate(exit, Reason, ?STACKTRACE(), Name, Module, NewState, NewDebug, Timers, {return, stop_reply})
end.
handleAR(Parent, Name, Module, HibernateAfterTimeout, CurState, Debug, Timers, LeftAction, Result) ->
@ -702,47 +730,55 @@ handleAR(Parent, Name, Module, HibernateAfterTimeout, CurState, Debug, Timers, L
terminate(exit, Reason, ?STACKTRACE(), Name, Module, NewState, Debug, Timers, {return, stop_reply})
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% timer deal start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
loopTimeoutsList([], Timers, _CycleData, Debug, TimeoutEvents) ->
{Timers, TimeoutEvents, Debug};
loopTimeoutsList([OneTimeout | LeftTimeouts], Timers, CycleData, Debug, TimeoutEvents) ->
case OneTimeout of
{TimeoutType, Time, TimeoutMsg, Options} ->
%% loopParseActionsList
doParseAL([], _Name, 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(TimeoutType, Timers),
loopTimeoutsList(LeftTimeouts, NewTimers, CycleData, Debug, TimeoutEvents);
0 ->
NewTimers = doCancelTimer(TimeoutType, Timers),
loopTimeoutsList(LeftTimeouts, NewTimers, CycleData, Debug, [{TimeoutType, TimeoutMsg} | TimeoutEvents]);
NewTimers = doCancelTimer(TimeoutName, Timers),
doParseAL(LeftActions, Name, Debug, IsHib, DoAfter, NewTimers);
_ ->
TimerRef = erlang:start_timer(Time, self(), TimeoutType, Options),
NewDebug = ?SYS_DEBUG(Debug, CycleData, {start_timer, {TimeoutType, Time, TimeoutMsg, Options}}),
NewTimers = doRegisterTimer(TimeoutType, TimerRef, TimeoutMsg, Timers),
loopTimeoutsList(LeftTimeouts, NewTimers, CycleData, NewDebug, TimeoutEvents)
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;
{TimeoutType, Time, TimeoutMsg} ->
{'nTimeout', TimeoutName, Time, TimeoutMsg} ->
case Time of
infinity ->
NewTimers = doCancelTimer(TimeoutType, Timers),
loopTimeoutsList(LeftTimeouts, NewTimers, CycleData, Debug, TimeoutEvents);
0 ->
NewTimers = doCancelTimer(TimeoutType, Timers),
loopTimeoutsList(LeftTimeouts, NewTimers, CycleData, Debug, [{TimeoutType, TimeoutMsg} | TimeoutEvents]);
NewTimers = doCancelTimer(TimeoutName, Timers),
doParseAL(LeftActions, Name, Debug, IsHib, DoAfter, NewTimers);
_ ->
TimerRef = erlang:start_timer(Time, self(), TimeoutType),
NewDebug = ?SYS_DEBUG(Debug, CycleData, {start_timer, {TimeoutType, Time, TimeoutMsg, []}}),
NewTimers = doRegisterTimer(TimeoutType, TimerRef, TimeoutMsg, Timers),
loopTimeoutsList(LeftTimeouts, NewTimers, CycleData, NewDebug, TimeoutEvents)
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;
{UpdateTimeoutType, NewTimeoutMsg} ->
NewTimers = doUpdateTimer(UpdateTimeoutType, NewTimeoutMsg, Timers),
loopTimeoutsList(LeftTimeouts, NewTimers, CycleData, Debug, TimeoutEvents);
CancelTimeoutType ->
NewTimers = doCancelTimer(CancelTimeoutType, Timers),
loopTimeoutsList(LeftTimeouts, NewTimers, CycleData, Debug, TimeoutEvents)
{'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 ->
ok;
Timeout when is_integer(Timeout) ->
TimerRef = erlang:start_timer(Timeout, self(), timeout),
NewDebug = ?SYS_DEBUG(Debug, Name, {start_timer, {timeout, Timeout, timeout, []}}),
NewTimers = doRegisterTimer(timeout, TimerRef, timeout, Timers),
doParseAL(LeftActions, Name, NewDebug, IsHib, DoAfter, NewTimers);
_ ->
{error, {bad_ActionType, OneAction}}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% timer deal start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
doRegisterTimer(TimeoutType, NewTimerRef, TimeoutMsg, Timers) ->
case Timers of
@ -771,18 +807,15 @@ doUpdateTimer(TimeoutType, Timers, TimeoutMsg) ->
cancelTimer(TimeoutType, TimerRef, Timers) ->
case erlang:cancel_timer(TimerRef) of
false ->
%%
false -> %
receive
{timeout, TimerRef, TimeoutType} ->
%%
ok
ok %
after 0 ->
ok
end;
_ ->
%% Timer
ok
ok % Timer
end,
maps:remove(TimeoutType, Timers).
@ -790,6 +823,11 @@ listify(Item) when is_list(Item) ->
Item;
listify(Item) ->
[Item].
listHib(true) ->
[hibernate];
listHib(_) ->
[].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% timer deal end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -809,22 +847,11 @@ listify(Item) ->
%%% always includes the stacktrace for errors and never
%%% for exits.
%%% ---------------------------------------------------
-spec terminate(_, _, _, _, _, _, _, _) -> no_return().
terminate(Reason, Stacktrace, Name, From, Msg, Module, State, Debug) ->
terminate(exit, Reason, Stacktrace, Reason, Name, From, Msg, Module, State, Debug).
-spec terminate(_, _, _, _, _, _, _, _, _) -> no_return().
terminate(Class, Reason, Stacktrace, Name, From, Msg, Module, State, Debug) ->
ReportReason = {Reason, Stacktrace},
terminate(Class, Reason, Stacktrace, ReportReason, Name, From, Msg, Module, State, Debug).
-spec terminate(_, _, _, _, _, _, _, _, _, _) -> no_return().
terminate(Class, Reason, Stacktrace, ReportReason, Name, From, Msg, Module, State, Debug) ->
Reply = try_terminate(Module, terminate_reason(Class, Reason, Stacktrace), State),
terminate(Class, Reason, Stacktrace, Name, Module, CurState, Debug, _Timers, MsgEvent) ->
Reply = try_terminate(Module, terminate_reason(Class, Reason, Stacktrace), CurState),
case Reply of
{'EXIT', C, R, S} ->
error_info({R, S}, Name, From, Msg, Module, State, Debug),
error_info({R, S}, Name, undefined, MsgEvent, Module, CurState, Debug),
erlang:raise(C, R, S);
_ ->
case {Class, Reason} of
@ -832,7 +859,7 @@ terminate(Class, Reason, Stacktrace, ReportReason, Name, From, Msg, Module, Stat
{exit, shutdown} -> ok;
{exit, {shutdown, _}} -> ok;
_ ->
error_info(ReportReason, Name, From, Msg, Module, State, Debug)
error_info(Reason, Name, undefined, MsgEvent, Module, CurState, Debug)
end
end,
case Stacktrace of
@ -842,6 +869,21 @@ terminate(Class, Reason, Stacktrace, ReportReason, Name, From, Msg, Module, Stat
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:Stacktrace ->
{'EXIT', Class, R, Stacktrace}
end;
false ->
{ok, ok}
end.
terminate_reason(error, Reason, Stacktrace) -> {Reason, Stacktrace};
terminate_reason(exit, Reason, _Stacktrace) -> Reason.
@ -1119,10 +1161,11 @@ format_status(Opt, StatusData) ->
[PDict, SysState, Parent, Debug, [Name, State, Module, _Time, _HibernateAfterTimeout]] = StatusData,
Header = gen:format_status_header("Status for generic server", Name),
Log = sys:get_log(Debug),
Specific = case format_status(Opt, Module, PDict, State) of
S when is_list(S) -> S;
S -> [S]
end,
Specific =
case format_status(Opt, Module, PDict, State) of
S when is_list(S) -> S;
S -> [S]
end,
[{header, Header},
{data, [{"Status", SysState},
{"Parent", Parent},
@ -1139,10 +1182,11 @@ format_log_state(Module, Log) ->
end || Event <- Log].
format_status(Opt, Module, PDict, State) ->
DefStatus = case Opt of
terminate -> State;
_ -> [{data, [{"State", State}]}]
end,
DefStatus =
case Opt of
terminate -> State;
_ -> [{data, [{"State", State}]}]
end,
case erlang:function_exported(Module, format_status, 2) of
true ->
case catch Module:format_status(Opt, [PDict, State]) of
@ -1159,10 +1203,10 @@ format_status(Opt, Module, PDict, State) ->
%%-----------------------------------------------------------------
print_event(Dev, {in, Msg}, Name) ->
case Msg of
{'$gen_call', {From, _Tag}, Call} ->
{{call, {From, _Tag}}, Call} ->
io:format(Dev, "*DBG* ~tp got call ~tp from ~tw~n",
[Name, Call, From]);
{'$gen_cast', Cast} ->
{cast, Cast} ->
io:format(Dev, "*DBG* ~tp got cast ~tp~n",
[Name, Cast]);
_ ->

Ladataan…
Peruuta
Tallenna