aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/stdlib/doc/src/gen_event.xml22
-rw-r--r--lib/stdlib/src/gen_event.erl80
-rw-r--r--lib/stdlib/test/gen_event_SUITE.erl126
3 files changed, 175 insertions, 53 deletions
diff --git a/lib/stdlib/doc/src/gen_event.xml b/lib/stdlib/doc/src/gen_event.xml
index c24542002a..42e952fd46 100644
--- a/lib/stdlib/doc/src/gen_event.xml
+++ b/lib/stdlib/doc/src/gen_event.xml
@@ -350,13 +350,18 @@ gen_event:stop -----> Module:terminate/2
<func>
<name>start() -> Result</name>
- <name>start(EventMgrName) -> Result</name>
+ <name>start(EventMgrName | Options) -> Result</name>
+ <name>start(EventMgrName, Options) -> Result</name>
<fsummary>Create a stand-alone event manager process.</fsummary>
<type>
- <v>EventMgrName = {local,Name} | {global,GlobalName}
- | {via,Module,ViaName}</v>
+ <v>EventMgrName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}</v>
<v>&nbsp;Name = atom()</v>
<v>&nbsp;GlobalName = ViaName = term()</v>
+ <v>Options = [Option]</v>
+ <v>&nbsp;Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}</v>
+ <v>&nbsp;&nbsp;Dbgs = [Dbg]</v>
+ <v>&nbsp;&nbsp;&nbsp;Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}</v>
+ <v>&nbsp;&nbsp;SOpts = [term()]</v>
<v>Result = {ok,Pid} | {error,{already_started,Pid}}</v>
<v>&nbsp;Pid = pid()</v>
</type>
@@ -371,14 +376,19 @@ gen_event:stop -----> Module:terminate/2
<func>
<name>start_link() -> Result</name>
- <name>start_link(EventMgrName) -> Result</name>
+ <name>start_link(EventMgrName | Options) -> Result</name>
+ <name>start_link(EventMgrName, Options) -> Result</name>
<fsummary>Create a generic event manager process in a supervision tree.
</fsummary>
<type>
- <v>EventMgrName = {local,Name} | {global,GlobalName}
- | {via,Module,ViaName}</v>
+ <v>EventMgrName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}</v>
<v>&nbsp;Name = atom()</v>
<v>&nbsp;GlobalName = ViaName = term()</v>
+ <v>Options = [Option]</v>
+ <v>&nbsp;Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}</v>
+ <v>&nbsp;&nbsp;Dbgs = [Dbg]</v>
+ <v>&nbsp;&nbsp;&nbsp;Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}</v>
+ <v>&nbsp;&nbsp;SOpts = [term()]</v>
<v>Result = {ok,Pid} | {error,{already_started,Pid}}</v>
<v>&nbsp;Pid = pid()</v>
</type>
diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl
index ccacf658e9..4839fe4f2c 100644
--- a/lib/stdlib/src/gen_event.erl
+++ b/lib/stdlib/src/gen_event.erl
@@ -32,7 +32,9 @@
%%% Modified by Martin - uses proc_lib, sys and gen!
--export([start/0, start/1, start_link/0, start_link/1, stop/1, stop/3,
+-export([start/0, start/1, start/2,
+ start_link/0, start_link/1, start_link/2,
+ stop/1, stop/3,
notify/2, sync_notify/2,
add_handler/3, add_sup_handler/3, delete_handler/3, swap_handler/3,
swap_sup_handler/3, which_handlers/1, call/3, call/4, wake_hib/4]).
@@ -117,30 +119,64 @@
-type del_handler_ret() :: ok | term() | {'EXIT',term()}.
-type emgr_name() :: {'local', atom()} | {'global', atom()}
- | {'via', atom(), term()}.
+ | {'via', atom(), term()}.
+-type debug_flag() :: 'trace' | 'log' | 'statistics' | 'debug'
+ | {'logfile', string()}.
+-type option() :: {'timeout', timeout()}
+ | {'debug', [debug_flag()]}
+ | {'spawn_opt', [proc_lib:spawn_option()]}.
-type emgr_ref() :: atom() | {atom(), atom()} | {'global', atom()}
- | {'via', atom(), term()} | pid().
+ | {'via', atom(), term()} | pid().
-type start_ret() :: {'ok', pid()} | {'error', term()}.
%%---------------------------------------------------------------------------
-define(NO_CALLBACK, 'no callback module').
+%% -----------------------------------------------------------------
+%% Starts a generic event handler.
+%% start()
+%% start(MgrName | Options)
+%% start(MgrName, Options)
+%% start_link()
+%% start_link(MgrName | Options)
+%% start_link(MgrName, Options)
+%% MgrName ::= {local, atom()} | {global, atom()} | {via, atom(), term()}
+%% Options ::= [{timeout, Timeout} | {debug, [Flag]} | {spawn_opt,SOpts}]
+%% Flag ::= trace | log | {logfile, File} | statistics | debug
+%% (debug == log && statistics)
+%% Returns: {ok, Pid} |
+%% {error, {already_started, Pid}} |
+%% {error, Reason}
+%% -----------------------------------------------------------------
+
-spec start() -> start_ret().
start() ->
gen:start(?MODULE, nolink, ?NO_CALLBACK, [], []).
--spec start(emgr_name()) -> start_ret().
-start(Name) ->
- gen:start(?MODULE, nolink, Name, ?NO_CALLBACK, [], []).
+-spec start(emgr_name() | [option()]) -> start_ret().
+start(Name) when is_tuple(Name) ->
+ gen:start(?MODULE, nolink, Name, ?NO_CALLBACK, [], []);
+start(Options) when is_list(Options) ->
+ gen:start(?MODULE, nolink, ?NO_CALLBACK, [], Options).
+
+-spec start(emgr_name(), [option()]) -> start_ret().
+start(Name, Options) ->
+ gen:start(?MODULE, nolink, Name, ?NO_CALLBACK, [], Options).
-spec start_link() -> start_ret().
start_link() ->
gen:start(?MODULE, link, ?NO_CALLBACK, [], []).
--spec start_link(emgr_name()) -> start_ret().
-start_link(Name) ->
- gen:start(?MODULE, link, Name, ?NO_CALLBACK, [], []).
+-spec start_link(emgr_name() | [option()]) -> start_ret().
+start_link(Name) when is_tuple(Name) ->
+ gen:start(?MODULE, link, Name, ?NO_CALLBACK, [], []);
+start_link(Options) when is_list(Options) ->
+ gen:start(?MODULE, link, ?NO_CALLBACK, [], Options).
+
+-spec start_link(emgr_name(), [option()]) -> start_ret().
+start_link(Name, Options) ->
+ gen:start(?MODULE, link, Name, ?NO_CALLBACK, [], Options).
%% -spec init_it(pid(), 'self' | pid(), emgr_name(), module(), [term()], [_]) ->
init_it(Starter, self, Name, Mod, Args, Options) ->
@@ -160,7 +196,7 @@ add_sup_handler(M, Handler, Args) ->
rpc(M, {add_sup_handler, Handler, Args, self()}).
-spec notify(emgr_ref(), term()) -> 'ok'.
-notify(M, Event) -> send(M, {notify, Event}).
+notify(M, Event) -> send(M, {notify, Event}).
-spec sync_notify(emgr_ref(), term()) -> 'ok'.
sync_notify(M, Event) -> rpc(M, {sync_notify, Event}).
@@ -193,7 +229,7 @@ stop(M) ->
stop(M, Reason, Timeout) ->
gen:stop(M, Reason, Timeout).
-rpc(M, Cmd) ->
+rpc(M, Cmd) ->
{ok, Reply} = gen:call(M, self(), Cmd, infinity),
Reply.
@@ -421,7 +457,7 @@ server_add_handler({Mod,Id}, Args, MSL) ->
Handler = #handler{module = Mod,
id = Id},
server_add_handler(Mod, Handler, Args, MSL);
-server_add_handler(Mod, Args, MSL) ->
+server_add_handler(Mod, Args, MSL) ->
Handler = #handler{module = Mod},
server_add_handler(Mod, Handler, Args, MSL).
@@ -446,7 +482,7 @@ server_add_sup_handler({Mod,Id}, Args, MSL, Parent) ->
id = Id,
supervised = Parent},
server_add_handler(Mod, Handler, Args, MSL);
-server_add_sup_handler(Mod, Args, MSL, Parent) ->
+server_add_sup_handler(Mod, Args, MSL, Parent) ->
link(Parent),
Handler = #handler{module = Mod,
supervised = Parent},
@@ -454,7 +490,7 @@ server_add_sup_handler(Mod, Args, MSL, Parent) ->
%% server_delete_handler(HandlerId, Args, MSL) -> {Ret, MSL'}
-server_delete_handler(HandlerId, Args, MSL, SName) ->
+server_delete_handler(HandlerId, Args, MSL, SName) ->
case split(HandlerId, MSL) of
{Mod, Handler, MSL1} ->
{do_terminate(Mod, Handler, Args,
@@ -511,7 +547,7 @@ split_and_terminate(HandlerId, Args, MSL, SName, Handler2, Sup) ->
%% server_notify(Event, Func, MSL, SName) -> MSL'
-server_notify(Event, Func, [Handler|T], SName) ->
+server_notify(Event, Func, [Handler|T], SName) ->
case server_update(Handler, Func, Event, SName) of
{ok, Handler1} ->
{Hib, NewHandlers} = server_notify(Event, Func, T, SName),
@@ -531,9 +567,9 @@ server_update(Handler1, Func, Event, SName) ->
Mod1 = Handler1#handler.module,
State = Handler1#handler.state,
case catch Mod1:Func(Event, State) of
- {ok, State1} ->
+ {ok, State1} ->
{ok, Handler1#handler{state = State1}};
- {ok, State1, hibernate} ->
+ {ok, State1, hibernate} ->
{hibernate, Handler1#handler{state = State1}};
{swap_handler, Args1, State1, Handler2, Args2} ->
do_swap(Mod1, Handler1, Args1, State1, Handler2, Args2, SName);
@@ -644,14 +680,14 @@ server_call_update(Handler1, Query, SName) ->
Mod1 = Handler1#handler.module,
State = Handler1#handler.state,
case catch Mod1:handle_call(Query, State) of
- {ok, Reply, State1} ->
+ {ok, Reply, State1} ->
{{ok, Handler1#handler{state = State1}}, Reply};
- {ok, Reply, State1, hibernate} ->
- {{hibernate, Handler1#handler{state = State1}},
+ {ok, Reply, State1, hibernate} ->
+ {{hibernate, Handler1#handler{state = State1}},
Reply};
{swap_handler, Reply, Args1, State1, Handler2, Args2} ->
{do_swap(Mod1,Handler1,Args1,State1,Handler2,Args2,SName), Reply};
- {remove_handler, Reply} ->
+ {remove_handler, Reply} ->
do_terminate(Mod1, Handler1, remove_handler, State,
remove, SName, normal),
{no, Reply};
@@ -686,7 +722,7 @@ report_error(_Handler, normal, _, _, _) -> ok;
report_error(_Handler, shutdown, _, _, _) -> ok;
report_error(_Handler, {swapped,_,_}, _, _, _) -> ok;
report_error(Handler, Reason, State, LastIn, SName) ->
- Reason1 =
+ Reason1 =
case Reason of
{'EXIT',{undef,[{M,F,A,L}|MFAs]}} ->
case code:is_loaded(M) of
diff --git a/lib/stdlib/test/gen_event_SUITE.erl b/lib/stdlib/test/gen_event_SUITE.erl
index 4415c2d09d..9a7400c84e 100644
--- a/lib/stdlib/test/gen_event_SUITE.erl
+++ b/lib/stdlib/test/gen_event_SUITE.erl
@@ -21,22 +21,24 @@
-include_lib("common_test/include/ct.hrl").
--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([start/1, add_handler/1, add_sup_handler/1,
delete_handler/1, swap_handler/1, swap_sup_handler/1,
notify/1, sync_notify/1, call/1, info/1, hibernate/1,
call_format_status/1, call_format_status_anon/1,
- error_format_status/1, get_state/1, replace_state/1]).
+ error_format_status/1, get_state/1, replace_state/1,
+ start_opt/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
-all() ->
+all() ->
[start, {group, test_all}, hibernate,
call_format_status, call_format_status_anon, error_format_status,
- get_state, replace_state].
+ get_state, replace_state,
+ start_opt].
-groups() ->
+groups() ->
[{test_all, [],
[add_handler, add_sup_handler, delete_handler,
swap_handler, swap_sup_handler, notify, sync_notify,
@@ -59,6 +61,9 @@ end_per_group(_GroupName, Config) ->
%% Start an event manager.
%% --------------------------------------
+-define(LMGR, {local, my_dummy_name}).
+-define(GMGR, {global, my_dummy_name}).
+
start(Config) when is_list(Config) ->
OldFl = process_flag(trap_exit, true),
@@ -72,40 +77,36 @@ start(Config) when is_list(Config) ->
[] = gen_event:which_handlers(Pid1),
ok = gen_event:stop(Pid1),
- {ok, Pid2} = gen_event:start({local, my_dummy_name}),
+ {ok, Pid2} = gen_event:start(?LMGR),
[] = gen_event:which_handlers(my_dummy_name),
[] = gen_event:which_handlers(Pid2),
ok = gen_event:stop(my_dummy_name),
- {ok, Pid3} = gen_event:start_link({local, my_dummy_name}),
+ {ok, Pid3} = gen_event:start_link(?LMGR),
[] = gen_event:which_handlers(my_dummy_name),
[] = gen_event:which_handlers(Pid3),
ok = gen_event:stop(my_dummy_name),
- {ok, Pid4} = gen_event:start_link({global, my_dummy_name}),
- [] = gen_event:which_handlers({global, my_dummy_name}),
+ {ok, Pid4} = gen_event:start_link(?GMGR),
+ [] = gen_event:which_handlers(?GMGR),
[] = gen_event:which_handlers(Pid4),
- ok = gen_event:stop({global, my_dummy_name}),
+ ok = gen_event:stop(?GMGR),
{ok, Pid5} = gen_event:start_link({via, dummy_via, my_dummy_name}),
[] = gen_event:which_handlers({via, dummy_via, my_dummy_name}),
[] = gen_event:which_handlers(Pid5),
ok = gen_event:stop({via, dummy_via, my_dummy_name}),
- {ok, _} = gen_event:start_link({local, my_dummy_name}),
- {error, {already_started, _}} =
- gen_event:start_link({local, my_dummy_name}),
- {error, {already_started, _}} =
- gen_event:start({local, my_dummy_name}),
+ {ok, _} = gen_event:start_link(?LMGR),
+ {error, {already_started, _}} = gen_event:start_link(?LMGR),
+ {error, {already_started, _}} = gen_event:start(?LMGR),
ok = gen_event:stop(my_dummy_name),
- {ok, Pid6} = gen_event:start_link({global, my_dummy_name}),
- {error, {already_started, _}} =
- gen_event:start_link({global, my_dummy_name}),
- {error, {already_started, _}} =
- gen_event:start({global, my_dummy_name}),
+ {ok, Pid6} = gen_event:start_link(?GMGR),
+ {error, {already_started, _}} = gen_event:start_link(?GMGR),
+ {error, {already_started, _}} = gen_event:start(?GMGR),
- ok = gen_event:stop({global, my_dummy_name}, shutdown, 10000),
+ ok = gen_event:stop(?GMGR, shutdown, 10000),
receive
{'EXIT', Pid6, shutdown} -> ok
after 10000 ->
@@ -113,10 +114,8 @@ start(Config) when is_list(Config) ->
end,
{ok, Pid7} = gen_event:start_link({via, dummy_via, my_dummy_name}),
- {error, {already_started, _}} =
- gen_event:start_link({via, dummy_via, my_dummy_name}),
- {error, {already_started, _}} =
- gen_event:start({via, dummy_via, my_dummy_name}),
+ {error, {already_started, _}} = gen_event:start_link({via, dummy_via, my_dummy_name}),
+ {error, {already_started, _}} = gen_event:start({via, dummy_via, my_dummy_name}),
exit(Pid7, shutdown),
receive
@@ -128,6 +127,83 @@ start(Config) when is_list(Config) ->
process_flag(trap_exit, OldFl),
ok.
+start_opt(Config) when is_list(Config) ->
+ OldFl = process_flag(trap_exit, true),
+
+ dummy_via:reset(),
+
+ {ok, Pid0} = gen_event:start([]), %anonymous
+ [] = gen_event:which_handlers(Pid0),
+ ok = gen_event:stop(Pid0),
+
+ {ok, Pid1} = gen_event:start_link([]), %anonymous
+ [] = gen_event:which_handlers(Pid1),
+ ok = gen_event:stop(Pid1),
+
+ {ok, Pid2} = gen_event:start(?LMGR, []),
+ [] = gen_event:which_handlers(my_dummy_name),
+ [] = gen_event:which_handlers(Pid2),
+ ok = gen_event:stop(my_dummy_name),
+
+ {ok, Pid3} = gen_event:start_link(?LMGR, []),
+ [] = gen_event:which_handlers(my_dummy_name),
+ [] = gen_event:which_handlers(Pid3),
+ ok = gen_event:stop(my_dummy_name),
+
+ {ok, Pid4} = gen_event:start_link(?GMGR, []),
+ [] = gen_event:which_handlers(?GMGR),
+ [] = gen_event:which_handlers(Pid4),
+ ok = gen_event:stop(?GMGR),
+
+ {ok, Pid5} = gen_event:start_link({via, dummy_via, my_dummy_name}, []),
+ [] = gen_event:which_handlers({via, dummy_via, my_dummy_name}),
+ [] = gen_event:which_handlers(Pid5),
+ ok = gen_event:stop({via, dummy_via, my_dummy_name}),
+
+ {ok, _} = gen_event:start_link(?LMGR, []),
+ {error, {already_started, _}} = gen_event:start_link(?LMGR, []),
+ {error, {already_started, _}} = gen_event:start(?LMGR, []),
+ ok = gen_event:stop(my_dummy_name),
+
+ {ok, Pid7} = gen_event:start_link(?GMGR),
+ {error, {already_started, _}} = gen_event:start_link(?GMGR, []),
+ {error, {already_started, _}} = gen_event:start(?GMGR, []),
+
+ ok = gen_event:stop(?GMGR, shutdown, 10000),
+ receive
+ {'EXIT', Pid7, shutdown} -> ok
+ after 10000 ->
+ ct:fail(exit_gen_event)
+ end,
+
+ {ok, Pid8} = gen_event:start_link({via, dummy_via, my_dummy_name}),
+ {error, {already_started, _}} = gen_event:start_link({via, dummy_via, my_dummy_name}, []),
+ {error, {already_started, _}} = gen_event:start({via, dummy_via, my_dummy_name}, []),
+
+ exit(Pid8, shutdown),
+ receive
+ {'EXIT', Pid8, shutdown} -> ok
+ after 10000 ->
+ ct:fail(exit_gen_event)
+ end,
+
+ %% test spawn_opt
+ MinHeapSz = 10000,
+ {ok, Pid9} = gen_event:start_link(?LMGR, [{spawn_opt, [{min_heap_size, MinHeapSz}]}]),
+ {error, {already_started, _}} = gen_event:start_link(?LMGR, []),
+ {error, {already_started, _}} = gen_event:start(?LMGR, []),
+ {heap_size, HeapSz} = erlang:process_info(Pid9, heap_size),
+ true = HeapSz > MinHeapSz,
+ ok = gen_event:stop(my_dummy_name),
+
+ %% test debug opt
+ {ok, _} = gen_event:start_link(?LMGR, [{debug,[debug]}]),
+ {error, {already_started, _}} = gen_event:start_link(?LMGR, []),
+ {error, {already_started, _}} = gen_event:start(?LMGR, []),
+ ok = gen_event:stop(my_dummy_name),
+
+ process_flag(trap_exit, OldFl),
+ ok.
hibernate(Config) when is_list(Config) ->
{ok,Pid} = gen_event:start({local, my_dummy_handler}),