1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1996-2018. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20-module(gen_event). 21 22%%% 23%%% A general event handler. 24%%% Several handlers (functions) can be added. 25%%% Each handler holds a state and will be called 26%%% for every event received of the handler. 27%%% 28 29%%% Modified by Magnus. 30%%% Take care of fault situations and made notify asynchronous. 31%%% Re-written by Joe with new functional interface ! 32%%% Modified by Martin - uses proc_lib, sys and gen! 33 34 35-export([start/0, start/1, start/2, 36 start_link/0, start_link/1, start_link/2, 37 stop/1, stop/3, 38 notify/2, sync_notify/2, 39 add_handler/3, add_sup_handler/3, delete_handler/3, swap_handler/3, 40 swap_sup_handler/3, which_handlers/1, call/3, call/4, wake_hib/5]). 41 42-export([init_it/6, 43 system_continue/3, 44 system_terminate/4, 45 system_code_change/4, 46 system_get_state/1, 47 system_replace_state/2, 48 format_status/2]). 49 50%% logger callback 51-export([format_log/1]). 52 53-export_type([handler/0, handler_args/0, add_handler_ret/0, 54 del_handler_ret/0]). 55 56-record(handler, {module :: atom(), 57 id = false, 58 state, 59 supervised = false :: 'false' | pid()}). 60 61-include("logger.hrl"). 62 63%%%========================================================================= 64%%% API 65%%%========================================================================= 66 67%% gen_event:start(Handler) -> {ok, Pid} | {error, What} 68%% gen_event:add_handler(Handler, Mod, Args) -> ok | Other 69%% gen_event:notify(Handler, Event) -> ok 70%% gen_event:call(Handler, Mod, Query) -> {ok, Val} | {error, Why} 71%% gen_event:call(Handler, Mod, Query, Timeout) -> {ok, Val} | {error, Why} 72%% gen_event:delete_handler(Handler, Mod, Args) -> Val 73%% gen_event:swap_handler(Handler, {OldMod, Args1}, {NewMod, Args2}) -> ok 74%% gen_event:which_handler(Handler) -> [Mod] 75%% gen_event:stop(Handler) -> ok 76 77-callback init(InitArgs :: term()) -> 78 {ok, State :: term()} | 79 {ok, State :: term(), hibernate} | 80 {error, Reason :: term()}. 81-callback handle_event(Event :: term(), State :: term()) -> 82 {ok, NewState :: term()} | 83 {ok, NewState :: term(), hibernate} | 84 {swap_handler, Args1 :: term(), NewState :: term(), 85 Handler2 :: (atom() | {atom(), Id :: term()}), Args2 :: term()} | 86 remove_handler. 87-callback handle_call(Request :: term(), State :: term()) -> 88 {ok, Reply :: term(), NewState :: term()} | 89 {ok, Reply :: term(), NewState :: term(), hibernate} | 90 {swap_handler, Reply :: term(), Args1 :: term(), NewState :: term(), 91 Handler2 :: (atom() | {atom(), Id :: term()}), Args2 :: term()} | 92 {remove_handler, Reply :: term()}. 93-callback handle_info(Info :: term(), State :: term()) -> 94 {ok, NewState :: term()} | 95 {ok, NewState :: term(), hibernate} | 96 {swap_handler, Args1 :: term(), NewState :: term(), 97 Handler2 :: (atom() | {atom(), Id :: term()}), Args2 :: term()} | 98 remove_handler. 99-callback terminate(Args :: (term() | {stop, Reason :: term()} | 100 stop | remove_handler | 101 {error, {'EXIT', Reason :: term()}} | 102 {error, term()}), 103 State :: term()) -> 104 term(). 105-callback code_change(OldVsn :: (term() | {down, term()}), 106 State :: term(), Extra :: term()) -> 107 {ok, NewState :: term()}. 108-callback format_status(Opt, StatusData) -> Status when 109 Opt :: 'normal' | 'terminate', 110 StatusData :: [PDict | State], 111 PDict :: [{Key :: term(), Value :: term()}], 112 State :: term(), 113 Status :: term(). 114 115-optional_callbacks( 116 [handle_info/2, terminate/2, code_change/3, format_status/2]). 117 118%%--------------------------------------------------------------------------- 119 120-type handler() :: atom() | {atom(), term()}. 121-type handler_args() :: term(). 122-type add_handler_ret() :: ok | term() | {'EXIT',term()}. 123-type del_handler_ret() :: ok | term() | {'EXIT',term()}. 124 125-type emgr_name() :: {'local', atom()} | {'global', term()} 126 | {'via', atom(), term()}. 127-type debug_flag() :: 'trace' | 'log' | 'statistics' | 'debug' 128 | {'logfile', string()}. 129-type option() :: {'timeout', timeout()} 130 | {'debug', [debug_flag()]} 131 | {'spawn_opt', [proc_lib:spawn_option()]} 132 | {'hibernate_after', timeout()}. 133-type emgr_ref() :: atom() | {atom(), atom()} | {'global', term()} 134 | {'via', atom(), term()} | pid(). 135-type start_ret() :: {'ok', pid()} | {'error', term()}. 136 137%%--------------------------------------------------------------------------- 138 139-define(NO_CALLBACK, 'no callback module'). 140 141%% ----------------------------------------------------------------- 142%% Starts a generic event handler. 143%% start() 144%% start(MgrName | Options) 145%% start(MgrName, Options) 146%% start_link() 147%% start_link(MgrName | Options) 148%% start_link(MgrName, Options) 149%% MgrName ::= {local, atom()} | {global, term()} | {via, atom(), term()} 150%% Options ::= [{timeout, Timeout} | {debug, [Flag]} | {spawn_opt,SOpts}] 151%% Flag ::= trace | log | {logfile, File} | statistics | debug 152%% (debug == log && statistics) 153%% Returns: {ok, Pid} | 154%% {error, {already_started, Pid}} | 155%% {error, Reason} 156%% ----------------------------------------------------------------- 157 158-spec start() -> start_ret(). 159start() -> 160 gen:start(?MODULE, nolink, ?NO_CALLBACK, [], []). 161 162-spec start(emgr_name() | [option()]) -> start_ret(). 163start(Name) when is_tuple(Name) -> 164 gen:start(?MODULE, nolink, Name, ?NO_CALLBACK, [], []); 165start(Options) when is_list(Options) -> 166 gen:start(?MODULE, nolink, ?NO_CALLBACK, [], Options). 167 168-spec start(emgr_name(), [option()]) -> start_ret(). 169start(Name, Options) -> 170 gen:start(?MODULE, nolink, Name, ?NO_CALLBACK, [], Options). 171 172-spec start_link() -> start_ret(). 173start_link() -> 174 gen:start(?MODULE, link, ?NO_CALLBACK, [], []). 175 176-spec start_link(emgr_name() | [option()]) -> start_ret(). 177start_link(Name) when is_tuple(Name) -> 178 gen:start(?MODULE, link, Name, ?NO_CALLBACK, [], []); 179start_link(Options) when is_list(Options) -> 180 gen:start(?MODULE, link, ?NO_CALLBACK, [], Options). 181 182-spec start_link(emgr_name(), [option()]) -> start_ret(). 183start_link(Name, Options) -> 184 gen:start(?MODULE, link, Name, ?NO_CALLBACK, [], Options). 185 186%% -spec init_it(pid(), 'self' | pid(), emgr_name(), module(), [term()], [_]) -> 187init_it(Starter, self, Name, Mod, Args, Options) -> 188 init_it(Starter, self(), Name, Mod, Args, Options); 189init_it(Starter, Parent, Name0, _, _, Options) -> 190 process_flag(trap_exit, true), 191 Name = gen:name(Name0), 192 Debug = gen:debug_options(Name, Options), 193 HibernateAfterTimeout = gen:hibernate_after(Options), 194 proc_lib:init_ack(Starter, {ok, self()}), 195 loop(Parent, Name, [], HibernateAfterTimeout, Debug, false). 196 197-spec add_handler(emgr_ref(), handler(), term()) -> term(). 198add_handler(M, Handler, Args) -> rpc(M, {add_handler, Handler, Args}). 199 200-spec add_sup_handler(emgr_ref(), handler(), term()) -> term(). 201add_sup_handler(M, Handler, Args) -> 202 rpc(M, {add_sup_handler, Handler, Args, self()}). 203 204-spec notify(emgr_ref(), term()) -> 'ok'. 205notify(M, Event) -> send(M, {notify, Event}). 206 207-spec sync_notify(emgr_ref(), term()) -> 'ok'. 208sync_notify(M, Event) -> rpc(M, {sync_notify, Event}). 209 210-spec call(emgr_ref(), handler(), term()) -> term(). 211call(M, Handler, Query) -> call1(M, Handler, Query). 212 213-spec call(emgr_ref(), handler(), term(), timeout()) -> term(). 214call(M, Handler, Query, Timeout) -> call1(M, Handler, Query, Timeout). 215 216-spec delete_handler(emgr_ref(), handler(), term()) -> term(). 217delete_handler(M, Handler, Args) -> rpc(M, {delete_handler, Handler, Args}). 218 219-spec swap_handler(emgr_ref(), {handler(), term()}, {handler(), term()}) -> 220 'ok' | {'error', term()}. 221swap_handler(M, {H1, A1}, {H2, A2}) -> rpc(M, {swap_handler, H1, A1, H2, A2}). 222 223-spec swap_sup_handler(emgr_ref(), {handler(), term()}, {handler(), term()}) -> 224 'ok' | {'error', term()}. 225swap_sup_handler(M, {H1, A1}, {H2, A2}) -> 226 rpc(M, {swap_sup_handler, H1, A1, H2, A2, self()}). 227 228-spec which_handlers(emgr_ref()) -> [handler()]. 229which_handlers(M) -> rpc(M, which_handlers). 230 231-spec stop(emgr_ref()) -> 'ok'. 232stop(M) -> 233 gen:stop(M). 234 235stop(M, Reason, Timeout) -> 236 gen:stop(M, Reason, Timeout). 237 238rpc(M, Cmd) -> 239 {ok, Reply} = gen:call(M, self(), Cmd, infinity), 240 Reply. 241 242call1(M, Handler, Query) -> 243 Cmd = {call, Handler, Query}, 244 try gen:call(M, self(), Cmd) of 245 {ok, Res} -> 246 Res 247 catch 248 exit:Reason -> 249 exit({Reason, {?MODULE, call, [M, Handler, Query]}}) 250 end. 251 252call1(M, Handler, Query, Timeout) -> 253 Cmd = {call, Handler, Query}, 254 try gen:call(M, self(), Cmd, Timeout) of 255 {ok, Res} -> 256 Res 257 catch 258 exit:Reason -> 259 exit({Reason, {?MODULE, call, [M, Handler, Query, Timeout]}}) 260 end. 261 262send({global, Name}, Cmd) -> 263 catch global:send(Name, Cmd), 264 ok; 265send({via, Mod, Name}, Cmd) -> 266 catch Mod:send(Name, Cmd), 267 ok; 268send(M, Cmd) -> 269 M ! Cmd, 270 ok. 271 272loop(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, true) -> 273 proc_lib:hibernate(?MODULE, wake_hib, [Parent, ServerName, MSL, HibernateAfterTimeout, Debug]); 274loop(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, _) -> 275 fetch_msg(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, false). 276 277wake_hib(Parent, ServerName, MSL, HibernateAfterTimeout, Debug) -> 278 fetch_msg(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, true). 279 280fetch_msg(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, Hib) -> 281 receive 282 {system, From, Req} -> 283 sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug, 284 [ServerName, MSL, HibernateAfterTimeout, Hib],Hib); 285 {'EXIT', Parent, Reason} -> 286 terminate_server(Reason, Parent, MSL, ServerName); 287 Msg when Debug =:= [] -> 288 handle_msg(Msg, Parent, ServerName, MSL, HibernateAfterTimeout, []); 289 Msg -> 290 Debug1 = sys:handle_debug(Debug, fun print_event/3, 291 ServerName, {in, Msg}), 292 handle_msg(Msg, Parent, ServerName, MSL, HibernateAfterTimeout, Debug1) 293 after HibernateAfterTimeout -> 294 loop(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, true) 295 end. 296 297handle_msg(Msg, Parent, ServerName, MSL, HibernateAfterTimeout, Debug) -> 298 case Msg of 299 {notify, Event} -> 300 {Hib,MSL1} = server_notify(Event, handle_event, MSL, ServerName), 301 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, Hib); 302 {_From, Tag, {sync_notify, Event}} -> 303 {Hib, MSL1} = server_notify(Event, handle_event, MSL, ServerName), 304 reply(Tag, ok), 305 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, Hib); 306 {'EXIT', From, Reason} -> 307 MSL1 = handle_exit(From, Reason, MSL, ServerName), 308 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, false); 309 {_From, Tag, {call, Handler, Query}} -> 310 {Hib, Reply, MSL1} = server_call(Handler, Query, MSL, ServerName), 311 reply(Tag, Reply), 312 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, Hib); 313 {_From, Tag, {add_handler, Handler, Args}} -> 314 {Hib, Reply, MSL1} = server_add_handler(Handler, Args, MSL), 315 reply(Tag, Reply), 316 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, Hib); 317 {_From, Tag, {add_sup_handler, Handler, Args, SupP}} -> 318 {Hib, Reply, MSL1} = server_add_sup_handler(Handler, Args, MSL, SupP), 319 reply(Tag, Reply), 320 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, Hib); 321 {_From, Tag, {delete_handler, Handler, Args}} -> 322 {Reply, MSL1} = server_delete_handler(Handler, Args, MSL, 323 ServerName), 324 reply(Tag, Reply), 325 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, false); 326 {_From, Tag, {swap_handler, Handler1, Args1, Handler2, Args2}} -> 327 {Hib, Reply, MSL1} = server_swap_handler(Handler1, Args1, Handler2, 328 Args2, MSL, ServerName), 329 reply(Tag, Reply), 330 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, Hib); 331 {_From, Tag, {swap_sup_handler, Handler1, Args1, Handler2, Args2, 332 Sup}} -> 333 {Hib, Reply, MSL1} = server_swap_handler(Handler1, Args1, Handler2, 334 Args2, MSL, Sup, ServerName), 335 reply(Tag, Reply), 336 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, Hib); 337 {_From, Tag, stop} -> 338 catch terminate_server(normal, Parent, MSL, ServerName), 339 reply(Tag, ok); 340 {_From, Tag, which_handlers} -> 341 reply(Tag, the_handlers(MSL)), 342 loop(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, false); 343 {_From, Tag, get_modules} -> 344 reply(Tag, get_modules(MSL)), 345 loop(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, false); 346 Other -> 347 {Hib, MSL1} = server_notify(Other, handle_info, MSL, ServerName), 348 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, Hib) 349 end. 350 351terminate_server(Reason, Parent, MSL, ServerName) -> 352 stop_handlers(MSL, ServerName), 353 do_unlink(Parent, MSL), 354 exit(Reason). 355 356reply({From, Ref}, Msg) -> 357 From ! {Ref, Msg}, 358 ok. 359 360%% unlink the supervisor process of all supervised handlers. 361%% We do not want a handler supervisor to EXIT due to the 362%% termination of the event manager (server). 363%% Do not unlink Parent ! 364do_unlink(Parent, MSL) -> 365 lists:foreach(fun(Handler) when Handler#handler.supervised =:= Parent -> 366 true; 367 (Handler) when is_pid(Handler#handler.supervised) -> 368 unlink(Handler#handler.supervised), 369 true; 370 (_) -> 371 true 372 end, 373 MSL). 374 375%% First terminate the supervised (if exists) handlers and 376%% then inform other handlers. 377%% We do not know if any handler really is interested but it 378%% may be so ! 379handle_exit(From, Reason, MSL, SName) -> 380 MSL1 = terminate_supervised(From, Reason, MSL, SName), 381 {_,MSL2}=server_notify({'EXIT', From, Reason}, handle_info, MSL1, SName), 382 MSL2. 383 384terminate_supervised(Pid, Reason, MSL, SName) -> 385 F = fun(Ha) when Ha#handler.supervised =:= Pid -> 386 do_terminate(Ha#handler.module, 387 Ha, 388 {stop,Reason}, 389 Ha#handler.state, 390 {parent_terminated, {Pid,Reason}}, 391 SName, 392 shutdown), 393 false; 394 (_) -> 395 true 396 end, 397 lists:filter(F, MSL). 398 399%%----------------------------------------------------------------- 400%% Callback functions for system messages handling. 401%%----------------------------------------------------------------- 402system_continue(Parent, Debug, [ServerName, MSL, HibernateAfterTimeout, Hib]) -> 403 loop(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, Hib). 404 405-spec system_terminate(_, _, _, [_]) -> no_return(). 406system_terminate(Reason, Parent, _Debug, [ServerName, MSL, _HibernateAfterTimeout, _Hib]) -> 407 terminate_server(Reason, Parent, MSL, ServerName). 408 409%%----------------------------------------------------------------- 410%% Module here is sent in the system msg change_code. It specifies 411%% which module should be changed. 412%%----------------------------------------------------------------- 413system_code_change([ServerName, MSL, HibernateAfterTimeout, Hib], Module, OldVsn, Extra) -> 414 MSL1 = lists:zf(fun(H) when H#handler.module =:= Module -> 415 {ok, NewState} = 416 Module:code_change(OldVsn, 417 H#handler.state, Extra), 418 {true, H#handler{state = NewState}}; 419 (_) -> true 420 end, 421 MSL), 422 {ok, [ServerName, MSL1, HibernateAfterTimeout, Hib]}. 423 424system_get_state([_ServerName, MSL, _HibernateAfterTimeout, _Hib]) -> 425 {ok, [{Mod,Id,State} || #handler{module=Mod, id=Id, state=State} <- MSL]}. 426 427system_replace_state(StateFun, [ServerName, MSL, HibernateAfterTimeout, Hib]) -> 428 {NMSL, NStates} = 429 lists:unzip([begin 430 Cur = {Mod,Id,State}, 431 try 432 NState = {Mod,Id,NS} = StateFun(Cur), 433 {HS#handler{state=NS}, NState} 434 catch 435 _:_ -> 436 {HS, Cur} 437 end 438 end || #handler{module=Mod, id=Id, state=State}=HS <- MSL]), 439 {ok, NStates, [ServerName, NMSL, HibernateAfterTimeout, Hib]}. 440 441%%----------------------------------------------------------------- 442%% Format debug messages. Print them as the call-back module sees 443%% them, not as the real erlang messages. Use trace for that. 444%%----------------------------------------------------------------- 445print_event(Dev, {in, Msg}, Name) -> 446 case Msg of 447 {notify, Event} -> 448 io:format(Dev, "*DBG* ~tp got event ~tp~n", [Name, Event]); 449 {_,_,{call, Handler, Query}} -> 450 io:format(Dev, "*DBG* ~tp(~tp) got call ~tp~n", 451 [Name, Handler, Query]); 452 _ -> 453 io:format(Dev, "*DBG* ~tp got ~tp~n", [Name, Msg]) 454 end; 455print_event(Dev, Dbg, Name) -> 456 io:format(Dev, "*DBG* ~tp : ~tp~n", [Name, Dbg]). 457 458 459%% server_add_handler(Handler, Args, MSL) -> {Ret, MSL'}. 460%% where MSL = [#handler{}] 461%% Ret goes to the top level MSL' is the new internal state of the 462%% event handler 463 464server_add_handler({Mod,Id}, Args, MSL) -> 465 Handler = #handler{module = Mod, 466 id = Id}, 467 server_add_handler(Mod, Handler, Args, MSL); 468server_add_handler(Mod, Args, MSL) -> 469 Handler = #handler{module = Mod}, 470 server_add_handler(Mod, Handler, Args, MSL). 471 472server_add_handler(Mod, Handler, Args, MSL) -> 473 case catch Mod:init(Args) of 474 {ok, State} -> 475 {false, ok, [Handler#handler{state = State}|MSL]}; 476 {ok, State, hibernate} -> 477 {true, ok, [Handler#handler{state = State}|MSL]}; 478 Other -> 479 {false, Other, MSL} 480 end. 481 482%% Set up a link to the supervising process. 483%% (Ought to be unidirected links here, Erl5.0 !!) 484%% NOTE: This link will not be removed then the 485%% handler is removed in case another handler has 486%% own link to this process. 487server_add_sup_handler({Mod,Id}, Args, MSL, Parent) -> 488 link(Parent), 489 Handler = #handler{module = Mod, 490 id = Id, 491 supervised = Parent}, 492 server_add_handler(Mod, Handler, Args, MSL); 493server_add_sup_handler(Mod, Args, MSL, Parent) -> 494 link(Parent), 495 Handler = #handler{module = Mod, 496 supervised = Parent}, 497 server_add_handler(Mod, Handler, Args, MSL). 498 499%% server_delete_handler(HandlerId, Args, MSL) -> {Ret, MSL'} 500 501server_delete_handler(HandlerId, Args, MSL, SName) -> 502 case split(HandlerId, MSL) of 503 {Mod, Handler, MSL1} -> 504 {do_terminate(Mod, Handler, Args, 505 Handler#handler.state, delete, SName, normal), 506 MSL1}; 507 error -> 508 {{error, module_not_found}, MSL} 509 end. 510 511%% server_swap_handler(Handler1, Args1, Handler2, Args2, MSL, SN) -> MSL' 512%% server_swap_handler(Handler1, Args1, Handler2, Args2, MSL, Sup, SN) -> MSL' 513 514server_swap_handler(Handler1, Args1, Handler2, Args2, MSL, SName) -> 515 {State2, Sup, MSL1} = split_and_terminate(Handler1, Args1, MSL, 516 SName, Handler2, false), 517 case s_s_h(Sup, Handler2, {Args2, State2}, MSL1) of 518 {Hib, ok, MSL2} -> 519 {Hib, ok, MSL2}; 520 {Hib, What, MSL2} -> 521 {Hib, {error, What}, MSL2} 522 end. 523 524server_swap_handler(Handler1, Args1, Handler2, Args2, MSL, Sup, SName) -> 525 {State2, _, MSL1} = split_and_terminate(Handler1, Args1, MSL, 526 SName, Handler2, Sup), 527 case s_s_h(Sup, Handler2, {Args2, State2}, MSL1) of 528 {Hib, ok, MSL2} -> 529 {Hib, ok, MSL2}; 530 {Hib, What, MSL2} -> 531 {Hib, {error, What}, MSL2} 532 end. 533 534s_s_h(false, Handler, Args, MSL) -> 535 server_add_handler(Handler, Args, MSL); 536s_s_h(Pid, Handler, Args, MSL) -> 537 server_add_sup_handler(Handler, Args, MSL, Pid). 538 539split_and_terminate(HandlerId, Args, MSL, SName, Handler2, Sup) -> 540 case split(HandlerId, MSL) of 541 {Mod, Handler, MSL1} -> 542 OldSup = Handler#handler.supervised, 543 NewSup = if 544 not Sup -> OldSup; 545 true -> Sup 546 end, 547 {do_terminate(Mod, Handler, Args, 548 Handler#handler.state, swapped, SName, 549 {swapped, Handler2, NewSup}), 550 OldSup, 551 MSL1}; 552 error -> 553 {error, false, MSL} 554 end. 555 556%% server_notify(Event, Func, MSL, SName) -> MSL' 557 558server_notify(Event, Func, [Handler|T], SName) -> 559 case server_update(Handler, Func, Event, SName) of 560 {ok, Handler1} -> 561 {Hib, NewHandlers} = server_notify(Event, Func, T, SName), 562 {Hib, [Handler1|NewHandlers]}; 563 {hibernate, Handler1} -> 564 {_Hib, NewHandlers} = server_notify(Event, Func, T, SName), 565 {true, [Handler1|NewHandlers]}; 566 no -> 567 server_notify(Event, Func, T, SName) 568 end; 569server_notify(_, _, [], _) -> 570 {false, []}. 571 572%% server_update(Handler, Func, Event, ServerName) -> Handler1 | no 573 574server_update(Handler1, Func, Event, SName) -> 575 Mod1 = Handler1#handler.module, 576 State = Handler1#handler.state, 577 case catch Mod1:Func(Event, State) of 578 {ok, State1} -> 579 {ok, Handler1#handler{state = State1}}; 580 {ok, State1, hibernate} -> 581 {hibernate, Handler1#handler{state = State1}}; 582 {swap_handler, Args1, State1, Handler2, Args2} -> 583 do_swap(Mod1, Handler1, Args1, State1, Handler2, Args2, SName); 584 remove_handler -> 585 do_terminate(Mod1, Handler1, remove_handler, State, 586 remove, SName, normal), 587 no; 588 {'EXIT', {undef, [{Mod1, handle_info, [_,_], _}|_]}} -> 589 ?LOG_WARNING(#{label=>{gen_event,no_handle_info}, 590 module=>Mod1, 591 message=>Event}, 592 #{domain=>[otp], 593 report_cb=>fun gen_event:format_log/1, 594 error_logger=>#{tag=>warning_msg}}), % warningmap?? 595 {ok, Handler1}; 596 Other -> 597 do_terminate(Mod1, Handler1, {error, Other}, State, 598 Event, SName, crash), 599 no 600 end. 601 602do_swap(Mod1, Handler1, Args1, State1, Handler2, Args2, SName) -> 603 %% finalise the existing handler 604 State2 = do_terminate(Mod1, Handler1, Args1, State1, 605 swapped, SName, 606 {swapped, Handler2, Handler1#handler.supervised}), 607 {Mod2, Handler} = new_handler(Handler2, Handler1), 608 case catch Mod2:init({Args2, State2}) of 609 {ok, State2a} -> 610 {ok, Handler#handler{state = State2a}}; 611 Other -> 612 report_terminate(Handler, crash, {error, Other}, SName, false), 613 no 614 end. 615 616new_handler({Mod,Id}, Handler1) -> 617 {Mod, #handler{module = Mod, 618 id = Id, 619 supervised = Handler1#handler.supervised}}; 620new_handler(Mod, Handler1) -> 621 {Mod, #handler{module = Mod, 622 supervised = Handler1#handler.supervised}}. 623 624 625-spec split(handler(), [#handler{}]) -> 626 {atom(), #handler{}, [#handler{}]} | 'error'. 627 628split(Ha, MSL) -> split(Ha, MSL, []). 629 630split({Mod,Id}, [Ha|T], L) when Ha#handler.module =:= Mod, 631 Ha#handler.id =:= Id -> 632 {Mod, Ha, lists:reverse(L, T)}; 633split(Mod, [Ha|T], L) when Ha#handler.module =:= Mod, 634 not Ha#handler.id -> 635 {Mod, Ha, lists:reverse(L, T)}; 636split(Ha, [H|T], L) -> 637 split(Ha, T, [H|L]); 638split(_, [], _) -> 639 error. 640 641%% server_call(Handler, Query, MSL, ServerName) -> 642%% {Reply, MSL1} 643 644server_call(Handler, Query, MSL, SName) -> 645 case search(Handler, MSL) of 646 {ok, Ha} -> 647 case server_call_update(Ha, Query, SName) of 648 {no, Reply} -> 649 {false, Reply, delete(Handler, MSL)}; 650 {{ok, Ha1}, Reply} -> 651 {false, Reply, replace(Handler, MSL, Ha1)}; 652 {{hibernate, Ha1}, Reply} -> 653 {true, Reply, replace(Handler, MSL, Ha1)} 654 end; 655 false -> 656 {false, {error, bad_module}, MSL} 657 end. 658 659search({Mod, Id}, [Ha|_MSL]) when Ha#handler.module =:= Mod, 660 Ha#handler.id =:= Id -> 661 {ok, Ha}; 662search(Mod, [Ha|_MSL]) when Ha#handler.module =:= Mod, 663 not Ha#handler.id -> 664 {ok, Ha}; 665search(Handler, [_|MSL]) -> 666 search(Handler, MSL); 667search(_, []) -> 668 false. 669 670delete({Mod, Id}, [Ha|MSL]) when Ha#handler.module =:= Mod, 671 Ha#handler.id =:= Id -> 672 MSL; 673delete(Mod, [Ha|MSL]) when Ha#handler.module =:= Mod, 674 not Ha#handler.id -> 675 MSL; 676delete(Handler, [Ha|MSL]) -> 677 [Ha|delete(Handler, MSL)]; 678delete(_, []) -> 679 []. 680 681replace({Mod, Id}, [Ha|MSL], NewHa) when Ha#handler.module =:= Mod, 682 Ha#handler.id =:= Id -> 683 [NewHa|MSL]; 684replace(Mod, [Ha|MSL], NewHa) when Ha#handler.module =:= Mod, 685 not Ha#handler.id -> 686 [NewHa|MSL]; 687replace(Handler, [Ha|MSL], NewHa) -> 688 [Ha|replace(Handler, MSL, NewHa)]; 689replace(_, [], NewHa) -> 690 [NewHa]. 691 692%% server_call_update(Handler, Query, ServerName) -> 693%% {{Handler1, State1} | 'no', Reply} 694 695server_call_update(Handler1, Query, SName) -> 696 Mod1 = Handler1#handler.module, 697 State = Handler1#handler.state, 698 case catch Mod1:handle_call(Query, State) of 699 {ok, Reply, State1} -> 700 {{ok, Handler1#handler{state = State1}}, Reply}; 701 {ok, Reply, State1, hibernate} -> 702 {{hibernate, Handler1#handler{state = State1}}, 703 Reply}; 704 {swap_handler, Reply, Args1, State1, Handler2, Args2} -> 705 {do_swap(Mod1,Handler1,Args1,State1,Handler2,Args2,SName), Reply}; 706 {remove_handler, Reply} -> 707 do_terminate(Mod1, Handler1, remove_handler, State, 708 remove, SName, normal), 709 {no, Reply}; 710 Other -> 711 do_terminate(Mod1, Handler1, {error, Other}, State, 712 Query, SName, crash), 713 {no, {error, Other}} 714 end. 715 716do_terminate(Mod, Handler, Args, State, LastIn, SName, Reason) -> 717 case erlang:function_exported(Mod, terminate, 2) of 718 true -> 719 Res = (catch Mod:terminate(Args, State)), 720 report_terminate(Handler, Reason, Args, State, LastIn, SName, Res), 721 Res; 722 false -> 723 report_terminate(Handler, Reason, Args, State, LastIn, SName, ok), 724 ok 725 end. 726 727report_terminate(Handler, crash, {error, Why}, State, LastIn, SName, _) -> 728 report_terminate(Handler, Why, State, LastIn, SName); 729report_terminate(Handler, How, _, State, LastIn, SName, _) -> 730 %% How == normal | shutdown | {swapped, NewHandler, NewSupervisor} 731 report_terminate(Handler, How, State, LastIn, SName). 732 733report_terminate(Handler, Reason, State, LastIn, SName) -> 734 report_error(Handler, Reason, State, LastIn, SName), 735 case Handler#handler.supervised of 736 false -> 737 ok; 738 Pid -> 739 Pid ! {gen_event_EXIT,handler(Handler),Reason}, 740 ok 741 end. 742 743report_error(_Handler, normal, _, _, _) -> ok; 744report_error(_Handler, shutdown, _, _, _) -> ok; 745report_error(_Handler, {swapped,_,_}, _, _, _) -> ok; 746report_error(Handler, Reason, State, LastIn, SName) -> 747 ?LOG_ERROR(#{label=>{gen_event,terminate}, 748 handler=>handler(Handler), 749 name=>SName, 750 last_message=>LastIn, 751 state=>format_status(terminate,Handler#handler.module, 752 get(),State), 753 reason=>Reason}, 754 #{domain=>[otp], 755 report_cb=>fun gen_event:format_log/1, 756 error_logger=>#{tag=>error}}). 757 758format_log(#{label:={gen_event,terminate}, 759 handler:=Handler, 760 name:=SName, 761 last_message:=LastIn, 762 state:=State, 763 reason:=Reason}) -> 764 Reason1 = 765 case Reason of 766 {'EXIT',{undef,[{M,F,A,L}|MFAs]}} -> 767 case code:is_loaded(M) of 768 false -> 769 {'module could not be loaded',[{M,F,A,L}|MFAs]}; 770 _ -> 771 case erlang:function_exported(M, F, length(A)) of 772 true -> 773 {undef,[{M,F,A,L}|MFAs]}; 774 false -> 775 {'function not exported',[{M,F,A,L}|MFAs]} 776 end 777 end; 778 {'EXIT',Why} -> 779 Why; 780 _ -> 781 Reason 782 end, 783 {"** gen_event handler ~p crashed.~n" 784 "** Was installed in ~tp~n" 785 "** Last event was: ~tp~n" 786 "** When handler state == ~tp~n" 787 "** Reason == ~tp~n", 788 [Handler,SName,LastIn,State,Reason1]}; 789format_log(#{label:={gen_event,no_handle_info}, 790 module:=Mod, 791 message:=Msg}) -> 792 {"** Undefined handle_info in ~tp~n" 793 "** Unhandled message: ~tp~n", 794 [Mod, Msg]}. 795 796handler(Handler) when not Handler#handler.id -> 797 Handler#handler.module; 798handler(Handler) -> 799 {Handler#handler.module, Handler#handler.id}. 800 801the_handlers(MSL) -> 802 [handler(Handler) || Handler <- MSL]. 803 804%% stop_handlers(MSL, ServerName) -> [] 805 806stop_handlers([Handler|T], SName) -> 807 Mod = Handler#handler.module, 808 do_terminate(Mod, Handler, stop, Handler#handler.state, 809 stop, SName, shutdown), 810 stop_handlers(T, SName); 811stop_handlers([], _) -> 812 []. 813 814%% Message from the release_handler. 815%% The list of modules got to be a set, i.e. no duplicate elements! 816get_modules(MSL) -> 817 Mods = [Handler#handler.module || Handler <- MSL], 818 ordsets:to_list(ordsets:from_list(Mods)). 819 820%%----------------------------------------------------------------- 821%% Status information 822%%----------------------------------------------------------------- 823format_status(Opt, StatusData) -> 824 [PDict, SysState, Parent, _Debug, [ServerName, MSL, _HibernateAfterTimeout, _Hib]] = StatusData, 825 Header = gen:format_status_header("Status for event handler", 826 ServerName), 827 FmtMSL = [MS#handler{state=format_status(Opt, Mod, PDict, State)} 828 || #handler{module = Mod, state = State} = MS <- MSL], 829 [{header, Header}, 830 {data, [{"Status", SysState}, 831 {"Parent", Parent}]}, 832 {items, {"Installed handlers", FmtMSL}}]. 833 834format_status(Opt, Mod, PDict, State) -> 835 case erlang:function_exported(Mod, format_status, 2) of 836 true -> 837 Args = [PDict, State], 838 case catch Mod:format_status(Opt, Args) of 839 {'EXIT', _} -> State; 840 Else -> Else 841 end; 842 false -> 843 State 844 end. 845