diff --git a/doc/gproc_dist.md b/doc/gproc_dist.md index a109df8..fb978f8 100644 --- a/doc/gproc_dist.md +++ b/doc/gproc_dist.md @@ -8,7 +8,7 @@ Extended process registry. -__Behaviours:__ [`gen_leader`](/Users/uwiger/tmp/rebar_edoc/gproc/deps/gen_leader/doc/gen_leader.md). +__Behaviours:__ [`gen_leader`](/Users/uwiger/FL/git/gen_leader/doc/gen_leader.md). __Authors:__ Ulf Wiger ([`ulf@wiger.net`](mailto:ulf@wiger.net)). diff --git a/doc/gproc_ps.md b/doc/gproc_ps.md index 5ae4955..ecb02aa 100644 --- a/doc/gproc_ps.md +++ b/doc/gproc_ps.md @@ -67,7 +67,7 @@ counters to good effect. ##Function Index## -
create_single/2Creates a single-shot subscription entry for Event.
delete_single/2Deletes the single-shot subscription for Event.
disable_single/2Disables the single-shot subscription for Event.
enable_single/2Enables the single-shot subscription for Event.
list_singles/2Lists all single-shot subscribers of Event, together with their status.
list_subs/2List the pids of all processes subscribing to Event
notify_single_if_true/4Create/enable a single subscription for event; notify at once if F() -> true.
publish/3Publish the message Msg to all subscribers of Event
subscribe/2Subscribe to events of type Event
tell_singles/3Publish Msg to all single-shot subscribers of Event
unsubscribe/2Remove subscribtion created using subscribe(Scope, Event)
+
create_single/2Creates a single-shot subscription entry for Event.
delete_single/2Deletes the single-shot subscription for Event.
disable_single/2Disables the single-shot subscription for Event.
enable_single/2Enables the single-shot subscription for Event.
list_singles/2Lists all single-shot subscribers of Event, together with their status.
list_subs/2List the pids of all processes subscribing to Event
notify_single_if_true/4Create/enable a single subscription for event; notify at once if F() -> true.
publish/3Publish the message Msg to all subscribers of Event
publish_cond/3Publishes the message Msg to conditional subscribers of Event
subscribe/2Subscribe to events of type Event
subscribe_cond/3Subscribe conditionally to events of type Event
tell_singles/3Publish Msg to all single-shot subscribers of Event
unsubscribe/2Remove subscribtion created using subscribe(Scope, Event)
@@ -227,7 +227,24 @@ The message delivered to each subscriber will be of the form: `{gproc_ps_event, Event, Msg}` The function uses `gproc:send/2` to send a message to all processes which have a -property `{p,Scope,{gproc_ps_event,Event}}`. +property `{p,Scope,{gproc_ps_event,Event}}`. + +###publish_cond/3## + + +
publish_cond(Scope::scope(), Event::event(), Msg::msg()) -> msg()
+

+ + + + +Publishes the message `Msg` to conditional subscribers of `Event` + +The message will be delivered to each subscriber provided their respective +condition tests succeed. + + +__See also:__ [subscribe_cond/3](#subscribe_cond-3). ###subscribe/2## @@ -246,7 +263,46 @@ Any messages published with `gproc_ps:publish(Scope, Event, Msg)` will be delive the current process, along with all other subscribers. This function creates a property, `{p,Scope,{gproc_ps_event,Event}}`, which can be -searched and displayed for debugging purposes. +searched and displayed for debugging purposes. + +###subscribe_cond/3## + + +
subscribe_cond(Scope::scope(), Event::event(), Spec::undefined | ets:match_spec()) -> true
+

+ + + + +Subscribe conditionally to events of type `Event` + + + +This function is similar to [`subscribe/2`](#subscribe-2), but adds a condition +in the form of a match specification. + + + +The condition is tested by the [`publish_cond/3`](#publish_cond-3) function +and a message is delivered only if the condition is true. Specifically, +the test is: + + + +`ets:match_spec_run([Msg], ets:match_spec_compile(Cond)) == [true]` + + + +In other words, if the match_spec returns true for a message, that message +is sent to the subscriber. For any other result from the match_spec, the +message is not sent. `Cond == undefined` means that all messages will be +delivered (that is, `publish_cond/3` will treat 'normal' subscribers just +like [`publish/3`](#publish-3) does, except that `publish/3` strictly speaking +ignores the Value part of the property completely, whereas `publish_cond/3` +expects it to be either undefined or a valid match spec). + +This means that `Cond=undefined` and `Cond=[{'_',[],[true]}]` are +equivalent. ###tell_singles/3## diff --git a/src/gproc_ps.erl b/src/gproc_ps.erl index 26a0374..e8852e1 100644 --- a/src/gproc_ps.erl +++ b/src/gproc_ps.erl @@ -35,8 +35,10 @@ -module(gproc_ps). -export([subscribe/2, + subscribe_cond/3, unsubscribe/2, publish/3, + publish_cond/3, list_subs/2 ]). @@ -70,6 +72,37 @@ subscribe(Scope, Event) when Scope==l; Scope==g -> gproc:reg({p,Scope,{?ETag, Event}}). +-spec subscribe_cond(scope(), event(), undefined | ets:match_spec()) -> true. +%% @doc Subscribe conditionally to events of type `Event' +%% +%% This function is similar to {@link subscribe/2}, but adds a condition +%% in the form of a match specification. +%% +%% The condition is tested by the {@link publish_cond/3} function +%% and a message is delivered only if the condition is true. Specifically, +%% the test is: +%% +%% `ets:match_spec_run([Msg], ets:match_spec_compile(Cond)) == [true]' +%% +%% In other words, if the match_spec returns true for a message, that message +%% is sent to the subscriber. For any other result from the match_spec, the +%% message is not sent. `Cond == undefined' means that all messages will be +%% delivered (that is, `publish_cond/3' will treat 'normal' subscribers just +%% like {@link publish/3} does, except that `publish/3' strictly speaking +%% ignores the Value part of the property completely, whereas `publish_cond/3' +%% expects it to be either undefined or a valid match spec). +%% +%% This means that `Cond=undefined' and ``Cond=[{'_',[],[true]}]'' are +%% equivalent. +%% @end +subscribe_cond(Scope, Event, Spec) when Scope==l; Scope==g -> + case Spec of + undefined -> ok; + [_|_] -> _ = ets:match_spec_compile(Spec); % validation + _ -> error(badarg) + end, + gproc:reg({p,Scope,{?ETag, Event}}, Spec). + -spec unsubscribe(scope(), event()) -> true. %% @doc Remove subscribtion created using `subscribe(Scope, Event)' %% @@ -91,6 +124,31 @@ unsubscribe(Scope, Event) when Scope==l; Scope==g -> publish(Scope, Event, Msg) when Scope==l; Scope==g -> gproc:send({p, Scope, {?ETag, Event}}, {?ETag, Event, Msg}). +-spec publish_cond(scope(), event(), msg()) -> msg(). +%% @doc Publishes the message `Msg' to conditional subscribers of `Event' +%% +%% The message will be delivered to each subscriber provided their respective +%% condition tests succeed. +%% +%% @see subscribe_cond/3. +%% +publish_cond(Scope, Event, Msg) when Scope==l; Scope==g -> + Message = {?ETag, Event, Msg}, + lists:foreach( + fun({Pid, undefined}) -> Pid ! Message; + ({Pid, Spec}) -> + try C = ets:match_spec_compile(Spec), + case ets:match_spec_run([Msg], C) of + [true] -> Pid ! Message; + _ -> ok + end + catch + error:_ -> + ok + end + end, gproc:select({Scope,p}, [{ {{p,Scope,{?ETag,Event}}, '$1', '$2'}, + [], [{{'$1','$2'}}] }])). + -spec list_subs(scope(), event()) -> [pid()]. %% @doc List the pids of all processes subscribing to `Event'