Module proc

Flexible Local Process Registry.

Copyright © Ericsson AB 2005 All rights reserved. The information in this document is the property of Ericsson. Except as specifically authorized in writing by Ericsson, the receiver of this document shall keep the information contained herein confidential and shall protect the same in whole or in part from disclosure and dissemination to third parties. Disclosure and disseminations to the receivers employees shall only be made on a strict need to know basis.

Behaviours: gen_server.

Description

Flexible Local Process Registry

This application supports local registration of processes using any erlang term. Furthermore, each process can register by several different names at the same time.

Semantics:

proc works with unique names and non-unique properties.

A name can be any erlang term (except a pid or '_'), and each process can register itself under many different unique names. A property can be any term (except '_'), and must be unique within a process, but several processes can register the same property.

Furthermore, there are "fold" and "select" functions to allow for efficient iteration over names or properties in the process registry.

Many of the operations to access names and properties rely on the semantics given by //stdlib/ets, and this is often mentioned in the interface documentation. This means that it is safe to assume that the functions conform to the search semantics of ordered_set ets tables. However, it is not safe to assume anything about whether the data in fact resides in ets tables, and if so, what those tables are called, or indeed how the data is represented internally.

Function Index

add_counter/2Publish a counter property for the current process.
add_counter/3Publish a counter property on behalf of Process.
add_property/1Publish a property of the current process.
add_property/2Publish a property on behalf of another process.
await_reg/1Request to be notified when someone registers as Name.
clear_await_reg/1Cancel waiting for notification of process registration of a given name.
del_counter/1Un-publish a counter property for the current process.
del_counter/2Un-publish a counter property on behalf of Process.
del_property/1Un-publishes the property Property for the current process.
del_property/2Un-publish the property Property on behalf of Process.
enable_i/0
first/1Analogous to ets:first/1.
fold_names/3Similar to lists:foldl/3, but based on a list of select patterns, identifying a sub-set of unique names.
fold_names/4Like fold_names/3, but works in batches of Limit objects at a time, in order to improve memory characteristics.
fold_names/5Like fold_names/4, but applies a "Regulator function" after each batch of objects before proceeding with the next one.
fold_properties/3Similar to //stdlib/lists:foldl/3, but based on a select pattern on Property, identifying a sub-set of published properties.
fold_properties/4Like fold_properties/3, but works in batches of Limit objects at a time, in order to improve raw performance.
fold_properties/5Like fold_properties/4, but applies a "Regulator function" after each batch of objects before proceeding with the next one.
guards/1Expand a list of select guards, allowing for the pseudo guard is_counter.
i/1Like c:i/0, but allows for filtering output with proc names and properties.
info/1Like process_info(PidOfProcess), but with added proc-related attributes.
info/2Like process_info(PidOfProcess, Attr) but accepts some additional attributes.
is_counter/1Check whether Property is a counter property.
is_counter/2Check whether Propery registered under Process is a counter property.
is_property/1Returns true if Property is a published property of the current process.
is_property/2Check whether Property is in fact a property registered with Process.
last/1Analogous to ets:last/1.
next/2Analogous to ets:next/2.
pids/1Returns all pids for which a property Property is published.
pids/2Similar to pids/1, but also allowing select guards.
previous/2Analogous to ets:previous/2.
properties_by_pid/1Lists all properties for a given process.
properties_by_pid/2Lists all properties for a given process that match the pattern KeyPat.
properties_by_pid/3Like properties_by_pid/2, but with an added list of guards.
read_counter/1Read the value of a counter property for the current process.
read_counter/2Read the value of a counter property published by Process.
reg/1Register a unique Name.
replace_property/2Equivalent to del_property(OldProperty), add_property(NewProperty), but much more efficient.
replace_property/3Replace OldProperty with NewProperty on behalf of Process.
select/1Analogous to ets:select/1.
select_fold_properties/3Like fold_properties/3 but more flexible as it allows for combining several patterns into one query.
select_fold_properties/4Like select_fold_properties/3, but works in batches of Limit objects at a time, in order to improve raw performance.
select_fold_properties/5Like select_fold_properties/4, but applies a "Regulator function" after each batch of objects before proceeding with the next one.
select_names/1Returns {Name,Pid} objects one at a time based on a given selection of all registered unique names.
select_names/2Like select_names/1, but works in batches of Limit objects at a time, in order to improve raw performance.
select_pattern/1Helper function to generate select patterns from the more intuitive patterns Property (or Name, as it works equally for names).
select_pattern/2As select_pattern/1, but with the option to add Guard expressions.
select_properties/1Returns {Property,Pid} objects one at a time based on a given selection of all registered instances of Key.
select_properties/2Like select_properties/1 but works in batches of Limit objects at a time in order to improve raw performance.
send/2Analogous to Name ! Msg, except that send({Node,Dest}, Msg) will be interpreted as 'send to the local process registered as {Node, Dest}'.
set_access/1Control the ability of Processes to perform certain functions on behalf of the current process.
start_link/0Starts the proc server.
unreg/1Unregister Name.
update_counter/2Update the counter attribute of a counter property.
update_counter/3Update counter attribute on behalf of Process.
where/1Analogous to erlang:whereis(Name).

Function Details

add_counter/2

add_counter(Name, InitialValue::integer()) -> true

Publish a counter property for the current process.

Counter properties behave as normal properties with the following exceptions:

add_counter/3

add_counter(Process, Name, InitialValue::integer()) -> true

Publish a counter property on behalf of Process.

This function is allowed only if permission to add counters has been given through Process calling grant_access/2.

If permission to add counters has not been given, this function exits with access.

add_property/1

add_property(Property::term()) -> true

Publish a property of the current process.

If Property is already published for the current process, this function exits with badarg.

This operation can be viewed as publishing the meta-data Property as part of the interface of the process. Several processes may publish the same property. The process can be found (as part of a group) through this property, using one of the functions fold_properties/3, pids/1, et al.

add_property/2

add_property(Process, Property) -> true

Publish a property on behalf of another process.

Adding properties on behalf of another process is only allowed if the other process has called set_access/1, giving this process the proper rights to act as proxy.

Process can be either a pid() or a registered name.

await_reg/1

await_reg(Pid::Name) -> {already_registered, pid()} | Reg

Request to be notified when someone registers as Name.

If Name is already registered, the function returns with the value {already_registered, Pid}. Otherwise, it returns a "reference" (not necessarily of type reference()) that can be used to recognize a future message.

When some process P registers as Name, a message on the form {sysProgReg, Ref, reg, Name, Pid} is sent to each waiting process (note that Ref will be different for each waiting process.)

clear_await_reg/1

clear_await_reg(Ref) -> true

Cancel waiting for notification of process registration of a given name.

This function exits with badarg if Ref does not appear to be a valid reference returned by await_reg/1; otherwise returns true.

del_counter/1

del_counter(Name) -> true

Un-publish a counter property for the current process.

del_counter/2

del_counter(Process, Name) -> true

Un-publish a counter property on behalf of Process.

This function is allowed only if permission to delete counters has been given through Process calling grant_access/2.

If permission to delete counters has not been given, this function exits with access.

del_property/1

del_property(Property) -> true

Un-publishes the property Property for the current process.

If there is no published property Property (see add_property/1), for the current process, the function exits with badarg.

del_property/2

del_property(Process, Property) -> true

Un-publish the property Property on behalf of Process.

This function is allowed only if permission to delete properties has been given through Process calling grant_access/2.

If permission to delete properties has not been given, this function exits with access.

enable_i/0

enable_i() -> term()

first/1

first(Type::names | properties) -> Key | '$end_of_table'

Analogous to ets:first/1.

The tables corresponding to names and properties both have ordered_set semantics.

fold_names/3

fold_names(Fun::function(), Acc, Patterns) -> NewAcc

Similar to lists:foldl/3, but based on a list of select patterns, identifying a sub-set of unique names.

For each matching name, a call is made to

Fun({Name1,Pid1}, Acc1)
, which is expected to return NewAcc.

Patterns is a list of match specifications on the same form as that used by ets:select_delete/2 and ets:select_count/2, that is:

     * Patterns = [MatchFunction] | '_'
     * MatchFunction = {MatchHead, [Guard], [Result]}
     * MatchHead = "Pattern as in ets:match"
     * Guard = {"Guardtest name", ...}
     * Result = true (if object is to be included)
   

The following expression would return a list of all registered unique names together with the processes that registered them:

   proc:fold_names(fun(X,Acc) -> [X|Acc] end, [], [{'_',[],[true]}])
   

For convenience, the special pattern '_' is also allowed. It is expanded to [{'_',[],[true]}].

This function is equivalent to fold_names(Fun,Acc,Patterns,100), (see fold_names/5.)

fold_names/4

fold_names(Fun, Acc, Patterns, Limit::integer()) -> NewAcc

Like fold_names/3, but works in batches of Limit objects at a time, in order to improve memory characteristics.

fold_names/3 uses a default limit of 1 object at a time.

This function is equivalent to fold_names(Fun,Acc,Patterns,Limit,fun(_) -> true end), (see fold_names/5.)

fold_names/5

fold_names(Fun::function(), Acc, Patterns, Limit::integer(), Regulator::function()) -> NewAcc

Like fold_names/4, but applies a "Regulator function" after each batch of objects before proceeding with the next one.

The Regulator function is expected to take the current accumulator as an argument and return either true (in which case processing continues), or false (in which case the fold_names/5 function breaks and returns the current accumulator.

fold_properties/3

fold_properties(Fun::function(), Acc, Property) -> NewAcc

Similar to //stdlib/lists:foldl/3, but based on a select pattern on Property, identifying a sub-set of published properties.

For each matching key, a call is made to

Fun({Property1,Pid1}, Acc1)
, which is expected to return NewAcc. Note that, as in pids/1, Property can be select a pattern. The following expression would return a list of all published instances of Property together with the processes that registered them:

   proc:fold_properties(fun(X,Acc) -> [X|Acc] end, [], '_')
   

This function is equivalent to fold_properties(Fun,Acc,Property,1), (see fold_properties/4.) See also select_pattern/1.

fold_properties/4

fold_properties(Fun::function(), Acc, Properties::Key, Limit::integer()) -> NewAcc

Like fold_properties/3, but works in batches of Limit objects at a time, in order to improve raw performance.

fold_properties/3 uses a default limit of 1 object at a time.

This function is equivalent to fold_properties(Fun,Acc,Property,Limit,fun(_) -> true end), (see fold_properties/5.) See also select_pattern/1.

fold_properties/5

fold_properties(Fun::function(), Acc, Property, Limit::integer(), Regulator::function()) -> NewAcc

Like fold_properties/4, but applies a "Regulator function" after each batch of objects before proceeding with the next one.

The Regulator function is expected to take the current accumulator as an argument and return either true (in which case processing continues), or false (in which case the fold_properties/5 function breaks and returns the current accumulator. See also select_pattern/1.

guards/1

guards(Gs::List) -> NewList

Expand a list of select guards, allowing for the pseudo guard is_counter.

How counter properties can be distinguished from regular properties internally is not defined in the proc interface. Using this function, it is however possible to specify a guard test, is_counter, which will expand to a legal guard. The is_counter test can be combined with the standard logical operators, not, and, or, orelse, andalso, and xor.

Example:

   proc:select_properties(
       [{'_', proc:guards([{'not', is_counter}]), [true]}]).
   

will list all published properties that are not counters.

i/1

i(Options::Option) -> ok

Like c:i/0, but allows for filtering output with proc names and properties.

Usage: i([{i | x, names | properties, Patterns}]).
calls c:i(Processes) for a subset of all running processes. {i, Type, Pattern} specifies by name or property which processes to include. {x, Type, Pattern} specifies which processes to exclude from the listing. If no {i,T,P} tuples are specified, all processes are included per default, then reduced by the {x,T,P} patterns. Multiple tuples are allowed. Pattern is a match specification where the result head is true.

Note that currently, using ets:fun2ms/1 may have severe impact on performance if there is a large number of registered names or keys.

info/1

info(NameOrPid::Process) -> [{Tag, Info}] | undefined

Like process_info(PidOfProcess), but with added proc-related attributes.

This function calls process_info(PidOfProcess), and adds to the result the following info items:

info/2

info(NameOrPid::Process, Attr) -> {Attr, Info}

Like process_info(PidOfProcess, Attr) but accepts some additional attributes.

All attributes supported by erlang:process_info/2 are supported by this function. In addition, the following attributes are handled:

is_counter/1

is_counter(Property) -> true | false

Check whether Property is a counter property.

Counter properties are created through add_counter/2, and behave as normal properties with the following exceptions:

is_counter/2

is_counter(Pid::Process, Property) -> true | false

Check whether Propery registered under Process is a counter property.

Process can be either a pid or a registered name.

is_property/1

is_property(Property) -> true | false

Returns true if Property is a published property of the current process.

is_property/2

is_property(Pid::Process, Property) -> true | false

Check whether Property is in fact a property registered with Process.

Process can be either a pid or a registered name.

last/1

last(Type::names | properties) -> Key | '$end_of_table'

Analogous to ets:last/1.

The tables corresponding to names and properties both have ordered_set semantics.

next/2

next(Type::names | properties, Prev::Key) -> Key | '$end_of_table'

Analogous to ets:next/2.

The tables corresponding to names and properties both have ordered_set semantics. The key format of the properties table is {Property, Pid}, while the key format of the names table is simply the name. Note that names and properties are not likely the physical names of the actual tables.

pids/1

pids(Property) -> [pid()]

Returns all pids for which a property Property is published.

To be more precise, Property can be any pattern that would be accepted by //stdlib/ets:select/2, e.g. '_'

If one imagines an ordered_set ets table Tab where all properties are stored on the form {{Property,Pid},1}, then calling this function is equivalent to calling

ets:select(Tab, [{{{Property,'$1'},'_'}, [], ['$1']}]).

Note that this is also true as regards performance. If the Key pattern is unbound, the operation will be a linear search.

pids/2

pids(Property, Guards::list()) -> [pid()]

Similar to pids/1, but also allowing select guards.

If one imagines an ordered_set ets table Tab where all non-unique keys are stored on the form {{Property,Pid},1}, then calling this function is equivalent to calling

ets:select(Tab, [{{{Property,'$1'},'_'}, Guards, ['$1']}]).

Note that this is also true as regards performance. If the Property pattern is unbound, the operation will be a linear search.

previous/2

previous(Type::names | properties, Next::Key) -> Key | '$end_of_table'

Analogous to ets:previous/2.

The tables corresponding to names and properties both have ordered_set semantics. The key format of the properties table is {Property, Pid}, while the key format of the names table is simply the name. Note that names and properties are not likely the physical names of the actual tables.

properties_by_pid/1

properties_by_pid(P::pid()) -> [Property]

Lists all properties for a given process.

properties_by_pid/2

properties_by_pid(P::pid(), KeyPat) -> [Property]

Lists all properties for a given process that match the pattern KeyPat.

Equivalend to properties_by_pid(P, KeyPat, []).

properties_by_pid/3

properties_by_pid(P::pid(), KeyPat, Guards) -> [Property]

Like properties_by_pid/2, but with an added list of guards.

The Guards list may be one returned from the function guards/1.

read_counter/1

read_counter(Name) -> integer()

Read the value of a counter property for the current process.

read_counter/2

read_counter(Pid::Process, Name) -> integer()

Read the value of a counter property published by Process.

reg/1

reg(Pid::Name) -> true

Register a unique Name. Returns true or exits.

This function differs from erlang:register(Name,Pid) in the following ways:

replace_property/2

replace_property(OldProp::OldProperty, NewProperty) -> true

Equivalent to del_property(OldProperty), add_property(NewProperty), but much more efficient.

If OldProperty is not a published property of the current process (see add_property/1), the function exits with badarg.

One could use properties as a "published process dictionary", e.g. by replacing put(Tag,Value) with proc:add_property({Tag,Value}), and get(Tag) with (roughly) proc:properties_by_pid(self(),Tag). While this would be somewhat less efficient than the built-in process dictionary, it has the advantage of allowing other processes to key on process meta-data in a much more efficient and disciplined way than {_,Dict} = process_info(Pid,dictionary), lists:keysearch(Tag,1,Dict) (Which makes no distinction between public and private data, and therefore is rightfully frowned upon, and hopefully never attempted.)"

Note: This function does not work on counter properties.

replace_property/3

replace_property(Process, OldProperty, NewProperty) -> true

Replace OldProperty with NewProperty on behalf of Process.

This function is allowed only if permission to replace properties has been given through Process calling grant_access/2.

If permission to replace properties has not been given, this function exits with access.

select/1

select(Continuation) -> {[Obj], NewContinuation} | '$end_of_table'

Analogous to ets:select/1.

This function is intended to be called with a Continuation returned from select_names/1 or select_properties/2.

select_fold_properties/3

select_fold_properties(Fun, Acc, Patterns) -> NewAcc

Like fold_properties/3 but more flexible as it allows for combining several patterns into one query.

Patterns is composed as for select_properties/1.

select_fold_properties/4

select_fold_properties(Fun, Acc, Patterns, Limit) -> NewAcc

Like select_fold_properties/3, but works in batches of Limit objects at a time, in order to improve raw performance.

select_fold_properties/3 uses a default limit of 1 object at a time.

This function is equivalent to select_fold_properties(Fun,Acc,Patterns,Limit,fun(_) -> true end), (see select_fold_properties/5.)

select_fold_properties/5

select_fold_properties(Fun::function(), Acc, Patterns::Property, Limit::integer(), Regulator::function()) -> NewAcc

Like select_fold_properties/4, but applies a "Regulator function" after each batch of objects before proceeding with the next one.

The Regulator function is expected to take the current accumulator as an argument and return either true (in which case processing continues), or false (in which case the select_fold_properties/5 function breaks and returns the current accumulator.

select_names/1

select_names(Patterns) -> {Objs, Continuation} | '$end_of_table'

Returns {Name,Pid} objects one at a time based on a given selection of all registered unique names.

Patterns can be written as follows:

     * Patterns = [MatchFunction] | '_'
     * MatchFunction = {MatchHead, [Guard], [Result]}
     * MatchHead = "Pattern as in ets:match"
     * Guard = {"Guardtest name", ...}
     * Result = true (if object is to be included)
   

or generated using select_pattern/1 or select_pattern/2.

The function is almost equivalent to ets:select(Tab,Patterns, 100) on an ordered_set table Tab with the following representation:

{{Key, Value}, Pid}

The difference compared to ets:select/3 is the Result expression. In this function, Result is expected to be 'true' for those objects that are to be included.

For convenience, the special pattern '_' is accepted, and expanded to [{'_', [], [true]}].

Any other patterns are ignored.

The Continuation returned can be used when calling select/1 in order to continue processing.

select_names/2

select_names(Patterns0::Patterns, Limit) -> {Objs, Continuation} | '$end_of_table'

Like select_names/1, but works in batches of Limit objects at a time, in order to improve raw performance.

select_pattern/1

select_pattern(What) -> Patterns

Helper function to generate select patterns from the more intuitive patterns Property (or Name, as it works equally for names).

The return value from this function can be used in e.g. select_properties/1, select_properties/2, select_fold_properties/3, select_fold_properties/4 or select_fold_properties/5, or similarly, select_names/1, select_names/2, select_fold_names/3, select_fold_names/4, or select_fold_names/5.

Patterns is a list of match specifications on the same form as that used by //stdlib/ets:select_delete/2 and //stdlib/ets:select_count/2, that is:

     * Patterns = [MatchFunction] | '_'
     * MatchFunction = {MatchHead, [Guard], [Result]}
     * MatchHead = "Pattern as in ets:match"
     * Guard = {"Guardtest name", ...}
     * Result = true (if object is to be included)
   

select_pattern/2

select_pattern(What, Guards) -> Patterns

As select_pattern/1, but with the option to add Guard expressions.

select_properties/1

select_properties(Patterns) -> {Objs, Continuation} | '$end_of_table'

Returns {Property,Pid} objects one at a time based on a given selection of all registered instances of Key.

Patterns can be written as follows:

     * Patterns = [MatchFunction] | '_'
     * MatchFunction = {MatchHead, [Guard], [Result]}
     * MatchHead = "Pattern as in ets:match"
     * Guard = {"Guardtest name", ...}
     * Result = true (if object is to be included)
   

or generated using select_pattern/1 or select_pattern/2.

For convenience, the special pattern '_' is also accepted. It expands to [{'_', [], [true]}].

The Continuation returned can be used when calling select/1 in order to continue processing.

select_properties/2

select_properties(Patterns0::Patterns, Limit::integer()) -> {Objs, Continuation} | '$end_of_table'

Like select_properties/1 but works in batches of Limit objects at a time in order to improve raw performance.

send/2

send(Pid::Name, Msg) -> Msg

Analogous to Name ! Msg, except that send({Node,Dest}, Msg) will be interpreted as 'send to the local process registered as {Node, Dest}'. If Name is a pid, this function will send the message to the process with process identifier Name (recall that it is not possible to register a pid as a unique name in proc.)

set_access/1

set_access(Access::[{Action, Processes, Ops}]) -> true

Control the ability of Processes to perform certain functions on behalf of the current process.

Op must be one of

Processes is a list of registered names and/or pids.

Example:

   set_access([{grant, ["foo","bar"], [update_counter]},
               {revoke, ["baz"], [properties]}])

Allows the processes registered as "foo" and "bar" to update counters, and makes sure that "baz" is no longer able to add, delete or replace properties.

start_link/0

start_link() -> {ok, pid()}

Starts the proc server.

proc assumes that the proc_tabs module is available, and that the proc_tabs process is running.

unreg/1

unreg(Name) -> true

Unregister Name

This function exits if Name isn't registered to the current process.

update_counter/2

update_counter(Name, Incr) -> integer()

Update the counter attribute of a counter property.

This function only works on counter properties. The Incr argument is passed as-is to //stlib/ets:update_counter/3. If a complex option, such as {Pos, Incr} is used, Pos must be equal to 2.

update_counter/3

update_counter(Process, Name, Value::Incr) -> integer()

Update counter attribute on behalf of Process.

This function is allowed only if permission to update counters has been given through Process calling grant_access/2.

If permission to update counters has not been given, this function exits with access.

where/1

where(Name) -> pid() | undefined

Analogous to erlang:whereis(Name)