Browse Source

case_clause in process_is_down()

The crash is funny. I don't know how another process could
register the name before the reverse mapping of (presumably) a waiter
is removed. Perhaps some earlier bug caused lingering garbage in the
table? Anyway, I have added a clause to handle the event, so it shouldn't
crash anymore.
Ulf Wiger 14 years ago
parent
commit
cad63c771e
8 changed files with 54 additions and 26 deletions
  1. 30 17
      doc/gproc.md
  2. 1 1
      doc/gproc_app.md
  3. 1 1
      doc/gproc_dist.md
  4. 1 1
      doc/gproc_init.md
  5. 1 1
      doc/gproc_lib.md
  6. 1 1
      doc/gproc_sup.md
  7. 16 4
      src/gproc.erl
  8. 3 0
      test/eqc/gproc_eqc_tests.erl

+ 30 - 17
doc/gproc.md

@@ -100,7 +100,7 @@ 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="#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></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_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>
 
 
 
 
 <a name="functions"></a>
 <a name="functions"></a>
@@ -562,21 +562,6 @@ Returns a list of pids with the published key Key
 If the type of registration entry is either name or aggregated counter,
 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.
 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.
 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>
-
-
-
-
-
-<tt>lookup_value(Key) -> Value</tt>
-
-
-
-Lookup the value stored with a key.
-
 <a name="lookup_values-1"></a>
 <a name="lookup_values-1"></a>
 
 
 
 
@@ -860,6 +845,20 @@ See [`http://www.erlang.org/doc/man/qlc.html`](http://www.erlang.org/doc/man/qlc
 
 
 
 
 Unregister a name or property.
 Unregister a name or property.
+<a name="unregister_name-1"></a>
+
+
+<h3>unregister_name/1</h3>
+
+
+
+
+
+`unregister_name(Key) -> any()`
+
+
+
+Equivalent to `unreg / 1`.
 <a name="update_counter-2"></a>
 <a name="update_counter-2"></a>
 
 
 
 
@@ -900,5 +899,19 @@ Returns the pid registered as Key
 The type of registration entry must be either name or aggregated counter.
 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
 Otherwise this function will exit. Use [`lookup_pids/1`](#lookup_pids-1) in these
 cases.
 cases.
+<a name="whereis_name-1"></a>
+
+
+<h3>whereis_name/1</h3>
+
+
+
+
+
+`whereis_name(Key) -> any()`
+
+
+
+Equivalent to `where / 1`.
 
 
-_Generated by EDoc, Mar 4 2011, 18:56:59._
+_Generated by EDoc, Mar 4 2011, 19:33:29._

+ 1 - 1
doc/gproc_app.md

@@ -64,4 +64,4 @@ __Behaviours:__ [`application`](application.md).
 
 
 
 
 
 
-_Generated by EDoc, Mar 4 2011, 18:56:59._
+_Generated by EDoc, Mar 4 2011, 19:33:29._

+ 1 - 1
doc/gproc_dist.md

@@ -329,4 +329,4 @@ Scope = l | g (global or local)
 
 
 
 
 
 
-_Generated by EDoc, Mar 4 2011, 18:56:59._
+_Generated by EDoc, Mar 4 2011, 19:33:29._

+ 1 - 1
doc/gproc_init.md

@@ -50,4 +50,4 @@ Module gproc_init
 
 
 
 
 
 
-_Generated by EDoc, Mar 4 2011, 18:56:59._
+_Generated by EDoc, Mar 4 2011, 19:33:29._

+ 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.
 For a detailed description, see gproc/doc/erlang07-wiger.pdf.
 
 
-_Generated by EDoc, Mar 4 2011, 18:56:59._
+_Generated by EDoc, Mar 4 2011, 19:33:29._

+ 1 - 1
doc/gproc_sup.md

@@ -54,4 +54,4 @@ The main GPROC supervisor.
 
 
 
 
 
 
-_Generated by EDoc, Mar 4 2011, 18:56:59._
+_Generated by EDoc, Mar 4 2011, 19:33:29._

+ 16 - 4
src/gproc.erl

@@ -49,7 +49,6 @@
          cancel_wait/2,
          cancel_wait/2,
          lookup_pid/1,
          lookup_pid/1,
          lookup_pids/1,
          lookup_pids/1,
-         lookup_value/1,
          lookup_values/1,
          lookup_values/1,
          update_counter/2,
          update_counter/2,
          send/2,
          send/2,
@@ -79,6 +78,10 @@
          lookup_local_aggr_counter/1,
          lookup_local_aggr_counter/1,
          lookup_global_aggr_counter/1]).
          lookup_global_aggr_counter/1]).
 
 
+%% Callbacks for behaviour support
+-export([whereis_name/1,
+	 unregister_name/1]).
+
 -export([default/1]).
 -export([default/1]).
 
 
 %%% internal exports
 %%% internal exports
@@ -408,6 +411,10 @@ unreg(Key) ->
             end
             end
     end.
     end.
 
 
+%% @equiv unreg/1
+unregister_name(Key) ->
+    unreg(Key).
+
 %% @spec (select_pattern()) -> list(sel_object())
 %% @spec (select_pattern()) -> list(sel_object())
 %% @doc
 %% @doc
 %% @equiv select(all, Pat)
 %% @equiv select(all, Pat)
@@ -519,9 +526,6 @@ lookup_pid({_T,_,_} = Key) ->
         P -> P
         P -> P
     end.
     end.
 
 
-%% @spec (Key) -> Value
-%% @doc Lookup the value stored with a key.
-%%
 lookup_value({T,_,_} = Key) ->
 lookup_value({T,_,_} = Key) ->
     if T==n orelse T==a ->
     if T==n orelse T==a ->
             ets:lookup_element(?TAB, {Key,T}, 3);
             ets:lookup_element(?TAB, {Key,T}, 3);
@@ -554,6 +558,10 @@ where({T,_,_}=Key) ->
             erlang:error(badarg)
             erlang:error(badarg)
     end.
     end.
 
 
+%% @equiv where/1
+whereis_name(Key) ->
+    where(Key).
+
 %% @spec (Key::key()) -> [pid()]
 %% @spec (Key::key()) -> [pid()]
 %%
 %%
 %% @doc Returns a list of pids with the published key Key
 %% @doc Returns a list of pids with the published key Key
@@ -955,6 +963,10 @@ process_is_down(Pid) ->
               case ets:lookup(?TAB, Key) of
               case ets:lookup(?TAB, Key) of
                   [{_, Pid, _}] ->
                   [{_, Pid, _}] ->
                       ets:delete(?TAB, Key);
                       ets:delete(?TAB, Key);
+		  [{_, OtherPid, _}] when OtherPid =/= Pid ->
+		      %% Has been known to happen, possibly due to a lingering
+		      %% reverse mapping
+		      true;
                   [{_, Waiters}] ->
                   [{_, Waiters}] ->
                       case [W || {P,_} = W <- Waiters,
                       case [W || {P,_} = W <- Waiters,
                                  P =/= Pid] of
                                  P =/= Pid] of

+ 3 - 0
test/eqc/gproc_eqc_tests.erl

@@ -11,6 +11,9 @@
 
 
 -include_lib("eqc/include/eqc.hrl").
 -include_lib("eqc/include/eqc.hrl").
 -include_lib("eqc/include/eqc_statem.hrl").
 -include_lib("eqc/include/eqc_statem.hrl").
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+-endif.
 
 
 -compile(export_all).
 -compile(export_all).