Browse Source

added surrender/2

Ulf Wiger 14 years ago
parent
commit
4ffd1faec8
8 changed files with 465 additions and 300 deletions
  1. 309 200
      doc/gproc.md
  2. 2 8
      doc/gproc_app.md
  3. 13 49
      doc/gproc_dist.md
  4. 2 6
      doc/gproc_init.md
  5. 1 1
      doc/gproc_lib.md
  6. 3 7
      doc/gproc_sup.md
  7. 84 18
      src/gproc.erl
  8. 51 11
      src/gproc_dist.erl

+ 309 - 200
doc/gproc.md

@@ -29,69 +29,98 @@ For a detailed description, see
 [erlang07-wiger.pdf](erlang07-wiger.pdf).
 
 
+
 <h2><a name="types">Data Types</a></h2>
 
 
-<a name="type-context"></a>
 
 
-<h3 class="typedecl">context()</h3>
 
-<tt>context() = {<a href="#type-scope">scope()</a>, <a href="#type-type">type()</a>} | <a href="#type-type">type()</a></tt>
+<h3 class="typedecl"><a name="type-context">context()</a></h3>
+
+
+
+
+`context() = {[scope()](#type-scope), [type()](#type-type)} | [type()](#type-type)`
+
 
 Local scope is the default
-<a name="type-headpat"></a>
 
 
-<h3 class="typedecl">headpat()</h3>
+<h3 class="typedecl"><a name="type-headpat">headpat()</a></h3>
+
+
+
+
+`headpat() = {[keypat()](#type-keypat), [pidpat()](#type-pidpat), ValPat}`
+
+
+
+<h3 class="typedecl"><a name="type-key">key()</a></h3>
+
 
-<tt>headpat() = {<a href="#type-keypat">keypat()</a>, <a href="#type-pidpat">pidpat()</a>, ValPat}</tt>
-<a name="type-key"></a>
 
 
-<h3 class="typedecl">key()</h3>
+`key() = {[type()](#type-type), [scope()](#type-scope), any()}`
 
-<tt>key() = {<a href="#type-type">type()</a>, <a href="#type-scope">scope()</a>, any()}</tt>
-<a name="type-keypat"></a>
 
 
-<h3 class="typedecl">keypat()</h3>
+<h3 class="typedecl"><a name="type-keypat">keypat()</a></h3>
 
-<tt>keypat() = {<a href="#type-sel_type">sel_type()</a> | <a href="#type-sel_var">sel_var()</a>, l | g | <a href="#type-sel_var">sel_var()</a>, any()}</tt>
-<a name="type-pidpat"></a>
 
 
-<h3 class="typedecl">pidpat()</h3>
 
-<tt>pidpat() = pid() | <a href="#type-sel_var">sel_var()</a></tt>
+`keypat() = {[sel_type()](#type-sel_type) | [sel_var()](#type-sel_var), l | g | [sel_var()](#type-sel_var), any()}`
+
+
+
+<h3 class="typedecl"><a name="type-pidpat">pidpat()</a></h3>
+
+
+
+
+`pidpat() = pid() | [sel_var()](#type-sel_var)`
+
 
 sel_var() = DollarVar | '_'.
-<a name="type-scope"></a>
 
 
-<h3 class="typedecl">scope()</h3>
+<h3 class="typedecl"><a name="type-scope">scope()</a></h3>
+
+
+
+
+`scope() = l | g`
 
-<tt>scope() = l | g</tt>
 
 l = local registration; g = global registration
-<a name="type-sel_pattern"></a>
 
 
-<h3 class="typedecl">sel_pattern()</h3>
+<h3 class="typedecl"><a name="type-sel_pattern">sel_pattern()</a></h3>
+
 
-<tt>sel_pattern() = [{<a href="#type-headpat">headpat()</a>, Guards, Prod}]</tt>
-<a name="type-sel_type"></a>
 
 
-<h3 class="typedecl">sel_type()</h3>
+`sel_pattern() = [{[headpat()](#type-headpat), Guards, Prod}]`
 
-<tt>sel_type() = n | p | c | a | names | props | counters | aggr_counters</tt>
-<a name="type-type"></a>
 
 
-<h3 class="typedecl">type()</h3>
+<h3 class="typedecl"><a name="type-sel_type">sel_type()</a></h3>
+
+
+
+
+`sel_type() = n | p | c | a | names | props | counters | aggr_counters`
+
+
+
+<h3 class="typedecl"><a name="type-type">type()</a></h3>
+
+
+
+
+`type() = n | p | c | a`
 
-<tt>type() = n | p | c | a</tt>
 
 n = name; p = property; c = counter;
 a = aggregate_counter
@@ -100,18 +129,16 @@ a = aggregate_counter
 
 
 
-<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="#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="#cancel_wait-2">cancel_wait/2</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="#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_value-1">get_value/1</a></td><td>Read the value stored with a key registered to the current process.</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="#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="#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="#select-1">select/1</a></td><td>Equivalent to <a href="#select-2"><tt>select(all, Pat)</tt></a>.</td></tr><tr><td valign="top"><a href="#select-2">select/2</a></td><td>Perform a select operation 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="#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_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-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="#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="#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>
+<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="#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="#cancel_wait-2">cancel_wait/2</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="#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_value-1">get_value/1</a></td><td>Read the value stored with a key registered to the current process.</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="#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="#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="#select-1">select/1</a></td><td>Equivalent to <a href="#select-2"><tt>select(all, Pat)</tt></a>.</td></tr><tr><td valign="top"><a href="#select-2">select/2</a></td><td>Perform a select operation 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="#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_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="#surrender-2">surrender/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="#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="#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="#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 name="functions"></a>
 
 
-<h2>Function Details</h2>
+<h2><a name="functions">Function Details</a></h2>
 
 
 <a name="add_global_aggr_counter-1"></a>
 
-
 <h3>add_global_aggr_counter/1</h3>
 
 
@@ -124,9 +151,7 @@ a = aggregate_counter
 
 Equivalent to [`reg({a, g, Name})`](#reg-1).
 
-Registers a global (unique) aggregated counter.
-<a name="add_global_counter-2"></a>
-
+Registers a global (unique) aggregated counter.<a name="add_global_counter-2"></a>
 
 <h3>add_global_counter/2</h3>
 
@@ -138,9 +163,7 @@ Registers a global (unique) aggregated counter.
 
 
 
-Registers a global (non-unique) counter. @equiv reg({c,g,Name},Value)
-<a name="add_global_name-1"></a>
-
+Registers a global (non-unique) counter. @equiv reg({c,g,Name},Value)<a name="add_global_name-1"></a>
 
 <h3>add_global_name/1</h3>
 
@@ -152,9 +175,7 @@ Registers a global (non-unique) counter. @equiv reg({c,g,Name},Value)
 
 
 
-Registers a global (unique) name. @equiv reg({n,g,Name})
-<a name="add_global_property-2"></a>
-
+Registers a global (unique) name. @equiv reg({n,g,Name})<a name="add_global_property-2"></a>
 
 <h3>add_global_property/2</h3>
 
@@ -166,9 +187,7 @@ Registers a global (unique) name. @equiv reg({n,g,Name})
 
 
 
-Registers a global (non-unique) property. @equiv reg({p,g,Name},Value)
-<a name="add_local_aggr_counter-1"></a>
-
+Registers a global (non-unique) property. @equiv reg({p,g,Name},Value)<a name="add_local_aggr_counter-1"></a>
 
 <h3>add_local_aggr_counter/1</h3>
 
@@ -182,9 +201,7 @@ Registers a global (non-unique) property. @equiv reg({p,g,Name},Value)
 
 Equivalent to [`reg({a, l, Name})`](#reg-1).
 
-Registers a local (unique) aggregated counter.
-<a name="add_local_counter-2"></a>
-
+Registers a local (unique) aggregated counter.<a name="add_local_counter-2"></a>
 
 <h3>add_local_counter/2</h3>
 
@@ -196,9 +213,7 @@ Registers a local (unique) aggregated counter.
 
 
 
-Registers a local (non-unique) counter. @equiv reg({c,l,Name},Value)
-<a name="add_local_name-1"></a>
-
+Registers a local (non-unique) counter. @equiv reg({c,l,Name},Value)<a name="add_local_name-1"></a>
 
 <h3>add_local_name/1</h3>
 
@@ -210,9 +225,7 @@ Registers a local (non-unique) counter. @equiv reg({c,l,Name},Value)
 
 
 
-Registers a local (unique) name. @equiv reg({n,l,Name})
-<a name="add_local_property-2"></a>
-
+Registers a local (unique) name. @equiv reg({n,l,Name})<a name="add_local_property-2"></a>
 
 <h3>add_local_property/2</h3>
 
@@ -224,9 +237,7 @@ Registers a local (unique) name. @equiv reg({n,l,Name})
 
 
 
-Registers a local (non-unique) property. @equiv reg({p,l,Name},Value)
-<a name="audit_process-1"></a>
-
+Registers a local (non-unique) property. @equiv reg({p,l,Name},Value)<a name="audit_process-1"></a>
 
 <h3>audit_process/1</h3>
 
@@ -236,32 +247,34 @@ Registers a local (non-unique) property. @equiv reg({p,l,Name},Value)
 
 `audit_process(Pid) -> any()`
 
-
 <a name="await-1"></a>
 
-
 <h3>await/1</h3>
 
 
 
 
 
-<tt>await(Key::<a href="#type-key">key()</a>) -> {pid(), Value}</tt>
 
+<pre>await(Key::<a href="#type-key">key()</a>) -> {pid(), Value}</pre>
+
+<br></br>
 
 
-Equivalent to [`await(Key, infinity)`](#await-2).
-<a name="await-2"></a>
 
 
+Equivalent to [`await(Key, infinity)`](#await-2).<a name="await-2"></a>
+
 <h3>await/2</h3>
 
 
 
 
 
-<tt>await(Key::<a href="#type-key">key()</a>, Timeout) -> {pid(), Value}</tt>* `Timeout = integer() | infinity`
 
+<pre>await(Key::<a href="#type-key">key()</a>, Timeout) -> {pid(), Value}</pre>
+
+<ul class="definitions"><li><tt>Timeout = integer() | infinity</tt></li></ul>
 
 
 
@@ -271,9 +284,7 @@ either an interger > 0 or 'infinity'.
 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
 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="cancel_wait-2"></a>
-
+registered (the difference: await/2 also returns the value).<a name="cancel_wait-2"></a>
 
 <h3>cancel_wait/2</h3>
 
@@ -283,10 +294,8 @@ registered (the difference: await/2 also returns the value).
 
 `cancel_wait(Key, Ref) -> any()`
 
-
 <a name="default-1"></a>
 
-
 <h3>default/1</h3>
 
 
@@ -295,17 +304,19 @@ registered (the difference: await/2 also returns the value).
 
 `default(X1) -> any()`
 
-
 <a name="first-1"></a>
 
-
 <h3>first/1</h3>
 
 
 
 
 
-<tt>first(Type::<a href="#type-type">type()</a>) -> <a href="#type-key">key()</a> | '$end_of_table'</tt>
+
+<pre>first(Type::<a href="#type-type">type()</a>) -> <a href="#type-key">key()</a> | '$end_of_table'</pre>
+
+<br></br>
+
 
 
 
@@ -314,9 +325,7 @@ registered (the difference: await/2 also returns the value).
 Behaves as ets:first(Tab) for a given type of registration object.
 
 See [`http://www.erlang.org/doc/man/ets.html#first-1`](http://www.erlang.org/doc/man/ets.html#first-1).
-The registry behaves as an ordered_set table.
-<a name="get_value-1"></a>
-
+The registry behaves as an ordered_set table.<a name="get_value-1"></a>
 
 <h3>get_value/1</h3>
 
@@ -324,17 +333,19 @@ The registry behaves as an ordered_set table.
 
 
 
-<tt>get_value(Key) -> Value</tt>
 
+<pre>get_value(Key) -> Value</pre>
+
+<br></br>
 
 
 
 
-Read the value stored with a key registered to the current process.
 
-If no such key is registered to the current process, this function exits.
-<a name="info-1"></a>
 
+Read the value stored with a key registered to the current process.
+
+If no such key is registered to the current process, this function exits.<a name="info-1"></a>
 
 <h3>info/1</h3>
 
@@ -342,8 +353,10 @@ If no such key is registered to the current process, this function exits.
 
 
 
-<tt>info(Pid::pid()) -> ProcessInfo</tt>* `ProcessInfo = [{gproc, [{Key, Value}]} | ProcessInfo]`
 
+<pre>info(Pid::pid()) -> ProcessInfo</pre>
+
+<ul class="definitions"><li><tt>ProcessInfo = [{gproc, [{Key, Value}]} | ProcessInfo]</tt></li></ul>
 
 
 
@@ -353,9 +366,7 @@ Similar to `process_info(Pid)` but with additional gproc info.
 
 Returns the same information as process_info(Pid), but with the
 addition of a `gproc` information item, containing the `{Key,Value}`
-pairs registered to the process.
-<a name="info-2"></a>
-
+pairs registered to the process.<a name="info-2"></a>
 
 <h3>info/2</h3>
 
@@ -363,7 +374,11 @@ pairs registered to the process.
 
 
 
-<tt>info(Pid::pid(), Item::atom()) -> {Item, Info}</tt>
+
+<pre>info(Pid::pid(), Item::atom()) -> {Item, Info}</pre>
+
+<br></br>
+
 
 
 
@@ -373,9 +388,7 @@ Similar to process_info(Pid, Item), but with additional gproc info.
 
 For `Item = gproc`, this function returns a list of `{Key, Value}` pairs
 registered to the process Pid. For other values of Item, it returns the
-same as [`http://www.erlang.org/doc/man/erlang.html#process_info-2`](http://www.erlang.org/doc/man/erlang.html#process_info-2).
-<a name="last-1"></a>
-
+same as [`http://www.erlang.org/doc/man/erlang.html#process_info-2`](http://www.erlang.org/doc/man/erlang.html#process_info-2).<a name="last-1"></a>
 
 <h3>last/1</h3>
 
@@ -383,7 +396,11 @@ same as [`http://www.erlang.org/doc/man/erlang.html#process_info-2`](http://www.
 
 
 
-<tt>last(Context::<a href="#type-context">context()</a>) -> <a href="#type-key">key()</a> | '$end_of_table'</tt>
+
+<pre>last(Context::<a href="#type-context">context()</a>) -> <a href="#type-key">key()</a> | '$end_of_table'</pre>
+
+<br></br>
+
 
 
 
@@ -392,9 +409,7 @@ same as [`http://www.erlang.org/doc/man/erlang.html#process_info-2`](http://www.
 Behaves as ets:last(Tab) for a given type of registration object.
 
 See [`http://www.erlang.org/doc/man/ets.html#last-1`](http://www.erlang.org/doc/man/ets.html#last-1).
-The registry behaves as an ordered_set table.
-<a name="lookup_global_aggr_counter-1"></a>
-
+The registry behaves as an ordered_set table.<a name="lookup_global_aggr_counter-1"></a>
 
 <h3>lookup_global_aggr_counter/1</h3>
 
@@ -402,16 +417,18 @@ The registry behaves as an ordered_set table.
 
 
 
-<tt>lookup_global_aggr_counter(Name::any()) -> integer()</tt>
+
+<pre>lookup_global_aggr_counter(Name::any()) -> integer()</pre>
+
+<br></br>
+
 
 
 
 Equivalent to [`where({a, g, Name})`](#where-1).
 
 Lookup a global (unique) aggregated counter and returns its value.
-Fails if there is no such object.
-<a name="lookup_global_counters-1"></a>
-
+Fails if there is no such object.<a name="lookup_global_counters-1"></a>
 
 <h3>lookup_global_counters/1</h3>
 
@@ -419,16 +436,18 @@ Fails if there is no such object.
 
 
 
-<tt>lookup_global_counters(Counter::any()) -> [{pid(), Value::integer()}]</tt>
+
+<pre>lookup_global_counters(Counter::any()) -> [{pid(), Value::integer()}]</pre>
+
+<br></br>
+
 
 
 
 Equivalent to [`lookup_values({c, g, Counter})`](#lookup_values-1).
 
 Look up all global (non-unique) instances of a given Counter.
-Returns a list of {Pid, Value} tuples for all matching objects.
-<a name="lookup_global_name-1"></a>
-
+Returns a list of {Pid, Value} tuples for all matching objects.<a name="lookup_global_name-1"></a>
 
 <h3>lookup_global_name/1</h3>
 
@@ -436,15 +455,17 @@ Returns a list of {Pid, Value} tuples for all matching objects.
 
 
 
-<tt>lookup_global_name(Name::any()) -> pid()</tt>
 
+<pre>lookup_global_name(Name::any()) -> pid()</pre>
+
+<br></br>
 
 
-Equivalent to [`where({n, g, Name})`](#where-1).
 
-Lookup a global unique name. Fails if there is no such name.
-<a name="lookup_global_properties-1"></a>
 
+Equivalent to [`where({n, g, Name})`](#where-1).
+
+Lookup a global unique name. Fails if there is no such name.<a name="lookup_global_properties-1"></a>
 
 <h3>lookup_global_properties/1</h3>
 
@@ -452,16 +473,18 @@ Lookup a global unique name. Fails if there is no such name.
 
 
 
-<tt>lookup_global_properties(Property::any()) -> [{pid(), Value}]</tt>
+
+<pre>lookup_global_properties(Property::any()) -> [{pid(), Value}]</pre>
+
+<br></br>
+
 
 
 
 Equivalent to [`lookup_values({p, g, Property})`](#lookup_values-1).
 
 Look up all global (non-unique) instances of a given Property.
-Returns a list of {Pid, Value} tuples for all matching objects.
-<a name="lookup_local_aggr_counter-1"></a>
-
+Returns a list of {Pid, Value} tuples for all matching objects.<a name="lookup_local_aggr_counter-1"></a>
 
 <h3>lookup_local_aggr_counter/1</h3>
 
@@ -469,16 +492,18 @@ Returns a list of {Pid, Value} tuples for all matching objects.
 
 
 
-<tt>lookup_local_aggr_counter(Name::any()) -> integer()</tt>
+
+<pre>lookup_local_aggr_counter(Name::any()) -> integer()</pre>
+
+<br></br>
+
 
 
 
 Equivalent to [`where({a, l, Name})`](#where-1).
 
 Lookup a local (unique) aggregated counter and returns its value.
-Fails if there is no such object.
-<a name="lookup_local_counters-1"></a>
-
+Fails if there is no such object.<a name="lookup_local_counters-1"></a>
 
 <h3>lookup_local_counters/1</h3>
 
@@ -486,16 +511,18 @@ Fails if there is no such object.
 
 
 
-<tt>lookup_local_counters(Counter::any()) -> [{pid(), Value::integer()}]</tt>
+
+<pre>lookup_local_counters(Counter::any()) -> [{pid(), Value::integer()}]</pre>
+
+<br></br>
+
 
 
 
 Equivalent to [`lookup_values({c, l, Counter})`](#lookup_values-1).
 
 Look up all local (non-unique) instances of a given Counter.
-Returns a list of {Pid, Value} tuples for all matching objects.
-<a name="lookup_local_name-1"></a>
-
+Returns a list of {Pid, Value} tuples for all matching objects.<a name="lookup_local_name-1"></a>
 
 <h3>lookup_local_name/1</h3>
 
@@ -503,15 +530,17 @@ Returns a list of {Pid, Value} tuples for all matching objects.
 
 
 
-<tt>lookup_local_name(Name::any()) -> pid()</tt>
+
+<pre>lookup_local_name(Name::any()) -> pid()</pre>
+
+<br></br>
 
 
 
-Equivalent to [`where({n, l, Name})`](#where-1).
 
-Lookup a local unique name. Fails if there is no such name.
-<a name="lookup_local_properties-1"></a>
+Equivalent to [`where({n, l, Name})`](#where-1).
 
+Lookup a local unique name. Fails if there is no such name.<a name="lookup_local_properties-1"></a>
 
 <h3>lookup_local_properties/1</h3>
 
@@ -519,16 +548,18 @@ Lookup a local unique name. Fails if there is no such name.
 
 
 
-<tt>lookup_local_properties(Property::any()) -> [{pid(), Value}]</tt>
+
+<pre>lookup_local_properties(Property::any()) -> [{pid(), Value}]</pre>
+
+<br></br>
+
 
 
 
 Equivalent to [`lookup_values({p, l, Property})`](#lookup_values-1).
 
 Look up all local (non-unique) instances of a given Property.
-Returns a list of {Pid, Value} tuples for all matching objects.
-<a name="lookup_pid-1"></a>
-
+Returns a list of {Pid, Value} tuples for all matching objects.<a name="lookup_pid-1"></a>
 
 <h3>lookup_pid/1</h3>
 
@@ -536,22 +567,28 @@ Returns a list of {Pid, Value} tuples for all matching objects.
 
 
 
-<tt>lookup_pid(Key) -> Pid</tt>
 
+<pre>lookup_pid(Key) -> Pid</pre>
 
+<br></br>
 
-Lookup the Pid stored with a key.
 
-<a name="lookup_pids-1"></a>
 
 
+Lookup the Pid stored with a key.
+<a name="lookup_pids-1"></a>
+
 <h3>lookup_pids/1</h3>
 
 
 
 
 
-<tt>lookup_pids(Key::<a href="#type-key">key()</a>) -> [pid()]</tt>
+
+<pre>lookup_pids(Key::<a href="#type-key">key()</a>) -> [pid()]</pre>
+
+<br></br>
+
 
 
 
@@ -561,9 +598,7 @@ Returns a list of pids with the published key Key
 
 If the type of registration entry is either name or aggregated counter,
 this function will return either an empty list, or a list of one pid.
-For non-unique types, the return value can be a list of any length.
-<a name="lookup_value-1"></a>
-
+For non-unique types, the return value can be a list of any length.<a name="lookup_value-1"></a>
 
 <h3>lookup_value/1</h3>
 
@@ -571,22 +606,28 @@ For non-unique types, the return value can be a list of any length.
 
 
 
-<tt>lookup_value(Key) -> Value</tt>
 
+<pre>lookup_value(Key) -> Value</pre>
 
+<br></br>
 
-Lookup the value stored with a key.
 
-<a name="lookup_values-1"></a>
 
 
+Lookup the value stored with a key.
+<a name="lookup_values-1"></a>
+
 <h3>lookup_values/1</h3>
 
 
 
 
 
-<tt>lookup_values(Key::<a href="#type-key">key()</a>) -> [{pid(), Value}]</tt>
+
+<pre>lookup_values(Key::<a href="#type-key">key()</a>) -> [{pid(), Value}]</pre>
+
+<br></br>
+
 
 
 
@@ -596,9 +637,7 @@ Retrieve the `{Pid,Value}` pairs corresponding to Key.
 
 Key refer to any type of registry object. If it refers to a unique
 object, the list will be of length 0 or 1. If it refers to a non-unique
-object, the return value can be a list of any length.
-<a name="mreg-3"></a>
-
+object, the return value can be a list of any length.<a name="mreg-3"></a>
 
 <h3>mreg/3</h3>
 
@@ -606,17 +645,19 @@ object, the return value can be a list of any length.
 
 
 
-<tt>mreg(T::<a href="#type-type">type()</a>, X2::<a href="#type-scope">scope()</a>, KVL::[{Key::any(), Value::any()}]) -> true</tt>
+
+<pre>mreg(T::<a href="#type-type">type()</a>, X2::<a href="#type-scope">scope()</a>, KVL::[{Key::any(), Value::any()}]) -> true</pre>
+
+<br></br>
 
 
 
 
 
-Register multiple {Key,Value} pairs of a given type and scope.
 
-This function is more efficient than calling [`reg/2`](#reg-2) repeatedly.
-<a name="nb_wait-1"></a>
+Register multiple {Key,Value} pairs of a given type and scope.
 
+This function is more efficient than calling [`reg/2`](#reg-2) repeatedly.<a name="nb_wait-1"></a>
 
 <h3>nb_wait/1</h3>
 
@@ -624,15 +665,17 @@ This function is more efficient than calling [`reg/2`](#reg-2) repeatedly.
 
 
 
-<tt>nb_wait(Key::<a href="#type-key">key()</a>) -> Ref</tt>
+
+<pre>nb_wait(Key::<a href="#type-key">key()</a>) -> Ref</pre>
+
+<br></br>
+
 
 
 
 Wait for a local name to be registered.
 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>
 
 <h3>next/2</h3>
 
@@ -640,7 +683,11 @@ The caller can expect to receive a message,
 
 
 
-<tt>next(Context::<a href="#type-context">context()</a>, Key::<a href="#type-key">key()</a>) -> <a href="#type-key">key()</a> | '$end_of_table'</tt>
+
+<pre>next(Context::<a href="#type-context">context()</a>, Key::<a href="#type-key">key()</a>) -> <a href="#type-key">key()</a> | '$end_of_table'</pre>
+
+<br></br>
+
 
 
 
@@ -649,9 +696,7 @@ The caller can expect to receive a message,
 Behaves as ets:next(Tab,Key) for a given type of registration object.
 
 See [`http://www.erlang.org/doc/man/ets.html#next-2`](http://www.erlang.org/doc/man/ets.html#next-2).
-The registry behaves as an ordered_set table.
-<a name="prev-2"></a>
-
+The registry behaves as an ordered_set table.<a name="prev-2"></a>
 
 <h3>prev/2</h3>
 
@@ -659,7 +704,11 @@ The registry behaves as an ordered_set table.
 
 
 
-<tt>prev(Context::<a href="#type-context">context()</a>, Key::<a href="#type-key">key()</a>) -> <a href="#type-key">key()</a> | '$end_of_table'</tt>
+
+<pre>prev(Context::<a href="#type-context">context()</a>, Key::<a href="#type-key">key()</a>) -> <a href="#type-key">key()</a> | '$end_of_table'</pre>
+
+<br></br>
+
 
 
 
@@ -668,9 +717,7 @@ The registry behaves as an ordered_set table.
 Behaves as ets:prev(Tab,Key) for a given type of registration object.
 
 See [`http://www.erlang.org/doc/man/ets.html#prev-2`](http://www.erlang.org/doc/man/ets.html#prev-2).
-The registry behaves as an ordered_set table.
-<a name="reg-1"></a>
-
+The registry behaves as an ordered_set table.<a name="reg-1"></a>
 
 <h3>reg/1</h3>
 
@@ -678,31 +725,35 @@ The registry behaves as an ordered_set table.
 
 
 
-<tt>reg(Key::<a href="#type-key">key()</a>) -> true</tt>
 
+<pre>reg(Key::<a href="#type-key">key()</a>) -> true</pre>
 
+<br></br>
 
-Equivalent to [`reg(Key, default(Key))`](#reg-2).
-<a name="reg-2"></a>
 
 
+
+Equivalent to [`reg(Key, default(Key))`](#reg-2).<a name="reg-2"></a>
+
 <h3>reg/2</h3>
 
 
 
 
 
-<tt>reg(Key::<a href="#type-key">key()</a>, Value) -> true</tt>
 
+<pre>reg(Key::<a href="#type-key">key()</a>, Value) -> true</pre>
 
+<br></br>
 
 
 
-Register a name or property for the current process
 
 
-<a name="select-1"></a>
 
+Register a name or property for the current process
+
+<a name="select-1"></a>
 
 <h3>select/1</h3>
 
@@ -710,21 +761,27 @@ Register a name or property for the current process
 
 
 
-<tt>select(Pat::<a href="#type-select_pattern">select_pattern()</a>) -> list(<a href="#type-sel_object">sel_object()</a>)</tt>
 
+<pre>select(Pat::<a href="#type-select_pattern">select_pattern()</a>) -> list(<a href="#type-sel_object">sel_object()</a>)</pre>
 
+<br></br>
 
-Equivalent to [`select(all, Pat)`](#select-2).
-<a name="select-2"></a>
 
 
+
+Equivalent to [`select(all, Pat)`](#select-2).<a name="select-2"></a>
+
 <h3>select/2</h3>
 
 
 
 
 
-<tt>select(Type::<a href="#type-sel_type">sel_type()</a>, Pat::<a href="#type-sel_pattern">sel_pattern()</a>) -> [{Key, Pid, Value}]</tt>
+
+<pre>select(Type::<a href="#type-sel_type">sel_type()</a>, Pat::<a href="#type-sel_pattern">sel_pattern()</a>) -> [{Key, Pid, Value}]</pre>
+
+<br></br>
+
 
 
 
@@ -733,9 +790,7 @@ Equivalent to [`select(all, Pat)`](#select-2).
 Perform a select operation on the process registry.
 
 The physical representation in the registry may differ from the above,
-but the select patterns are transformed appropriately.
-<a name="select-3"></a>
-
+but the select patterns are transformed appropriately.<a name="select-3"></a>
 
 <h3>select/3</h3>
 
@@ -743,17 +798,19 @@ but the select patterns are transformed appropriately.
 
 
 
-<tt>select(Type::<a href="#type-sel_type">sel_type()</a>, Pat::<a href="#type-sel_patten">sel_patten()</a>, Limit::integer()) -> [{Key, Pid, Value}]</tt>
+
+<pre>select(Type::<a href="#type-sel_type">sel_type()</a>, Pat::<a href="#type-sel_patten">sel_patten()</a>, Limit::integer()) -> [{Key, Pid, Value}]</pre>
+
+<br></br>
 
 
 
 
 
-Like [`select/2`](#select-2) but returns Limit objects at a time.
 
-See [`http://www.erlang.org/doc/man/ets.html#select-3`](http://www.erlang.org/doc/man/ets.html#select-3).
-<a name="send-2"></a>
+Like [`select/2`](#select-2) but returns Limit objects at a time.
 
+See [`http://www.erlang.org/doc/man/ets.html#select-3`](http://www.erlang.org/doc/man/ets.html#select-3).<a name="send-2"></a>
 
 <h3>send/2</h3>
 
@@ -761,7 +818,11 @@ See [`http://www.erlang.org/doc/man/ets.html#select-3`](http://www.erlang.org/do
 
 
 
-<tt>send(Key::<a href="#type-key">key()</a>, Msg::any()) -> Msg</tt>
+
+<pre>send(Key::<a href="#type-key">key()</a>, Msg::any()) -> Msg</pre>
+
+<br></br>
+
 
 
 
@@ -772,9 +833,7 @@ Sends a message to the process, or processes, corresponding to Key.
 If Key belongs to a unique object (name or aggregated counter), this
 function will send a message to the corresponding process, or fail if there
 is no such process. If Key is for a non-unique object type (counter or
-property), Msg will be send to all processes that have such an object.
-<a name="set_value-2"></a>
-
+property), Msg will be send to all processes that have such an object.<a name="set_value-2"></a>
 
 <h3>set_value/2</h3>
 
@@ -782,7 +841,11 @@ property), Msg will be send to all processes that have such an object.
 
 
 
-<tt>set_value(Key::<a href="#type-key">key()</a>, Value) -> true</tt>
+
+<pre>set_value(Key::<a href="#type-key">key()</a>, Value) -> true</pre>
+
+<br></br>
+
 
 
 
@@ -796,9 +859,7 @@ Key is assumed to exist and belong to the calling process.
 If it doesn't, this function will exit.
 
 Value can be any term, unless the object is a counter, in which case
-it must be an integer.
-<a name="start_link-0"></a>
-
+it must be an integer.<a name="start_link-0"></a>
 
 <h3>start_link/0</h3>
 
@@ -806,7 +867,11 @@ it must be an integer.
 
 
 
-<tt>start_link() -> {ok, pid()}</tt>
+
+<pre>start_link() -> {ok, pid()}</pre>
+
+<br></br>
+
 
 
 
@@ -815,39 +880,79 @@ it must be an integer.
 Starts the gproc server.
 
 This function is intended to be called from gproc_sup, as part of
-starting the gproc application.
-<a name="table-1"></a>
+starting the gproc application.<a name="surrender-2"></a>
+
+<h3>surrender/2</h3>
+
+
+
+
+
+
+<pre>surrender(From::<a href="#type-key">key()</a>, To::pid() | <a href="#type-key">key()</a>) -> undefined | pid()</pre>
+
+<br></br>
+
+
+
+
+
+
+Atomically transfers the key `From` to the process identified by `To`.
 
 
+
+This function transfers any gproc key (name, property, counter, aggr. counter)  
+from one process to another, and returns the pid of the new owner.
+
+
+
+`To` must be either a pid or a unique name (name or aggregated counter), but
+does not necessarily have to resolve to an existing process. If there is
+no process registered with the `To` key, `surrender/2` returns `undefined`,
+and the `From` key is effectively unregistered.
+
+
+
+It is allowed to surrender a key to oneself, but of course, this operation  
+will have no effect.
+
+Fails with `badarg` if the calling process does not have a `From` key
+registered.<a name="table-1"></a>
+
 <h3>table/1</h3>
 
 
 
 
 
-<tt>table(Context::<a href="#type-context">context()</a>) -> any()</tt>
 
+<pre>table(Context::<a href="#type-context">context()</a>) -> any()</pre>
+
+<br></br>
 
 
-Equivalent to [`table(Context, [])`](#table-2).
-<a name="table-2"></a>
 
 
+Equivalent to [`table(Context, [])`](#table-2).<a name="table-2"></a>
+
 <h3>table/2</h3>
 
 
 
 
 
-<tt>table(Context::<a href="#type-context">context()</a>, Opts) -> any()</tt>
+
+<pre>table(Context::<a href="#type-context">context()</a>, Opts) -> any()</pre>
+
+<br></br>
+
 
 
 
 QLC table generator for the gproc registry.
 Context specifies which subset of the registry should be queried.
-See [`http://www.erlang.org/doc/man/qlc.html`](http://www.erlang.org/doc/man/qlc.html).
-<a name="unreg-1"></a>
-
+See [`http://www.erlang.org/doc/man/qlc.html`](http://www.erlang.org/doc/man/qlc.html).<a name="unreg-1"></a>
 
 <h3>unreg/1</h3>
 
@@ -855,13 +960,15 @@ See [`http://www.erlang.org/doc/man/qlc.html`](http://www.erlang.org/doc/man/qlc
 
 
 
-<tt>unreg(Key::<a href="#type-key">key()</a>) -> true</tt>
+
+<pre>unreg(Key::<a href="#type-key">key()</a>) -> true</pre>
+
+<br></br>
 
 
 
-Unregister a name or property.
-<a name="unregister_name-1"></a>
 
+Unregister a name or property.<a name="unregister_name-1"></a>
 
 <h3>unregister_name/1</h3>
 
@@ -873,9 +980,7 @@ Unregister a name or property.
 
 
 
-Equivalent to `unreg / 1`.
-<a name="update_counter-2"></a>
-
+Equivalent to `unreg / 1`.<a name="update_counter-2"></a>
 
 <h3>update_counter/2</h3>
 
@@ -883,7 +988,11 @@ Equivalent to `unreg / 1`.
 
 
 
-<tt>update_counter(Key::<a href="#type-key">key()</a>, Incr::integer()) -> integer()</tt>
+
+<pre>update_counter(Key::<a href="#type-key">key()</a>, Incr::integer()) -> integer()</pre>
+
+<br></br>
+
 
 
 
@@ -893,9 +1002,7 @@ Updates the counter registered as Key for the current process.
 
 This function works like ets:update_counter/3
 (see [`http://www.erlang.org/doc/man/ets.html#update_counter-3`](http://www.erlang.org/doc/man/ets.html#update_counter-3)), but
-will fail if the type of object referred to by Key is not a counter.
-<a name="where-1"></a>
-
+will fail if the type of object referred to by Key is not a counter.<a name="where-1"></a>
 
 <h3>where/1</h3>
 
@@ -903,7 +1010,11 @@ will fail if the type of object referred to by Key is not a counter.
 
 
 
-<tt>where(Key::<a href="#type-key">key()</a>) -> pid()</tt>
+
+<pre>where(Key::<a href="#type-key">key()</a>) -> pid()</pre>
+
+<br></br>
+
 
 
 
@@ -913,9 +1024,7 @@ Returns the pid registered as Key
 
 The type of registration entry must be either name or aggregated counter.
 Otherwise this function will exit. Use [`lookup_pids/1`](#lookup_pids-1) in these
-cases.
-<a name="whereis_name-1"></a>
-
+cases.<a name="whereis_name-1"></a>
 
 <h3>whereis_name/1</h3>
 
@@ -929,4 +1038,4 @@ cases.
 
 Equivalent to `where / 1`.
 
-_Generated by EDoc, Mar 18 2011, 13:31:52._
+_Generated by EDoc, Mar 29 2011, 14:24:55._

+ 2 - 8
doc/gproc_app.md

@@ -21,15 +21,13 @@ __Behaviours:__ [`application`](application.md).
 <table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#start-0">start/0</a></td><td></td></tr><tr><td valign="top"><a href="#start-2">start/2</a></td><td></td></tr><tr><td valign="top"><a href="#stop-1">stop/1</a></td><td></td></tr></table>
 
 
-<a name="functions"></a>
 
 
-<h2>Function Details</h2>
+<h2><a name="functions">Function Details</a></h2>
 
 
 <a name="start-0"></a>
 
-
 <h3>start/0</h3>
 
 
@@ -38,10 +36,8 @@ __Behaviours:__ [`application`](application.md).
 
 `start() -> any()`
 
-
 <a name="start-2"></a>
 
-
 <h3>start/2</h3>
 
 
@@ -50,10 +46,8 @@ __Behaviours:__ [`application`](application.md).
 
 `start(Type, StartArgs) -> any()`
 
-
 <a name="stop-1"></a>
 
-
 <h3>stop/1</h3>
 
 
@@ -64,4 +58,4 @@ __Behaviours:__ [`application`](application.md).
 
 
 
-_Generated by EDoc, Mar 18 2011, 13:31:52._
+_Generated by EDoc, Mar 29 2011, 14:24:55._

+ 13 - 49
doc/gproc_dist.md

@@ -13,7 +13,7 @@ Extended process registry.
 
 
 
-__Behaviours:__ [`gen_leader`](gen_leader.md).
+__Behaviours:__ [`gen_leader`](/Users/uwiger/ETC/git/gproc/deps/gen_leader/doc/gen_leader.md).
 
 __Authors:__ Ulf Wiger ([`ulf.wiger@ericsson.com`](mailto:ulf.wiger@ericsson.com)).
 
@@ -35,18 +35,16 @@ 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="#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="#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="#update_counter-2">update_counter/2</a></td><td></td></tr></table>
+Scope = l | g (global or local).</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="#surrender-2">surrender/2</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="#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="#update_counter-2">update_counter/2</a></td><td></td></tr></table>
 
 
-<a name="functions"></a>
 
 
-<h2>Function Details</h2>
+<h2><a name="functions">Function Details</a></h2>
 
 
 <a name="code_change-4"></a>
 
-
 <h3>code_change/4</h3>
 
 
@@ -55,10 +53,8 @@ Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#set_val
 
 `code_change(FromVsn, S, Extra, E) -> any()`
 
-
 <a name="elected-2"></a>
 
-
 <h3>elected/2</h3>
 
 
@@ -67,10 +63,8 @@ Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#set_val
 
 `elected(S, E) -> any()`
 
-
 <a name="elected-3"></a>
 
-
 <h3>elected/3</h3>
 
 
@@ -79,10 +73,8 @@ Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#set_val
 
 `elected(S, E, Node) -> any()`
 
-
 <a name="from_leader-3"></a>
 
-
 <h3>from_leader/3</h3>
 
 
@@ -91,10 +83,8 @@ Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#set_val
 
 `from_leader(Ops, S, E) -> any()`
 
-
 <a name="handle_DOWN-3"></a>
 
-
 <h3>handle_DOWN/3</h3>
 
 
@@ -103,10 +93,8 @@ Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#set_val
 
 `handle_DOWN(Node, S, E) -> any()`
 
-
 <a name="handle_call-4"></a>
 
-
 <h3>handle_call/4</h3>
 
 
@@ -115,10 +103,8 @@ Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#set_val
 
 `handle_call(X1, X2, S, X4) -> any()`
 
-
 <a name="handle_cast-3"></a>
 
-
 <h3>handle_cast/3</h3>
 
 
@@ -127,10 +113,8 @@ Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#set_val
 
 `handle_cast(Msg, S, X3) -> any()`
 
-
 <a name="handle_info-2"></a>
 
-
 <h3>handle_info/2</h3>
 
 
@@ -139,10 +123,8 @@ Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#set_val
 
 `handle_info(X1, S) -> any()`
 
-
 <a name="handle_leader_call-4"></a>
 
-
 <h3>handle_leader_call/4</h3>
 
 
@@ -151,10 +133,8 @@ Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#set_val
 
 `handle_leader_call(X1, From, S, E) -> any()`
 
-
 <a name="handle_leader_cast-3"></a>
 
-
 <h3>handle_leader_cast/3</h3>
 
 
@@ -163,10 +143,8 @@ Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#set_val
 
 `handle_leader_cast(X1, S, E) -> any()`
 
-
 <a name="init-1"></a>
 
-
 <h3>init/1</h3>
 
 
@@ -175,10 +153,8 @@ Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#set_val
 
 `init(Opts) -> any()`
 
-
 <a name="leader_call-1"></a>
 
-
 <h3>leader_call/1</h3>
 
 
@@ -187,10 +163,8 @@ Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#set_val
 
 `leader_call(Req) -> any()`
 
-
 <a name="leader_cast-1"></a>
 
-
 <h3>leader_cast/1</h3>
 
 
@@ -199,10 +173,8 @@ Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#set_val
 
 `leader_cast(Msg) -> any()`
 
-
 <a name="mreg-2"></a>
 
-
 <h3>mreg/2</h3>
 
 
@@ -211,10 +183,8 @@ Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#set_val
 
 `mreg(T, KVL) -> any()`
 
-
 <a name="reg-1"></a>
 
-
 <h3>reg/1</h3>
 
 
@@ -223,10 +193,8 @@ Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#set_val
 
 `reg(Key) -> any()`
 
-
 <a name="reg-2"></a>
 
-
 <h3>reg/2</h3>
 
 
@@ -243,10 +211,8 @@ Class = n  - unique name
 | c  - counter
 | a  - aggregated counter
 Scope = l | g (global or local)
-
 <a name="set_value-2"></a>
 
-
 <h3>set_value/2</h3>
 
 
@@ -255,10 +221,8 @@ Scope = l | g (global or local)
 
 `set_value(Key, Value) -> any()`
 
-
 <a name="start_link-0"></a>
 
-
 <h3>start_link/0</h3>
 
 
@@ -267,10 +231,8 @@ Scope = l | g (global or local)
 
 `start_link() -> any()`
 
-
 <a name="start_link-1"></a>
 
-
 <h3>start_link/1</h3>
 
 
@@ -279,10 +241,18 @@ Scope = l | g (global or local)
 
 `start_link(Nodes) -> any()`
 
+<a name="surrender-2"></a>
 
-<a name="surrendered-3"></a>
+<h3>surrender/2</h3>
 
 
+
+
+
+`surrender(Key, To) -> any()`
+
+<a name="surrendered-3"></a>
+
 <h3>surrendered/3</h3>
 
 
@@ -291,10 +261,8 @@ Scope = l | g (global or local)
 
 `surrendered(S, X2, E) -> any()`
 
-
 <a name="terminate-2"></a>
 
-
 <h3>terminate/2</h3>
 
 
@@ -303,10 +271,8 @@ Scope = l | g (global or local)
 
 `terminate(Reason, S) -> any()`
 
-
 <a name="unreg-1"></a>
 
-
 <h3>unreg/1</h3>
 
 
@@ -315,10 +281,8 @@ Scope = l | g (global or local)
 
 `unreg(Key) -> any()`
 
-
 <a name="update_counter-2"></a>
 
-
 <h3>update_counter/2</h3>
 
 
@@ -329,4 +293,4 @@ Scope = l | g (global or local)
 
 
 
-_Generated by EDoc, Mar 18 2011, 13:31:52._
+_Generated by EDoc, Mar 29 2011, 14:24:55._

+ 2 - 6
doc/gproc_init.md

@@ -19,15 +19,13 @@ Module gproc_init
 <table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#hard_reset-0">hard_reset/0</a></td><td></td></tr><tr><td valign="top"><a href="#soft_reset-0">soft_reset/0</a></td><td></td></tr></table>
 
 
-<a name="functions"></a>
 
 
-<h2>Function Details</h2>
+<h2><a name="functions">Function Details</a></h2>
 
 
 <a name="hard_reset-0"></a>
 
-
 <h3>hard_reset/0</h3>
 
 
@@ -36,10 +34,8 @@ Module gproc_init
 
 `hard_reset() -> any()`
 
-
 <a name="soft_reset-0"></a>
 
-
 <h3>soft_reset/0</h3>
 
 
@@ -50,4 +46,4 @@ Module gproc_init
 
 
 
-_Generated by EDoc, Mar 18 2011, 13:31:51._
+_Generated by EDoc, Mar 29 2011, 14:24:55._

+ 1 - 1
doc/gproc_lib.md

@@ -22,4 +22,4 @@ This module implements an extended process registry
 
 For a detailed description, see gproc/doc/erlang07-wiger.pdf.
 
-_Generated by EDoc, Mar 18 2011, 13:31:51._
+_Generated by EDoc, Mar 29 2011, 14:24:55._

+ 3 - 7
doc/gproc_sup.md

@@ -21,15 +21,13 @@ __Behaviours:__ [`supervisor`](supervisor.md).
 <table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#init-1">init/1</a></td><td>The main GPROC supervisor.</td></tr><tr><td valign="top"><a href="#start_link-1">start_link/1</a></td><td></td></tr></table>
 
 
-<a name="functions"></a>
 
 
-<h2>Function Details</h2>
+<h2><a name="functions">Function Details</a></h2>
 
 
 <a name="init-1"></a>
 
-
 <h3>init/1</h3>
 
 
@@ -40,9 +38,7 @@ __Behaviours:__ [`supervisor`](supervisor.md).
 
 
 
-The main GPROC supervisor.
-<a name="start_link-1"></a>
-
+The main GPROC supervisor.<a name="start_link-1"></a>
 
 <h3>start_link/1</h3>
 
@@ -54,4 +50,4 @@ The main GPROC supervisor.
 
 
 
-_Generated by EDoc, Mar 18 2011, 13:31:51._
+_Generated by EDoc, Mar 29 2011, 14:24:55._

+ 84 - 18
src/gproc.erl

@@ -52,6 +52,7 @@
 	 lookup_value/1,
          lookup_values/1,
          update_counter/2,
+	 surrender/2,
          send/2,
          info/1, info/2,
          select/1, select/2, select/3,
@@ -631,7 +632,31 @@ update_counter({c,g,_} = Key, Incr) when is_integer(Incr) ->
 update_counter(_, _) ->
     erlang:error(badarg).
 
-
+%% @spec (From::key(), To::pid() | key()) -> undefined | pid()
+%%
+%% @doc Atomically transfers the key `From' to the process identified by `To'.
+%%
+%% This function transfers any gproc key (name, property, counter, aggr. counter)
+%% from one process to another, and returns the pid of the new owner.
+%%
+%% `To' must be either a pid or a unique name (name or aggregated counter), but
+%% does not necessarily have to resolve to an existing process. If there is 
+%% no process registered with the `To' key, `surrender/2' returns `undefined',
+%% and the `From' key is effectively unregistered.
+%%
+%% It is allowed to surrender a key to oneself, but of course, this operation
+%% will have no effect.
+%%
+%% Fails with `badarg' if the calling process does not have a `From' key 
+%% registered.
+%% @end
+surrender({_,l,_} = Key, ToPid) when is_pid(ToPid), node(ToPid) == node() ->
+    call({surrender, Key, ToPid});
+surrender({_,l,_} = Key, {n,l,_} = ToKey) ->
+    call({surrender, Key, ToKey});
+surrender({_,g,_} = Key, To) ->
+    ?CHK_DIST,
+    gproc_dist:surrender(Key, To).
 
 %% @spec (Key::key(), Msg::any()) -> Msg
 %%
@@ -840,23 +865,6 @@ handle_call({await, {_,l,_} = Key, Pid}, {_, Ref}, S) ->
         {reply, Reply, _} ->
             {reply, Reply, S}
     end;
-%%     Rev = {{Pid,Key}, r},
-%%     case ets:lookup(?TAB, {Key,T}) of
-%%         [{_, P, Value}] ->
-%%             %% for symmetry, we always reply with Ref and then send a message
-%%             gen_server:reply(From, Ref),
-%%             Pid ! {gproc, Ref, registered, {Key, P, Value}},
-%%             {noreply, S};
-%%         [{K, Waiters}] ->
-%%             NewWaiters = [{Pid,Ref} | Waiters],
-%%             ets:insert(?TAB, [{K, NewWaiters}, Rev]),
-%%             gproc_lib:ensure_monitor(Pid,l),
-%%             {reply, Ref, S};
-%%         [] ->
-%%             ets:insert(?TAB, [{{Key,T}, [{Pid,Ref}]}, Rev]),
-%%             gproc_lib:ensure_monitor(Pid,l),
-%%             {reply, Ref, S}
-%%     end;
 handle_call({mreg, T, l, L}, {Pid,_}, S) ->
     try gproc_lib:insert_many(T, l, L, Pid) of
         {true,_} -> {reply, true, S};
@@ -879,6 +887,9 @@ handle_call({audit_process, Pid}, _, S) ->
 	    ignore
     end,
     {reply, ok, S};
+handle_call({surrender, Key, To}, {Pid,_}, S) ->
+    Reply = do_surrender(Key, To, Pid),
+    {reply, Reply, S};
 handle_call(_, _, S) ->
     {reply, badarg, S}.
 
@@ -1000,6 +1011,61 @@ process_is_down(Pid) ->
     ets:select_delete(?TAB, [{{{Pid,{'_',l,'_'}},'_'}, [], [true]}]),
     ok.
 
+do_surrender({T,l,_} = K, To, Pid) when T==n; T==a ->
+    Key = {K, T},
+    case ets:lookup(?TAB, Key) of
+	[{_, Pid, Value}] ->
+	    %% Pid owns the reg; allowed to surrender
+	    case pid_to_surrender_to(To) of
+		Pid ->
+		    %% Surrender to ourselves? Why not? We'll allow it,
+		    %% but nothing needs to be done.
+		    Pid;
+		ToPid when is_pid(ToPid) ->
+		    ets:insert(?TAB, [{Key, ToPid, Value},
+				      {{ToPid, K}, r}]),
+		    ets:delete(?TAB, {Pid, K}),
+		    gproc_lib:ensure_monitor(ToPid, l),
+		    ToPid;
+		undefined ->
+		    gproc_lib:remove_reg(K, Pid),
+		    undefined
+	    end;
+	_ ->
+	    badarg
+    end;
+do_surrender({T,l,_} = K, To, Pid) when T==c; T==p ->
+    Key = {K, Pid},
+    case ets:lookup(?TAB, Key) of
+	[{_, Pid, Value}] ->
+	    case pid_to_surrender_to(To) of
+		ToPid when is_pid(ToPid) ->
+		    ToKey = {K, ToPid},
+		    ets:insert(?TAB, [{ToKey, ToPid, Value},
+				      {{ToPid, K}, r}]),
+		    ets:delete(?TAB, {Pid, K}),
+		    ets:delete(?TAB, Key),
+		    gproc_lib:ensure_monitor(ToPid, l),
+		    ToPid;
+		undefined ->
+		    gproc_lib:remove_reg(K, Pid),
+		    undefined
+	    end;
+	_ ->
+	    badarg
+    end.
+			
+
+pid_to_surrender_to(P) when is_pid(P), node(P) == node() ->		    
+    P;
+pid_to_surrender_to({T,l,_} = Key) when T==n; T==a ->
+    case ets:lookup(?TAB, {Key, T}) of
+	[{_, Pid, _}] ->
+	    Pid;
+	_ ->
+	    undefined
+    end.
+
 create_tabs() ->
     case ets:info(?TAB, name) of
 	undefined ->

+ 51 - 11
src/gproc_dist.erl

@@ -26,6 +26,7 @@
 	 reg/1, reg/2, unreg/1,
 	 mreg/2,
 	 set_value/2,
+	 surrender/2,
 	 update_counter/2]).
 
 -export([leader_call/1, leader_cast/1]).
@@ -57,6 +58,8 @@
 start_link() ->
     start_link({[node()|nodes()], []}).
 
+start_link(all) ->
+    start_link({[node()|nodes()], []});
 start_link(Nodes) when is_list(Nodes) ->
     start_link({Nodes, []});
 start_link({Nodes, Opts}) ->
@@ -107,7 +110,8 @@ set_value({_,g,_} = Key, Value) ->
 set_value(_, _) ->
     erlang:error(badarg).
 
-
+surrender({_,g,_} = Key, To) ->
+    leader_call({surrender, Key, To, self()}).
 
 
 update_counter({c,g,_} = Key, Incr) when is_integer(Incr) ->
@@ -216,17 +220,39 @@ handle_leader_call({unreg, {T,g,Name} = K, Pid}, _From, S, _E) ->
 		    case ets:lookup(?TAB, {{a,g,Name},a}) of
 			[Aggr] ->
 			    %% updated by remove_reg/2
-			    {reply, true, [{delete,[{K,Pid}]},
+			    {reply, true, [{delete,[Key, {Pid,K}]},
 					   {insert, [Aggr]}], S};
 			[] ->
-			    {reply, true, [{delete, [{K, Pid}]}], S}
+			    {reply, true, [{delete, [Key, {Pid,K}]}], S}
 		    end;
 	       true ->
-		    {reply, true, [{delete, [{K,Pid}]}], S}
+		    {reply, true, [{delete, [Key]}], S}
 	    end;
 	false ->
 	    {reply, badarg, S}
     end;
+handle_leader_call({surrender, {T,g,_} = K, To, Pid}, _From, S, _E)
+  when T == a; T == n ->
+    Key = {K, T},
+    case ets:lookup(?TAB, Key) of
+	[{_, Pid, Value}] ->
+	    case pid_to_surrender_to(To) of 
+		Pid ->
+		    {reply, Pid, S};
+		ToPid when is_pid(ToPid) ->
+		    ets:insert(?TAB, [{Key, ToPid, Value},
+				      {{ToPid,K}, r}]),
+		    gproc_lib:ensure_monitor(ToPid, g),
+		    {reply, ToPid, [{delete, [Key, {Pid,K}]},
+				   {insert, [{Key, ToPid, Value}]}], S};
+		undefined ->
+		    ets:delete(?TAB, Key),
+		    ets:delete(?TAB, {Pid, K}),
+		    {reply, undefined, [{delete, [Key, {Pid,K}]}], S}
+	    end;
+	_ ->
+	    {reply, badarg, S}
+    end;
 handle_leader_call({mreg, T, g, L, Pid}, _From, S, _E) ->
     if T==p; T==n ->
 	    try gproc_lib:insert_many(T, g, Pid, L) of
@@ -346,15 +372,19 @@ from_leader(Ops, S, _E) ->
 
 delete_globals(Globals) ->
     lists:foreach(
-      fun({Key, Pid}) ->
+      fun({{_,g,_},T} = K) when is_atom(T) ->
+	      ets:delete(?TAB, K);
+	 ({Key, Pid}) when is_pid(Pid) ->
               K = ets_key(Key,Pid),
 	      ets:delete(?TAB, K),
-	      ets:delete(?TAB, {Pid, Key}),
-		  case node(Pid) =:= node() of
-			  true ->
-				  ets:delete(?TAB, {Pid,g});
-			  _ -> ok
-		  end
+	      ets:delete(?TAB, {Pid, Key});
+	 ({Pid, K}) when is_pid(Pid) ->
+	      ets:delete(?TAB, {Pid, K})
+	      %% case node(Pid) =:= node() of
+	      %% 	  true ->
+	      %% 	      ets:delete(?TAB, {Pid,g});
+	      %% 	  _ -> ok
+	      %% end
       end, Globals).
 
 ets_key({T,_,_} = K, _) when T==n; T==a ->
@@ -428,3 +458,13 @@ update_aggr_counter({c,g,Ctr}, Incr) ->
             ets:insert(?TAB, New),
             [New]
     end.
+
+pid_to_surrender_to(P) when is_pid(P) ->                 
+    P;
+pid_to_surrender_to({T,g,_} = Key) when T==n; T==a ->
+    case ets:lookup(?TAB, {Key, T}) of
+        [{_, Pid, _}] ->
+            Pid;
+        _ ->
+            undefined
+    end.