2 Gen_Server Behaviour

The client-server model is characterized by a central server
and an arbitrary number of clients. The client-server model is
generally used for resource management operations, where several
different clients want to share a common resource. The server is
responsible for managing this resource.

start_link calls the function
gen_server:start_link/4. This function spawns and links to
a new process, a gen_server.

The first argument {local, ch3} specifies the name. In
this case, the gen_server will be locally registered as
ch3.

If the name is omitted, the gen_server is not registered.
Instead its pid must be used. The name could also be given
as {global, Name}, in which case the gen_server is
registered using global:register_name/2.

The second argument, ch3, is the name of the callback
module, that is the module where the callback functions are
located.

In this case, the interface functions (start_link,
alloc and free) are located in the same module
as the callback functions (init, handle_call and
handle_cast). This is normally good programming
practice, to have the code corresponding to one process
contained in one module.

The third argument, [], is a term which is passed as-is to
the callback function init. Here, init does not
need any indata and ignores the argument.

The fourth argument, [], is a list of options. See
gen_server(3) for available options.

If name registration succeeds, the new gen_server process calls
the callback function ch3:init([]). init is expected
to return {ok, State}, where State is the internal
state of the gen_server. In this case, the state is the available
channels.

init(_Args) ->
{ok, channels()}.

Note that gen_server:start_link is synchronous. It does
not return until the gen_server has been initialized and is ready
to receive requests.

gen_server:start_link must be used if the gen_server is
part of a supervision tree, i.e. is started by a supervisor.
There is another function gen_server:start to start a
stand-alone gen_server, i.e. a gen_server which is not part of a
supervision tree.

The synchronous request alloc() is implemented using
gen_server:call/2:

alloc() ->
gen_server:call(ch3, alloc).

ch3 is the name of the gen_server and must agree with
the name used to start it. alloc is the actual request.

The request is made into a message and sent to the gen_server.
When the request is received, the gen_server calls
handle_call(Request, From, State) which is expected to
return a tuple {reply, Reply, State1}. Reply is
the reply which should be sent back to the client, and
State1 is a new value for the state of the gen_server.

In a Supervision Tree

If the gen_server is part of a supervision tree, no stop
function is needed. The gen_server will automatically be
terminated by its supervisor. Exactly how this is done is
defined by a shutdown strategy set in the supervisor.

If it is necessary to clean up before termination, the shutdown
strategy must be a timeout value and the gen_server must be set
to trap exit signals in the init function. When ordered
to shutdown, the gen_server will then call the callback function
terminate(shutdown, State):

The callback function handling the stop request returns
a tuple {stop, normal, State1}, where normal
specifies that it is a normal termination and State1 is
a new value for the state of the gen_server. This will cause
the gen_server to call terminate(normal,State1) and then
terminate gracefully.

If the gen_server should be able to receive other messages than
requests, the callback function handle_info(Info, State)
must be implemented to handle them. Examples of other messages
are exit messages, if the gen_server is linked to other processes
(than the supervisor) and trapping exit signals.