Browse Source

added gproc:reg_or_locate/[1,2]

Ulf Wiger 13 years ago
parent
commit
9661221442
6 changed files with 148 additions and 4 deletions
  1. 26 2
      doc/gproc.md
  2. 9 2
      doc/gproc_dist.md
  3. 44 0
      src/gproc.erl
  4. 22 0
      src/gproc_dist.erl
  5. 17 0
      test/gproc_dist_tests.erl
  6. 30 0
      test/gproc_tests.erl

+ 26 - 2
doc/gproc.md

@@ -212,7 +212,7 @@ This function is the reverse of monitor/1.</td></tr><tr><td valign="top"><a href
 to forget about the calling process.</td></tr><tr><td valign="top"><a href="#i-0">i/0</a></td><td>Similar to the built-in shell command <code>i()</code> but inserts information
 about names and properties registered in Gproc, where applicable.</td></tr><tr><td valign="top"><a href="#info-1">info/1</a></td><td>Similar to <code>process_info(Pid)</code> but with additional gproc info.</td></tr><tr><td valign="top"><a href="#info-2">info/2</a></td><td>Similar to process_info(Pid, Item), but with additional gproc info.</td></tr><tr><td valign="top"><a href="#last-1">last/1</a></td><td>Behaves as ets:last(Tab) for a given type of registration object.</td></tr><tr><td valign="top"><a href="#lookup_global_aggr_counter-1">lookup_global_aggr_counter/1</a></td><td>Lookup a global (unique) aggregated counter and returns its value.</td></tr><tr><td valign="top"><a href="#lookup_global_counters-1">lookup_global_counters/1</a></td><td>Look up all global (non-unique) instances of a given Counter.</td></tr><tr><td valign="top"><a href="#lookup_global_name-1">lookup_global_name/1</a></td><td>Lookup a global unique name.</td></tr><tr><td valign="top"><a href="#lookup_global_properties-1">lookup_global_properties/1</a></td><td>Look up all global (non-unique) instances of a given Property.</td></tr><tr><td valign="top"><a href="#lookup_local_aggr_counter-1">lookup_local_aggr_counter/1</a></td><td>Lookup a local (unique) aggregated counter and returns its value.</td></tr><tr><td valign="top"><a href="#lookup_local_counters-1">lookup_local_counters/1</a></td><td>Look up all local (non-unique) instances of a given Counter.</td></tr><tr><td valign="top"><a href="#lookup_local_name-1">lookup_local_name/1</a></td><td>Lookup a local unique name.</td></tr><tr><td valign="top"><a href="#lookup_local_properties-1">lookup_local_properties/1</a></td><td>Look up all local (non-unique) instances of a given Property.</td></tr><tr><td valign="top"><a href="#lookup_pid-1">lookup_pid/1</a></td><td>Lookup the Pid stored with a key.</td></tr><tr><td valign="top"><a href="#lookup_pids-1">lookup_pids/1</a></td><td>Returns a list of pids with the published key Key.</td></tr><tr><td valign="top"><a href="#lookup_value-1">lookup_value/1</a></td><td>Lookup the value stored with a key.</td></tr><tr><td valign="top"><a href="#lookup_values-1">lookup_values/1</a></td><td>Retrieve the <code>{Pid,Value}</code> pairs corresponding to Key.</td></tr><tr><td valign="top"><a href="#monitor-1">monitor/1</a></td><td>monitor a registered name
 This function works much like erlang:monitor(process, Pid), but monitors
-a unique name registered via gproc.</td></tr><tr><td valign="top"><a href="#mreg-3">mreg/3</a></td><td>Register multiple {Key,Value} pairs of a given type and scope.</td></tr><tr><td valign="top"><a href="#munreg-3">munreg/3</a></td><td>Unregister multiple Key items of a given type and scope.</td></tr><tr><td valign="top"><a href="#nb_wait-1">nb_wait/1</a></td><td>Wait for a local name to be registered.</td></tr><tr><td valign="top"><a href="#nb_wait-2">nb_wait/2</a></td><td>Wait for a local name to be registered on <code>Node</code>.</td></tr><tr><td valign="top"><a href="#next-2">next/2</a></td><td>Behaves as ets:next(Tab,Key) for a given type of registration object.</td></tr><tr><td valign="top"><a href="#prev-2">prev/2</a></td><td>Behaves as ets:prev(Tab,Key) for a given type of registration object.</td></tr><tr><td valign="top"><a href="#reg-1">reg/1</a></td><td>Equivalent to <a href="#reg-2"><tt>reg(Key, default(Key))</tt></a>.</td></tr><tr><td valign="top"><a href="#reg-2">reg/2</a></td><td>Register a name or property for the current process.</td></tr><tr><td valign="top"><a href="#reg_shared-1">reg_shared/1</a></td><td>Register a resource, but don't tie it to a particular process.</td></tr><tr><td valign="top"><a href="#reg_shared-2">reg_shared/2</a></td><td>Register a resource, but don't tie it to a particular process.</td></tr><tr><td valign="top"><a href="#register_name-2">register_name/2</a></td><td>Behaviour support callback.</td></tr><tr><td valign="top"><a href="#reset_counter-1">reset_counter/1</a></td><td>Reads and resets a counter in a "thread-safe" way.</td></tr><tr><td valign="top"><a href="#select-1">select/1</a></td><td>Perform a select operation on the process registry.</td></tr><tr><td valign="top"><a href="#select-2">select/2</a></td><td>Perform a select operation with limited context on the process registry.</td></tr><tr><td valign="top"><a href="#select-3">select/3</a></td><td>Like <a href="#select-2"><code>select/2</code></a> but returns Limit objects at a time.</td></tr><tr><td valign="top"><a href="#select_count-1">select_count/1</a></td><td>Equivalent to <a href="#select_count-2"><tt>select_count(all, Pat)</tt></a>.</td></tr><tr><td valign="top"><a href="#select_count-2">select_count/2</a></td><td>Perform a select_count operation on the process registry.</td></tr><tr><td valign="top"><a href="#send-2">send/2</a></td><td>Sends a message to the process, or processes, corresponding to Key.</td></tr><tr><td valign="top"><a href="#set_env-5">set_env/5</a></td><td>Updates the cached value as well as underlying environment.</td></tr><tr><td valign="top"><a href="#set_value-2">set_value/2</a></td><td>Sets the value of the registeration entry given by Key.</td></tr><tr><td valign="top"><a href="#start_link-0">start_link/0</a></td><td>Starts the gproc server.</td></tr><tr><td valign="top"><a href="#table-0">table/0</a></td><td>Equivalent to <a href="#table-1"><tt>table({all, all})</tt></a>.</td></tr><tr><td valign="top"><a href="#table-1">table/1</a></td><td>Equivalent to <a href="#table-2"><tt>table(Context, [])</tt></a>.</td></tr><tr><td valign="top"><a href="#table-2">table/2</a></td><td>QLC table generator for the gproc registry.</td></tr><tr><td valign="top"><a href="#unreg-1">unreg/1</a></td><td>Unregister a name or property.</td></tr><tr><td valign="top"><a href="#unreg_shared-1">unreg_shared/1</a></td><td>Unregister a shared resource.</td></tr><tr><td valign="top"><a href="#unregister_name-1">unregister_name/1</a></td><td>Equivalent to <tt>unreg / 1</tt>.</td></tr><tr><td valign="top"><a href="#update_counter-2">update_counter/2</a></td><td>Updates the counter registered as Key for the current process.</td></tr><tr><td valign="top"><a href="#update_counters-2">update_counters/2</a></td><td>Update a list of counters.</td></tr><tr><td valign="top"><a href="#update_shared_counter-2">update_shared_counter/2</a></td><td>Updates the shared counter registered as Key.</td></tr><tr><td valign="top"><a href="#where-1">where/1</a></td><td>Returns the pid registered as Key.</td></tr><tr><td valign="top"><a href="#whereis_name-1">whereis_name/1</a></td><td>Equivalent to <tt>where / 1</tt>.</td></tr><tr><td valign="top"><a href="#wide_await-3">wide_await/3</a></td><td>Wait for a local name to be registered on any of <code>Nodes</code>.</td></tr></table>
+a unique name registered via gproc.</td></tr><tr><td valign="top"><a href="#mreg-3">mreg/3</a></td><td>Register multiple {Key,Value} pairs of a given type and scope.</td></tr><tr><td valign="top"><a href="#munreg-3">munreg/3</a></td><td>Unregister multiple Key items of a given type and scope.</td></tr><tr><td valign="top"><a href="#nb_wait-1">nb_wait/1</a></td><td>Wait for a local name to be registered.</td></tr><tr><td valign="top"><a href="#nb_wait-2">nb_wait/2</a></td><td>Wait for a local name to be registered on <code>Node</code>.</td></tr><tr><td valign="top"><a href="#next-2">next/2</a></td><td>Behaves as ets:next(Tab,Key) for a given type of registration object.</td></tr><tr><td valign="top"><a href="#prev-2">prev/2</a></td><td>Behaves as ets:prev(Tab,Key) for a given type of registration object.</td></tr><tr><td valign="top"><a href="#reg-1">reg/1</a></td><td>Equivalent to <a href="#reg-2"><tt>reg(Key, default(Key))</tt></a>.</td></tr><tr><td valign="top"><a href="#reg-2">reg/2</a></td><td>Register a name or property for the current process.</td></tr><tr><td valign="top"><a href="#reg_or_locate-1">reg_or_locate/1</a></td><td>Equivalent to <a href="#reg_or_locate-2"><tt>reg_or_locate(Key, default(Key))</tt></a>.</td></tr><tr><td valign="top"><a href="#reg_or_locate-2">reg_or_locate/2</a></td><td>Try registering a unique name, or return existing registration.</td></tr><tr><td valign="top"><a href="#reg_shared-1">reg_shared/1</a></td><td>Register a resource, but don't tie it to a particular process.</td></tr><tr><td valign="top"><a href="#reg_shared-2">reg_shared/2</a></td><td>Register a resource, but don't tie it to a particular process.</td></tr><tr><td valign="top"><a href="#register_name-2">register_name/2</a></td><td>Behaviour support callback.</td></tr><tr><td valign="top"><a href="#reset_counter-1">reset_counter/1</a></td><td>Reads and resets a counter in a "thread-safe" way.</td></tr><tr><td valign="top"><a href="#select-1">select/1</a></td><td>Perform a select operation on the process registry.</td></tr><tr><td valign="top"><a href="#select-2">select/2</a></td><td>Perform a select operation with limited context on the process registry.</td></tr><tr><td valign="top"><a href="#select-3">select/3</a></td><td>Like <a href="#select-2"><code>select/2</code></a> but returns Limit objects at a time.</td></tr><tr><td valign="top"><a href="#select_count-1">select_count/1</a></td><td>Equivalent to <a href="#select_count-2"><tt>select_count(all, Pat)</tt></a>.</td></tr><tr><td valign="top"><a href="#select_count-2">select_count/2</a></td><td>Perform a select_count operation on the process registry.</td></tr><tr><td valign="top"><a href="#send-2">send/2</a></td><td>Sends a message to the process, or processes, corresponding to Key.</td></tr><tr><td valign="top"><a href="#set_env-5">set_env/5</a></td><td>Updates the cached value as well as underlying environment.</td></tr><tr><td valign="top"><a href="#set_value-2">set_value/2</a></td><td>Sets the value of the registeration entry given by Key.</td></tr><tr><td valign="top"><a href="#start_link-0">start_link/0</a></td><td>Starts the gproc server.</td></tr><tr><td valign="top"><a href="#table-0">table/0</a></td><td>Equivalent to <a href="#table-1"><tt>table({all, all})</tt></a>.</td></tr><tr><td valign="top"><a href="#table-1">table/1</a></td><td>Equivalent to <a href="#table-2"><tt>table(Context, [])</tt></a>.</td></tr><tr><td valign="top"><a href="#table-2">table/2</a></td><td>QLC table generator for the gproc registry.</td></tr><tr><td valign="top"><a href="#unreg-1">unreg/1</a></td><td>Unregister a name or property.</td></tr><tr><td valign="top"><a href="#unreg_shared-1">unreg_shared/1</a></td><td>Unregister a shared resource.</td></tr><tr><td valign="top"><a href="#unregister_name-1">unregister_name/1</a></td><td>Equivalent to <tt>unreg / 1</tt>.</td></tr><tr><td valign="top"><a href="#update_counter-2">update_counter/2</a></td><td>Updates the counter registered as Key for the current process.</td></tr><tr><td valign="top"><a href="#update_counters-2">update_counters/2</a></td><td>Update a list of counters.</td></tr><tr><td valign="top"><a href="#update_shared_counter-2">update_shared_counter/2</a></td><td>Updates the shared counter registered as Key.</td></tr><tr><td valign="top"><a href="#where-1">where/1</a></td><td>Returns the pid registered as Key.</td></tr><tr><td valign="top"><a href="#whereis_name-1">whereis_name/1</a></td><td>Equivalent to <tt>where / 1</tt>.</td></tr><tr><td valign="top"><a href="#wide_await-3">wide_await/3</a></td><td>Wait for a local name to be registered on any of <code>Nodes</code>.</td></tr></table>
 
 
 <a name="functions"></a>
@@ -905,7 +905,31 @@ Equivalent to [`reg(Key, default(Key))`](#reg-2).<a name="reg-2"></a>
 
 Register a name or property for the current process
 
-<a name="reg_shared-1"></a>
+<a name="reg_or_locate-1"></a>
+
+###reg_or_locate/1##
+
+
+<pre>reg_or_locate(Key::<a href="#type-key">key()</a>) -> true</pre>
+<br></br>
+
+
+Equivalent to [`reg_or_locate(Key, default(Key))`](#reg_or_locate-2).<a name="reg_or_locate-2"></a>
+
+###reg_or_locate/2##
+
+
+<pre>reg_or_locate(Key::<a href="#type-key">key()</a>, Value) -> {pid(), NewValue}</pre>
+<br></br>
+
+
+
+
+Try registering a unique name, or return existing registration.
+
+This function tries to register the name `Key`, if available.
+If such a registration already exists, the pid and value of
+the current registration is returned instead.<a name="reg_shared-1"></a>
 
 ###reg_shared/1##
 

+ 9 - 2
doc/gproc_dist.md

@@ -28,7 +28,7 @@ Class = n  - unique name
 | p  - non-unique property
 | c  - counter
 | a  - aggregated counter
-Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#reg_shared-2">reg_shared/2</a></td><td></td></tr><tr><td valign="top"><a href="#reset_counter-1">reset_counter/1</a></td><td></td></tr><tr><td valign="top"><a href="#set_value-2">set_value/2</a></td><td></td></tr><tr><td valign="top"><a href="#start_link-0">start_link/0</a></td><td></td></tr><tr><td valign="top"><a href="#start_link-1">start_link/1</a></td><td></td></tr><tr><td valign="top"><a href="#surrendered-3">surrendered/3</a></td><td></td></tr><tr><td valign="top"><a href="#sync-0">sync/0</a></td><td>Synchronize with the gproc leader.</td></tr><tr><td valign="top"><a href="#terminate-2">terminate/2</a></td><td></td></tr><tr><td valign="top"><a href="#unreg-1">unreg/1</a></td><td></td></tr><tr><td valign="top"><a href="#unreg_shared-1">unreg_shared/1</a></td><td></td></tr><tr><td valign="top"><a href="#update_counter-2">update_counter/2</a></td><td></td></tr><tr><td valign="top"><a href="#update_counters-1">update_counters/1</a></td><td></td></tr><tr><td valign="top"><a href="#update_shared_counter-2">update_shared_counter/2</a></td><td></td></tr></table>
+Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#reg_or_locate-2">reg_or_locate/2</a></td><td></td></tr><tr><td valign="top"><a href="#reg_shared-2">reg_shared/2</a></td><td></td></tr><tr><td valign="top"><a href="#reset_counter-1">reset_counter/1</a></td><td></td></tr><tr><td valign="top"><a href="#set_value-2">set_value/2</a></td><td></td></tr><tr><td valign="top"><a href="#start_link-0">start_link/0</a></td><td></td></tr><tr><td valign="top"><a href="#start_link-1">start_link/1</a></td><td></td></tr><tr><td valign="top"><a href="#surrendered-3">surrendered/3</a></td><td></td></tr><tr><td valign="top"><a href="#sync-0">sync/0</a></td><td>Synchronize with the gproc leader.</td></tr><tr><td valign="top"><a href="#terminate-2">terminate/2</a></td><td></td></tr><tr><td valign="top"><a href="#unreg-1">unreg/1</a></td><td></td></tr><tr><td valign="top"><a href="#unreg_shared-1">unreg_shared/1</a></td><td></td></tr><tr><td valign="top"><a href="#update_counter-2">update_counter/2</a></td><td></td></tr><tr><td valign="top"><a href="#update_counters-1">update_counters/1</a></td><td></td></tr><tr><td valign="top"><a href="#update_shared_counter-2">update_shared_counter/2</a></td><td></td></tr></table>
 
 
 <a name="functions"></a>
@@ -175,7 +175,14 @@ Class = n  - unique name
 | p  - non-unique property
 | c  - counter
 | a  - aggregated counter
-Scope = l | g (global or local)<a name="reg_shared-2"></a>
+Scope = l | g (global or local)<a name="reg_or_locate-2"></a>
+
+###reg_or_locate/2##
+
+
+`reg_or_locate(Key, Value) -> any()`
+
+<a name="reg_shared-2"></a>
 
 ###reg_shared/2##
 

+ 44 - 0
src/gproc.erl

@@ -72,6 +72,7 @@
 
 -export([start_link/0,
          reg/1, reg/2, unreg/1,
+	 reg_or_locate/1, reg_or_locate/2,
 	 reg_shared/1, reg_shared/2, unreg_shared/1,
          mreg/3,
          munreg/3,
@@ -604,6 +605,17 @@ reg(Key) ->
 reg1(Key) ->
     reg1(Key, default(Key)).
 
+%% @spec reg_or_locate(Key::key()) -> true
+%%
+%% @doc
+%% @equiv reg_or_locate(Key, default(Key))
+%% @end
+reg_or_locate(Key) ->
+    ?CATCH_GPROC_ERROR(reg_or_locate1(Key), [Key]).
+
+reg_or_locate1(Key) ->
+    reg_or_locate1(Key, default(Key)).
+
 default({T,_,_}) when T==c -> 0;
 default(_) -> undefined.
 
@@ -924,6 +936,24 @@ reg1({n,l,_} = Key, Value) ->
 reg1(_, _) ->
     ?THROW_GPROC_ERROR(badarg).
 
+%% @spec reg_or_locate(Key::key(), Value) -> {pid(), NewValue}
+%%
+%% @doc Try registering a unique name, or return existing registration.
+%%
+%% This function tries to register the name `Key', if available.
+%% If such a registration already exists, the pid and value of
+%% the current registration is returned instead.
+%% @end
+reg_or_locate(Key, Value) ->
+    ?CATCH_GPROC_ERROR(reg_or_locate1(Key, Value), [Key, Value]).
+
+reg_or_locate1({_,g,_} = Key, Value) ->
+    ?CHK_DIST,
+    gproc_dist:reg_or_locate(Key, Value);
+reg_or_locate1({n,l,_} = Key, Value) ->
+    call({reg_or_locate, Key, Value});
+reg_or_locate1(_, _) ->
+    ?THROW_GPROC_ERROR(badarg).
 
 %% @spec reg_shared(Key::key()) -> true
 %%
@@ -1771,6 +1801,20 @@ handle_call({reg, {_T,l,_} = Key, Val}, {Pid,_}, S) ->
         false ->
             {reply, badarg, S}
     end;
+handle_call({reg_or_locate, {T,l,_} = Key, Val}, {Pid,_}, S) ->
+    case try_insert_reg(Key, Val, Pid) of
+	true ->
+	    _ = gproc_lib:ensure_monitor(Pid, l),
+	    {reply, {Pid, Val}, S};
+	false ->
+	    case ets:lookup(?TAB, {Key, T}) of
+		[{_, OtherPid, OtherValue}] ->
+		    {reply, {OtherPid, OtherValue}, S};
+		_ ->
+		    %% ?? - shouldn't be possible, but don't let the server crash
+		    {reply, badarg, S}
+	    end
+    end;
 handle_call({monitor, {T,l,_} = Key, Pid}, _From, S)
   when T==n; T==a ->
     Ref = make_ref(),

+ 22 - 0
src/gproc_dist.erl

@@ -24,6 +24,7 @@
 
 -export([start_link/0, start_link/1,
          reg/1, reg/2, unreg/1,
+	 reg_or_locate/2,
 	 reg_shared/2, unreg_shared/1,
          mreg/2,
          munreg/2,
@@ -87,6 +88,13 @@ start_link({Nodes, Opts}) ->
 reg(Key) ->
     reg(Key, gproc:default(Key)).
 
+%% {@see gproc:reg_or_locate/2}
+%%
+reg_or_locate({n,g,_} = Key, Value) ->
+    leader_call({reg_or_locate, Key, Value, self()});
+reg_or_locate(_, _) ->
+    ?THROW_GPROC_ERROR(badarg).
+
 
 %%% @spec({Class,Scope, Key}, Value) -> true
 %%% @doc
@@ -286,6 +294,20 @@ handle_leader_call({reg, {C,g,Name} = K, Value, Pid}, _From, S, _E) ->
                 end,
             {reply, true, [{insert, Vals}], S}
     end;
+handle_leader_call({reg_or_locate, {n,g,Name} = K, Value, Pid}, _From, S, _E) ->
+    case gproc_lib:insert_reg(K, Value, Pid, g) of
+	false ->
+	    case ets:lookup(?TAB, {K,n}) of
+		[{_, OtherPid, OtherVal}] ->
+		    {reply, {OtherPid, OtherVal}, S};
+		[] ->
+		    {reply, badarg, S}
+	    end;
+	true ->
+	    _ = gproc_lib:ensure_monitor(Pid,g),
+	    Vals = [{{K,n},Pid,Value}],
+	    {reply, {Pid, Value}, [{insert, Vals}], S}
+    end;
 handle_leader_call({monitor, {T,g,_} = Key, Pid}, _From, S, _E)
   when T==n; T==a ->
     Ref = make_ref(),

+ 17 - 0
test/gproc_dist_tests.erl

@@ -44,6 +44,9 @@ dist_test_() ->
 			       	       ?debugVal(t_simple_reg(Ns))
 			       end,
 			       fun() ->
+			       	       ?debugVal(t_simple_reg_or_locate(Ns))
+			       end,
+			       fun() ->
 			       	       ?debugVal(t_simple_counter(Ns))
 			       end,
 			       fun() ->
@@ -103,6 +106,20 @@ t_simple_reg([H|_] = Ns) ->
     ?assertMatch(ok, t_lookup_everywhere(Name, Ns, undefined)),
     ?assertMatch(ok, t_call(P, die)).
 
+t_simple_reg_or_locate([A,B|_] = Ns) ->
+    Name = ?T_NAME,
+    P1 = t_spawn(A),
+    Ref = erlang:monitor(process, P1),
+    ?assertMatch({P1, the_value},
+		 t_call(P1, {apply, gproc, reg_or_locate, [Name, the_value]})),
+    P2 = t_spawn(B),
+    Ref2 = erlang:monitor(process, P2),
+    ?assertMatch({P1, the_value},
+		 t_call(P2, {apply, gproc, reg_or_locate, [Name, other_value]})),
+    ?assertMatch(ok, t_call(P1, die)),
+    ?assertMatch(ok, t_call(P2, die)).
+
+
 t_simple_counter([H|_] = Ns) ->
     Ctr = ?T_COUNTER,
     P = t_spawn_reg(H, Ctr, 3),

+ 30 - 0
test/gproc_tests.erl

@@ -71,6 +71,10 @@ reg_test_() ->
      [
       {spawn, ?_test(?debugVal(t_simple_reg()))}
       , ?_test(t_is_clean())
+      , {spawn, ?_test(?debugVal(t_simple_reg_or_locate()))}
+      , ?_test(t_is_clean())
+      , {spawn, ?_test(?debugVal(t_reg_or_locate2()))}
+      , ?_test(t_is_clean())
       , {spawn, ?_test(?debugVal(t_simple_counter()))}
       , ?_test(t_is_clean())
       , {spawn, ?_test(?debugVal(t_simple_aggr_counter()))}
@@ -133,6 +137,32 @@ t_simple_reg() ->
     ?assert(gproc:unreg({n,l,name}) =:= true),
     ?assert(gproc:where({n,l,name}) =:= undefined).
 
+t_simple_reg_or_locate() ->
+    P = self(),
+    ?assertMatch({P, undefined}, gproc:reg_or_locate({n,l,name})),
+    ?assertMatch(P, gproc:where({n,l,name})),
+    ?assertMatch({P, my_val}, gproc:reg_or_locate({n,l,name2}, my_val)),
+    ?assertMatch(my_val, gproc:get_value({n,l,name2})).
+
+t_reg_or_locate2() ->
+    P = self(),
+    {P1,R1} = spawn_monitor(fun() ->
+				    Ref = erlang:monitor(process, P),
+				    gproc:reg({n,l,foo}, the_value),
+				    P ! {self(), ok},
+				    receive
+					{'DOWN',Ref,_,_,_} -> ok
+				    end
+			    end),
+    receive {P1, ok} -> ok end,
+    ?assertMatch({P1, the_value}, gproc:reg_or_locate({n,l,foo})),
+    exit(P1, kill),
+    receive
+	{'DOWN',R1,_,_,_} ->
+	    ok
+    end.
+
+
 t_simple_counter() ->
     ?assert(gproc:reg({c,l,c1}, 3) =:= true),
     ?assert(gproc:get_value({c,l,c1}) =:= 3),