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 + -
显示快捷键?