1-module(dummy_via).
2-export([reset/0,
3	 register_name/2,
4	 whereis_name/1,
5	 unregister_name/1,
6	 send/2]).
7
8
9reset() ->
10    P = whereis(?MODULE),
11    catch unlink(P),
12    Ref = erlang:monitor(process, P),
13    catch exit(P, kill),
14    receive {'DOWN',Ref,_,_,_} -> ok end,
15    Me = self(),
16    Pid = spawn_link(fun() ->
17			     register(?MODULE, self()),
18			     Me ! {self(), started},
19			     loop([])
20		     end),
21    receive
22	{Pid, started} ->
23	    Pid
24    after 10000 ->
25	    exit(timeout)
26    end.
27
28register_name(Name, Pid) when is_pid(Pid) ->
29    call({register_name, Name, Pid}).
30
31unregister_name(Name) ->
32    call({unregister_name, Name}).
33
34whereis_name(Name) ->
35    call({whereis_name, Name}).
36
37send(Name, Msg) ->
38    case whereis_name(Name) of
39	undefined ->
40	    exit({badarg, {Name, Msg}});
41	Pid when is_pid(Pid) ->
42	    Pid ! Msg,
43	    Pid
44    end.
45
46call(Req) ->
47    MRef = erlang:monitor(process, ?MODULE),
48    ?MODULE ! {self(), MRef, Req},
49    receive
50	{'DOWN', MRef, _, _, _} ->
51	    erlang:error(badarg);
52	{MRef, badarg} ->
53	    erlang:demonitor(MRef),
54	    erlang:error(badarg);
55	{MRef, Reply} ->
56	    erlang:demonitor(MRef),
57	    Reply
58    after 5000 ->
59	    erlang:error(timeout)
60    end.
61
62loop(Reg) ->
63    receive
64	{'DOWN', _, _, P, _} when is_pid(P) ->
65	    loop([X || {_,Pid,_} = X <- Reg, Pid =/= P]);
66	{From, Ref, Request} when is_pid(From), is_reference(Ref) ->
67	    {Reply, NewReg} = handle_request(Request, Reg),
68	    From ! {Ref, Reply},
69	    loop(NewReg)
70    end.
71
72handle_request({register_name, Name, Pid}, Reg) when is_pid(Pid) ->
73    case lists:keyfind(Name, 1, Reg) of
74	false ->
75	    Ref = erlang:monitor(process, Pid),
76	    {yes, [{Name, Pid, Ref}|Reg]};
77	_ ->
78	    {no, Reg}
79    end;
80handle_request({whereis_name, Name}, Reg) ->
81    case lists:keyfind(Name, 1, Reg) of
82	{_, Pid, _} ->
83	    {Pid, Reg};
84	false ->
85	    {undefined, Reg}
86    end;
87handle_request({unregister_name, Name}, Reg) ->
88    case lists:keyfind(Name, 1, Reg) of
89	{_, _, Ref} ->
90	    catch erlang:demonitor(Ref);
91	_ ->
92	    ok
93    end,
94    {ok, lists:keydelete(Name, 1, Reg)};
95handle_request(_, Reg) ->
96    {badarg, Reg}.
97