gen_event.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 659 行 · 第 1/2 页

ERL
659
字号
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %%     $Id$%%-module(gen_event).%%% %%% A general event handler.%%% Several handlers (functions) can be added.%%% Each handler holds a state and will be called%%% for every event received of the handler.%%% %%% Modified by Magnus.%%%       Take care of fault situations and made notify asynchronous.%%% Re-written by Joe with new functional interface !%%% Modified by Martin - uses proc_lib, sys and gen!-export([start/0, start/1, start_link/0, start_link/1, stop/1, 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]).-export([behaviour_info/1]).-export([init_it/6,	 system_continue/3,	 system_terminate/4,	 system_code_change/4,	 print_event/3,	 format_status/2]).-import(error_logger, [error_msg/2]).-define(reply(X), From ! {element(2,Tag), X}).-record(handler, {module,		  id = false,		  state,		  supervised = false}).behaviour_info(callbacks) ->    [{init,1},{handle_event,2},{handle_call,2},{handle_info,2},     {terminate,2},{code_change,3}];behaviour_info(_Other) ->    undefined.%% gen_event:start(Handler) -> ok | {error, What}%%   gen_event:add_handler(Handler, Mod, Args) -> ok | Other%%      gen_event:notify(Handler, Event) -> ok%%      gen_event:call(Handler, Mod, Query) -> {ok, Val} | {error, Why}%%      gen_event:call(Handler, Mod, Query, Timeout) -> {ok, Val} | {error, Why}%%   gen_event:delete_handler(Handler, Mod, Args) -> Val%%   gen_event:swap_handler(Handler, {OldMod, Args1}, {NewMod, Args2}) -> ok%%   gen_event:which_handler(Handler) ->  [Mod]%% gen_event:stop(Handler)  -> ok %% handlers must export%% Mod:init(Args) -> {ok, State} | Other%% Mod:handle_event(Event, State) -> %%    {ok, State'} | remove_handler | {swap_handler,Args1,State1,Mod2,Args2}%% Mod:handle_info(Info, State) ->%%    {ok, State'} | remove_handler | {swap_handler,Args1,State1,Mod2,Args2}%% Mod:handle_call(Query, State) -> %%    {ok, Reply, State'} | {remove_handler, Reply} | %%    {swap_handler, Reply, Args1,State1,Mod2,Args2}%% Mod:terminate(Args, State) -> Val%% add_handler(H, Mod, Args) -> ok | Other%%    Mod:init(Args) -> {ok, State} | Other%% delete_handler(H, Mod, Args) -> Val%%    Mod:terminate(Args, State) -> Val%% notify(H, Event) %%    Mod:handle_event(Event, State) ->%%         {ok, State1}%%         remove_handler%%               Mod:terminate(remove_handler, State) is called%%               the return value is ignored%%         {swap_handler, Args1, State1, Mod2, Args2}%%               State2 = Mod:terminate(Args1, State1) is called%%               the return value is chained into the new module and%%               Mod2:init({Args2, State2}) is called%%         Other%%               Mod:terminate({error, Other}, State) is called%%               The return value is ignored%% call(H, Mod, Query) -> Val%% call(H, Mod, Query, Timeout) -> Val%%      Mod:handle_call(Query, State) -> as abovestart() ->    gen:start(gen_event, nolink, [], [], []).start(Name) ->    gen:start(gen_event, nolink, Name, [], [], []).start_link() ->    gen:start(gen_event, link, [], [], []).start_link(Name) ->    gen:start(gen_event, link, Name, [], [], []).init_it(Starter, self, Name, Mod, Args, Options) ->    init_it(Starter, self(), Name, Mod, Args, Options);init_it(Starter, Parent, Name, _, _, Options) ->    process_flag(trap_exit, true),    Debug = gen:debug_options(Options),    proc_lib:init_ack(Starter, {ok, self()}),    loop(Parent, Name, [], Debug).add_handler(M, Handler, Args)      -> rpc (M, {add_handler, Handler, Args}).add_sup_handler(M, Handler, Args)  ->    rpc (M, {add_sup_handler, Handler, Args, self()}).notify(M, Event)                   -> send(M, {notify, Event}). sync_notify(M, Event)              -> rpc (M, {sync_notify, Event}).call(M, Handler, Query)            -> call1(M, Handler, Query).call(M, Handler, Query, Timeout)   -> call1(M, Handler, Query, Timeout).delete_handler(M, Handler, Args)   -> rpc (M, {delete_handler, Handler, Args}).swap_handler(M, {H1, A1},{H2, A2}) -> rpc (M, {swap_handler, H1, A1, H2, A2}).swap_sup_handler(M, {H1, A1},{H2, A2}) ->    rpc (M, {swap_sup_handler, H1, A1, H2, A2, self()}).which_handlers(M)                  -> rpc (M, which_handlers).stop(M)                            -> rpc (M, stop).rpc(M, Cmd) ->     {ok,Reply} = gen:call(M, self(), Cmd, infinity),    Reply.call1(M, Handler, Query) ->    Cmd = {call, Handler, Query},    case catch gen:call(M, self(), Cmd) of	{ok,Res} ->	    Res;	{'EXIT', Reason} ->	    exit({Reason, {gen_event, call, [M, Handler, Query]}})    end.call1(M, Handler, Query, Timeout) ->    Cmd = {call, Handler, Query},    case catch gen:call(M, self(), Cmd, Timeout) of	{ok,Res} ->	    Res;	{'EXIT', Reason} ->	    exit({Reason, {gen_event, call, [M, Handler, Query, Timeout]}})    end.send({global, Name}, Cmd) ->    catch global:send(Name, Cmd),    ok;send(M, Cmd) ->    M ! Cmd,    ok.loop(Parent, ServerName, MSL, Debug) ->    receive	{system, From, Req} ->	    sys:handle_system_msg(Req, From, Parent, gen_event, Debug,				  [ServerName, MSL]);	{'EXIT', Parent, Reason} ->	    terminate_server(Reason, Parent, MSL, ServerName);	Msg when Debug =:= [] ->	    handle_msg(Msg, Parent, ServerName, MSL, []);	Msg ->	    Debug1 = sys:handle_debug(Debug, {gen_event, print_event}, 				      ServerName, {in, Msg}),	    handle_msg(Msg, Parent, ServerName, MSL, Debug1)    end.handle_msg(Msg, Parent, ServerName, MSL, Debug) ->    case Msg of	{notify, Event} ->	    MSL1 = server_notify(Event, handle_event, MSL, ServerName),	    loop(Parent, ServerName, MSL1, Debug);	{From, Tag, {sync_notify, Event}} ->	    MSL1 = server_notify(Event, handle_event, MSL, ServerName),	    ?reply(ok),	    loop(Parent, ServerName, MSL1, Debug);	{'EXIT', From, Reason} ->	    MSL1 = handle_exit(From, Reason, MSL, ServerName),	    loop(Parent, ServerName, MSL1, Debug);	{From, Tag, {call, Handler, Query}} ->	    {Reply, MSL1} = server_call(Handler, Query, MSL, ServerName),	    ?reply(Reply),	    loop(Parent, ServerName, MSL1, Debug);	{From, Tag, {add_handler, Handler, Args}} ->	    {Reply, MSL1} = server_add_handler(Handler, Args, MSL),	    ?reply(Reply),	    loop(Parent, ServerName, MSL1, Debug);	{From, Tag, {add_sup_handler, Handler, Args, SupP}} ->	    {Reply, MSL1} = server_add_sup_handler(Handler, Args, MSL, SupP),	    ?reply(Reply),	    loop(Parent, ServerName, MSL1, Debug);	{From, Tag, {delete_handler, Handler, Args}} ->	    {Reply, MSL1} = server_delete_handler(Handler, Args, MSL,						  ServerName),	    ?reply(Reply),	    loop(Parent, ServerName, MSL1, Debug);	{From, Tag, {swap_handler, Handler1, Args1, Handler2, Args2}} ->	    {Reply, MSL1} = server_swap_handler(Handler1, Args1, Handler2,						Args2, MSL, ServerName),	    ?reply(Reply),	    loop(Parent, ServerName, MSL1, Debug);	{From, Tag, {swap_sup_handler, Handler1, Args1, Handler2, Args2,		     Sup}} ->	    {Reply, MSL1} = server_swap_handler(Handler1, Args1, Handler2,						Args2, MSL, Sup, ServerName),	    ?reply(Reply),	    loop(Parent, ServerName, MSL1, Debug);	{From, Tag, stop} ->	    catch terminate_server(normal, Parent, MSL, ServerName),	    ?reply(ok);	{From, Tag, which_handlers} ->	    ?reply(the_handlers(MSL)),	    loop(Parent, ServerName, MSL, Debug);	{From, Tag, get_modules} ->	    ?reply(get_modules(MSL)),	    loop(Parent, ServerName, MSL, Debug);	Other  ->	    MSL1 = server_notify(Other, handle_info, MSL, ServerName),	    loop(Parent, ServerName, MSL1, Debug)    end.terminate_server(Reason, Parent, MSL, ServerName) ->    stop_handlers(MSL, ServerName),    do_unlink(Parent, MSL),    exit(Reason).%% unlink the supervisor process of all supervised handlers.%% We do not want a handler supervisor to EXIT due to the%% termination of the event manager (server).%% Do not unlink Parent !do_unlink(Parent, MSL) ->    lists:foreach(fun(Handler) when Handler#handler.supervised =:= Parent ->			  true;		     (Handler) when is_pid(Handler#handler.supervised) ->			  unlink(Handler#handler.supervised),			  true;		     (_) ->			  true		  end,		  MSL).%% First terminate the supervised (if exists) handlers and%% then inform other handlers.%% We do not know if any handler really is interested but it%% may be so !handle_exit(From, Reason, MSL, SName) ->    MSL1 = terminate_supervised(From, Reason, MSL, SName),    server_notify({'EXIT', From, Reason}, handle_info, MSL1, SName).terminate_supervised(Pid, Reason, MSL, SName) ->    F = fun(Ha) when Ha#handler.supervised =:= Pid ->		do_terminate(Ha#handler.module,			     Ha,			     {stop,Reason},			     Ha#handler.state,			     {parent_terminated, {Pid,Reason}},			     SName,			     shutdown),		false;	   (_) ->		true	end,    lists:filter(F, MSL).%%-----------------------------------------------------------------%% Callback functions for system messages handling.%%-----------------------------------------------------------------system_continue(Parent, Debug, [ServerName, MSL]) ->    loop(Parent, ServerName, MSL, Debug).system_terminate(Reason, Parent, _Debug, [ServerName, MSL]) ->    terminate_server(Reason, Parent, MSL, ServerName).%%-----------------------------------------------------------------%% Module here is sent in the system msg change_code.  It specifies%% which module should be changed.%%-----------------------------------------------------------------system_code_change([ServerName, MSL], Module, OldVsn, Extra) ->    MSL1 = lists:zf(fun(H) when H#handler.module =:= Module ->			    {ok, NewState} =				Module:code_change(OldVsn,						   H#handler.state, Extra),			    {true, H#handler{state = NewState}};		       (_) -> true		    end,		    MSL),    {ok, [ServerName, MSL1]}.%%-----------------------------------------------------------------%% Format debug messages.  Print them as the call-back module sees%% them, not as the real erlang messages.  Use trace for that.%%-----------------------------------------------------------------print_event(Dev, {in, Msg}, Name) ->    case Msg of	{notify, Event} ->	    io:format(Dev, "*DBG* ~p got event ~p~n", [Name, Event]);	{_,_,{call, Handler, Query}} ->	    io:format(Dev, "*DBG* ~p(~p) got call ~p~n",		      [Name, Handler, Query]);	_ ->	    io:format(Dev, "*DBG* ~p got ~p~n", [Name, Msg])    end;print_event(Dev, Dbg, Name) ->    io:format(Dev, "*DBG* ~p : ~p~n", [Name, Dbg]).%% server_add_handler(Handler, Args, MSL) -> {Ret, MSL'}.%%   where MSL = [#handler]%%   Ret goes to the top level MSL' is the new internal state of the%%   event handler

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?