-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathsrv.erl
91 lines (77 loc) · 2.64 KB
/
srv.erl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
-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.