Browse Source

renamed CATCH/THROW macros, counter thresholds

Ulf Wiger 13 years ago
parent
commit
b1855cb881
5 changed files with 166 additions and 86 deletions
  1. 29 9
      doc/gproc.md
  2. 88 61
      src/gproc.erl
  3. 12 12
      src/gproc_dist.erl
  4. 2 2
      src/gproc_int.hrl
  5. 35 2
      src/gproc_lib.erl

+ 29 - 9
doc/gproc.md

@@ -173,7 +173,7 @@ to forget about the calling process.</td></tr><tr><td valign="top"><a href="#i-0
 about names and properties registered in Gproc, where applicable.</td></tr><tr><td valign="top"><a href="#info-1">info/1</a></td><td>Similar to <code>process_info(Pid)</code> but with additional gproc info.</td></tr><tr><td valign="top"><a href="#info-2">info/2</a></td><td>Similar to process_info(Pid, Item), but with additional gproc info.</td></tr><tr><td valign="top"><a href="#last-1">last/1</a></td><td>Behaves as ets:last(Tab) for a given type of registration object.</td></tr><tr><td valign="top"><a href="#lookup_global_aggr_counter-1">lookup_global_aggr_counter/1</a></td><td>Lookup a global (unique) aggregated counter and returns its value.</td></tr><tr><td valign="top"><a href="#lookup_global_counters-1">lookup_global_counters/1</a></td><td>Look up all global (non-unique) instances of a given Counter.</td></tr><tr><td valign="top"><a href="#lookup_global_name-1">lookup_global_name/1</a></td><td>Lookup a global unique name.</td></tr><tr><td valign="top"><a href="#lookup_global_properties-1">lookup_global_properties/1</a></td><td>Look up all global (non-unique) instances of a given Property.</td></tr><tr><td valign="top"><a href="#lookup_local_aggr_counter-1">lookup_local_aggr_counter/1</a></td><td>Lookup a local (unique) aggregated counter and returns its value.</td></tr><tr><td valign="top"><a href="#lookup_local_counters-1">lookup_local_counters/1</a></td><td>Look up all local (non-unique) instances of a given Counter.</td></tr><tr><td valign="top"><a href="#lookup_local_name-1">lookup_local_name/1</a></td><td>Lookup a local unique name.</td></tr><tr><td valign="top"><a href="#lookup_local_properties-1">lookup_local_properties/1</a></td><td>Look up all local (non-unique) instances of a given Property.</td></tr><tr><td valign="top"><a href="#lookup_pid-1">lookup_pid/1</a></td><td>Lookup the Pid stored with a key.</td></tr><tr><td valign="top"><a href="#lookup_pids-1">lookup_pids/1</a></td><td>Returns a list of pids with the published key Key.</td></tr><tr><td valign="top"><a href="#lookup_value-1">lookup_value/1</a></td><td>Lookup the value stored with a key.</td></tr><tr><td valign="top"><a href="#lookup_values-1">lookup_values/1</a></td><td>Retrieve the <code>{Pid,Value}</code> pairs corresponding to Key.</td></tr><tr><td valign="top"><a href="#monitor-1">monitor/1</a></td><td>monitor a registered name
 This function works much like erlang:monitor(process, Pid), but monitors
 a unique name registered via gproc.</td></tr><tr><td valign="top"><a href="#mreg-3">mreg/3</a></td><td>Register multiple {Key,Value} pairs of a given type and scope.</td></tr><tr><td valign="top"><a href="#munreg-3">munreg/3</a></td><td>Unregister multiple Key items of a given type and scope.</td></tr><tr><td valign="top"><a href="#nb_wait-1">nb_wait/1</a></td><td>Wait for a local name to be registered.</td></tr><tr><td valign="top"><a href="#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>
-see http://www.erlang.org/doc/man/ets.html#select-1.</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="#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_shared_counter-2">update_shared_counter/2</a></td><td></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>
+see http://www.erlang.org/doc/man/ets.html#select-1.</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="#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_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 name="functions"></a>
@@ -1321,9 +1321,8 @@ Equivalent to `unreg / 1`.<a name="update_counter-2"></a>
 
 
 
-<pre>update_counter(Key::<a href="#type-key">key()</a>, Incr::integer()) -> integer()</pre>
-<br></br>
-
+<pre>update_counter(Key::<a href="#type-key">key()</a>, Incr) -> integer() | [integer()]</pre>
+<ul class="definitions"><li><pre>Incr = IncrVal | UpdateOp | [UpdateOp]</pre></li><li><pre>UpdateOp = IncrVal | {IncrVal, Threshold, SetValue}</pre></li><li><pre>IncrVal = integer()</pre></li></ul>
 
 
 
@@ -1331,18 +1330,39 @@ Equivalent to `unreg / 1`.<a name="update_counter-2"></a>
 
 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="update_shared_counter-2"></a>
+
+
+This function works almost exactly 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.
+
+Aggregated counters with the same name will be updated automatically.
+The `UpdateOp` patterns are the same as for `ets:update_counter/3`, except
+that the position is omitted; in gproc, the value position is always `3`.<a name="update_shared_counter-2"></a>
 
 ###update_shared_counter/2##
 
 
 
 
-`update_shared_counter(Key, Incr) -> any()`
+<pre>update_shared_counter(Key::<a href="#type-key">key()</a>, Incr) -> integer() | [integer()]</pre>
+<ul class="definitions"><li><pre>Incr = IncrVal | UpdateOp | [UpdateOp]</pre></li><li><pre>UpdateOp = IncrVal | {IncrVal, Threshold, SetValue}</pre></li><li><pre>IncrVal = integer()</pre></li></ul>
+
+
+
+
+
+Updates the shared counter registered as Key.
+
+
+
+This function works almost exactly 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>
+Aggregated counters with the same name will be updated automatically.
+The `UpdateOp` patterns are the same as for `ets:update_counter/3`, except
+that the position is omitted; in gproc, the value position is always `3`.<a name="where-1"></a>
 
 ###where/1##
 

+ 88 - 61
src/gproc.erl

@@ -149,7 +149,7 @@
 -define(CHK_DIST,
         case whereis(gproc_dist) of
             undefined ->
-		?THROW(local_only);
+		?THROW_GPROC_ERROR(local_only);
             _ ->
                 ok
         end).
@@ -174,7 +174,7 @@ start_link() ->
 %% @doc Registers a local (unique) name. @equiv reg({n,l,Name})
 %% @end
 %%
-add_local_name(Name)  -> ?CATCH(reg1({n,l,Name}, undefined), [Name]).
+add_local_name(Name)  -> ?CATCH_GPROC_ERROR(reg1({n,l,Name}, undefined), [Name]).
 
 
 %% spec(Name::any()) -> true
@@ -182,7 +182,7 @@ add_local_name(Name)  -> ?CATCH(reg1({n,l,Name}, undefined), [Name]).
 %% @doc Registers a global (unique) name. @equiv reg({n,g,Name})
 %% @end
 %%
-add_global_name(Name) -> ?CATCH(reg1({n,g,Name}, undefined), [Name]).
+add_global_name(Name) -> ?CATCH_GPROC_ERROR(reg1({n,g,Name}, undefined), [Name]).
 
 
 %% spec(Name::any(), Value::any()) -> true
@@ -190,14 +190,16 @@ add_global_name(Name) -> ?CATCH(reg1({n,g,Name}, undefined), [Name]).
 %% @doc Registers a local (non-unique) property. @equiv reg({p,l,Name},Value)
 %% @end
 %%
-add_local_property(Name , Value) -> ?CATCH(reg1({p,l,Name}, Value), [Name, Value]).
+add_local_property(Name , Value) ->
+    ?CATCH_GPROC_ERROR(reg1({p,l,Name}, Value), [Name, Value]).
 
 %% spec(Name::any(), Value::any()) -> true
 %%
 %% @doc Registers a global (non-unique) property. @equiv reg({p,g,Name},Value)
 %% @end
 %%
-add_global_property(Name, Value) -> ?CATCH(reg1({p,g,Name}, Value), [Name, Value]).
+add_global_property(Name, Value) ->
+    ?CATCH_GPROC_ERROR(reg1({p,g,Name}, Value), [Name, Value]).
 
 %% spec(Name::any(), Initial::integer()) -> true
 %%
@@ -205,7 +207,7 @@ add_global_property(Name, Value) -> ?CATCH(reg1({p,g,Name}, Value), [Name, Value
 %% @end
 %%
 add_local_counter(Name, Initial) when is_integer(Initial) ->
-    ?CATCH(reg1({c,l,Name}, Initial), [Name, Initial]).
+    ?CATCH_GPROC_ERROR(reg1({c,l,Name}, Initial), [Name, Initial]).
 
 
 %% spec(Name::any(), Initial::integer()) -> true
@@ -224,7 +226,7 @@ add_shared_local_counter(Name, Initial) when is_integer(Initial) ->
 %% @end
 %%
 add_global_counter(Name, Initial) when is_integer(Initial) ->
-    ?CATCH(reg1({c,g,Name}, Initial), [Name, Initial]).
+    ?CATCH_GPROC_ERROR(reg1({c,g,Name}, Initial), [Name, Initial]).
 
 %% spec(Name::any()) -> true
 %%
@@ -232,7 +234,7 @@ add_global_counter(Name, Initial) when is_integer(Initial) ->
 %% @equiv reg({a,l,Name})
 %% @end
 %%
-add_local_aggr_counter(Name)  -> ?CATCH(reg1({a,l,Name}), [Name]).
+add_local_aggr_counter(Name)  -> ?CATCH_GPROC_ERROR(reg1({a,l,Name}), [Name]).
 
 %% spec(Name::any()) -> true
 %%
@@ -240,7 +242,7 @@ add_local_aggr_counter(Name)  -> ?CATCH(reg1({a,l,Name}), [Name]).
 %% @equiv reg({a,g,Name})
 %% @end
 %%
-add_global_aggr_counter(Name) -> ?CATCH(reg1({a,g,Name}), [Name]).
+add_global_aggr_counter(Name) -> ?CATCH_GPROC_ERROR(reg1({a,g,Name}), [Name]).
 
 
 %% @spec (Name::any()) -> pid()
@@ -513,7 +515,9 @@ lookup_env(Scope, App, Key, P) ->
     end.
 
 cache_env(Scope, App, Key, Value) ->
-    ?CATCH(reg1({p, Scope, {gproc_env, App, Key}}, Value), [Scope,App,Key,Value]).
+    ?CATCH_GPROC_ERROR(
+       reg1({p, Scope, {gproc_env, App, Key}}, Value),
+       [Scope,App,Key,Value]).
 
 update_cached_env(Scope, App, Key, Value) ->
     case lookup_env(Scope, App, Key, self()) of
@@ -581,7 +585,7 @@ is_string(S) ->
 %% @equiv reg(Key, default(Key))
 %% @end
 reg(Key) ->
-    ?CATCH(reg1(Key), [Key]).
+    ?CATCH_GPROC_ERROR(reg1(Key), [Key]).
 
 reg1(Key) ->
     reg1(Key, default(Key)).
@@ -593,7 +597,7 @@ default(_) -> undefined.
 %% @equiv await(Key,infinity)
 %%
 await(Key) ->
-    ?CATCH(await1(Key, infinity), [Key]).
+    ?CATCH_GPROC_ERROR(await1(Key, infinity), [Key]).
 
 %% @spec await(Key::key(), Timeout) -> {pid(),Value}
 %%   Timeout = integer() | infinity
@@ -608,7 +612,7 @@ await(Key) ->
 %% @end
 %%
 await(Key, Timeout) ->
-    ?CATCH(await1(Key, Timeout), [Key, Timeout]).
+    ?CATCH_GPROC_ERROR(await1(Key, Timeout), [Key, Timeout]).
 
 await1({n,g,_} = Key, Timeout) ->
     ?CHK_DIST,
@@ -641,7 +645,7 @@ request_wait({n,C,_} = Key, Timeout) when C==l; C==g ->
                T when is_integer(T), T > 0 ->
                    erlang:start_timer(T, self(), gproc_timeout);
                _ ->
-                   ?THROW(badarg)
+                   ?THROW_GPROC_ERROR(badarg)
            end,
     WRef = case {call({await,Key,self()}, C), C} of
                {{R, {Kg,Pg,Vg}}, g} ->
@@ -659,7 +663,7 @@ request_wait({n,C,_} = Key, Timeout) when C==l; C==g ->
             {Pid, V};
         {timeout, TRef, gproc_timeout} ->
             cancel_wait(Key, WRef),
-            ?THROW(timeout)
+            ?THROW_GPROC_ERROR(timeout)
     end.
 
 
@@ -671,7 +675,7 @@ request_wait({n,C,_} = Key, Timeout) when C==l; C==g ->
 %% @end
 %%
 nb_wait(Key) ->
-    ?CATCH(nb_wait1(Key), [Key]).
+    ?CATCH_GPROC_ERROR(nb_wait1(Key), [Key]).
 
 nb_wait1({n,g,_} = Key) ->
     ?CHK_DIST,
@@ -679,7 +683,7 @@ nb_wait1({n,g,_} = Key) ->
 nb_wait1({n,l,_} = Key) ->
     call({await, Key, self()}, l);
 nb_wait1(_) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 %% @spec cancel_wait(Key::key(), Ref) -> ok
 %%    Ref = all | reference()
@@ -691,7 +695,7 @@ nb_wait1(_) ->
 %% @end
 %%
 cancel_wait(Key, Ref) ->
-    ?CATCH(cancel_wait1(Key, Ref), [Key, Ref]).
+    ?CATCH_GPROC_ERROR(cancel_wait1(Key, Ref), [Key, Ref]).
 
 cancel_wait1({_,g,_} = Key, Ref) ->
     ?CHK_DIST,
@@ -702,7 +706,7 @@ cancel_wait1({_,l,_} = Key, Ref) ->
     ok.
 
 cancel_wait_or_monitor(Key) ->
-    ?CATCH(cancel_wait_or_monitor1(Key), [Key]).
+    ?CATCH_GPROC_ERROR(cancel_wait_or_monitor1(Key), [Key]).
 
 cancel_wait_or_monitor1({_,g,_} = Key) ->
     ?CHK_DIST,
@@ -724,7 +728,7 @@ cancel_wait_or_monitor1({_,l,_} = Key) ->
 %% If the name is not yet registered, the same message is sent immediately.
 %% @end
 monitor(Key) ->
-    ?CATCH(monitor1(Key), [Key]).
+    ?CATCH_GPROC_ERROR(monitor1(Key), [Key]).
 
 monitor1({T,g,_} = Key) when T==n; T==a ->
     ?CHK_DIST,
@@ -732,7 +736,7 @@ monitor1({T,g,_} = Key) when T==n; T==a ->
 monitor1({T,l,_} = Key) when T==n; T==a ->
     call({monitor, Key, self()}, l);
 monitor1(_) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 %% @spec demonitor(key(), reference()) -> ok
 %%
@@ -741,7 +745,7 @@ monitor1(_) ->
 %% set on a unique name. This function always succeeds given legal input.
 %% @end
 demonitor(Key, Ref) ->
-    ?CATCH(demonitor1(Key, Ref), [Key, Ref]).
+    ?CATCH_GPROC_ERROR(demonitor1(Key, Ref), [Key, Ref]).
 
 demonitor1({T,g,_} = Key, Ref) when T==n; T==a ->
     ?CHK_DIST,
@@ -749,7 +753,7 @@ demonitor1({T,g,_} = Key, Ref) when T==n; T==a ->
 demonitor1({T,l,_} = Key, Ref) when T==n; T==a ->
     call({demonitor, Key, Ref, self()}, l);
 demonitor1(_, _) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 %% @spec reg(Key::key(), Value) -> true
 %%
@@ -757,7 +761,7 @@ demonitor1(_, _) ->
 %%
 %%
 reg(Key, Value) ->
-    ?CATCH(reg1(Key, Value), [Key, Value]).
+    ?CATCH_GPROC_ERROR(reg1(Key, Value), [Key, Value]).
 
 reg1({_,g,_} = Key, Value) ->
     %% anything global
@@ -772,7 +776,7 @@ reg1({c,l,_} = Key, Value) when is_integer(Value) ->
 reg1({n,l,_} = Key, Value) ->
     call({reg, Key, Value});
 reg1(_, _) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 
 %% @spec reg_shared(Key::key()) -> true
@@ -783,7 +787,7 @@ reg1(_, _) ->
 %% `reg_shared({a,l,A}) -> reg_shared({a,l,A}, undefined).'
 %% @end
 reg_shared(Key) ->
-    ?CATCH(reg_shared1(Key), [Key]).
+    ?CATCH_GPROC_ERROR(reg_shared1(Key), [Key]).
 
 reg_shared1({c,_,_} = Key) ->
     reg_shared(Key, 0);
@@ -807,7 +811,7 @@ reg_shared1({a,_,_} = Key) ->
 %% @end
 %%
 reg_shared(Key, Value) ->
-    ?CATCH(reg_shared1(Key, Value), [Key, Value]).
+    ?CATCH_GPROC_ERROR(reg_shared1(Key, Value), [Key, Value]).
 
 reg_shared1({_,g,_} = Key, Value) ->
     %% anything global
@@ -818,7 +822,7 @@ reg_shared1({a,l,_} = Key, undefined) ->
 reg_shared1({c,l,_} = Key, Value) when is_integer(Value) ->
     call({reg_shared, Key, Value});
 reg_shared1(_, _) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 %% @spec mreg(type(), scope(), [{Key::any(), Value::any()}]) -> true
 %%
@@ -829,7 +833,7 @@ reg_shared1(_, _) ->
 %% or none are.
 %% @end
 mreg(T, C, KVL) ->
-    ?CATCH(mreg1(T, C, KVL), [T, C, KVL]).
+    ?CATCH_GPROC_ERROR(mreg1(T, C, KVL), [T, C, KVL]).
 
 mreg1(T, g, KVL) ->
     ?CHK_DIST,
@@ -843,7 +847,7 @@ mreg1(T, l, KVL) when T==a; T==n ->
 mreg1(p, l, KVL) ->
     local_mreg(p, KVL);
 mreg1(_, _, _) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 %% @spec munreg(type(), scope(), [Key::any()]) -> true
 %%
@@ -853,7 +857,7 @@ mreg1(_, _, _) ->
 %% repeatedly.
 %% @end
 munreg(T, C, L) ->
-    ?CATCH(munreg1(T, C, L), [T, C, L]).
+    ?CATCH_GPROC_ERROR(munreg1(T, C, L), [T, C, L]).
 
 munreg1(T, g, L) ->
     ?CHK_DIST,
@@ -867,7 +871,7 @@ munreg1(T, l, L) when T==a; T==n ->
 munreg1(p, l, L) ->
     local_munreg(p, existing(p,l,L));
 munreg1(_, _, _) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 existing(T,Scope,L) ->
     Keys = if T==p; T==c ->
@@ -887,7 +891,7 @@ existing(T,Scope,L) ->
 %% @doc Unregister a name or property.
 %% @end
 unreg(Key) ->
-    ?CATCH(unreg1(Key), [Key]).
+    ?CATCH_GPROC_ERROR(unreg1(Key), [Key]).
 
 unreg1(Key) ->
     case Key of
@@ -902,7 +906,7 @@ unreg1(Key) ->
                     _ = gproc_lib:remove_reg(Key, self(), unreg),
                     true;
                 false ->
-                    ?THROW(badarg)
+                    ?THROW_GPROC_ERROR(badarg)
             end
     end.
 
@@ -911,7 +915,7 @@ unreg1(Key) ->
 %% @doc Unregister a shared resource.
 %% @end
 unreg_shared(Key) ->
-    ?CATCH(unreg_shared1(Key), [Key]).
+    ?CATCH_GPROC_ERROR(unreg_shared1(Key), [Key]).
 
 unreg_shared1(Key) ->
     case Key of
@@ -921,7 +925,7 @@ unreg_shared1(Key) ->
         {T, l, _} when T == c;
                        T == a -> call({unreg_shared, Key});
         _ ->
-	    ?THROW(badarg)
+	    ?THROW_GPROC_ERROR(badarg)
     end.
 
 %% @spec (key(), pid()) -> yes | no
@@ -996,14 +1000,14 @@ select_count(Context, Pat) ->
 %%%
 local_reg(Key, Value) ->
     case gproc_lib:insert_reg(Key, Value, self(), l) of
-        false -> ?THROW(badarg);
+        false -> ?THROW_GPROC_ERROR(badarg);
         true  -> monitor_me()
     end.
 
 local_mreg(_, []) -> true;
 local_mreg(T, [_|_] = KVL) ->
     case gproc_lib:insert_many(T, l, KVL, self()) of
-        false     -> ?THROW(badarg);
+        false     -> ?THROW_GPROC_ERROR(badarg);
         {true,_}  -> monitor_me()
     end.
 
@@ -1022,7 +1026,7 @@ local_munreg(T, L) when T==p; T==c ->
 %% @end
 %%
 set_value(Key, Value) ->
-    ?CATCH(set_value1(Key, Value), [Key, Value]).
+    ?CATCH_GPROC_ERROR(set_value1(Key, Value), [Key, Value]).
 
 set_value1({_,g,_} = Key, Value) ->
     ?CHK_DIST,
@@ -1044,7 +1048,7 @@ set_value1({p,l,_} = Key, Value) ->
 set_value1({c,l,_} = Key, Value) when is_integer(Value) ->
     gproc_lib:do_set_counter_value(Key, Value, self());
 set_value1(_, _) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 %% @spec (Key) -> Value
 %% @doc Reads the value stored with a key registered to the current process.
@@ -1052,7 +1056,7 @@ set_value1(_, _) ->
 %% If no such key is registered to the current process, this function exits.
 %% @end
 get_value(Key) ->
-    ?CATCH(get_value1(Key, self()), [Key]).
+    ?CATCH_GPROC_ERROR(get_value1(Key, self()), [Key]).
 
 %% @spec (Key, Pid) -> Value
 %% @doc Reads the value stored with a key registered to the process Pid.
@@ -1062,13 +1066,13 @@ get_value(Key) ->
 %% @end
 %%
 get_value(Key, Pid) ->
-    ?CATCH(get_value1(Key, Pid), [Key, Pid]).
+    ?CATCH_GPROC_ERROR(get_value1(Key, Pid), [Key, Pid]).
 
 get_value1({T,_,_} = Key, Pid) when is_pid(Pid) ->
     if T==n orelse T==a ->
             case ets:lookup(?TAB, {Key, T}) of
                 [{_, P, Value}] when P == Pid -> Value;
-                _ -> ?THROW(badarg)
+                _ -> ?THROW_GPROC_ERROR(badarg)
             end;
        true ->
             ets:lookup_element(?TAB, {Key, Pid}, 3)
@@ -1080,10 +1084,10 @@ get_value1({T,_,_} = K, shared) when T==c; T==a ->
 	  end,
     case ets:lookup(?TAB, Key) of
 	[{_, shared, Value}] -> Value;
-	_ -> ?THROW(badarg)
+	_ -> ?THROW_GPROC_ERROR(badarg)
     end;
 get_value1(_, _) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 
 %% @spec (Key) -> Pid
@@ -1115,7 +1119,7 @@ lookup_value({T,_,_} = Key) ->
 %% @end
 %%
 where(Key) ->
-    ?CATCH(where1(Key), [Key]).
+    ?CATCH_GPROC_ERROR(where1(Key), [Key]).
 
 where1({T,_,_}=Key) ->
     if T==n orelse T==a ->
@@ -1130,12 +1134,12 @@ where1({T,_,_}=Key) ->
                     undefined
             end;
        true ->
-            ?THROW(badarg)
+            ?THROW_GPROC_ERROR(badarg)
     end.
 
 %% @equiv where/1
 whereis_name(Key) ->
-    ?CATCH(where1(Key), [Key]).
+    ?CATCH_GPROC_ERROR(where1(Key), [Key]).
 
 %% @spec (Key::key()) -> [pid()]
 %%
@@ -1180,25 +1184,32 @@ lookup_values({T,_,_} = Key) ->
         end,
     [Pair || {P,_} = Pair <- L, my_is_process_alive(P)].
 
-%% @spec (Key::key(), Incr::integer()) -> integer()
+%% @spec (Key::key(), Incr) -> integer() | [integer()]
+%%    Incr = IncrVal | UpdateOp | [UpdateOp]
+%%    UpdateOp = IncrVal | {IncrVal, Threshold, SetValue}
+%%    IncrVal = integer()
 %%
 %% @doc Updates the counter registered as Key for the current process.
 %%
-%% This function works like ets:update_counter/3
+%% This function works almost exactly like ets:update_counter/3
 %% (see [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.
+%%
+%% Aggregated counters with the same name will be updated automatically.
+%% The `UpdateOp' patterns are the same as for `ets:update_counter/3', except
+%% that the position is omitted; in gproc, the value position is always `3'.
 %% @end
 %%
 update_counter(Key, Incr) ->
-    ?CATCH(update_counter1(Key, Incr), [Key, Incr]).
+    ?CATCH_GPROC_ERROR(update_counter1(Key, Incr), [Key, Incr]).
 
-update_counter1({c,l,_} = Key, Incr) when is_integer(Incr) ->
+update_counter1({c,l,_} = Key, Incr) ->
     gproc_lib:update_counter(Key, Incr, self());
-update_counter1({c,g,_} = Key, Incr) when is_integer(Incr) ->
+update_counter1({c,g,_} = Key, Incr) ->
     ?CHK_DIST,
     gproc_dist:update_counter(Key, Incr);
 update_counter1(_, _) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 
 %% @spec (Key) -> {ValueBefore, ValueAfter}
@@ -1216,7 +1227,7 @@ update_counter1(_, _) ->
 %% @end
 %%
 reset_counter(Key) ->
-    ?CATCH(reset_counter1(Key), [Key]).
+    ?CATCH_GPROC_ERROR(reset_counter1(Key), [Key]).
 
 reset_counter1({c,g,_} = Key) ->
     ?CHK_DIST,
@@ -1230,8 +1241,24 @@ reset_counter1({c,l,_} = Key) ->
 	      end,
     {Current, update_counter(Key, Initial - Current)}.
 
+%% @spec (Key::key(), Incr) -> integer() | [integer()]
+%%    Incr = IncrVal | UpdateOp | [UpdateOp]
+%%    UpdateOp = IncrVal | {IncrVal, Threshold, SetValue}
+%%    IncrVal = integer()
+%%
+%% @doc Updates the shared counter registered as Key.
+%%
+%% This function works almost exactly like ets:update_counter/3
+%% (see [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.
+%%
+%% Aggregated counters with the same name will be updated automatically.
+%% The `UpdateOp' patterns are the same as for `ets:update_counter/3', except
+%% that the position is omitted; in gproc, the value position is always `3'.
+%% @end
+%%
 update_shared_counter(Key, Incr) ->
-    ?CATCH(update_shared_counter1(Key, Incr), [Key, Incr]).
+    ?CATCH_GPROC_ERROR(update_shared_counter1(Key, Incr), [Key, Incr]).
 
 update_shared_counter1({c,g,_} = Key, Incr) ->
     ?CHK_DIST,
@@ -1258,7 +1285,7 @@ update_shared_counter1({c,l,_} = Key, Incr) ->
 %% registered.
 %% @end
 give_away(Key, ToPid) ->
-    ?CATCH(give_away1(Key, ToPid), [Key, ToPid]).
+    ?CATCH_GPROC_ERROR(give_away1(Key, ToPid), [Key, ToPid]).
 
 give_away1({_,l,_} = Key, ToPid) when is_pid(ToPid), node(ToPid) == node() ->
     call({give_away, Key, ToPid});
@@ -1290,7 +1317,7 @@ goodbye() ->
 %% @end
 %%
 send(Key, Msg) ->
-    ?CATCH(send1(Key, Msg), [Key, Msg]).
+    ?CATCH_GPROC_ERROR(send1(Key, Msg), [Key, Msg]).
 
 send1({T,C,_} = Key, Msg) when C==l; C==g ->
     if T == n orelse T == a ->
@@ -1298,7 +1325,7 @@ send1({T,C,_} = Key, Msg) when C==l; C==g ->
                 [{_, Pid, _}] ->
                     Pid ! Msg;
                 _ ->
-                    ?THROW(badarg)
+                    ?THROW_GPROC_ERROR(badarg)
             end;
        T==p orelse T==c ->
             %% BUG - if the key part contains select wildcards, we may end up
@@ -1311,7 +1338,7 @@ send1({T,C,_} = Key, Msg) when C==l; C==g ->
             erlang:error(badarg)
     end;
 send1(_, _) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 
 %% @spec (Context :: context()) -> key() | '$end_of_table'
@@ -1654,7 +1681,7 @@ call(Req, g) ->
 
 chk_reply(Reply) ->
     case Reply of
-        badarg -> ?THROW(badarg);
+        badarg -> ?THROW_GPROC_ERROR(badarg);
         _  -> Reply
     end.
 

+ 12 - 12
src/gproc_dist.erl

@@ -99,45 +99,45 @@ reg({_,g,_} = Key, Value) ->
     %% anything global
     leader_call({reg, Key, Value, self()});
 reg(_, _) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 reg_shared({_,g,_} = Key, Value) ->
     leader_call({reg, Key, Value, shared});
 reg_shared(_, _) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 
 mreg(T, KVL) ->
     if is_list(KVL) -> leader_call({mreg, T, g, KVL, self()});
-       true -> ?THROW(badarg)
+       true -> ?THROW_GPROC_ERROR(badarg)
     end.
 
 munreg(T, Keys) ->
     if is_list(Keys) -> leader_call({munreg, T, g, Keys, self()});
-       true -> ?THROW(badarg)
+       true -> ?THROW_GPROC_ERROR(badarg)
     end.
 
 unreg({_,g,_} = Key) ->
     leader_call({unreg, Key, self()});
 unreg(_) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 unreg_shared({T,g,_} = Key) when T==c; T==a ->
     leader_call({unreg, Key, shared});
 unreg_shared(_) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 
 set_value({T,g,_} = Key, Value) when T==a; T==c ->
     if is_integer(Value) ->
             leader_call({set, Key, Value});
        true ->
-            ?THROW(badarg)
+            ?THROW_GPROC_ERROR(badarg)
     end;
 set_value({_,g,_} = Key, Value) ->
     leader_call({set, Key, Value, self()});
 set_value(_, _) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 give_away({_,g,_} = Key, To) ->
     leader_call({give_away, Key, To, self()}).
@@ -146,18 +146,18 @@ give_away({_,g,_} = Key, To) ->
 update_counter({c,g,_} = Key, Incr) when is_integer(Incr) ->
     leader_call({update_counter, Key, Incr, self()});
 update_counter(_, _) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 update_shared_counter({c,g,_} = Key, Incr) when is_integer(Incr) ->
     leader_call({update_counter, Key, Incr, shared});
 update_shared_counter(_, _) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 
 reset_counter({c,g,_} = Key) ->
     leader_call({reset_counter, Key, self()});
 reset_counter(_) ->
-    ?THROW(badarg).
+    ?THROW_GPROC_ERROR(badarg).
 
 
 %% @spec sync() -> true
@@ -579,7 +579,7 @@ ets_key(K, Pid) ->
 
 leader_call(Req) ->
     case gen_leader:leader_call(?MODULE, Req) of
-        badarg -> ?THROW(badarg);
+        badarg -> ?THROW_GPROC_ERROR(badarg);
         Reply  -> Reply
     end.
 

+ 2 - 2
src/gproc_int.hrl

@@ -17,11 +17,11 @@
 %%
 %% gproc_int.hrl: Shared internal definitions
 
--define(CATCH(Expr, Args),
+-define(CATCH_GPROC_ERROR(Expr, Args),
 	try Expr
 	catch
 	    throw:{gproc_error, GprocError} ->
 		erlang:error(GprocError, Args)
 	end).
 
--define(THROW(E), throw({gproc_error, E})).
+-define(THROW_GPROC_ERROR(E), throw({gproc_error, E})).

+ 35 - 2
src/gproc_lib.erl

@@ -39,6 +39,7 @@
          update_counter/3,
 	 valid_opts/2]).
 
+-include("gproc_int.hrl").
 -include("gproc.hrl").
 
 %% We want to store names and aggregated counters with the same
@@ -364,10 +365,42 @@ do_set_counter_value({_,C,N} = Key, Value, Pid) ->
     update_aggr_counter(C, N, Value - OldVal),
     Res.
 
-update_counter({c,l,Ctr} = Key, Incr, Pid) ->
+update_counter({c,l,Ctr} = Key, Incr, Pid) when is_integer(Incr) ->
     Res = ets:update_counter(?TAB, {Key, Pid}, {3,Incr}),
     update_aggr_counter(l, Ctr, Incr),
-    Res.
+    Res;
+update_counter({c,l,Ctr} = Key, {Incr, Threshold, SetValue}, Pid)
+  when is_integer(Incr), is_integer(Threshold), is_integer(SetValue) ->
+    [Prev, New] = ets:update_counter(?TAB, {Key, Pid},
+				     [{3, 0}, {3, Incr, Threshold, SetValue}]),
+    update_aggr_counter(l, Ctr, New - Prev),
+    New;
+update_counter({c,l,Ctr} = Key, Ops, Pid) when is_list(Ops) ->
+    case ets:update_counter(?TAB, {Key, Pid},
+			    [{3, 0} | expand_ops(Ops)]) of
+	[_] ->
+	    [];
+	[Prev | Rest] ->
+	    [New | _] = lists:reverse(Rest),
+	    update_aggr_counter(l, Ctr, New - Prev),
+	    Rest
+    end;
+update_counter(_, _, _) ->
+    ?THROW_GPROC_ERROR(badarg).
+
+expand_ops([{Incr,Thr,SetV}|T])
+  when is_integer(Incr), is_integer(Thr), is_integer(SetV) ->
+    [{3, Incr, Thr, SetV}|expand_ops(T)];
+expand_ops([Incr|T]) when is_integer(Incr) ->
+    [{3, Incr}|expand_ops(T)];
+expand_ops([]) ->
+    [];
+expand_ops(_) ->
+    ?THROW_GPROC_ERROR(badarg).
+
+
+
+
 
 update_aggr_counter(C, N, Val) ->
     catch ets:update_counter(?TAB, {{a,C,N},a}, {3, Val}).