Browse Source

reg_or_locate must handle waiters; global reg_or_locate with fun supported

Ulf Wiger 12 years ago
parent
commit
6e6cd7fab0
3 changed files with 53 additions and 28 deletions
  1. 3 3
      doc/gproc.md
  2. 17 12
      src/gproc.erl
  3. 33 13
      src/gproc_dist.erl

+ 3 - 3
doc/gproc.md

@@ -1279,9 +1279,9 @@ a new process (with `spawn(Fun)`) and gives it the name.
 The pid and value of the resulting registration is returned.
 
 
-This function is only available for local registration. While it could
-theoretically be done in the global case, the spawning of a new process
-on a remote node by the leader instance is more problematic.
+When a global name is registered in this fashion, the process is
+spawned on the caller's node, and the group_leader of the spawned
+process is set to the group_leader of the calling process.
 <a name="reg_shared-1"></a>
 
 ### reg_shared/1 ###

+ 17 - 12
src/gproc.erl

@@ -955,11 +955,11 @@ reg_or_locate(Key, Value) ->
 %% a new process (with `spawn(Fun)') and gives it the name.
 %% The pid and value of the resulting registration is returned.
 %%
-%% This function is only available for local registration. While it could
-%% theoretically be done in the global case, the spawning of a new process
-%% on a remote node by the leader instance is more problematic.
+%% When a global name is registered in this fashion, the process is
+%% spawned on the caller's node, and the group_leader of the spawned
+%% process is set to the group_leader of the calling process.
 %% @end
-reg_or_locate({_,l,_} = Key, Value, F) when is_function(F, 0) ->
+reg_or_locate({n,_,_} = Key, Value, F) when is_function(F, 0) ->
     ?CATCH_GPROC_ERROR(reg_or_locate1(Key, Value, F), [Key, Value, F]).
 
 reg_or_locate1({_,g,_} = Key, Value, P) ->
@@ -2015,16 +2015,21 @@ handle_call({set_attributes_shared, {_,l,_} = Key, Attrs}, _, S) ->
 	    {reply, true, S}
     end;
 handle_call({reg_or_locate, {T,l,_} = Key, Val, P}, _, S) ->
+    Reg = fun() ->
+		  Pid = if is_function(P, 0) ->
+				spawn(P);
+			   is_pid(P) ->
+				P
+			end,
+		  true = gproc_lib:insert_reg(Key, Val, Pid, l),
+		  _ = gproc_lib:ensure_monitor(Pid, l),
+		  {reply, {Pid, Val}, S}
+	  end,
     case ets:lookup(?TAB, {Key, T}) of
 	[] ->
-	    Pid = if is_function(P, 0) ->
-			  spawn(P);
-		     is_pid(P) ->
-			  P
-		  end,
-	    true = gproc_lib:insert_reg(Key, Val, Pid, l),
-	    _ = gproc_lib:ensure_monitor(Pid, l),
-	    {reply, {Pid, Val}, S};
+	    Reg();
+	[{_, _Waiters}] ->
+	    Reg();
 	[{_, OtherPid, OtherValue}] ->
 	    {reply, {OtherPid, OtherValue}, S}
     end;

+ 33 - 13
src/gproc_dist.erl

@@ -94,6 +94,14 @@ reg(Key) ->
 %%
 reg_or_locate({n,g,_} = Key, Value, Pid) when is_pid(Pid) ->
     leader_call({reg_or_locate, Key, Value, Pid});
+reg_or_locate({n,g,_} = Key, Value, F) when is_function(F, 0) ->
+    MyGroupLeader = group_leader(),
+    leader_call({reg_or_locate, Key, Value,
+		 fun() ->
+			 %% leader will spawn on caller's node
+			 group_leader(MyGroupLeader, self()),
+			 F()
+		 end});
 reg_or_locate(_, _, _) ->
     ?THROW_GPROC_ERROR(badarg).
 
@@ -328,19 +336,31 @@ handle_leader_call({set_attributes, {_,g,_} = K, Attrs, Pid}, _From, S, _E) ->
 	NewAttrs when is_list(NewAttrs) ->
 	    {reply, true, [{insert, [{{Pid,K}, NewAttrs}]}], S}
     end;
-handle_leader_call({reg_or_locate, {n,g,_} = 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}
+handle_leader_call({reg_or_locate, {n,g,_} = K, Value, P},
+		   {FromPid, _}, S, _E) ->
+    FromNode = node(FromPid),
+    Reg = fun() ->
+		  Pid = if is_function(P, 0) ->
+				spawn(FromNode, P);
+			   is_pid(P) ->
+				P
+			end,
+		  case gproc_lib:insert_reg(K, Value, Pid, g) of
+		      true ->
+			  _ = gproc_lib:ensure_monitor(Pid,g),
+			  Vals = [{{K,n},Pid,Value}],
+			  {reply, {Pid, Value}, [{insert, Vals}], S};
+		      false ->
+			  {reply, badarg, S}
+		  end
+	  end,
+    case ets:lookup(?TAB, {K, n}) of
+	[] ->
+	    Reg();
+	[{_, _Waiters}] ->
+	    Reg();
+	[{_, OtherPid, OtherVal}] ->
+	    {reply, {OtherPid, OtherVal}, S}
     end;
 handle_leader_call({monitor, {T,g,_} = Key, Pid}, _From, S, _E)
   when T==n; T==a ->