aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib/test/dummy_via.erl
blob: 026b329688c2d502c8570a187d0fa600783c08a6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
-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}.