Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added rebar support

  • Loading branch information...
commit 98ba2d9bfaf4742fded8f5796af5429c64e708b7 1 parent 94cb9af
Ulf Wiger authored
View
27 Makefile
@@ -20,24 +20,21 @@
## FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
## DEALINGS IN THE SOFTWARE.
+.PHONY: all compile clean eunit test eqc
+
DIRS=src
-all:
- for D in $(DIRS) ; do \
- (cd $$D; ${MAKE}) ; \
- done
+all: compile eunit test
+
+compile:
+ ./rebar compile
+
clean:
- for D in $(DIRS) ; do \
- (cd $$D; ${MAKE} clean) ; \
- done
+ ./rebar clean
eunit:
- for D in $(DIRS) ; do \
- (cd $$D; ${MAKE} eunit) ; \
- done
-
-test:
- for D in $(DIRS) ; do \
- (cd $$D; ${MAKE} test) ; \
- done
+ ./rebar eunit
+
+test: eunit
+
View
18 README.md
@@ -0,0 +1,18 @@
+Gproc - Extended Process Dictionary for Erlang
+==============================================
+
+Gproc is a process dictionary for Erlang, which provides a number of useful features beyond what the built-in dictionary has:
+
+* Use any term as a process alias
+* Register a process under several aliases
+* Non-unique properties can be registered simultaneously by many processes
+* QLC and match specification interface for efficient queries on the
+ dictionary
+* Await registration, let's you wait until a process registers itself
+* Counters, and aggregated counters, which automatically maintain the
+ total of all counters with a given name.
+* Global registry, with all the above functions applied to a network of nodes.
+
+Gproc has a QuickCheck test suite, covering a fairly large part of the local gproc functionality, although none of the global registry. It requires a commercial EQC license, but rebar is smart enough to detect whether EQC is available, and if it isn't, the code in gproc_eqc.erl will be "defined away".
+
+There is also an eunit suite in gproc.erl, but it covers only some of the most basic functions (local only). Lots more tests need to be written... some day. Contributions are most welcome.
View
22 doc/gproc.html
@@ -67,6 +67,9 @@ <h3 class="typedecl"><a name="type-type">type()</a></h3>
<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>
@@ -152,6 +155,17 @@ <h3 class="function"><a name="add_local_property-2">add_local_property/2</a></h3
<p><tt>add_local_property(Name, Value) -&gt; any()</tt></p>
</div><p>Registers a local (non-unique) property. @equiv reg({p,l,Name},Value)</p>
+<h3 class="function"><a name="audit_process-1">audit_process/1</a></h3>
+<div class="spec">
+<p><tt>audit_process(Pid) -&gt; any()</tt></p>
+</div>
+
+<h3 class="function"><a name="await-1">await/1</a></h3>
+<div class="spec">
+<p><tt>await(Key::<a href="#type-key">key()</a>) -&gt; {pid(), Value}</tt></p>
+</div><p>Equivalent to <a href="#await-2"><tt>await(Key, infinity)</tt></a>.</p>
+
+
<h3 class="function"><a name="await-2">await/2</a></h3>
<div class="spec">
<p><tt>await(Key::<a href="#type-key">key()</a>, Timeout) -&gt; {pid(), Value}</tt>
@@ -159,7 +173,11 @@ <h3 class="function"><a name="await-2">await/2</a></h3>
</ul></p>
</div><p>Wait for a local name to be registered.
The function raises an exception if the timeout expires. Timeout must be
- either an interger &gt; 0 or 'infinity'.</p>
+ either an interger &gt; 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).</p>
<h3 class="function"><a name="cancel_wait-2">cancel_wait/2</a></h3>
<div class="spec">
@@ -423,6 +441,6 @@ <h3 class="function"><a name="where-1">where/1</a></h3>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
-<p><i>Generated by EDoc, Feb 11 2010, 05:33:39.</i></p>
+<p><i>Generated by EDoc, Sep 11 2010, 18:22:25.</i></p>
</body>
</html>
View
2  doc/gproc_app.html
@@ -38,6 +38,6 @@ <h3 class="function"><a name="stop-1">stop/1</a></h3>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
-<p><i>Generated by EDoc, Feb 11 2010, 05:33:39.</i></p>
+<p><i>Generated by EDoc, Sep 11 2010, 18:22:25.</i></p>
</body>
</html>
View
40 doc/gproc_dist.html
@@ -20,15 +20,19 @@
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#code_change-4">code_change/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#elected-2">elected/2</a></td><td></td></tr>
+<tr><td valign="top"><a href="#elected-3">elected/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#from_leader-3">from_leader/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#handle_DOWN-3">handle_DOWN/3</a></td><td></td></tr>
-<tr><td valign="top"><a href="#handle_call-3">handle_call/3</a></td><td></td></tr>
-<tr><td valign="top"><a href="#handle_cast-2">handle_cast/2</a></td><td></td></tr>
+<tr><td valign="top"><a href="#handle_call-4">handle_call/4</a></td><td></td></tr>
+<tr><td valign="top"><a href="#handle_cast-3">handle_cast/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#handle_info-2">handle_info/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#handle_leader_call-4">handle_leader_call/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#handle_leader_cast-3">handle_leader_cast/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#init-1">init/1</a></td><td></td></tr>
+<tr><td valign="top"><a href="#leader_call-1">leader_call/1</a></td><td></td></tr>
+<tr><td valign="top"><a href="#leader_cast-1">leader_cast/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#mreg-2">mreg/2</a></td><td></td></tr>
+<tr><td valign="top"><a href="#reg-1">reg/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#reg-2">reg/2</a></td><td>
Class = n - unique name
| p - non-unique property
@@ -56,6 +60,11 @@ <h3 class="function"><a name="elected-2">elected/2</a></h3>
<p><tt>elected(S, E) -&gt; any()</tt></p>
</div>
+<h3 class="function"><a name="elected-3">elected/3</a></h3>
+<div class="spec">
+<p><tt>elected(S, E, Node) -&gt; any()</tt></p>
+</div>
+
<h3 class="function"><a name="from_leader-3">from_leader/3</a></h3>
<div class="spec">
<p><tt>from_leader(Ops, S, E) -&gt; any()</tt></p>
@@ -66,14 +75,14 @@ <h3 class="function"><a name="handle_DOWN-3">handle_DOWN/3</a></h3>
<p><tt>handle_DOWN(Node, S, E) -&gt; any()</tt></p>
</div>
-<h3 class="function"><a name="handle_call-3">handle_call/3</a></h3>
+<h3 class="function"><a name="handle_call-4">handle_call/4</a></h3>
<div class="spec">
-<p><tt>handle_call(X1, X2, S) -&gt; any()</tt></p>
+<p><tt>handle_call(X1, X2, S, X4) -&gt; any()</tt></p>
</div>
-<h3 class="function"><a name="handle_cast-2">handle_cast/2</a></h3>
+<h3 class="function"><a name="handle_cast-3">handle_cast/3</a></h3>
<div class="spec">
-<p><tt>handle_cast(Msg, S) -&gt; any()</tt></p>
+<p><tt>handle_cast(Msg, S, X3) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="handle_info-2">handle_info/2</a></h3>
@@ -93,7 +102,17 @@ <h3 class="function"><a name="handle_leader_cast-3">handle_leader_cast/3</a></h3
<h3 class="function"><a name="init-1">init/1</a></h3>
<div class="spec">
-<p><tt>init(X1) -&gt; any()</tt></p>
+<p><tt>init(Opts) -&gt; any()</tt></p>
+</div>
+
+<h3 class="function"><a name="leader_call-1">leader_call/1</a></h3>
+<div class="spec">
+<p><tt>leader_call(Req) -&gt; any()</tt></p>
+</div>
+
+<h3 class="function"><a name="leader_cast-1">leader_cast/1</a></h3>
+<div class="spec">
+<p><tt>leader_cast(Msg) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="mreg-2">mreg/2</a></h3>
@@ -101,6 +120,11 @@ <h3 class="function"><a name="mreg-2">mreg/2</a></h3>
<p><tt>mreg(T, KVL) -&gt; any()</tt></p>
</div>
+<h3 class="function"><a name="reg-1">reg/1</a></h3>
+<div class="spec">
+<p><tt>reg(Key) -&gt; any()</tt></p>
+</div>
+
<h3 class="function"><a name="reg-2">reg/2</a></h3>
<div class="spec">
<p><tt>reg(Key, Value) -&gt; any()</tt></p>
@@ -149,6 +173,6 @@ <h3 class="function"><a name="update_counter-2">update_counter/2</a></h3>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
-<p><i>Generated by EDoc, Feb 11 2010, 05:33:38.</i></p>
+<p><i>Generated by EDoc, Sep 11 2010, 18:22:25.</i></p>
</body>
</html>
View
2  doc/gproc_init.html
@@ -31,6 +31,6 @@ <h3 class="function"><a name="soft_reset-0">soft_reset/0</a></h3>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
-<p><i>Generated by EDoc, Feb 11 2010, 05:33:38.</i></p>
+<p><i>Generated by EDoc, Sep 11 2010, 18:22:25.</i></p>
</body>
</html>
View
2  doc/gproc_lib.html
@@ -18,6 +18,6 @@
<p>For a detailed description, see gproc/doc/erlang07-wiger.pdf.</p><hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
-<p><i>Generated by EDoc, Feb 11 2010, 05:33:39.</i></p>
+<p><i>Generated by EDoc, Sep 11 2010, 18:22:25.</i></p>
</body>
</html>
View
2  doc/gproc_sup.html
@@ -32,6 +32,6 @@ <h3 class="function"><a name="start_link-1">start_link/1</a></h3>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
-<p><i>Generated by EDoc, Feb 11 2010, 05:33:39.</i></p>
+<p><i>Generated by EDoc, Sep 11 2010, 18:22:25.</i></p>
</body>
</html>
View
2  doc/overview-summary.html
@@ -35,6 +35,6 @@
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
-<p><i>Generated by EDoc, Feb 11 2010, 05:33:39.</i></p>
+<p><i>Generated by EDoc, Sep 11 2010, 18:22:25.</i></p>
</body>
</html>
View
28 ebin/gproc.app
@@ -1,19 +1,9 @@
-%%% -*- mode: erlang -*-
-%%% $Id$
-%%%
-
-{application, gproc,
- [
- {description, "GPROC"},
- {vsn, "0.01"},
- {id, "GPROC"},
- {modules, [
- %% TODO: fill in this list, perhaps
- ]
- },
- {registered, [ ] },
- %% NOTE: do not list applications which are load-only!
- {applications, [ kernel, stdlib ] },
- {mod, {gproc_app, []} }
- ]
-}.
+{application,gproc,
+ [{description,"GPROC"},
+ {vsn,"0.01"},
+ {id,"GPROC"},
+ {registered,[]},
+ {applications,[kernel,stdlib]},
+ {mod,{gproc_app,[]}},
+ {modules,[gproc,gproc_app,gproc_dist,gproc_eqc,gproc_init,
+ gproc_lib,gproc_sup]}]}.
View
BIN  rebar
Binary file not shown
View
1  rebar.config
@@ -0,0 +1 @@
+{erl_opts, [debug_info]}.
View
BIN  reference/erlang07-wiger.pdf
Binary file not shown
View
4 src/Makefile
@@ -33,7 +33,7 @@ ERLC += +debug_info
#EQC ?= /host/dev/eqc-1.16
-EQC_ERLC = $(ERLC) -pa $(EQC)/ebin
+EQC_ERLC = $(ERLC) -pa $(EQC)/ebin -I ../include
EQC_ERL = erl -pz ../ebin -pz $(EQC)/ebin -pz ./Unit-Quick-Files -kernel error_logger silent -sasl errlog_type error
SOURCES = $(wildcard *.erl)
@@ -68,7 +68,7 @@ eunit: all
erl -noshell -boot start_clean -sasl errlog_type error \
-pa ../ebin -eval 'eunit:test("../ebin", [verbose])' -s init stop
-test : all ./Unit-Quick-Files/gproc_eqc.beam
+eqc : all ./Unit-Quick-Files/gproc_eqc.beam
$(EQC_ERL) -s gproc_eqc run -s erlang halt
itest : all ./Unit-Quick-Files/gproc_eqc.beam
View
19 src/Unit-Quick-Files/gproc_eqc.erl
@@ -7,12 +7,13 @@
-module(gproc_eqc).
+-ifdef(EQC).
+
-include_lib("eqc/include/eqc.hrl").
-include_lib("eqc/include/eqc_statem.hrl").
-compile(export_all).
-
%%
%% QUESTIONS:
%%
@@ -55,6 +56,18 @@
%% external API
%% UW: renamed to avoid confusion with eunit
+
+gproc_test_() ->
+ {timeout, 60, [fun() -> run(3000) end]}.
+
+%% When run from eunit, we need to set the group leader so that EQC
+%% reporting (the dots) are made visible - that is, if that's what we want.
+verbose_run(N) ->
+ erlang:group_leader(whereis(user), self()),
+ run(N).
+
+%% 3000 tests seems like a large number, but this seems to be needed
+%% to reach enough variation in the tests.
all_tests() ->
eqc:module({numtests, 3000}, ?MODULE).
@@ -456,7 +469,7 @@ postcondition(S,{call,_,lookup_pids,[#key{class=Class}=Key]},Res)
Pids = [ Pid1 || #reg{pid=Pid1,key=Key1} <- S#state.regs
, Key==Key1 ],
lists:sort(Res) == lists:sort(Pids);
-postcondition(S,{call,_,await_new,[#key{}]}, Pid) ->
+postcondition(_S, {call,_,await_new,[#key{}]}, Pid) ->
is_pid(Pid);
postcondition(S,{call,_,await_existing,[#reg{key=Key}]}, {P1,V1}) ->
case lists:keyfind(Key, #reg.key, S#state.regs) of
@@ -652,3 +665,5 @@ check_waiter(WPid, Pid, _Key, Value) ->
after 1000 ->
erlang:error(timeout)
end.
+
+-endif.
View
15 src/gproc.app.src
@@ -0,0 +1,15 @@
+%%% -*- mode: erlang -*-
+%%% $Id$
+%%%
+
+{application, gproc,
+ [
+ {description, "GPROC"},
+ {vsn, "0.01"},
+ {id, "GPROC"},
+ {registered, [ ] },
+ %% NOTE: do not list applications which are load-only!
+ {applications, [ kernel, stdlib ] },
+ {mod, {gproc_app, []} }
+ ]
+}.
View
10 src/gproc.erl
@@ -270,6 +270,11 @@ reg(Key) ->
default({T,_,_}) when T==c -> 0;
default(_) -> undefined.
+%% @spec await(Key::key()) -> {pid(),Value}
+%% @equiv await(Key,infinity)
+%%
+await(Key) ->
+ await(Key, infinity).
%% @spec await(Key::key(), Timeout) -> {pid(),Value}
%% Timeout = integer() | infinity
@@ -283,9 +288,6 @@ default(_) -> undefined.
%% registered (the difference: await/2 also returns the value).
%% @end
%%
-await(Key) ->
- await(Key, infinity).
-
await({n,g,_} = Key, Timeout) ->
?CHK_DIST,
request_wait(Key, Timeout);
@@ -1284,7 +1286,6 @@ reg_test_() ->
]}.
t_simple_reg() ->
- ?debugFmt("self() = ~p~n", [self()]),
?assert(gproc:reg({n,l,name}) =:= true),
?assert(gproc:where({n,l,name}) =:= self()),
?assert(gproc:unreg({n,l,name}) =:= true),
@@ -1300,7 +1301,6 @@ t_simple_prop() ->
?assert(gproc:unreg({p,l,prop}) =:= true).
t_other_proc(F) ->
- ?debugFmt("self() = ~p~n", [self()]),
{_Pid,Ref} = spawn_monitor(fun() -> exit(F()) end),
receive
{'DOWN',Ref,_,_,R} ->
Please sign in to comment.
Something went wrong with that request. Please try again.