A generic server

The code must expose the following features:

We will achieve all of this with approximately 20 lines of code!

Generic server's code

The engine of the server consists of a function F of the following type:

F :: (State,Data) -> (Result, NewState)
loop(State, F) ->
    receive
          stop -> true ;

          {update, From, Ref, NewF} ->
                   From ! {ok, Ref},
                   loop(State, NewF) ;

          {request, From, Ref, Data} ->
                    {R, NS} = F(State, Data),
                    From ! {result, Ref, R},
                    loop(NS, F)
    end.

Exceptions

The evaluation of expressions can fail

[] = [1].
** exception error: no match of right hand side value [1]
net_adm:ping(1,2).
** exception error: undefined function net_adm:ping/2
> catch(1/0).
{'EXIT',{badarith,[{erlang,'/',[1,0]},
                   {erl_eval,do_apply,5},
                   {erl_eval,expr,5},
                   {shell,exprs,7},
                   {shell,eval_exprs,7},
                   {shell,eval_loop,3}]}}
> catch([] = [1]).
{'EXIT',{{badmatch,[1]},[{erl_eval,expr,3}]}}
> catch(net_adm:ping(1,2)).
{'EXIT',{undef,[{net_adm,ping,[1,2]},
                {erl_eval,do_apply,5},
                {erl_eval,expr,5},
                {shell,exprs,7},
                {shell,eval_exprs,7},
                {shell,eval_loop,3}]}}
> 

Robust generic server

code

loop(State, F) ->
    receive
        stop -> true ;

        {update, From, Ref, NewF} ->
                 From ! {ok, Ref},
                 loop(State, NewF);

        {request, From, Ref, Data} ->
                  case catch(F(State, Data)) of
                      {'EXIT', Reason} ->
                             From!{exit, Ref, Reason},
                             loop(State, F);
                      {R, NewState} ->
                             From!{result, Ref, R},
                             loop(NewState, F)
                  end
    end.

Generic client

code

request(Pid, Data) ->
    Ref = make_ref(),
    Pid!{request, self(), Ref, Data},
    receive
        {result, Ref, Result} ->
            Result;
        {exit, Ref, Reason} ->
            exit(Reason)
    end.
update(Pid, Fun) ->
    Ref = make_ref(),
    Pid!{update, self(), Ref, Fun},
    receive
    {ok, Ref} ->
        ok
    end.

Mathematical server revisited

code

Message passing

Barrier synchronisation revisited

code

Barrier synchronization

reach_wait(Server) ->
    Ref = make_ref(), 
    Server ! {reach, self(), Ref},
    receive 
       {ack, Ref} -> true
    end. 

start(N) -> 
    Pid = spawn(fun() -> coordinator(N,N,[]) end),
    register(coordinator, Pid).


coordinator(N,0,Ps) ->
    [ From ! {ack, Ref} || {From, Ref} <- Ps ],
    coordinator(N,N,[]) ;

coordinator(N,M,Ps) ->
    receive 
        {reach, From, Ref} -> 
                 coordinator(N,M-1, [ {From,Ref} | Ps]) 
    end.

Resource allocation revisited

code

loop(Resources) ->
    Available = length(Resources),
    receive 
       {req, From, Ref, Number} when Number =< Available ->
            From ! {res, Ref, lists:sublist(Resources, Number)},
            loop(lists:sublist(Resources, Number+1, Available)) ;

       {ret, List} -> loop(lists:append(Resources, List))
    end.      

start(Init) ->
    Pid = spawn (fun () -> loop(Init) end),
    register(rserver, Pid).


request(N) ->
    Ref = make_ref(),    
    rserver ! {req, self(), Ref, N},
    receive 
        {res, Ref, List} -> List
    end.

release(List) ->
    rserver ! {ret, List},
    ok
> c(ralloc).
{ok,ralloc}
> ralloc:start([1,1,1,1]).
true
> ralloc:request(3).
[1,1,1]
> ralloc:release([1]).
ok
> ralloc:request(2).
[1,1]
> ralloc:request(10).

Readers and writers revisited

loop(Rs, Ws) ->
    receive
       {start_read, From, Ref} when Ws =:= 0 -> 
            From ! {ok_to_read, Ref},
            loop(Rs+1,Ws) ;

       {start_write, From, Ref} when Ws =:= 0 and Rs =:= 0 ->
            From ! {ok_to_write, Ref},
            loop(Rs, Ws+1) ;

       end_read  -> loop(Rs-1, Ws) ;

       end_write -> loop(Rs, Ws-1)
    end.      

Fair readers and writers

code

Fair
readers/writers

loop() ->
    receive
       {start_read, From, Ref} -> 
            From ! {ok_to_read, Ref},
            loop_read(1),
            loop() ;

       {start_write, From, Ref} ->
            From ! {ok_to_write, Ref},
            receive 
                end_write -> loop() 
            end 
    end.      

loop_read(0) -> ok ;
loop_read(Rs) ->
    receive 
       {start_read, From, Ref} ->  
            From ! {ok_to_read, Ref},
            loop_read(Rs+1) ;

       end_read -> loop_read(Rs-1) ;

       {start_write, From, Ref} ->
            [ receive end_read -> ok end 
              || _ <- lists:seq(1,Rs) ],
            From ! {ok_to_write, Ref},
            receive 
                   end_write -> ok 
            end
     end.