Current section
Files
Jump to
Current section
Files
src/srv.erl
-module(srv).
-export([start_link/1, spawn_link/1, hibernate/4]).
-include_lib("rt/include/pi.hrl").
name(App) -> list_to_atom(lists:concat([otp, App])).
emulate_otp(Parent, App) ->
catch unregister(name(App)),
catch register(name(App), self()),
process_flag(trap_exit, true),
put('$ancestors', [Parent]),
put('$initial_call',
{application_controller, start, 1}).
start_link(#pi{} = PI) ->
X = spawn(srv, spawn_link, [PI]),
X ! {init, self(), []},
X.
spawn_link(#pi{parent = Parent, mod = Mod,
name = Name, hibernate = Hibernate} =
PI) ->
emulate_otp(Parent, Name),
hiber_loop(Parent, {local, srv}, PI, Mod, Hibernate).
hiber_loop(Parent, Name, State, Mod, hibernate) ->
erlang:hibernate(srv,
hibernate,
[Parent, Name, State, Mod]);
hiber_loop(Parent, Name, State, Mod, Time) ->
server_loop(drain(Time), Parent, Name, State, Mod).
hibernate(Parent, Name, State, Mod) ->
server_loop(drain(), Parent, Name, State, Mod).
drain() -> receive Input -> Input end.
drain(Timeout) ->
receive
Input -> Input after Timeout -> {timeout, [], []}
end.
reply({To, Tag}, Reply) -> To ! {Tag, Reply}.
server_loop({Fun, Sender, Msg}, Parent, Name, State,
Mod) ->
try dispatch(call(Fun, Msg, Sender, State, Mod),
Sender,
Parent,
Name,
Mod)
catch
Error:Reason:Stack ->
Crash = {Error, Reason, Stack},
Parent ! {crash, Crash},
io:format("Exception: ~p~n", [Crash])
end;
server_loop(Msg, Parent, Name, State, Mod) ->
server_loop({'$gen_cast', {self(), []}, Msg},
Parent,
Name,
State,
Mod).
dispatch(Call, Sender, Parent, Name, Mod) ->
Time = infinity,
case Call of
{noreply, State} ->
hiber_loop(Parent, Name, State, Mod, Time);
{stop, _, _} -> ok;
{stop, Reply, F, _} ->
reply(F, Reply),
Reply;
{ok, Reply, State} ->
reply(Sender, Reply),
hiber_loop(Parent, Name, State, Mod, Time);
{ok, State} ->
hiber_loop(Parent, Name, State, Mod, Time)
end.
call(Fun, Msg, Sender, State, Mod) ->
case Fun of
init -> Mod:server(init, Sender, State);
timeout -> Mod:server(timeout, Sender, State);
system -> Mod:server(terminate, Sender, State);
'EXIT' -> Mod:server(terminate, Sender, State);
'$gen_call' -> Mod:server(Msg, Sender, State);
'$gen_cast' -> Mod:server(Msg, Sender, State)
end.