aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib')
-rw-r--r--lib/stdlib/doc/src/gen_event.xml61
-rw-r--r--lib/stdlib/doc/src/gen_fsm.xml55
-rw-r--r--lib/stdlib/doc/src/gen_server.xml39
-rw-r--r--lib/stdlib/doc/src/supervisor.xml12
-rw-r--r--lib/stdlib/doc/src/supervisor_bridge.xml7
-rw-r--r--lib/stdlib/src/gen.erl22
-rw-r--r--lib/stdlib/src/gen_event.erl10
-rw-r--r--lib/stdlib/src/gen_fsm.erl25
-rw-r--r--lib/stdlib/src/gen_server.erl23
-rw-r--r--lib/stdlib/test/Makefile1
-rw-r--r--lib/stdlib/test/dummy_via.erl94
-rw-r--r--lib/stdlib/test/gen_event_SUITE.erl26
-rw-r--r--lib/stdlib/test/gen_fsm_SUITE.erl71
-rw-r--r--lib/stdlib/test/gen_server_SUITE.erl62
14 files changed, 436 insertions, 72 deletions
diff --git a/lib/stdlib/doc/src/gen_event.xml b/lib/stdlib/doc/src/gen_event.xml
index 24bcb419fe..0f50b37de6 100644
--- a/lib/stdlib/doc/src/gen_event.xml
+++ b/lib/stdlib/doc/src/gen_event.xml
@@ -120,8 +120,10 @@ gen_event:stop -----> Module:terminate/2
<name>start_link(EventMgrName) -> Result</name>
<fsummary>Create a generic event manager process in a supervision tree.</fsummary>
<type>
- <v>EventMgrName = {local,Name} | {global,Name}</v>
+ <v>EventMgrName = {local,Name} | {global,GlobalName}
+ | {via,Module,ViaName}</v>
<v>&nbsp;Name = atom()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Result = {ok,Pid} | {error,{already_started,Pid}}</v>
<v>&nbsp;Pid = pid()</v>
</type>
@@ -132,10 +134,17 @@ gen_event:stop -----> Module:terminate/2
the event manager is linked to the supervisor.</p>
<p>If <c>EventMgrName={local,Name}</c>, the event manager is
registered locally as <c>Name</c> using <c>register/2</c>.
- If <c>EventMgrName={global,Name}</c>, the event manager is
- registered globally as <c>Name</c> using
+ If <c>EventMgrName={global,GlobalName}</c>, the event manager is
+ registered globally as <c>GlobalName</c> using
<c>global:register_name/2</c>. If no name is provided,
- the event manager is not registered.</p>
+ the event manager is not registered.
+ If <c>EventMgrName={via,Module,ViaName}</c>, the event manager will
+ register with the registry represented by <c>Module</c>.
+ The <c>Module</c> callback should export the functions
+ <c>register_name/2</c>, <c>unregister_name/1</c>,
+ <c>whereis_name/1</c> and <c>send/2</c>, which should behave like the
+ corresponding functions in <c>global</c>. Thus,
+ <c>{via,global,GlobalName}</c> is a valid reference.</p>
<p>If the event manager is successfully created the function
returns <c>{ok,Pid}</c>, where <c>Pid</c> is the pid of
the event manager. If there already exists a process with
@@ -149,8 +158,10 @@ gen_event:stop -----> Module:terminate/2
<name>start(EventMgrName) -> Result</name>
<fsummary>Create a stand-alone event manager process.</fsummary>
<type>
- <v>EventMgrName = {local,Name} | {global,Name}</v>
+ <v>EventMgrName = {local,Name} | {global,GlobalName}
+ | {via,Module,ViaName}</v>
<v>&nbsp;Name = atom()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Result = {ok,Pid} | {error,{already_started,Pid}}</v>
<v>&nbsp;Pid = pid()</v>
</type>
@@ -166,8 +177,10 @@ gen_event:stop -----> Module:terminate/2
<name>add_handler(EventMgrRef, Handler, Args) -> Result</name>
<fsummary>Add an event handler to a generic event manager.</fsummary>
<type>
- <v>EventMgr = Name | {Name,Node} | {global,Name} | pid()</v>
+ <v>EventMgr = Name | {Name,Node} | {global,GlobalName}
+ | {via,Module,ViaName} | pid()</v>
<v>&nbsp;Name = Node = atom()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Handler = Module | {Module,Id}</v>
<v>&nbsp;Module = atom()</v>
<v>&nbsp;Id = term()</v>
@@ -185,8 +198,10 @@ gen_event:stop -----> Module:terminate/2
<item><c>Name</c>, if the event manager is locally registered,</item>
<item><c>{Name,Node}</c>, if the event manager is locally
registered at another node, or</item>
- <item><c>{global,Name}</c>, if the event manager is globally
+ <item><c>{global,GlobalName}</c>, if the event manager is globally
registered.</item>
+ <item><c>{via,Module,ViaName}</c>, if the event manager is registered
+ through an alternative process registry.</item>
</list>
<p><c>Handler</c> is the name of the callback module <c>Module</c> or
a tuple <c>{Module,Id}</c>, where <c>Id</c> is any term.
@@ -207,8 +222,10 @@ gen_event:stop -----> Module:terminate/2
<name>add_sup_handler(EventMgrRef, Handler, Args) -> Result</name>
<fsummary>Add a supervised event handler to a generic event manager.</fsummary>
<type>
- <v>EventMgr = Name | {Name,Node} | {global,Name} | pid()</v>
+ <v>EventMgr = Name | {Name,Node} | {global,GlobalName}
+ | {via,Module,ViaName} | pid()</v>
<v>&nbsp;Name = Node = atom()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Handler = Module | {Module,Id}</v>
<v>&nbsp;Module = atom()</v>
<v>&nbsp;Id = term()</v>
@@ -252,8 +269,10 @@ gen_event:stop -----> Module:terminate/2
<name>sync_notify(EventMgrRef, Event) -> ok</name>
<fsummary>Notify an event manager about an event.</fsummary>
<type>
- <v>EventMgrRef = Name | {Name,Node} | {global,Name} | pid()</v>
+ <v>EventMgrRef = Name | {Name,Node} | {global,GlobalName}
+ | {via,Module,ViaName} | pid()</v>
<v>&nbsp;Name = Node = atom()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Event = term()</v>
</type>
<desc>
@@ -277,8 +296,10 @@ gen_event:stop -----> Module:terminate/2
<name>call(EventMgrRef, Handler, Request, Timeout) -> Result</name>
<fsummary>Make a synchronous call to a generic event manager.</fsummary>
<type>
- <v>EventMgrRef = Name | {Name,Node} | {global,Name} | pid()</v>
+ <v>EventMgrRef = Name | {Name,Node} | {global,GlobalName}
+ | {via,Module,ViaName} | pid()</v>
<v>&nbsp;Name = Node = atom()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Handler = Module | {Module,Id}</v>
<v>&nbsp;Module = atom()</v>
<v>&nbsp;Id = term()</v>
@@ -317,8 +338,10 @@ gen_event:stop -----> Module:terminate/2
<name>delete_handler(EventMgrRef, Handler, Args) -> Result</name>
<fsummary>Delete an event handler from a generic event manager.</fsummary>
<type>
- <v>EventMgrRef = Name | {Name,Node} | {global,Name} | pid()</v>
+ <v>EventMgrRef = Name | {Name,Node} | {global,GlobalName}
+ | {via,Module,ViaName} | pid()</v>
<v>&nbsp;Name = Node = atom()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Handler = Module | {Module,Id}</v>
<v>&nbsp;Module = atom()</v>
<v>&nbsp;Id = term()</v>
@@ -345,8 +368,10 @@ gen_event:stop -----> Module:terminate/2
<name>swap_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result</name>
<fsummary>Replace an event handler in a generic event manager.</fsummary>
<type>
- <v>EventMgrRef = Name | {Name,Node} | {global,Name} | pid()</v>
+ <v>EventMgrRef = Name | {Name,Node} | {global,GlobalName}
+ | {via,Module,ViaName} | pid()</v>
<v>&nbsp;Name = Node = atom()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Handler1 = Handler2 = Module | {Module,Id}</v>
<v>&nbsp;Module = atom()</v>
<v>&nbsp;Id = term()</v>
@@ -389,8 +414,10 @@ gen_event:stop -----> Module:terminate/2
<name>swap_sup_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result</name>
<fsummary>Replace an event handler in a generic event manager.</fsummary>
<type>
- <v>EventMgrRef = Name | {Name,Node} | {global,Name} | pid()</v>
+ <v>EventMgrRef = Name | {Name,Node} | {global,GlobalName}
+ | {via,Module,ViaName} | pid()</v>
<v>&nbsp;Name = Node = atom()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Handler1 = Handler 2 = Module | {Module,Id}</v>
<v>&nbsp;Module = atom()</v>
<v>&nbsp;Id = term()</v>
@@ -411,8 +438,10 @@ gen_event:stop -----> Module:terminate/2
<name>which_handlers(EventMgrRef) -> [Handler]</name>
<fsummary>Return all event handlers installed in a generic event manager.</fsummary>
<type>
- <v>EventMgrRef = Name | {Name,Node} | {global,Name} | pid()</v>
+ <v>EventMgrRef = Name | {Name,Node} | {global,GlobalName}
+ | {via,Module,ViaName} | pid()</v>
<v>&nbsp;Name = Node = atom()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Handler = Module | {Module,Id}</v>
<v>&nbsp;Module = atom()</v>
<v>&nbsp;Id = term()</v>
@@ -428,8 +457,10 @@ gen_event:stop -----> Module:terminate/2
<name>stop(EventMgrRef) -> ok</name>
<fsummary>Terminate a generic event manager.</fsummary>
<type>
- <v>EventMgrRef = Name | {Name,Node} | {global,Name} | pid()</v>
+ <v>EventMgrRef = Name | {Name,Node} | {global,GlobalName}
+ | {via,Module,ViaName} | pid()</v>
<v>Name = Node = atom()</v>
+ <v>GlobalName = ViaName = term()</v>
</type>
<desc>
<p>Terminates the event manager <c>EventMgrRef</c>. Before
diff --git a/lib/stdlib/doc/src/gen_fsm.xml b/lib/stdlib/doc/src/gen_fsm.xml
index 421eeb4fd3..73c1911f1e 100644
--- a/lib/stdlib/doc/src/gen_fsm.xml
+++ b/lib/stdlib/doc/src/gen_fsm.xml
@@ -84,9 +84,10 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
<name>start_link(FsmName, Module, Args, Options) -> Result</name>
<fsummary>Create a gen_fsm process in a supervision tree.</fsummary>
<type>
- <v>FsmName = {local,Name} | {global,GlobalName}</v>
+ <v>FsmName = {local,Name} | {global,GlobalName}
+ | {via,Module,ViaName}</v>
<v>&nbsp;Name = atom()</v>
- <v>&nbsp;GlobalName = term()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Module = atom()</v>
<v>Args = term()</v>
<v>Options = [Option]</v>
@@ -113,8 +114,16 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
locally as <c>Name</c> using <c>register/2</c>.
If <c>FsmName={global,GlobalName}</c>, the gen_fsm is
registered globally as <c>GlobalName</c> using
- <c>global:register_name/2</c>. If no name is provided,
- the gen_fsm is not registered.</p>
+ <c>global:register_name/2</c>.
+ If <c>EventMgrName={via,Module,ViaName}</c>, the event manager will
+ register with the registry represented by <c>Module</c>.
+ The <c>Module</c> callback should export the functions
+ <c>register_name/2</c>, <c>unregister_name/1</c>,
+ <c>whereis_name/1</c> and <c>send/2</c>, which should behave like the
+ corresponding functions in <c>global</c>. Thus,
+ <c>{via,global,GlobalName}</c> is a valid reference.</p>
+ <p>If no name is provided,
+ the gen_fsm is not registered.</p>
<p><c>Module</c> is the name of the callback module.</p>
<p><c>Args</c> is an arbitrary term which is passed as
the argument to <c>Module:init/1</c>.</p>
@@ -154,9 +163,10 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
<name>start(FsmName, Module, Args, Options) -> Result</name>
<fsummary>Create a stand-alone gen_fsm process.</fsummary>
<type>
- <v>FsmName = {local,Name} | {global,GlobalName}</v>
+ <v>FsmName = {local,Name} | {global,GlobalName}
+ | {via,Module,ViaName}</v>
<v>&nbsp;Name = atom()</v>
- <v>&nbsp;GlobalName = term()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Module = atom()</v>
<v>Args = term()</v>
<v>Options = [Option]</v>
@@ -180,9 +190,10 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
<name>send_event(FsmRef, Event) -> ok</name>
<fsummary>Send an event asynchronously to a generic FSM.</fsummary>
<type>
- <v>FsmRef = Name | {Name,Node} | {global,GlobalName} | pid()</v>
+ <v>FsmRef = Name | {Name,Node} | {global,GlobalName}
+ | {via,Module,ViaName} | pid()</v>
<v>&nbsp;Name = Node = atom()</v>
- <v>&nbsp;GlobalName = term()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Event = term()</v>
</type>
<desc>
@@ -196,9 +207,11 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
<item>the pid,</item>
<item><c>Name</c>, if the gen_fsm is locally registered,</item>
<item><c>{Name,Node}</c>, if the gen_fsm is locally
- registered at another node, or</item>
- <item><c>{global,GlobalName}</c>, if the gen_fsm is globally
- registered.</item>
+ registered at another node, or</item>
+ <item><c>{global,GlobalName}</c>, if the gen_fsm is globally
+ registered.</item>
+ <item><c>{via,Module,ViaName}</c>, if the event manager is registered
+ through an alternative process registry.</item>
</list>
<p><c>Event</c> is an arbitrary term which is passed as one of
the arguments to <c>Module:StateName/2</c>.</p>
@@ -208,9 +221,10 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
<name>send_all_state_event(FsmRef, Event) -> ok</name>
<fsummary>Send an event asynchronously to a generic FSM.</fsummary>
<type>
- <v>FsmRef = Name | {Name,Node} | {global,GlobalName} | pid()</v>
+ <v>FsmRef = Name | {Name,Node} | {global,GlobalName}
+ | {via,Module,ViaName} | pid()</v>
<v>&nbsp;Name = Node = atom()</v>
- <v>&nbsp;GlobalName = term()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Event = term()</v>
</type>
<desc>
@@ -232,9 +246,10 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
<name>sync_send_event(FsmRef, Event, Timeout) -> Reply</name>
<fsummary>Send an event synchronously to a generic FSM.</fsummary>
<type>
- <v>FsmRef = Name | {Name,Node} | {global,GlobalName} | pid()</v>
+ <v>FsmRef = Name | {Name,Node} | {global,GlobalName}
+ | {via,Module,ViaName} | pid()</v>
<v>&nbsp;Name = Node = atom()</v>
- <v>&nbsp;GlobalName = term()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Event = term()</v>
<v>Timeout = int()>0 | infinity</v>
<v>Reply = term()</v>
@@ -264,9 +279,10 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
<name>sync_send_all_state_event(FsmRef, Event, Timeout) -> Reply</name>
<fsummary>Send an event synchronously to a generic FSM.</fsummary>
<type>
- <v>FsmRef = Name | {Name,Node} | {global,GlobalName} | pid()</v>
+ <v>FsmRef = Name | {Name,Node} | {global,GlobalName}
+ | {via,Module,ViaName} | pid()</v>
<v>&nbsp;Name = Node = atom()</v>
- <v>&nbsp;GlobalName = term()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Event = term()</v>
<v>Timeout = int()>0 | infinity</v>
<v>Reply = term()</v>
@@ -388,9 +404,10 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
<v>&nbsp;&nbsp;&nbsp;&nbsp;| {log_to_file,FileName} | {install,{Func,FuncState}}</v>
<v>StateName = atom()</v>
<v>StateData = term()</v>
- <v>FsmName = {local,Name} | {global,GlobalName}</v>
+ <v>FsmName = {local,Name} | {global,GlobalName}
+ | {via,Module,ViaName}</v>
<v>&nbsp;Name = atom()</v>
- <v>&nbsp;GlobalName = term()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Timeout = int() | infinity</v>
</type>
<desc>
diff --git a/lib/stdlib/doc/src/gen_server.xml b/lib/stdlib/doc/src/gen_server.xml
index 1045766e01..90b77d5cb6 100644
--- a/lib/stdlib/doc/src/gen_server.xml
+++ b/lib/stdlib/doc/src/gen_server.xml
@@ -83,9 +83,10 @@ gen_server:abcast -----> Module:handle_cast/2
<name>start_link(ServerName, Module, Args, Options) -> Result</name>
<fsummary>Create a gen_server process in a supervision tree.</fsummary>
<type>
- <v>ServerName = {local,Name} | {global,GlobalName}</v>
+ <v>ServerName = {local,Name} | {global,GlobalName}
+ | {via,Module,ViaName}</v>
<v>&nbsp;Name = atom()</v>
- <v>&nbsp;GlobalName = term()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Module = atom()</v>
<v>Args = term()</v>
<v>Options = [Option]</v>
@@ -111,14 +112,22 @@ gen_server:abcast -----> Module:handle_cast/2
If <c>ServerName={global,GlobalName}</c> the gen_server is
registered globally as <c>GlobalName</c> using
<c>global:register_name/2</c>. If no name is provided,
- the gen_server is not registered.</p>
+ the gen_server is not registered.
+ If <c>EventMgrName={via,Module,ViaName}</c>, the event manager will
+ register with the registry represented by <c>Module</c>.
+ The <c>Module</c> callback should export the functions
+ <c>register_name/2</c>, <c>unregister_name/1</c>,
+ <c>whereis_name/1</c> and <c>send/2</c>, which should behave like the
+ corresponding functions in <c>global</c>. Thus,
+ <c>{via,global,GlobalName}</c> is a valid reference.</p>
<p><c>Module</c> is the name of the callback module.</p>
<p><c>Args</c> is an arbitrary term which is passed as
the argument to <c>Module:init/1</c>.</p>
<p>If the option <c>{timeout,Time}</c> is present,
the gen_server is allowed to spend <c>Time</c> milliseconds
initializing or it will be terminated and the start function
- will return <c>{error,timeout}</c>.</p>
+ will return <c>{error,timeout}</c>.
+ </p>
<p>If the option <c>{debug,Dbgs}</c> is present,
the corresponding <c>sys</c> function will be called for each
item in <c>Dbgs</c>. See
@@ -151,9 +160,10 @@ gen_server:abcast -----> Module:handle_cast/2
<name>start(ServerName, Module, Args, Options) -> Result</name>
<fsummary>Create a stand-alone gen_server process.</fsummary>
<type>
- <v>ServerName = {local,Name} | {global,GlobalName}</v>
+ <v>ServerName = {local,Name} | {global,GlobalName}
+ | {via,Module,ViaName}</v>
<v>&nbsp;Name = atom()</v>
- <v>&nbsp;GlobalName = term()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Module = atom()</v>
<v>Args = term()</v>
<v>Options = [Option]</v>
@@ -178,9 +188,10 @@ gen_server:abcast -----> Module:handle_cast/2
<name>call(ServerRef, Request, Timeout) -> Reply</name>
<fsummary>Make a synchronous call to a generic server.</fsummary>
<type>
- <v>ServerRef = Name | {Name,Node} | {global,GlobalName} | pid()</v>
+ <v>ServerRef = Name | {Name,Node} | {global,GlobalName}
+ | {via,Module,ViaName} | pid()</v>
<v>&nbsp;Node = atom()</v>
- <v>&nbsp;GlobalName = term()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Request = term()</v>
<v>Timeout = int()>0 | infinity</v>
<v>Reply = term()</v>
@@ -198,6 +209,8 @@ gen_server:abcast -----> Module:handle_cast/2
registered at another node, or</item>
<item><c>{global,GlobalName}</c>, if the gen_server is
globally registered.</item>
+ <item><c>{via,Module,ViaName}</c>, if the gen_server is
+ registered through an alternative process registry.</item>
</list>
<p><c>Request</c> is an arbitrary term which is passed as one of
the arguments to <c>Module:handle_call/3</c>.</p>
@@ -281,9 +294,10 @@ gen_server:abcast -----> Module:handle_cast/2
<name>cast(ServerRef, Request) -> ok</name>
<fsummary>Send an asynchronous request to a generic server.</fsummary>
<type>
- <v>ServerRef = Name | {Name,Node} | {global,GlobalName} | pid()</v>
+ <v>ServerRef = Name | {Name,Node} | {global,GlobalName}
+ | {via,Module,ViaName} | pid()</v>
<v>&nbsp;Node = atom()</v>
- <v>&nbsp;GlobalName = term()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Request = term()</v>
</type>
<desc>
@@ -355,9 +369,10 @@ gen_server:abcast -----> Module:handle_cast/2
<v>&nbsp;&nbsp;&nbsp;Dbg = trace | log | statistics</v>
<v>&nbsp;&nbsp;&nbsp;&nbsp;| {log_to_file,FileName} | {install,{Func,FuncState}}</v>
<v>State = term()</v>
- <v>ServerName = {local,Name} | {global,GlobalName}</v>
+ <v>ServerName = {local,Name} | {global,GlobalName}
+ | {via,Module,ViaName}</v>
<v>&nbsp;Name = atom()</v>
- <v>&nbsp;GlobalName = term()</v>
+ <v>&nbsp;GlobalName = ViaName = term()</v>
<v>Timeout = int() | infinity</v>
</type>
<desc>
diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml
index cddb55e5c5..73df7183e6 100644
--- a/lib/stdlib/doc/src/supervisor.xml
+++ b/lib/stdlib/doc/src/supervisor.xml
@@ -271,8 +271,14 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules}
<p>If <c><anno>SupName</anno>={local,Name}</c> the supervisor is registered
locally as <c>Name</c> using <c>register/2</c>. If
<c><anno>SupName</anno>={global,Name}</c> the supervisor is registered
- globally as <c>Name</c> using <c>global:register_name/2</c>.
- If no name is provided, the supervisor is not registered.</p>
+ globally as <c>Name</c> using <c>global:register_name/2</c>. If
+ <c><anno>SupName</anno>={via,Module,Name}</c> the supervisor
+ is registered as <c>Name</c> using the registry represented by
+ <c>Module</c>. The <c>Module</c> callback should export the functions
+ <c>register_name/2</c>, <c>unregister_name/1</c> and <c>send/2</c>,
+ which should behave like the corresponding functions in <c>global</c>.
+ Thus, <c>{via,global,Name}</c> is a valid reference.</p>
+ <p>If no name is provided, the supervisor is not registered.</p>
<p><c><anno>Module</anno></c> is the name of the callback module.</p>
<p><c><anno>Args</anno></c> is an arbitrary term which is passed as
the argument to <c><anno>Module</anno>:init/1</c>.</p>
@@ -315,6 +321,8 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules}
registered at another node, or</item>
<item><c>{global,Name}</c>, if the supervisor is globally
registered.</item>
+ <item><c>{via,Module,Name}</c>, if the supervisor is registered
+ through an alternative process registry.</item>
</list>
<p><c><anno>ChildSpec</anno></c> should be a valid child specification
(unless the supervisor is a <c>simple_one_for_one</c>
diff --git a/lib/stdlib/doc/src/supervisor_bridge.xml b/lib/stdlib/doc/src/supervisor_bridge.xml
index c1a5e7947f..f6712d6c1d 100644
--- a/lib/stdlib/doc/src/supervisor_bridge.xml
+++ b/lib/stdlib/doc/src/supervisor_bridge.xml
@@ -63,6 +63,13 @@
If <c><anno>SupBridgeName</anno>={global,<anno>Name</anno>}</c> the supervisor_bridge is
registered globally as <c><anno>Name</anno></c> using
<c>global:register_name/2</c>.
+ If <c><anno>SupBridgeName</anno>={via,<anno>Module</anno>,<anno>Name</anno>}</c> the supervisor_bridge is
+ registered as <c><anno>Name</anno></c> using a registry represented
+ by <anno>Module</anno>. The <c>Module</c> callback should export
+ the functions <c>register_name/2</c>, <c>unregister_name/1</c>
+ and <c>send/2</c>, which should behave like the
+ corresponding functions in <c>global</c>. Thus,
+ <c>{via,global,GlobalName}</c> is a valid reference.
If no name is provided, the supervisor_bridge is not registered.
If there already exists a process with the specified
<c><anno>SupBridgeName</anno></c> the function returns
diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl
index 5d803091b6..42555aedd7 100644
--- a/lib/stdlib/src/gen.erl
+++ b/lib/stdlib/src/gen.erl
@@ -36,7 +36,7 @@
%%-----------------------------------------------------------------
-type linkage() :: 'link' | 'nolink'.
--type emgr_name() :: {'local', atom()} | {'global', term()}.
+-type emgr_name() :: {'local', atom()} | {'global', term()} | {via, atom(), term()}.
-type start_ret() :: {'ok', pid()} | 'ignore' | {'error', term()}.
@@ -53,7 +53,7 @@
%% start(GenMod, LinkP, Name, Mod, Args, Options)
%% GenMod = atom(), callback module implementing the 'real' fsm
%% LinkP = link | nolink
-%% Name = {local, atom()} | {global, term()}
+%% Name = {local, atom()} | {global, term()} | {via, atom(), term()}
%% Args = term(), init arguments (to Mod:init/1)
%% Options = [{timeout, Timeout} | {debug, [Flag]} | {spawn_opt, OptionList}]
%% Flag = trace | log | {logfile, File} | statistics | debug
@@ -158,9 +158,12 @@ call(Name, Label, Request, Timeout)
exit(noproc)
end;
%% Global by name
-call({global, _Name}=Process, Label, Request, Timeout)
- when Timeout =:= infinity;
- is_integer(Timeout), Timeout >= 0 ->
+call(Process, Label, Request, Timeout)
+ when ((tuple_size(Process) == 2 andalso element(1, Process) == global)
+ orelse
+ (tuple_size(Process) == 3 andalso element(1, Process) == via))
+ andalso
+ (Timeout =:= infinity orelse (is_integer(Timeout) andalso Timeout >= 0)) ->
case where(Process) of
Pid when is_pid(Pid) ->
Node = node(Pid),
@@ -274,6 +277,7 @@ reply({To, Tag}, Reply) ->
%%% Misc. functions.
%%%-----------------------------------------------------------------
where({global, Name}) -> global:whereis_name(Name);
+where({via, Module, Name}) -> Module:whereis_name(Name);
where({local, Name}) -> whereis(Name).
name_register({local, Name} = LN) ->
@@ -287,8 +291,16 @@ name_register({global, Name} = GN) ->
case global:register_name(Name, self()) of
yes -> true;
no -> {false, where(GN)}
+ end;
+name_register({via, Module, Name} = GN) ->
+ case Module:register_name(Name, self()) of
+ yes ->
+ true;
+ no ->
+ {false, where(GN)}
end.
+
timeout(Options) ->
case opt(timeout, Options) of
{ok, Time} ->
diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl
index 9879b76391..343eb7d4e4 100644
--- a/lib/stdlib/src/gen_event.erl
+++ b/lib/stdlib/src/gen_event.erl
@@ -106,8 +106,10 @@
-type add_handler_ret() :: ok | term() | {'EXIT',term()}.
-type del_handler_ret() :: ok | term() | {'EXIT',term()}.
--type emgr_name() :: {'local', atom()} | {'global', atom()}.
--type emgr_ref() :: atom() | {atom(), atom()} | {'global', atom()} | pid().
+-type emgr_name() :: {'local', atom()} | {'global', atom()}
+ | {'via', atom(), term()}.
+-type emgr_ref() :: atom() | {atom(), atom()} | {'global', atom()}
+ | {'via', atom(), term()} | pid().
-type start_ret() :: {'ok', pid()} | {'error', term()}.
%%---------------------------------------------------------------------------
@@ -142,6 +144,7 @@ init_it(Starter, Parent, Name0, _, _, Options) ->
name({local,Name}) -> Name;
name({global,Name}) -> Name;
+name({via,_, Name}) -> Name;
name(Pid) when is_pid(Pid) -> Pid.
-spec add_handler(emgr_ref(), handler(), term()) -> term().
@@ -208,6 +211,9 @@ call1(M, Handler, Query, Timeout) ->
send({global, Name}, Cmd) ->
catch global:send(Name, Cmd),
ok;
+send({via, Mod, Name}, Cmd) ->
+ catch Mod:send(Name, Cmd),
+ ok;
send(M, Cmd) ->
M ! Cmd,
ok.
diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl
index 57734a075c..8d43846c92 100644
--- a/lib/stdlib/src/gen_fsm.erl
+++ b/lib/stdlib/src/gen_fsm.erl
@@ -165,7 +165,7 @@
%%% start(Name, Mod, Args, Options)
%%% start_link(Mod, Args, Options)
%%% start_link(Name, Mod, Args, Options) where:
-%%% Name ::= {local, atom()} | {global, atom()}
+%%% Name ::= {local, atom()} | {global, atom()} | {via, atom(), term()}
%%% Mod ::= atom(), callback module implementing the 'real' fsm
%%% Args ::= term(), init arguments (to Mod:init/1)
%%% Options ::= [{debug, [Flag]}]
@@ -191,6 +191,9 @@ start_link(Name, Mod, Args, Options) ->
send_event({global, Name}, Event) ->
catch global:send(Name, {'$gen_event', Event}),
ok;
+send_event({via, Mod, Name}, Event) ->
+ catch Mod:send(Name, {'$gen_event', Event}),
+ ok;
send_event(Name, Event) ->
Name ! {'$gen_event', Event},
ok.
@@ -214,6 +217,9 @@ sync_send_event(Name, Event, Timeout) ->
send_all_state_event({global, Name}, Event) ->
catch global:send(Name, {'$gen_all_state_event', Event}),
ok;
+send_all_state_event({via, Mod, Name}, Event) ->
+ catch Mod:send(Name, {'$gen_all_state_event', Event}),
+ ok;
send_all_state_event(Name, Event) ->
Name ! {'$gen_all_state_event', Event},
ok.
@@ -273,7 +279,10 @@ cancel_timer(Ref) ->
enter_loop(Mod, Options, StateName, StateData) ->
enter_loop(Mod, Options, StateName, StateData, self(), infinity).
-enter_loop(Mod, Options, StateName, StateData, ServerName = {_,_}) ->
+enter_loop(Mod, Options, StateName, StateData, {Scope,_} = ServerName)
+ when Scope == local; Scope == global ->
+ enter_loop(Mod, Options, StateName, StateData, ServerName,infinity);
+enter_loop(Mod, Options, StateName, StateData, {via,_,_} = ServerName) ->
enter_loop(Mod, Options, StateName, StateData, ServerName,infinity);
enter_loop(Mod, Options, StateName, StateData, Timeout) ->
enter_loop(Mod, Options, StateName, StateData, self(), Timeout).
@@ -303,6 +312,15 @@ get_proc_name({global, Name}) ->
Name;
_Pid ->
exit(process_not_registered_globally)
+ end;
+get_proc_name({via, Mod, Name}) ->
+ case Mod:whereis_name(Name) of
+ undefined ->
+ exit({process_not_registered_via, Mod});
+ Pid when Pid =:= self() ->
+ Name;
+ _Pid ->
+ exit({process_not_registered_via, Mod})
end.
get_parent() ->
@@ -367,12 +385,15 @@ init_it(Starter, Parent, Name0, Mod, Args, Options) ->
name({local,Name}) -> Name;
name({global,Name}) -> Name;
+name({via,_, Name}) -> Name;
name(Pid) when is_pid(Pid) -> Pid.
unregister_name({local,Name}) ->
_ = (catch unregister(Name));
unregister_name({global,Name}) ->
_ = global:unregister_name(Name);
+unregister_name({via, Mod, Name}) ->
+ _ = Mod:unregister_name(Name);
unregister_name(Pid) when is_pid(Pid) ->
Pid.
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index 6f075bbe5a..244795df9f 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -142,7 +142,7 @@
%%% start(Name, Mod, Args, Options)
%%% start_link(Mod, Args, Options)
%%% start_link(Name, Mod, Args, Options) where:
-%%% Name ::= {local, atom()} | {global, atom()}
+%%% Name ::= {local, atom()} | {global, atom()} | {via, atom(), term()}
%%% Mod ::= atom(), callback module implementing the 'real' server
%%% Args ::= term(), init arguments (to Mod:init/1)
%%% Options ::= [{timeout, Timeout} | {debug, [Flag]}]
@@ -194,6 +194,9 @@ call(Name, Request, Timeout) ->
cast({global,Name}, Request) ->
catch global:send(Name, cast_msg(Request)),
ok;
+cast({via, Mod, Name}, Request) ->
+ catch Mod:send(Name, cast_msg(Request)),
+ ok;
cast({Name,Node}=Dest, Request) when is_atom(Name), is_atom(Node) ->
do_cast(Dest, Request);
cast(Dest, Request) when is_atom(Dest) ->
@@ -266,7 +269,11 @@ multi_call(Nodes, Name, Req, Timeout)
enter_loop(Mod, Options, State) ->
enter_loop(Mod, Options, State, self(), infinity).
-enter_loop(Mod, Options, State, ServerName = {_, _}) ->
+enter_loop(Mod, Options, State, ServerName = {Scope, _})
+ when Scope == local; Scope == local ->
+ enter_loop(Mod, Options, State, ServerName, infinity);
+
+enter_loop(Mod, Options, State, ServerName = {via, _, _}) ->
enter_loop(Mod, Options, State, ServerName, infinity);
enter_loop(Mod, Options, State, Timeout) ->
@@ -327,12 +334,15 @@ init_it(Starter, Parent, Name0, Mod, Args, Options) ->
name({local,Name}) -> Name;
name({global,Name}) -> Name;
+name({via,_, Name}) -> Name;
name(Pid) when is_pid(Pid) -> Pid.
unregister_name({local,Name}) ->
_ = (catch unregister(Name));
unregister_name({global,Name}) ->
_ = global:unregister_name(Name);
+unregister_name({via, Mod, Name}) ->
+ _ = Mod:unregister_name(Name);
unregister_name(Pid) when is_pid(Pid) ->
Pid.
@@ -827,6 +837,15 @@ get_proc_name({global, Name}) ->
Name;
_Pid ->
exit(process_not_registered_globally)
+ end;
+get_proc_name({via, Mod, Name}) ->
+ case Mod:whereis_name(Name) of
+ undefined ->
+ exit({process_not_registered_via, Mod});
+ Pid when Pid =:= self() ->
+ Name;
+ _Pid ->
+ exit({process_not_registered_via, Mod})
end.
get_parent() ->
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
index aa6a660c34..b36265302c 100644
--- a/lib/stdlib/test/Makefile
+++ b/lib/stdlib/test/Makefile
@@ -20,6 +20,7 @@ MODULES= \
digraph_utils_SUITE \
dummy1_h \
dummy_h \
+ dummy_via \
edlin_expand_SUITE \
epp_SUITE \
erl_eval_helper \
diff --git a/lib/stdlib/test/dummy_via.erl b/lib/stdlib/test/dummy_via.erl
new file mode 100644
index 0000000000..e405811cbe
--- /dev/null
+++ b/lib/stdlib/test/dummy_via.erl
@@ -0,0 +1,94 @@
+-module(dummy_via).
+-export([reset/0,
+ register_name/2,
+ whereis_name/1,
+ unregister_name/1,
+ send/2]).
+
+
+reset() ->
+ P = whereis(?MODULE),
+ catch unlink(P),
+ Ref = erlang:monitor(process, P),
+ catch exit(P, kill),
+ receive {'DOWN',Ref,_,_,_} -> ok end,
+ Me = self(),
+ Pid = spawn_link(fun() ->
+ register(?MODULE, self()),
+ Me ! {self(), started},
+ loop([])
+ end),
+ receive
+ {Pid, started} ->
+ Pid
+ after 10000 ->
+ exit(timeout)
+ end.
+
+register_name(Name, Pid) when is_pid(Pid) ->
+ call({register_name, Name, Pid}).
+
+unregister_name(Name) ->
+ call({unregister_name, Name}).
+
+whereis_name(Name) ->
+ call({whereis_name, Name}).
+
+send(Name, Msg) ->
+ case whereis_name(Name) of
+ undefined ->
+ exit({badarg, {Name, Msg}});
+ Pid when is_pid(Pid) ->
+ Pid ! Msg,
+ Pid
+ end.
+
+call(Req) ->
+ MRef = erlang:monitor(process, ?MODULE),
+ ?MODULE ! {self(), MRef, Req},
+ receive
+ {'DOWN', MRef, _, _, _} ->
+ erlang:error(badarg);
+ {MRef, badarg} ->
+ erlang:error(badarg);
+ {MRef, Reply} ->
+ Reply
+ after 5000 ->
+ erlang:error(timeout)
+ end.
+
+loop(Reg) ->
+ receive
+ {'DOWN', _, _, P, _} when is_pid(P) ->
+ loop([X || {_,Pid,_} = X <- Reg, Pid =/= P]);
+ {From, Ref, Request} when is_pid(From), is_reference(Ref) ->
+ {Reply, NewReg} = handle_request(Request, Reg),
+ From ! {Ref, Reply},
+ loop(NewReg)
+ end.
+
+handle_request({register_name, Name, Pid}, Reg) when is_pid(Pid) ->
+ case lists:keyfind(Name, 1, Reg) of
+ false ->
+ Ref = erlang:monitor(process, Pid),
+ {yes, [{Name, Pid, Ref}|Reg]};
+ _ ->
+ {no, Reg}
+ end;
+handle_request({whereis_name, Name}, Reg) ->
+ case lists:keyfind(Name, 1, Reg) of
+ {_, Pid, _} ->
+ {Pid, Reg};
+ false ->
+ {undefined, Reg}
+ end;
+handle_request({unregister_name, Name}, Reg) ->
+ case lists:keyfind(Name, 1, Reg) of
+ {_, _, Ref} ->
+ catch erlang:demonitor(Ref);
+ _ ->
+ ok
+ end,
+ {ok, lists:keydelete(Name, 1, Reg)};
+handle_request(_, Reg) ->
+ {badarg, Reg}.
diff --git a/lib/stdlib/test/gen_event_SUITE.erl b/lib/stdlib/test/gen_event_SUITE.erl
index b3a7edc140..5c51e12e35 100644
--- a/lib/stdlib/test/gen_event_SUITE.erl
+++ b/lib/stdlib/test/gen_event_SUITE.erl
@@ -62,6 +62,8 @@ start(suite) -> [];
start(Config) when is_list(Config) ->
OldFl = process_flag(trap_exit, true),
+ ?line dummy_via:reset(),
+
?line {ok, Pid0} = gen_event:start(), %anonymous
?line [] = gen_event:which_handlers(Pid0),
?line ok = gen_event:stop(Pid0),
@@ -85,6 +87,11 @@ start(Config) when is_list(Config) ->
?line [] = gen_event:which_handlers(Pid4),
?line ok = gen_event:stop({global, my_dummy_name}),
+ ?line {ok, Pid5} = gen_event:start_link({via, dummy_via, my_dummy_name}),
+ ?line [] = gen_event:which_handlers({via, dummy_via, my_dummy_name}),
+ ?line [] = gen_event:which_handlers(Pid5),
+ ?line ok = gen_event:stop({via, dummy_via, my_dummy_name}),
+
?line {ok, _} = gen_event:start_link({local, my_dummy_name}),
?line {error, {already_started, _}} =
gen_event:start_link({local, my_dummy_name}),
@@ -92,15 +99,28 @@ start(Config) when is_list(Config) ->
gen_event:start({local, my_dummy_name}),
?line ok = gen_event:stop(my_dummy_name),
- ?line {ok, Pid5} = gen_event:start_link({global, my_dummy_name}),
+ ?line {ok, Pid6} = gen_event:start_link({global, my_dummy_name}),
?line {error, {already_started, _}} =
gen_event:start_link({global, my_dummy_name}),
?line {error, {already_started, _}} =
gen_event:start({global, my_dummy_name}),
- exit(Pid5, shutdown),
+ exit(Pid6, shutdown),
+ receive
+ {'EXIT', Pid6, shutdown} -> ok
+ after 10000 ->
+ ?t:fail(exit_gen_event)
+ end,
+
+ ?line {ok, Pid7} = gen_event:start_link({via, dummy_via, my_dummy_name}),
+ ?line {error, {already_started, _}} =
+ gen_event:start_link({via, dummy_via, my_dummy_name}),
+ ?line {error, {already_started, _}} =
+ gen_event:start({via, dummy_via, my_dummy_name}),
+
+ exit(Pid7, shutdown),
receive
- {'EXIT', Pid5, shutdown} -> ok
+ {'EXIT', Pid7, shutdown} -> ok
after 10000 ->
?t:fail(exit_gen_event)
end,
diff --git a/lib/stdlib/test/gen_fsm_SUITE.erl b/lib/stdlib/test/gen_fsm_SUITE.erl
index d60629d841..bdb4ea65b5 100644
--- a/lib/stdlib/test/gen_fsm_SUITE.erl
+++ b/lib/stdlib/test/gen_fsm_SUITE.erl
@@ -21,11 +21,11 @@
-include_lib("test_server/include/test_server.hrl").
%% Test cases
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
+-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
--export([ start1/1, start2/1, start3/1, start4/1 , start5/1, start6/1,
- start7/1, start8/1, start9/1, start10/1, start11/1]).
+-export([start1/1, start2/1, start3/1, start4/1, start5/1, start6/1,
+ start7/1, start8/1, start9/1, start10/1, start11/1, start12/1]).
-export([ abnormal1/1, abnormal2/1]).
@@ -56,14 +56,14 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
-all() ->
+all() ->
[{group, start}, {group, abnormal}, shutdown,
{group, sys}, hibernate, enter_loop].
-groups() ->
+groups() ->
[{start, [],
[start1, start2, start3, start4, start5, start6, start7,
- start8, start9, start10, start11]},
+ start8, start9, start10, start11, start12]},
{abnormal, [], [abnormal1, abnormal2]},
{sys, [],
[sys1, call_format_status, error_format_status]}].
@@ -258,6 +258,25 @@ start11(Config) when is_list(Config) ->
test_server:messages_get(),
ok.
+%% Via register linked
+start12(Config) when is_list(Config) ->
+ ?line dummy_via:reset(),
+ ?line {ok, Pid} =
+ gen_fsm:start_link({via, dummy_via, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line {error, {already_started, Pid}} =
+ gen_fsm:start_link({via, dummy_via, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line {error, {already_started, Pid}} =
+ gen_fsm:start({via, dummy_via, my_fsm}, gen_fsm_SUITE, [], []),
+
+ ?line ok = do_func_test(Pid),
+ ?line ok = do_sync_func_test(Pid),
+ ?line ok = do_func_test({via, dummy_via, my_fsm}),
+ ?line ok = do_sync_func_test({via, dummy_via, my_fsm}),
+ ?line stop_it({via, dummy_via, my_fsm}),
+
+ test_server:messages_get(),
+ ok.
+
%% Check that time outs in calls work
abnormal1(suite) -> [];
@@ -362,7 +381,25 @@ call_format_status(Config) when is_list(Config) ->
?line Status4 = sys:get_status(GlobalName2),
?line {status, Pid4, _Mod, [_PDict4, running, _, _, Data4]} = Status4,
?line [format_status_called | _] = lists:reverse(Data4),
- ?line stop_it(Pid4).
+ ?line stop_it(Pid4),
+
+ %% check that format_status can handle a name being a term other than a
+ %% pid or atom
+ ?line dummy_via:reset(),
+ ViaName1 = {via, dummy_via, "CallFormatStatus"},
+ ?line {ok, Pid5} = gen_fsm:start(ViaName1, gen_fsm_SUITE, [], []),
+ ?line Status5 = sys:get_status(ViaName1),
+ ?line {status, Pid5, _Mod, [_PDict5, running, _, _, Data5]} = Status5,
+ ?line [format_status_called | _] = lists:reverse(Data5),
+ ?line stop_it(Pid5),
+ ViaName2 = {via, dummy_via, {name, "term"}},
+ ?line {ok, Pid6} = gen_fsm:start(ViaName2, gen_fsm_SUITE, [], []),
+ ?line Status6 = sys:get_status(ViaName2),
+ ?line {status, Pid6, _Mod, [_PDict6, running, _, _, Data6]} = Status6,
+ ?line [format_status_called | _] = lists:reverse(Data6),
+ ?line stop_it(Pid6).
+
+
error_format_status(Config) when is_list(Config) ->
?line error_logger_forwarder:register(),
@@ -520,6 +557,8 @@ enter_loop(doc) ->
enter_loop(Config) when is_list(Config) ->
OldFlag = process_flag(trap_exit, true),
+ ?line dummy_via:reset(),
+
%% Locally registered process + {local, Name}
?line {ok, Pid1a} =
proc_lib:start_link(?MODULE, enter_loop, [local, local]),
@@ -623,10 +662,22 @@ enter_loop(Config) when is_list(Config) ->
{'EXIT', Pid6b, process_not_registered_globally} ->
ok
after 1000 ->
- ?line test_server:fail(gen_server_started)
+ ?line test_server:fail(gen_fsm_started)
end,
global:unregister_name(armitage),
+ dummy_via:register_name(armitage, self()),
+ ?line {ok, Pid6c} =
+ proc_lib:start_link(?MODULE, enter_loop, [anon, via]),
+ receive
+ {'EXIT', Pid6c, {process_not_registered_via, dummy_via}} ->
+ ok
+ after 1000 ->
+ ?line test_server:fail({gen_fsm_started, process_info(self(),
+ messages)})
+ end,
+ dummy_via:unregister_name(armitage),
+
process_flag(trap_exit, OldFlag),
ok.
@@ -635,6 +686,7 @@ enter_loop(Reg1, Reg2) ->
case Reg1 of
local -> register(armitage, self());
global -> global:register_name(armitage, self());
+ via -> dummy_via:register_name(armitage, self());
anon -> ignore
end,
proc_lib:init_ack({ok, self()}),
@@ -643,6 +695,9 @@ enter_loop(Reg1, Reg2) ->
gen_fsm:enter_loop(?MODULE, [], state0, [], {local,armitage});
global ->
gen_fsm:enter_loop(?MODULE, [], state0, [], {global,armitage});
+ via ->
+ gen_fsm:enter_loop(?MODULE, [], state0, [],
+ {via, dummy_via, armitage});
anon ->
gen_fsm:enter_loop(?MODULE, [], state0, [])
end.
diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl
index 7fb8d54f2d..cdf15ba017 100644
--- a/lib/stdlib/test/gen_server_SUITE.erl
+++ b/lib/stdlib/test/gen_server_SUITE.erl
@@ -36,7 +36,7 @@
]).
% spawn export
--export([spec_init_local/2, spec_init_global/2,
+-export([spec_init_local/2, spec_init_global/2, spec_init_via/2,
spec_init_default_timeout/2, spec_init_anonymous/1,
spec_init_anonymous_default_timeout/1,
spec_init_not_proc_lib/1, cast_fast_messup/0]).
@@ -199,6 +199,35 @@ start(Config) when is_list(Config) ->
test_server:fail(not_stopped)
end,
+ %% via register
+ ?line dummy_via:reset(),
+ ?line {ok, Pid6} =
+ gen_server:start({via, dummy_via, my_test_name},
+ gen_server_SUITE, [], []),
+ ?line ok = gen_server:call({via, dummy_via, my_test_name}, started_p),
+ ?line {error, {already_started, Pid6}} =
+ gen_server:start({via, dummy_via, my_test_name},
+ gen_server_SUITE, [], []),
+ ?line ok = gen_server:call({via, dummy_via, my_test_name}, stop),
+ test_server:sleep(1),
+ ?line {'EXIT', {noproc,_}} = (catch gen_server:call(Pid6, started_p, 10)),
+
+ %% via register linked
+ ?line dummy_via:reset(),
+ ?line {ok, Pid7} =
+ gen_server:start_link({via, dummy_via, my_test_name},
+ gen_server_SUITE, [], []),
+ ?line ok = gen_server:call({via, dummy_via, my_test_name}, started_p),
+ ?line {error, {already_started, Pid7}} =
+ gen_server:start({via, dummy_via, my_test_name},
+ gen_server_SUITE, [], []),
+ ?line ok = gen_server:call({via, dummy_via, my_test_name}, stop),
+ ?line receive
+ {'EXIT', Pid7, stopped} ->
+ ok
+ after 5000 ->
+ test_server:fail(not_stopped)
+ end,
test_server:messages_get(),
%% Must wait for all error messages before going to next test.
@@ -853,6 +882,8 @@ otp_5854(doc) ->
otp_5854(Config) when is_list(Config) ->
OldFlag = process_flag(trap_exit, true),
+ ?line dummy_via:reset(),
+
%% Make sure gen_server:enter_loop does not accept {local,Name}
%% when it's another process than the calling one which is
%% registered under that name
@@ -881,6 +912,18 @@ otp_5854(Config) when is_list(Config) ->
end,
global:unregister_name(armitage),
+ %% (same for {via, Mod, Name})
+ dummy_via:register_name(armitage, self()),
+ ?line {ok, Pid3} =
+ start_link(spec_init_via, [{not_ok, armitage}, []]),
+ receive
+ {'EXIT', Pid3, {process_not_registered_via, dummy_via}} ->
+ ok
+ after 1000 ->
+ ?line test_server:fail(gen_server_started)
+ end,
+ dummy_via:unregister_name(armitage),
+
process_flag(trap_exit, OldFlag),
ok.
@@ -1060,7 +1103,22 @@ spec_init_global({not_ok, Name}, Options) ->
%% Supervised init can occur here ...
gen_server:enter_loop(?MODULE, Options, {}, {global, Name}, infinity).
-spec_init_default_timeout({ok, Name}, Options) ->
+spec_init_via({ok, Name}, Options) ->
+ process_flag(trap_exit, true),
+ dummy_via:register_name(Name, self()),
+ proc_lib:init_ack({ok, self()}),
+ %% Supervised init can occur here ...
+ gen_server:enter_loop(?MODULE, Options, {},
+ {via, dummy_via, Name}, infinity);
+
+spec_init_via({not_ok, Name}, Options) ->
+ process_flag(trap_exit, true),
+ proc_lib:init_ack({ok, self()}),
+ %% Supervised init can occur here ...
+ gen_server:enter_loop(?MODULE, Options, {},
+ {via, dummy_via, Name}, infinity).
+
+spec_init_default_timeout({ok, Name}, Options) ->
process_flag(trap_exit, true),
register(Name, self()),
proc_lib:init_ack({ok, self()}),