-
Notifications
You must be signed in to change notification settings - Fork 0
/
f3.erl
executable file
·137 lines (114 loc) · 4.39 KB
/
f3.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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
%% Based on code from
%% Erlang Programming
%% Francecso Cesarini and Simon Thompson
%% O'Reilly, 2008
%% http://oreilly.com/catalog/9780596518189/
%% http://www.erlangprogramming.org/
%% (c) Francesco Cesarini and Simon Thompson
-module(f3).
-export([start_simulation/0,start_server/0,start_client/2,allocate/0,deallocate/1,stop/0]).
-export([init_server/0,init_client/1]).
%% These are the start functions used to create and
%% initialize the server.
start_simulation() ->
start_server(),
start_client(client1, [allocate, wait, deallocate,wait]),
%start_client(client1, [allocate,allocate,wait,allocate,wait,deallocate,wait,deallocate,wait,deallocate]),
start_client(client2, [allocate, wait, deallocate,wait]).
start_client(ClientName, Commands) ->
register(ClientName, spawn(f3, init_client, [Commands])).
init_client(Commands) ->
process_flag(trap_exit, true),
client_loop(Commands).
client_loop(Commands) -> client_loop(Commands, [], []).
client_loop([], Commands, Frequencies) -> client_loop(lists:reverse(Commands), [], Frequencies); % Start the loop agin, and loop forever (until exit signal)
client_loop([Command |CommandsRemaining], CommandsProcessed, Frequencies) ->
receive
{'EXIT', _Pid, normal} -> io:format("[~w] Exited", [self()]);
{'EXIT', _Pid, Reason} -> io:format("[~w] Server killed: ~w~n",[self(), Reason]);
stop -> io:format("[~w] Stopped~n", [self()]);
UnknownMsg -> io:format("[~w] Dropping unknown message: ~w~n",[self(), UnknownMsg])
after 0 ->
case Command of
allocate ->
{ok, Freq} = allocate(),
io:format("[~w] Allocated frequency: ~w~n",[self(),Freq]),
client_loop(CommandsRemaining, [Command | CommandsProcessed], [Freq | Frequencies]);
deallocate ->
case Frequencies of
[] ->
io:format("[~w] No frequencies to deallocate!~n", [self()]),
client_loop(CommandsRemaining, [Command | CommandsProcessed], Frequencies);
[Freq | AllocatedFrequencies] ->
io:format("[~w] Deallocating frequency: ~w~n",[self(), Freq]),
deallocate(Freq),
client_loop(CommandsRemaining, [Command | CommandsProcessed], AllocatedFrequencies)
end;
wait ->
io:format("[~w] Sleeping~n", [self()]),
timer:sleep(5000),
client_loop(CommandsRemaining, [Command | CommandsProcessed], Frequencies)
end
end.
start_server() ->
register(f3,
spawn(f3, init_server, [])).
init_server() ->
process_flag(trap_exit, true), %%% ADDED
Frequencies = {get_frequencies(), []},
server_loop(Frequencies).
% Hard Coded
get_frequencies() -> [10,11,12,13,14,15].
%% The Main Loop
server_loop(Frequencies) ->
receive
{request, Pid, allocate} ->
{NewFrequencies, Reply} = allocate(Frequencies, Pid),
Pid ! {reply, Reply},
server_loop(NewFrequencies);
{request, Pid , {deallocate, Freq}} ->
NewFrequencies = deallocate(Frequencies, Freq),
Pid ! {reply, ok},
server_loop(NewFrequencies);
{request, Pid, stop} ->
Pid ! {reply, stopped};
{'EXIT', Pid, _Reason} -> %%% CLAUSE ADDED
NewFrequencies = exited(Frequencies, Pid),
server_loop(NewFrequencies)
end.
%% Functional interface
allocate() ->
f3 ! {request, self(), allocate},
receive
{reply, Reply} -> Reply
end.
deallocate(Freq) ->
f3 ! {request, self(), {deallocate, Freq}},
receive
{reply, Reply} -> Reply
end.
stop() ->
f3 ! {request, self(), stop},
receive
{reply, Reply} -> Reply
end.
%% The Internal Help Functions used to allocate and
%% deallocate frequencies.
allocate({[], Allocated}, _Pid) ->
{{[], Allocated}, {error, no_frequency}};
allocate({[Freq|Free], Allocated}, Pid) ->
link(Pid), %%% ADDED
{{Free, [{Freq, Pid}|Allocated]}, {ok, Freq}}.
deallocate({Free, Allocated}, Freq) ->
{value,{Freq,Pid}} = lists:keysearch(Freq,1,Allocated), %%% ADDED
unlink(Pid), %%% ADDED
NewAllocated=lists:keydelete(Freq, 1, Allocated),
{[Freq|Free], NewAllocated}.
exited({Free, Allocated}, Pid) -> %%% FUNCTION ADDED
case lists:keysearch(Pid,2,Allocated) of
{value,{Freq,Pid}} ->
NewAllocated = lists:keydelete(Freq,1,Allocated),
{[Freq|Free],NewAllocated};
false ->
{Free,Allocated}
end.