Просмотр исходного кода

distributed wait (await/3, wide_await/3, et al)

Ulf Wiger 13 лет назад
Родитель
Сommit
603dd7e323
3 измененных файлов с 200 добавлено и 12 удалено
  1. 58 5
      doc/gproc.md
  2. 141 6
      src/gproc.erl
  3. 1 1
      src/gproc_lib.erl

+ 58 - 5
doc/gproc.md

@@ -207,12 +207,12 @@ a = aggregate_counter
 ##Function Index##
 ##Function Index##
 
 
 
 
-<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#add_global_aggr_counter-1">add_global_aggr_counter/1</a></td><td>Registers a global (unique) aggregated counter.</td></tr><tr><td valign="top"><a href="#add_global_counter-2">add_global_counter/2</a></td><td>Registers a global (non-unique) counter.</td></tr><tr><td valign="top"><a href="#add_global_name-1">add_global_name/1</a></td><td>Registers a global (unique) name.</td></tr><tr><td valign="top"><a href="#add_global_property-2">add_global_property/2</a></td><td>Registers a global (non-unique) property.</td></tr><tr><td valign="top"><a href="#add_local_aggr_counter-1">add_local_aggr_counter/1</a></td><td>Registers a local (unique) aggregated counter.</td></tr><tr><td valign="top"><a href="#add_local_counter-2">add_local_counter/2</a></td><td>Registers a local (non-unique) counter.</td></tr><tr><td valign="top"><a href="#add_local_name-1">add_local_name/1</a></td><td>Registers a local (unique) name.</td></tr><tr><td valign="top"><a href="#add_local_property-2">add_local_property/2</a></td><td>Registers a local (non-unique) property.</td></tr><tr><td valign="top"><a href="#add_shared_local_counter-2">add_shared_local_counter/2</a></td><td>Registers a local shared (unique) counter.</td></tr><tr><td valign="top"><a href="#audit_process-1">audit_process/1</a></td><td></td></tr><tr><td valign="top"><a href="#await-1">await/1</a></td><td>Equivalent to <a href="#await-2"><tt>await(Key, infinity)</tt></a>.</td></tr><tr><td valign="top"><a href="#await-2">await/2</a></td><td>Wait for a local name to be registered.</td></tr><tr><td valign="top"><a href="#bcast-2">bcast/2</a></td><td>Equivalent to <a href="#bcast-3"><tt>bcast(nodes(), Key, Msg)</tt></a>.</td></tr><tr><td valign="top"><a href="#bcast-3">bcast/3</a></td><td>Sends a message to processes corresponding to Key on Nodes.</td></tr><tr><td valign="top"><a href="#cancel_wait-2">cancel_wait/2</a></td><td>Cancels a previous call to nb_wait/1.</td></tr><tr><td valign="top"><a href="#cancel_wait_or_monitor-1">cancel_wait_or_monitor/1</a></td><td></td></tr><tr><td valign="top"><a href="#default-1">default/1</a></td><td></td></tr><tr><td valign="top"><a href="#demonitor-2">demonitor/2</a></td><td>Remove a monitor on a registered name
+<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#add_global_aggr_counter-1">add_global_aggr_counter/1</a></td><td>Registers a global (unique) aggregated counter.</td></tr><tr><td valign="top"><a href="#add_global_counter-2">add_global_counter/2</a></td><td>Registers a global (non-unique) counter.</td></tr><tr><td valign="top"><a href="#add_global_name-1">add_global_name/1</a></td><td>Registers a global (unique) name.</td></tr><tr><td valign="top"><a href="#add_global_property-2">add_global_property/2</a></td><td>Registers a global (non-unique) property.</td></tr><tr><td valign="top"><a href="#add_local_aggr_counter-1">add_local_aggr_counter/1</a></td><td>Registers a local (unique) aggregated counter.</td></tr><tr><td valign="top"><a href="#add_local_counter-2">add_local_counter/2</a></td><td>Registers a local (non-unique) counter.</td></tr><tr><td valign="top"><a href="#add_local_name-1">add_local_name/1</a></td><td>Registers a local (unique) name.</td></tr><tr><td valign="top"><a href="#add_local_property-2">add_local_property/2</a></td><td>Registers a local (non-unique) property.</td></tr><tr><td valign="top"><a href="#add_shared_local_counter-2">add_shared_local_counter/2</a></td><td>Registers a local shared (unique) counter.</td></tr><tr><td valign="top"><a href="#audit_process-1">audit_process/1</a></td><td></td></tr><tr><td valign="top"><a href="#await-1">await/1</a></td><td>Equivalent to <a href="#await-2"><tt>await(Key, infinity)</tt></a>.</td></tr><tr><td valign="top"><a href="#await-2">await/2</a></td><td>Wait for a local name to be registered.</td></tr><tr><td valign="top"><a href="#await-3">await/3</a></td><td>Wait for a local name to be registered on <code>Node</code>.</td></tr><tr><td valign="top"><a href="#bcast-2">bcast/2</a></td><td>Equivalent to <a href="#bcast-3"><tt>bcast(nodes(), Key, Msg)</tt></a>.</td></tr><tr><td valign="top"><a href="#bcast-3">bcast/3</a></td><td>Sends a message to processes corresponding to Key on Nodes.</td></tr><tr><td valign="top"><a href="#cancel_wait-2">cancel_wait/2</a></td><td>Cancels a previous call to nb_wait/1.</td></tr><tr><td valign="top"><a href="#cancel_wait-3">cancel_wait/3</a></td><td>Cancels a previous call to nb_wait/2.</td></tr><tr><td valign="top"><a href="#cancel_wait_or_monitor-1">cancel_wait_or_monitor/1</a></td><td></td></tr><tr><td valign="top"><a href="#default-1">default/1</a></td><td></td></tr><tr><td valign="top"><a href="#demonitor-2">demonitor/2</a></td><td>Remove a monitor on a registered name
 This function is the reverse of monitor/1.</td></tr><tr><td valign="top"><a href="#first-1">first/1</a></td><td>Behaves as ets:first(Tab) for a given type of registration object.</td></tr><tr><td valign="top"><a href="#get_env-3">get_env/3</a></td><td>Equivalent to <a href="#get_env-4"><tt>get_env(Scope, App, Key, [app_env])</tt></a>.</td></tr><tr><td valign="top"><a href="#get_env-4">get_env/4</a></td><td>Read an environment value, potentially cached as a <code>gproc_env</code> property.</td></tr><tr><td valign="top"><a href="#get_set_env-3">get_set_env/3</a></td><td>Equivalent to <a href="#get_set_env-4"><tt>get_set_env(Scope, App, Key, [app_env])</tt></a>.</td></tr><tr><td valign="top"><a href="#get_set_env-4">get_set_env/4</a></td><td>Fetch and cache an environment value, if not already cached.</td></tr><tr><td valign="top"><a href="#get_value-1">get_value/1</a></td><td>Reads the value stored with a key registered to the current process.</td></tr><tr><td valign="top"><a href="#get_value-2">get_value/2</a></td><td>Reads the value stored with a key registered to the process Pid.</td></tr><tr><td valign="top"><a href="#give_away-2">give_away/2</a></td><td>Atomically transfers the key <code>From</code> to the process identified by <code>To</code>.</td></tr><tr><td valign="top"><a href="#goodbye-0">goodbye/0</a></td><td>Unregister all items of the calling process and inform gproc
 This function is the reverse of monitor/1.</td></tr><tr><td valign="top"><a href="#first-1">first/1</a></td><td>Behaves as ets:first(Tab) for a given type of registration object.</td></tr><tr><td valign="top"><a href="#get_env-3">get_env/3</a></td><td>Equivalent to <a href="#get_env-4"><tt>get_env(Scope, App, Key, [app_env])</tt></a>.</td></tr><tr><td valign="top"><a href="#get_env-4">get_env/4</a></td><td>Read an environment value, potentially cached as a <code>gproc_env</code> property.</td></tr><tr><td valign="top"><a href="#get_set_env-3">get_set_env/3</a></td><td>Equivalent to <a href="#get_set_env-4"><tt>get_set_env(Scope, App, Key, [app_env])</tt></a>.</td></tr><tr><td valign="top"><a href="#get_set_env-4">get_set_env/4</a></td><td>Fetch and cache an environment value, if not already cached.</td></tr><tr><td valign="top"><a href="#get_value-1">get_value/1</a></td><td>Reads the value stored with a key registered to the current process.</td></tr><tr><td valign="top"><a href="#get_value-2">get_value/2</a></td><td>Reads the value stored with a key registered to the process Pid.</td></tr><tr><td valign="top"><a href="#give_away-2">give_away/2</a></td><td>Atomically transfers the key <code>From</code> to the process identified by <code>To</code>.</td></tr><tr><td valign="top"><a href="#goodbye-0">goodbye/0</a></td><td>Unregister all items of the calling process and inform gproc
 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
 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
 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
 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="#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></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_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>
 <a name="functions"></a>
@@ -320,7 +320,19 @@ either an interger > 0 or 'infinity'.
 A small optimization: we first perform a lookup, to see if the name
 A small optimization: we first perform a lookup, to see if the name
 is already registered. This way, the cost of the operation will be
 is already registered. This way, the cost of the operation will be
 roughly the same as of where/1 in the case where the name is already
 roughly the same as of where/1 in the case where the name is already
-registered (the difference: await/2 also returns the value).<a name="bcast-2"></a>
+registered (the difference: await/2 also returns the value).<a name="await-3"></a>
+
+###await/3##
+
+
+<pre>await(Node::node(), Key::<a href="#type-key">key()</a>, Timeout) -> {pid(), Value}</pre>
+<ul class="definitions"><li><pre>Timeout = integer() | infinity</pre></li></ul>
+
+Wait for a local name to be registered on `Node`.
+This function works exactly like [`await/2`](#await-2), but queries a remote
+node instead. An exception is thrown if `Node` cannot be reached. If gproc
+is not running on a given node, this is treated the same as the node being
+down.<a name="bcast-2"></a>
 
 
 ###bcast/2##
 ###bcast/2##
 
 
@@ -361,7 +373,20 @@ __See also:__ [send/2](#send-2).<a name="cancel_wait-2"></a>
 Cancels a previous call to nb_wait/1
 Cancels a previous call to nb_wait/1
 
 
 If `Ref = all`, all wait requests on `Key` from the calling process
 If `Ref = all`, all wait requests on `Key` from the calling process
-are canceled.<a name="cancel_wait_or_monitor-1"></a>
+are canceled.<a name="cancel_wait-3"></a>
+
+###cancel_wait/3##
+
+
+<pre>cancel_wait(Node::node(), Key::<a href="#type-key">key()</a>, Ref) -> ok</pre>
+<ul class="definitions"><li><pre>Ref = all | reference()</pre></li></ul>
+
+
+
+Cancels a previous call to nb_wait/2
+
+This function works just like [`cancel_wait/2`](#cancel_wait-2), but talks to a remote
+node.<a name="cancel_wait_or_monitor-1"></a>
 
 
 ###cancel_wait_or_monitor/1##
 ###cancel_wait_or_monitor/1##
 
 
@@ -819,6 +844,17 @@ repeatedly.<a name="nb_wait-1"></a>
 
 
 Wait for a local name to be registered.
 Wait for a local name to be registered.
 The caller can expect to receive a message,
 The caller can expect to receive a message,
+{gproc, Ref, registered, {Key, Pid, Value}}, once the name is registered.<a name="nb_wait-2"></a>
+
+###nb_wait/2##
+
+
+<pre>nb_wait(Node::node(), Key::<a href="#type-key">key()</a>) -> Ref</pre>
+<br></br>
+
+
+Wait for a local name to be registered on `Node`.
+The caller can expect to receive a message,
 {gproc, Ref, registered, {Key, Pid, Value}}, once the name is registered.<a name="next-2"></a>
 {gproc, Ref, registered, {Key, Pid, Value}}, once the name is registered.<a name="next-2"></a>
 
 
 ###next/2##
 ###next/2##
@@ -1231,4 +1267,21 @@ cases.<a name="whereis_name-1"></a>
 
 
 `whereis_name(Key) -> any()`
 `whereis_name(Key) -> any()`
 
 
-Equivalent to `where / 1`.
+Equivalent to `where / 1`.<a name="wide_await-3"></a>
+
+###wide_await/3##
+
+
+<pre>wide_await(Nodes::[node()], Key::<a href="#type-key">key()</a>, Timeout) -> {pid(), Value}</pre>
+<ul class="definitions"><li><pre>Timeout = integer() | infinity</pre></li></ul>
+
+
+
+Wait for a local name to be registered on any of `Nodes`.
+This function works rather like [`await/2`](#await-2), but queries all nodes in
+the `Nodes` list at the same time. The first node to respond with a
+process registered as `Key` will provide the result. Other results are
+ignored. `Key` must be a unique name with local scope, i.e. `{n,l,Name}`.
+
+An exception is thrown upon timeout, or if no node can be reached (if gproc is
+not running on a given node, this is treated the same as the node being down).

+ 141 - 6
src/gproc.erl

@@ -78,9 +78,10 @@
          set_value/2,
          set_value/2,
          get_value/1, get_value/2,
          get_value/1, get_value/2,
          where/1,
          where/1,
-         await/1, await/2,
-         nb_wait/1,
-         cancel_wait/2,
+         await/1, await/2, await/3,
+	 wide_await/3,
+         nb_wait/1, nb_wait/2,
+         cancel_wait/2, cancel_wait/3,
 	 cancel_wait_or_monitor/1,
 	 cancel_wait_or_monitor/1,
 	 monitor/1,
 	 monitor/1,
 	 demonitor/2,
 	 demonitor/2,
@@ -624,6 +625,21 @@ await(Key) ->
 await(Key, Timeout) ->
 await(Key, Timeout) ->
     ?CATCH_GPROC_ERROR(await1(Key, Timeout), [Key, Timeout]).
     ?CATCH_GPROC_ERROR(await1(Key, Timeout), [Key, Timeout]).
 
 
+%% @spec await(Node::node(), Key::key(), Timeout) -> {pid(),Value}
+%%   Timeout = integer() | infinity
+%%
+%% @doc Wait for a local name to be registered on `Node'.
+%% This function works exactly like {@link await/2}, but queries a remote
+%% node instead. An exception is thrown if `Node' cannot be reached. If gproc
+%% is not running on a given node, this is treated the same as the node being
+%% down.
+%% @end
+%%
+await(Node, Key, Timeout) when Node == node() ->
+    await(Key, Timeout);
+await(Node, Key, Timeout) when is_atom(Node) ->
+    ?CATCH_GPROC_ERROR(await1(Node, Key, Timeout), [Node, Key, Timeout]).
+
 await1({n,g,_} = Key, Timeout) ->
 await1({n,g,_} = Key, Timeout) ->
     ?CHK_DIST,
     ?CHK_DIST,
     request_wait(Key, Timeout);
     request_wait(Key, Timeout);
@@ -649,7 +665,16 @@ await1({n,l,_} = Key, Timeout) ->
 await1(_, _) ->
 await1(_, _) ->
     throw(badarg).
     throw(badarg).
 
 
-request_wait({n,C,_} = Key, Timeout) when C==l; C==g ->
+await1(N, {n,l,_} = Key, Timeout) when is_atom(N) ->
+    request_wait(N, Key, Timeout);
+await1(_, _, _) ->
+    throw(badarg).
+
+
+request_wait(Key, Timeout) ->
+    request_wait(node(), Key, Timeout).
+
+request_wait(N, {n,C,_} = Key, Timeout) when C==l; C==g ->
     TRef = case Timeout of
     TRef = case Timeout of
                infinity -> no_timer;
                infinity -> no_timer;
                T when is_integer(T), T > 0 ->
                T when is_integer(T), T > 0 ->
@@ -657,7 +682,7 @@ request_wait({n,C,_} = Key, Timeout) when C==l; C==g ->
                _ ->
                _ ->
                    ?THROW_GPROC_ERROR(badarg)
                    ?THROW_GPROC_ERROR(badarg)
            end,
            end,
-    WRef = case {call({await,Key,self()}, C), C} of
+    WRef = case {call(N, {await,Key,self()}, C), C} of
                {{R, {Kg,Pg,Vg}}, g} ->
                {{R, {Kg,Pg,Vg}}, g} ->
                    self() ! {gproc, R, registered, {Kg,Pg,Vg}},
                    self() ! {gproc, R, registered, {Kg,Pg,Vg}},
                    R;
                    R;
@@ -672,10 +697,80 @@ request_wait({n,C,_} = Key, Timeout) when C==l; C==g ->
                 end,
                 end,
             {Pid, V};
             {Pid, V};
         {timeout, TRef, gproc_timeout} ->
         {timeout, TRef, gproc_timeout} ->
-            cancel_wait(Key, WRef),
+            cancel_wait(N, Key, WRef),
             ?THROW_GPROC_ERROR(timeout)
             ?THROW_GPROC_ERROR(timeout)
     end.
     end.
 
 
+%% @spec wide_await(Nodes::[node()], Key::key(), Timeout) -> {pid(),Value}
+%%   Timeout = integer() | infinity
+%%
+%% @doc Wait for a local name to be registered on any of `Nodes'.
+%% This function works rather like {@link await/2}, but queries all nodes in
+%% the `Nodes' list at the same time. The first node to respond with a
+%% process registered as `Key' will provide the result. Other results are
+%% ignored. `Key' must be a unique name with local scope, i.e. `{n,l,Name}'.
+%%
+%% An exception is thrown upon timeout, or if no node can be reached (if gproc is
+%% not running on a given node, this is treated the same as the node being down).
+%% @end
+%%
+wide_await(Nodes, Key, Timeout) ->
+    ?CATCH_GPROC_ERROR(wide_await1(Nodes, Key, Timeout), [Nodes, Key, Timeout]).
+
+wide_await1(Nodes, {n,l,_} = Key, Timeout) ->
+    {_, Ref} = spawn_monitor(fun() ->
+				     wide_request_wait(Nodes, Key, Timeout)
+			     end),
+    receive
+	{'DOWN', Ref, _, _, Reason} ->
+	    case Reason of
+		{ok, {gproc,_,registered,{_,Pid,V}}} ->
+		    {Pid, V};
+		Other ->
+		    ?THROW_GPROC_ERROR(Other)
+	    end
+    end;
+wide_await1(_, _, _) ->
+    ?THROW_GPROC_ERROR(badarg).
+
+
+wide_request_wait(Nodes, {n,l,_} = Key, Timeout) ->
+        TRef = case Timeout of
+               infinity -> no_timer;
+               T when is_integer(T), T > 0 ->
+                   erlang:start_timer(T, self(), gproc_timeout);
+               _ ->
+                   exit(badarg)
+           end,
+    Req = {await, Key, self()},
+    Refs = lists:map(
+	     fun(Node) ->
+		     S = {?MODULE, Node},
+		     Ref = erlang:monitor(process, S),
+		     catch erlang:send(S, {'$gen_call', {self(), Ref}, Req},
+				       [noconnect]),
+		     {Node, Ref}
+	     end, Nodes),
+    collect_replies(Refs, Key, TRef).
+
+collect_replies(Refs, Key, TRef) ->
+    receive
+	{gproc, _Ref, registered, {_, _, _}} = Result ->
+	    exit({ok, Result});
+	{'DOWN', Ref, _, _, _} ->
+	    case lists:keydelete(Ref, 2, Refs) of
+		[] ->
+		    exit(nodedown);
+		Refs1 ->
+		    collect_replies(Refs1, Key, TRef)
+	    end;
+	{timeout, TRef, gproc_timeout} ->
+	    exit(timeout);
+	{Ref, Ref} ->
+	    %% ignore
+	    collect_replies(Refs, Key, TRef)
+    end.
+
 
 
 %% @spec nb_wait(Key::key()) -> Ref
 %% @spec nb_wait(Key::key()) -> Ref
 %%
 %%
@@ -687,6 +782,16 @@ request_wait({n,C,_} = Key, Timeout) when C==l; C==g ->
 nb_wait(Key) ->
 nb_wait(Key) ->
     ?CATCH_GPROC_ERROR(nb_wait1(Key), [Key]).
     ?CATCH_GPROC_ERROR(nb_wait1(Key), [Key]).
 
 
+%% @spec nb_wait(Node::node(), Key::key()) -> Ref
+%%
+%% @doc Wait for a local name to be registered on `Node'.
+%% The caller can expect to receive a message,
+%% {gproc, Ref, registered, {Key, Pid, Value}}, once the name is registered.
+%% @end
+%%
+nb_wait(Node, {n,l,_} = Key) when is_atom(Node) ->
+    ?CATCH_GPROC_ERROR(nb_wait1(Node, Key), [Node, Key]).
+
 nb_wait1({n,g,_} = Key) ->
 nb_wait1({n,g,_} = Key) ->
     ?CHK_DIST,
     ?CHK_DIST,
     call({await, Key, self()}, g);
     call({await, Key, self()}, g);
@@ -695,6 +800,12 @@ nb_wait1({n,l,_} = Key) ->
 nb_wait1(_) ->
 nb_wait1(_) ->
     ?THROW_GPROC_ERROR(badarg).
     ?THROW_GPROC_ERROR(badarg).
 
 
+nb_wait1(Node, {n,l,_} = Key) when is_atom(Node) ->
+    call(Node, {await, Key, self()}, l);
+nb_wait1(_, _) ->
+    ?THROW_GPROC_ERROR(badarg).
+
+
 %% @spec cancel_wait(Key::key(), Ref) -> ok
 %% @spec cancel_wait(Key::key(), Ref) -> ok
 %%    Ref = all | reference()
 %%    Ref = all | reference()
 %%
 %%
@@ -707,6 +818,21 @@ nb_wait1(_) ->
 cancel_wait(Key, Ref) ->
 cancel_wait(Key, Ref) ->
     ?CATCH_GPROC_ERROR(cancel_wait1(Key, Ref), [Key, Ref]).
     ?CATCH_GPROC_ERROR(cancel_wait1(Key, Ref), [Key, Ref]).
 
 
+%% @spec cancel_wait(Node::node(), Key::key(), Ref) -> ok
+%%    Ref = all | reference()
+%%
+%% @doc Cancels a previous call to nb_wait/2
+%%
+%% This function works just like {@link cancel_wait/2}, but talks to a remote
+%% node.
+%% @end
+%%
+cancel_wait(N, Key, Ref) when N == node() ->
+    cancel_wait(Key, Ref);
+cancel_wait(N, Key, Ref) ->
+    ?CATCH_GPROC_ERROR(cancel_wait1(N, Key, Ref), [N, Key, Ref]).
+
+
 cancel_wait1({_,g,_} = Key, Ref) ->
 cancel_wait1({_,g,_} = Key, Ref) ->
     ?CHK_DIST,
     ?CHK_DIST,
     cast({cancel_wait, self(), Key, Ref}, g),
     cast({cancel_wait, self(), Key, Ref}, g),
@@ -715,6 +841,9 @@ cancel_wait1({_,l,_} = Key, Ref) ->
     cast({cancel_wait, self(), Key, Ref}, l),
     cast({cancel_wait, self(), Key, Ref}, l),
     ok.
     ok.
 
 
+cancel_wait1(N, {_,l,_} = Key, Ref) ->
+    cast(N, {cancel_wait, self(), Key, Ref}, l).
+
 cancel_wait_or_monitor(Key) ->
 cancel_wait_or_monitor(Key) ->
     ?CATCH_GPROC_ERROR(cancel_wait_or_monitor1(Key), [Key]).
     ?CATCH_GPROC_ERROR(cancel_wait_or_monitor1(Key), [Key]).
 
 
@@ -1770,6 +1899,9 @@ call(Req, l) ->
 call(Req, g) ->
 call(Req, g) ->
     chk_reply(gproc_dist:leader_call(Req)).
     chk_reply(gproc_dist:leader_call(Req)).
 
 
+call(N, Req, l) ->
+    chk_reply(gen_server:call({?MODULE, N}, Req)).
+
 chk_reply(Reply) ->
 chk_reply(Reply) ->
     case Reply of
     case Reply of
         badarg -> ?THROW_GPROC_ERROR(badarg);
         badarg -> ?THROW_GPROC_ERROR(badarg);
@@ -1785,6 +1917,9 @@ cast(Msg, l) ->
 cast(Msg, g) ->
 cast(Msg, g) ->
     gproc_dist:leader_cast(Msg).
     gproc_dist:leader_cast(Msg).
 
 
+cast(N, Msg, l) ->
+    gen_server:cast({?MODULE, N}, Msg).
+
 try_insert_reg({T,l,_} = Key, Val, Pid) ->
 try_insert_reg({T,l,_} = Key, Val, Pid) ->
     case gproc_lib:insert_reg(Key, Val, Pid, l) of
     case gproc_lib:insert_reg(Key, Val, Pid, l) of
         false ->
         false ->

+ 1 - 1
src/gproc_lib.erl

@@ -255,7 +255,7 @@ mk_reg_rev_objs(T, Scope, Pid, L) ->
 ensure_monitor(shared, _) ->
 ensure_monitor(shared, _) ->
     ok;
     ok;
 ensure_monitor(Pid, Scope) when Scope==g; Scope==l ->
 ensure_monitor(Pid, Scope) when Scope==g; Scope==l ->
-    case node(Pid) == node() andalso ets:insert_new(?TAB, {{Pid, Scope}}) of
+    case ets:insert_new(?TAB, {{Pid, Scope}}) of
         false -> ok;
         false -> ok;
         true  -> erlang:monitor(process, Pid)
         true  -> erlang:monitor(process, Pid)
     end.
     end.