-module(dummy_via). -export([reset/0, register_name/2, whereis_name/1, unregister_name/1, send/2]). reset() -> P = whereis(?MODULE), catch unlink(P), Ref = erlang:monitor(process, P), catch exit(P, kill), receive {'DOWN',Ref,_,_,_} -> ok end, Me = self(), Pid = spawn_link(fun() -> register(?MODULE, self()), Me ! {self(), started}, loop([]) end), receive {Pid, started} -> Pid after 10000 -> exit(timeout) end. register_name(Name, Pid) when is_pid(Pid) -> call({register_name, Name, Pid}). unregister_name(Name) -> call({unregister_name, Name}). whereis_name(Name) -> call({whereis_name, Name}). send(Name, Msg) -> case whereis_name(Name) of undefined -> exit({badarg, {Name, Msg}}); Pid when is_pid(Pid) -> Pid ! Msg, Pid end. call(Req) -> MRef = erlang:monitor(process, ?MODULE), ?MODULE ! {self(), MRef, Req}, receive {'DOWN', MRef, _, _, _} -> erlang:error(badarg); {MRef, badarg} -> erlang:demonitor(MRef), erlang:error(badarg); {MRef, Reply} -> erlang:demonitor(MRef), Reply after 5000 -> erlang:error(timeout) end. loop(Reg) -> receive {'DOWN', _, _, P, _} when is_pid(P) -> loop([X || {_,Pid,_} = X <- Reg, Pid =/= P]); {From, Ref, Request} when is_pid(From), is_reference(Ref) -> {Reply, NewReg} = handle_request(Request, Reg), From ! {Ref, Reply}, loop(NewReg) end. handle_request({register_name, Name, Pid}, Reg) when is_pid(Pid) -> case lists:keyfind(Name, 1, Reg) of false -> Ref = erlang:monitor(process, Pid), {yes, [{Name, Pid, Ref}|Reg]}; _ -> {no, Reg} end; handle_request({whereis_name, Name}, Reg) -> case lists:keyfind(Name, 1, Reg) of {_, Pid, _} -> {Pid, Reg}; false -> {undefined, Reg} end; handle_request({unregister_name, Name}, Reg) -> case lists:keyfind(Name, 1, Reg) of {_, _, Ref} -> catch erlang:demonitor(Ref); _ -> ok end, {ok, lists:keydelete(Name, 1, Reg)}; handle_request(_, Reg) -> {badarg, Reg}.