Skip to content

Instantly share code, notes, and snippets.

@tecnowilliam
Created July 7, 2020 01:35
Show Gist options
  • Select an option

  • Save tecnowilliam/13fb587f350d5a9eacd86dc4e7433897 to your computer and use it in GitHub Desktop.

Select an option

Save tecnowilliam/13fb587f350d5a9eacd86dc4e7433897 to your computer and use it in GitHub Desktop.
% Compile: c(frequency_hardened).
-module(frequency_hardened).
-author("William Vargas").
-version("1.0").
-export([init/0, start/0, stop/0, allocate/0, deallocate/1, tests/0]).
% Register the server as frequency_hardened
-spec start() -> ?MODULE.
start() ->
register(?MODULE, spawn(?MODULE, init, [])).
% Stop the frequency_hardened server
-spec stop() -> any().
stop() ->
?MODULE ! {request, self(), stop},
io:format("Server stopped~n"),
reply(1000).
% Initialize the server
-spec init() -> any().
init() ->
process_flag(trap_exit, true),
Frequencies = {get_frequencies(), []},
io:format("Server started~n"),
loop(Frequencies).
% Get the frequencies
-spec get_frequencies() -> list(integer()).
get_frequencies() -> [10,11,12,13,14,15].
% Reply/timeout any message
-spec reply(integer()) -> any().
reply(Timeout) ->
receive
{reply, Reply} ->
io:format("~w~n",[Reply]),
Reply;
_ ->
ok
after Timeout ->
clear(),
{error, timeout}
end.
% Clear all the mailbox
-spec clear() -> ok.
clear() ->
receive
_Msg -> clear()
after 0 ->
io:format("Mailbox cleared~n"),
ok
end.
% Process the server messages
-spec loop(list(integer())) -> any().
loop(Frequencies) ->
io:format("Frequencies: ~w~n", [Frequencies]),
receive
{request, Pid, allocate} ->
try allocate(Frequencies, Pid) of
{NewFrequencies, Reply} ->
Pid ! {reply, Reply},
loop(NewFrequencies)
catch
throw:no_frequency ->
Pid ! {reply, {error,no_frequency}},
loop(Frequencies)
end;
{request, Pid , {deallocate, Freq}} ->
try deallocate(Frequencies, Freq) of
NewFrequencies ->
Pid ! {reply, {deallocate_ok, -Freq}},
loop(NewFrequencies)
catch
throw:unallocated_frequency ->
Pid ! {reply, {error,unallocated_frequency}},
loop(Frequencies)
end;
{request, _Pid, overload} ->
timer:sleep(1000),
loop(Frequencies);
{'EXIT', Pid, _Reason} ->
NewFrequencies = exited(Frequencies, Pid),
loop(NewFrequencies);
{request, _Pid, stop} ->
stop()
end.
% Functional interface: allocate
-spec allocate() -> any().
allocate() ->
?MODULE ! {request, self(), allocate},
reply(1000).
% Allocate a frequency
-spec allocate(list(), pid()) -> tuple().
allocate({[], _Allocated}, _Pid) ->
% {{[], Allocated}, {allocate_error, no_frequency}};
throw(no_frequency);
allocate({[Freq|Free], Allocated}, Pid) ->
link(Pid),
{{Free, [{Freq, Pid}|Allocated]}, {allocate_ok, Freq}}.
% Functional interface: deallocate
-spec deallocate(integer()) -> any().
deallocate(Freq) ->
?MODULE ! {request, self(), {deallocate, Freq}},
reply(1000).
% Deallocate a frequency
-spec deallocate(tuple(), integer()) -> tuple().
deallocate({Free, Allocated}, Freq) ->
case lists:keyfind(Freq, 1, Allocated) of
{Freq, Pid} ->
NewAllocated = lists:delete({Freq, Pid}, Allocated),
unlink(Pid),
{[Freq|Free], NewAllocated};
_ ->
throw(unallocated_frequency)
end.
% Exit from a frequency
-spec exited({list(), list()}, string()) -> tuple().
exited({Free, Allocated}, Pid) ->
case lists:keysearch(Pid, 2, Allocated) of
{value, {Freq,Pid}} ->
NewAllocated = lists:keydelete(Freq,1,Allocated),
{[Freq|Free],NewAllocated};
false ->
{Free,Allocated}
end.
% Tests
-spec tests() -> any().
tests() ->
% Test: Clean mailbox
clear(),
% Test: Start the server
start(),
% Test: Allocate 10,11 and 12
allocate(), allocate(), allocate(),
% Test: Deallocate 11
deallocate(11),
% Test: Allocate 11 and 13
allocate(), allocate(),
% Test: Error - Unallocated frequency
deallocate(15),
% Test: Error - No frequency
allocate(), allocate(), allocate(),
% Test: Overloaded server
io:format("Test overloaded server~n"),
?MODULE ! {request, self(), overload},
reply(1000).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment