|
@@ -315,7 +315,13 @@ request_wait({n,C,_} = Key, Timeout) when C==l; C==g ->
|
|
|
_ ->
|
|
|
erlang:error(badarg, [Key, Timeout])
|
|
|
end,
|
|
|
- WRef = call({await,Key,self()}, C),
|
|
|
+ WRef = case {call({await,Key,self()}, C), C} of
|
|
|
+ {{R, {Kg,Pg,Vg}}, g} ->
|
|
|
+ self() ! {gproc, R, registered, {Kg,Pg,Vg}},
|
|
|
+ R;
|
|
|
+ {R,_} ->
|
|
|
+ R
|
|
|
+ end,
|
|
|
receive
|
|
|
{gproc, WRef, registered, {_K, Pid, V}} ->
|
|
|
case TRef of
|
|
@@ -855,11 +861,11 @@ handle_call({unreg, {_,l,_} = Key}, {Pid,_}, S) ->
|
|
|
false ->
|
|
|
{reply, badarg, S}
|
|
|
end;
|
|
|
-handle_call({await, {_,l,_} = Key, Pid}, {_, Ref}, S) ->
|
|
|
+handle_call({await, {_,l,_} = Key, Pid}, From, S) ->
|
|
|
%% Passing the pid explicitly is needed when leader_call is used,
|
|
|
%% since the Pid given as From in the leader is the local gen_leader
|
|
|
%% instance on the calling node.
|
|
|
- case gproc_lib:await(Key, {Pid, Ref}) of
|
|
|
+ case gproc_lib:await(Key, Pid, From) of
|
|
|
noreply ->
|
|
|
{noreply, S};
|
|
|
{reply, Reply, _} ->
|
|
@@ -929,7 +935,7 @@ call(Req, g) ->
|
|
|
chk_reply(Reply, Req) ->
|
|
|
case Reply of
|
|
|
badarg -> erlang:error(badarg, Req);
|
|
|
- Reply -> Reply
|
|
|
+ _ -> Reply
|
|
|
end.
|
|
|
|
|
|
|
|
@@ -1372,207 +1378,3 @@ is_unique({_,n}) -> true;
|
|
|
is_unique({_,a}) -> true;
|
|
|
is_unique(_) -> false.
|
|
|
|
|
|
-
|
|
|
-%% =============== EUNIT tests
|
|
|
-
|
|
|
-reg_test_() ->
|
|
|
- {setup,
|
|
|
- fun() ->
|
|
|
- application:start(gproc)
|
|
|
- end,
|
|
|
- fun(_) ->
|
|
|
- application:stop(gproc)
|
|
|
- end,
|
|
|
- [
|
|
|
- {spawn, ?_test(t_simple_reg())}
|
|
|
- , ?_test(t_is_clean())
|
|
|
- , {spawn, ?_test(t_simple_prop())}
|
|
|
- , ?_test(t_is_clean())
|
|
|
- , {spawn, ?_test(t_await())}
|
|
|
- , ?_test(t_is_clean())
|
|
|
- , {spawn, ?_test(t_simple_mreg())}
|
|
|
- , ?_test(t_is_clean())
|
|
|
- , {spawn, ?_test(t_gproc_crash())}
|
|
|
- , ?_test(t_is_clean())
|
|
|
- , {spawn, ?_test(t_cancel_wait_and_register())}
|
|
|
- , ?_test(t_is_clean())
|
|
|
- , {spawn, ?_test(t_give_away_to_pid())}
|
|
|
- , ?_test(t_is_clean())
|
|
|
- , {spawn, ?_test(t_give_away_to_self())}
|
|
|
- , ?_test(t_is_clean())
|
|
|
- , {spawn, ?_test(t_give_away_badarg())}
|
|
|
- , ?_test(t_is_clean())
|
|
|
- , {spawn, ?_test(t_give_away_to_unknown())}
|
|
|
- , ?_test(t_is_clean())
|
|
|
- , {spawn, ?_test(t_give_away_and_back())}
|
|
|
- , ?_test(t_is_clean())
|
|
|
- ]}.
|
|
|
-
|
|
|
-t_simple_reg() ->
|
|
|
- ?assert(gproc:reg({n,l,name}) =:= true),
|
|
|
- ?assert(gproc:where({n,l,name}) =:= self()),
|
|
|
- ?assert(gproc:unreg({n,l,name}) =:= true),
|
|
|
- ?assert(gproc:where({n,l,name}) =:= undefined).
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-t_simple_prop() ->
|
|
|
- ?assert(gproc:reg({p,l,prop}) =:= true),
|
|
|
- ?assert(t_other_proc(fun() ->
|
|
|
- ?assert(gproc:reg({p,l,prop}) =:= true)
|
|
|
- end) =:= ok),
|
|
|
- ?assert(gproc:unreg({p,l,prop}) =:= true).
|
|
|
-
|
|
|
-t_other_proc(F) ->
|
|
|
- {_Pid,Ref} = spawn_monitor(fun() -> exit(F()) end),
|
|
|
- receive
|
|
|
- {'DOWN',Ref,_,_,R} ->
|
|
|
- R
|
|
|
- after 10000 ->
|
|
|
- erlang:error(timeout)
|
|
|
- end.
|
|
|
-
|
|
|
-t_await() ->
|
|
|
- Me = self(),
|
|
|
- {_Pid,Ref} = spawn_monitor(
|
|
|
- fun() -> exit(?assert(gproc:await({n,l,t_await}) =:= {Me,val})) end),
|
|
|
- ?assert(gproc:reg({n,l,t_await},val) =:= true),
|
|
|
- receive
|
|
|
- {'DOWN', Ref, _, _, R} ->
|
|
|
- ?assertEqual(R, ok)
|
|
|
- after 10000 ->
|
|
|
- erlang:error(timeout)
|
|
|
- end.
|
|
|
-
|
|
|
-t_is_clean() ->
|
|
|
- sys:get_status(gproc), % in order to synch
|
|
|
- T = ets:tab2list(gproc),
|
|
|
- ?assert(T =:= []).
|
|
|
-
|
|
|
-
|
|
|
-t_simple_mreg() ->
|
|
|
- ok.
|
|
|
-
|
|
|
-
|
|
|
-t_gproc_crash() ->
|
|
|
- P = spawn_helper(),
|
|
|
- ?assert(gproc:where({n,l,P}) =:= P),
|
|
|
- exit(whereis(gproc), kill),
|
|
|
- give_gproc_some_time(100),
|
|
|
- ?assert(whereis(gproc) =/= undefined),
|
|
|
- %%
|
|
|
- %% Check that the registration is still there using an ets:lookup(),
|
|
|
- %% Once we've killed the process, gproc will always return undefined
|
|
|
- %% if the process is not alive, regardless of whether the registration
|
|
|
- %% is still there. So, here, the lookup should find something...
|
|
|
- %%
|
|
|
- ?assert(ets:lookup(gproc,{{n,l,P},n}) =/= []),
|
|
|
- ?assert(gproc:where({n,l,P}) =:= P),
|
|
|
- exit(P, kill),
|
|
|
- %% ...and here, it shouldn't.
|
|
|
- %% (sleep for a while first to let gproc handle the EXIT
|
|
|
- give_gproc_some_time(10),
|
|
|
- ?assert(ets:lookup(gproc,{{n,l,P},n}) =:= []).
|
|
|
-
|
|
|
-t_cancel_wait_and_register() ->
|
|
|
- Alias = {n, l, foo},
|
|
|
- Me = self(),
|
|
|
- P = spawn(fun() ->
|
|
|
- {'EXIT',_} = (catch gproc:await(Alias, 100)),
|
|
|
- ?assert(element(1,sys:get_status(gproc)) == status),
|
|
|
- Me ! {self(), go_ahead},
|
|
|
- timer:sleep(infinity)
|
|
|
- end),
|
|
|
- receive
|
|
|
- {P, go_ahead} ->
|
|
|
- ?assertEqual(gproc:reg(Alias, undefined), true),
|
|
|
- exit(P, kill),
|
|
|
- timer:sleep(500),
|
|
|
- ?assert(element(1,sys:get_status(gproc)) == status)
|
|
|
- end.
|
|
|
-
|
|
|
-
|
|
|
-t_give_away_to_pid() ->
|
|
|
- From = {n, l, foo},
|
|
|
- Me = self(),
|
|
|
- P = spawn_link(fun t_loop/0),
|
|
|
- ?assertEqual(true, gproc:reg(From, undefined)),
|
|
|
- ?assertEqual(Me, gproc:where(From)),
|
|
|
- ?assertEqual(P, gproc:give_away(From, P)),
|
|
|
- ?assertEqual(P, gproc:where(From)),
|
|
|
- ?assertEqual(ok, t_call(P, die)).
|
|
|
-
|
|
|
-t_give_away_to_self() ->
|
|
|
- From = {n, l, foo},
|
|
|
- Me = self(),
|
|
|
- ?assertEqual(true, gproc:reg(From, undefined)),
|
|
|
- ?assertEqual(Me, gproc:where(From)),
|
|
|
- ?assertEqual(Me, gproc:give_away(From, Me)),
|
|
|
- ?assertEqual(Me, gproc:where(From)),
|
|
|
- ?assertEqual(true, gproc:unreg(From)).
|
|
|
-
|
|
|
-t_give_away_badarg() ->
|
|
|
- From = {n, l, foo},
|
|
|
- Me = self(),
|
|
|
- ?assertEqual(undefined, gproc:where(From)),
|
|
|
- ?assertError(badarg, gproc:give_away(From, Me)).
|
|
|
-
|
|
|
-t_give_away_to_unknown() ->
|
|
|
- From = {n, l, foo},
|
|
|
- Unknown = {n, l, unknown},
|
|
|
- Me = self(),
|
|
|
- ?assertEqual(true, gproc:reg(From, undefined)),
|
|
|
- ?assertEqual(Me, gproc:where(From)),
|
|
|
- ?assertEqual(undefined, gproc:where(Unknown)),
|
|
|
- ?assertEqual(undefined, gproc:give_away(From, Unknown)),
|
|
|
- ?assertEqual(undefined, gproc:where(From)).
|
|
|
-
|
|
|
-t_give_away_and_back() ->
|
|
|
- From = {n, l, foo},
|
|
|
- Me = self(),
|
|
|
- P = spawn_link(fun t_loop/0),
|
|
|
- ?assertEqual(true, gproc:reg(From, undefined)),
|
|
|
- ?assertEqual(Me, gproc:where(From)),
|
|
|
- ?assertEqual(P, gproc:give_away(From, P)),
|
|
|
- ?assertEqual(P, gproc:where(From)),
|
|
|
- ?assertEqual(ok, t_call(P, {give_away, From})),
|
|
|
- ?assertEqual(Me, gproc:where(From)),
|
|
|
- ?assertEqual(ok, t_call(P, die)).
|
|
|
-
|
|
|
-t_loop() ->
|
|
|
- receive
|
|
|
- {From, {give_away, Key}} ->
|
|
|
- ?assertEqual(From, gproc:give_away(Key, From)),
|
|
|
- From ! {self(), ok},
|
|
|
- t_loop();
|
|
|
- {From, die} ->
|
|
|
- From ! {self(), ok}
|
|
|
- end.
|
|
|
-
|
|
|
-
|
|
|
-t_call(P, Msg) ->
|
|
|
- P ! {self(), Msg},
|
|
|
- receive
|
|
|
- {P, Reply} ->
|
|
|
- Reply
|
|
|
- end.
|
|
|
-
|
|
|
-spawn_helper() ->
|
|
|
- Parent = self(),
|
|
|
- P = spawn(fun() ->
|
|
|
- ?assert(gproc:reg({n,l,self()}) =:= true),
|
|
|
- Ref = erlang:monitor(process, Parent),
|
|
|
- Parent ! {ok,self()},
|
|
|
- receive
|
|
|
- {'DOWN', Ref, _, _, _} ->
|
|
|
- ok
|
|
|
- end
|
|
|
- end),
|
|
|
- receive
|
|
|
- {ok,P} ->
|
|
|
- P
|
|
|
- end.
|
|
|
-
|
|
|
-give_gproc_some_time(T) ->
|
|
|
- timer:sleep(T),
|
|
|
- sys:get_status(gproc).
|