Skip to content

Instantly share code, notes, and snippets.

@redink
Created May 17, 2018 03:30
Show Gist options
  • Save redink/6e58d4147444665f460e5df78bc0d90a to your computer and use it in GitHub Desktop.
Save redink/6e58d4147444665f460e5df78bc0d90a to your computer and use it in GitHub Desktop.
% sys.erl
get_state(Name) ->
case send_system_msg(Name, get_state) of
{error, Reason} -> error(Reason);
State -> State
end.
send_system_msg(Name, Request) ->
case catch gen:call(Name, system, Request) of
{ok,Res} -> Res;
{'EXIT', Reason} -> exit({Reason, mfa(Name, Request)})
end.
% gen_server.erl
decode_msg(Msg, Parent, Name, State, Mod, Time, HibernateAfterTimeout, Debug, Hib) ->
case Msg of
{system, From, Req} ->
sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
[Name, State, Mod, Time, HibernateAfterTimeout], Hib);
{'EXIT', Parent, Reason} ->
terminate(Reason, ?STACKTRACE(), Name, undefined, Msg, Mod, State, Debug);
_Msg when Debug =:= [] ->
handle_msg(Msg, Parent, Name, State, Mod, HibernateAfterTimeout);
_Msg ->
Debug1 = sys:handle_debug(Debug, fun print_event/3,
Name, {in, Msg}),
handle_msg(Msg, Parent, Name, State, Mod, HibernateAfterTimeout, Debug1)
end.
% sys.erl
handle_system_msg(Msg, From, Parent, Module, Debug, Misc) ->
handle_system_msg(running, Msg, From, Parent, Module, Debug, Misc, false).
handle_system_msg(Msg, From, Parent, Mod, Debug, Misc, Hib) ->
handle_system_msg(running, Msg, From, Parent, Mod, Debug, Misc, Hib).
handle_system_msg(SysState, Msg, From, Parent, Mod, Debug, Misc, Hib) ->
case do_cmd(SysState, Msg, Parent, Mod, Debug, Misc) of
{suspended, Reply, NDebug, NMisc} ->
_ = gen:reply(From, Reply),
suspend_loop(suspended, Parent, Mod, NDebug, NMisc, Hib);
{running, Reply, NDebug, NMisc} ->
_ = gen:reply(From, Reply),
Mod:system_continue(Parent, NDebug, NMisc);
{{terminating, Reason}, Reply, NDebug, NMisc} ->
_ = gen:reply(From, Reply),
Mod:system_terminate(Reason, Parent, NDebug, NMisc)
end.
do_cmd(SysState, {replace_state, StateFun}, _Parent, Mod, Debug, Misc) ->
{Res, NMisc} = do_replace_state(StateFun, Mod, Misc),
{SysState, Res, Debug, NMisc};
do_replace_state(StateFun, Mod, Misc) ->
case erlang:function_exported(Mod, system_replace_state, 2) of
true ->
try
{ok, State, NMisc} = Mod:system_replace_state(StateFun, Misc),
{State, NMisc}
catch
Cl:Exc ->
{{error, {callback_failed,{Mod,system_replace_state},{Cl,Exc}}}, Misc}
end;
false ->
try
NMisc = StateFun(Misc),
{NMisc, NMisc}
catch
Cl:Exc ->
{{error, {callback_failed,StateFun,{Cl,Exc}}}, Misc}
end
end.
% gen_server.erl
system_replace_state(StateFun, [Name, State, Mod, Time, HibernateAfterTimeout]) ->
NState = StateFun(State),
{ok, NState, [Name, NState, Mod, Time, HibernateAfterTimeout]}.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment