1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1996-2019. 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%%% NOTE: If init_ack() return values are modified, see comment 36%%% above monitor_return() in gen.erl! 37%%% 38 39-export([start/0, start/1, start/2, 40 start_link/0, start_link/1, start_link/2, 41 start_monitor/0, start_monitor/1, start_monitor/2, 42 stop/1, stop/3, 43 notify/2, sync_notify/2, 44 add_handler/3, add_sup_handler/3, delete_handler/3, swap_handler/3, 45 swap_sup_handler/3, which_handlers/1, call/3, call/4, 46 send_request/3, wait_response/2, check_response/2, 47 wake_hib/5]). 48 49-export([init_it/6, 50 system_continue/3, 51 system_terminate/4, 52 system_code_change/4, 53 system_get_state/1, 54 system_replace_state/2, 55 format_status/2]). 56 57%% logger callback 58-export([format_log/1, format_log/2]). 59 60-export_type([handler/0, handler_args/0, add_handler_ret/0, 61 del_handler_ret/0]). 62 63-record(handler, {module :: atom(), 64 id = false, 65 state, 66 supervised = false :: 'false' | pid()}). 67 68-include("logger.hrl"). 69 70%%%========================================================================= 71%%% API 72%%%========================================================================= 73 74%% gen_event:start(Handler) -> {ok, Pid} | {error, What} 75%% gen_event:add_handler(Handler, Mod, Args) -> ok | Other 76%% gen_event:notify(Handler, Event) -> ok 77%% gen_event:call(Handler, Mod, Query) -> {ok, Val} | {error, Why} 78%% gen_event:call(Handler, Mod, Query, Timeout) -> {ok, Val} | {error, Why} 79%% gen_event:delete_handler(Handler, Mod, Args) -> Val 80%% gen_event:swap_handler(Handler, {OldMod, Args1}, {NewMod, Args2}) -> ok 81%% gen_event:which_handler(Handler) -> [Mod] 82%% gen_event:stop(Handler) -> ok 83 84-callback init(InitArgs :: term()) -> 85 {ok, State :: term()} | 86 {ok, State :: term(), hibernate} | 87 {error, Reason :: term()}. 88-callback handle_event(Event :: term(), State :: term()) -> 89 {ok, NewState :: term()} | 90 {ok, NewState :: term(), hibernate} | 91 {swap_handler, Args1 :: term(), NewState :: term(), 92 Handler2 :: (atom() | {atom(), Id :: term()}), Args2 :: term()} | 93 remove_handler. 94-callback handle_call(Request :: term(), State :: term()) -> 95 {ok, Reply :: term(), NewState :: term()} | 96 {ok, Reply :: term(), NewState :: term(), hibernate} | 97 {swap_handler, Reply :: term(), Args1 :: term(), NewState :: term(), 98 Handler2 :: (atom() | {atom(), Id :: term()}), Args2 :: term()} | 99 {remove_handler, Reply :: term()}. 100-callback handle_info(Info :: term(), State :: term()) -> 101 {ok, NewState :: term()} | 102 {ok, NewState :: term(), hibernate} | 103 {swap_handler, Args1 :: term(), NewState :: term(), 104 Handler2 :: (atom() | {atom(), Id :: term()}), Args2 :: term()} | 105 remove_handler. 106-callback terminate(Args :: (term() | {stop, Reason :: term()} | 107 stop | remove_handler | 108 {error, {'EXIT', Reason :: term()}} | 109 {error, term()}), 110 State :: term()) -> 111 term(). 112-callback code_change(OldVsn :: (term() | {down, term()}), 113 State :: term(), Extra :: term()) -> 114 {ok, NewState :: term()}. 115-callback format_status(Opt, StatusData) -> Status when 116 Opt :: 'normal' | 'terminate', 117 StatusData :: [PDict | State], 118 PDict :: [{Key :: term(), Value :: term()}], 119 State :: term(), 120 Status :: term(). 121 122-optional_callbacks( 123 [handle_info/2, terminate/2, code_change/3, format_status/2]). 124 125%%--------------------------------------------------------------------------- 126 127-type handler() :: atom() | {atom(), term()}. 128-type handler_args() :: term(). 129-type add_handler_ret() :: ok | term() | {'EXIT',term()}. 130-type del_handler_ret() :: ok | term() | {'EXIT',term()}. 131 132-type emgr_name() :: {'local', atom()} | {'global', term()} 133 | {'via', atom(), term()}. 134-type debug_flag() :: 'trace' | 'log' | 'statistics' | 'debug' 135 | {'logfile', string()}. 136-type option() :: {'timeout', timeout()} 137 | {'debug', [debug_flag()]} 138 | {'spawn_opt', [proc_lib:start_spawn_option()]} 139 | {'hibernate_after', timeout()}. 140-type emgr_ref() :: atom() | {atom(), atom()} | {'global', term()} 141 | {'via', atom(), term()} | pid(). 142-type start_ret() :: {'ok', pid()} | {'error', term()}. 143-type start_mon_ret() :: {'ok', {pid(),reference()}} | {'error', term()}. 144-type request_id() :: term(). 145 146%%--------------------------------------------------------------------------- 147 148-define(NO_CALLBACK, 'no callback module'). 149 150%% ----------------------------------------------------------------- 151%% Starts a generic event handler. 152%% start() 153%% start(MgrName | Options) 154%% start(MgrName, Options) 155%% start_link() 156%% start_link(MgrName | Options) 157%% start_link(MgrName, Options) 158%% MgrName ::= {local, atom()} | {global, term()} | {via, atom(), term()} 159%% Options ::= [{timeout, Timeout} | {debug, [Flag]} | {spawn_opt,SOpts}] 160%% Flag ::= trace | log | {logfile, File} | statistics | debug 161%% (debug == log && statistics) 162%% Returns: {ok, Pid} | 163%% {error, {already_started, Pid}} | 164%% {error, Reason} 165%% ----------------------------------------------------------------- 166 167-spec start() -> start_ret(). 168start() -> 169 gen:start(?MODULE, nolink, ?NO_CALLBACK, [], []). 170 171-spec start(emgr_name() | [option()]) -> start_ret(). 172start(Name) when is_tuple(Name) -> 173 gen:start(?MODULE, nolink, Name, ?NO_CALLBACK, [], []); 174start(Options) when is_list(Options) -> 175 gen:start(?MODULE, nolink, ?NO_CALLBACK, [], Options). 176 177-spec start(emgr_name(), [option()]) -> start_ret(). 178start(Name, Options) -> 179 gen:start(?MODULE, nolink, Name, ?NO_CALLBACK, [], Options). 180 181-spec start_link() -> start_ret(). 182start_link() -> 183 gen:start(?MODULE, link, ?NO_CALLBACK, [], []). 184 185-spec start_link(emgr_name() | [option()]) -> start_ret(). 186start_link(Name) when is_tuple(Name) -> 187 gen:start(?MODULE, link, Name, ?NO_CALLBACK, [], []); 188start_link(Options) when is_list(Options) -> 189 gen:start(?MODULE, link, ?NO_CALLBACK, [], Options). 190 191-spec start_link(emgr_name(), [option()]) -> start_ret(). 192start_link(Name, Options) -> 193 gen:start(?MODULE, link, Name, ?NO_CALLBACK, [], Options). 194 195-spec start_monitor() -> start_mon_ret(). 196start_monitor() -> 197 gen:start(?MODULE, monitor, ?NO_CALLBACK, [], []). 198 199-spec start_monitor(emgr_name() | [option()]) -> start_mon_ret(). 200start_monitor(Name) when is_tuple(Name) -> 201 gen:start(?MODULE, monitor, Name, ?NO_CALLBACK, [], []); 202start_monitor(Options) when is_list(Options) -> 203 gen:start(?MODULE, monitor, ?NO_CALLBACK, [], Options). 204 205-spec start_monitor(emgr_name(), [option()]) -> start_mon_ret(). 206start_monitor(Name, Options) -> 207 gen:start(?MODULE, monitor, Name, ?NO_CALLBACK, [], Options). 208 209%% -spec init_it(pid(), 'self' | pid(), emgr_name(), module(), [term()], [_]) -> 210init_it(Starter, self, Name, Mod, Args, Options) -> 211 init_it(Starter, self(), Name, Mod, Args, Options); 212init_it(Starter, Parent, Name0, _, _, Options) -> 213 process_flag(trap_exit, true), 214 Name = gen:name(Name0), 215 Debug = gen:debug_options(Name, Options), 216 HibernateAfterTimeout = gen:hibernate_after(Options), 217 proc_lib:init_ack(Starter, {ok, self()}), 218 loop(Parent, Name, [], HibernateAfterTimeout, Debug, false). 219 220-spec add_handler(emgr_ref(), handler(), term()) -> term(). 221add_handler(M, Handler, Args) -> rpc(M, {add_handler, Handler, Args}). 222 223-spec add_sup_handler(emgr_ref(), handler(), term()) -> term(). 224add_sup_handler(M, Handler, Args) -> 225 rpc(M, {add_sup_handler, Handler, Args, self()}). 226 227-spec notify(emgr_ref(), term()) -> 'ok'. 228notify(M, Event) -> send(M, {notify, Event}). 229 230-spec sync_notify(emgr_ref(), term()) -> 'ok'. 231sync_notify(M, Event) -> rpc(M, {sync_notify, Event}). 232 233-spec call(emgr_ref(), handler(), term()) -> term(). 234call(M, Handler, Query) -> call1(M, Handler, Query). 235 236-spec call(emgr_ref(), handler(), term(), timeout()) -> term(). 237call(M, Handler, Query, Timeout) -> call1(M, Handler, Query, Timeout). 238 239-spec send_request(emgr_ref(), handler(), term()) -> request_id(). 240send_request(M, Handler, Query) -> 241 gen:send_request(M, self(), {call, Handler, Query}). 242 243-spec wait_response(RequestId::request_id(), timeout()) -> 244 {reply, Reply::term()} | 'timeout' | {error, {Reason::term(), emgr_ref()}}. 245wait_response(RequestId, Timeout) -> 246 case gen:wait_response(RequestId, Timeout) of 247 {reply, {error, _} = Err} -> Err; 248 Return -> Return 249 end. 250 251-spec check_response(Msg::term(), RequestId::request_id()) -> 252 {reply, Reply::term()} | 'no_reply' | {error, {Reason::term(), emgr_ref()}}. 253check_response(Msg, RequestId) -> 254 case gen:check_response(Msg, RequestId) of 255 {reply, {error, _} = Err} -> Err; 256 Return -> Return 257 end. 258 259-spec delete_handler(emgr_ref(), handler(), term()) -> term(). 260delete_handler(M, Handler, Args) -> rpc(M, {delete_handler, Handler, Args}). 261 262-spec swap_handler(emgr_ref(), {handler(), term()}, {handler(), term()}) -> 263 'ok' | {'error', term()}. 264swap_handler(M, {H1, A1}, {H2, A2}) -> rpc(M, {swap_handler, H1, A1, H2, A2}). 265 266-spec swap_sup_handler(emgr_ref(), {handler(), term()}, {handler(), term()}) -> 267 'ok' | {'error', term()}. 268swap_sup_handler(M, {H1, A1}, {H2, A2}) -> 269 rpc(M, {swap_sup_handler, H1, A1, H2, A2, self()}). 270 271-spec which_handlers(emgr_ref()) -> [handler()]. 272which_handlers(M) -> rpc(M, which_handlers). 273 274-spec stop(emgr_ref()) -> 'ok'. 275stop(M) -> 276 gen:stop(M). 277 278stop(M, Reason, Timeout) -> 279 gen:stop(M, Reason, Timeout). 280 281rpc(M, Cmd) -> 282 {ok, Reply} = gen:call(M, self(), Cmd, infinity), 283 Reply. 284 285call1(M, Handler, Query) -> 286 Cmd = {call, Handler, Query}, 287 try gen:call(M, self(), Cmd) of 288 {ok, Res} -> 289 Res 290 catch 291 exit:Reason -> 292 exit({Reason, {?MODULE, call, [M, Handler, Query]}}) 293 end. 294 295call1(M, Handler, Query, Timeout) -> 296 Cmd = {call, Handler, Query}, 297 try gen:call(M, self(), Cmd, Timeout) of 298 {ok, Res} -> 299 Res 300 catch 301 exit:Reason -> 302 exit({Reason, {?MODULE, call, [M, Handler, Query, Timeout]}}) 303 end. 304 305send({global, Name}, Cmd) -> 306 catch global:send(Name, Cmd), 307 ok; 308send({via, Mod, Name}, Cmd) -> 309 catch Mod:send(Name, Cmd), 310 ok; 311send(M, Cmd) -> 312 M ! Cmd, 313 ok. 314 315loop(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, true) -> 316 proc_lib:hibernate(?MODULE, wake_hib, [Parent, ServerName, MSL, HibernateAfterTimeout, Debug]); 317loop(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, _) -> 318 fetch_msg(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, false). 319 320wake_hib(Parent, ServerName, MSL, HibernateAfterTimeout, Debug) -> 321 fetch_msg(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, true). 322 323fetch_msg(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, Hib) -> 324 receive 325 {system, From, Req} -> 326 sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug, 327 [ServerName, MSL, HibernateAfterTimeout, Hib],Hib); 328 {'EXIT', Parent, Reason} -> 329 terminate_server(Reason, Parent, MSL, ServerName); 330 Msg when Debug =:= [] -> 331 handle_msg(Msg, Parent, ServerName, MSL, HibernateAfterTimeout, []); 332 Msg -> 333 Debug1 = sys:handle_debug(Debug, fun print_event/3, 334 ServerName, {in, Msg}), 335 handle_msg(Msg, Parent, ServerName, MSL, HibernateAfterTimeout, Debug1) 336 after HibernateAfterTimeout -> 337 loop(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, true) 338 end. 339 340handle_msg(Msg, Parent, ServerName, MSL, HibernateAfterTimeout, Debug) -> 341 case Msg of 342 {notify, Event} -> 343 {Hib,MSL1} = server_notify(Event, handle_event, MSL, ServerName), 344 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, Hib); 345 {_From, Tag, {sync_notify, Event}} -> 346 {Hib, MSL1} = server_notify(Event, handle_event, MSL, ServerName), 347 reply(Tag, ok), 348 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, Hib); 349 {'EXIT', From, Reason} -> 350 MSL1 = handle_exit(From, Reason, MSL, ServerName), 351 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, false); 352 {_From, Tag, {call, Handler, Query}} -> 353 {Hib, Reply, MSL1} = server_call(Handler, Query, MSL, ServerName), 354 reply(Tag, Reply), 355 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, Hib); 356 {_From, Tag, {add_handler, Handler, Args}} -> 357 {Hib, Reply, MSL1} = server_add_handler(Handler, Args, MSL), 358 reply(Tag, Reply), 359 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, Hib); 360 {_From, Tag, {add_sup_handler, Handler, Args, SupP}} -> 361 {Hib, Reply, MSL1} = server_add_sup_handler(Handler, Args, MSL, SupP), 362 reply(Tag, Reply), 363 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, Hib); 364 {_From, Tag, {delete_handler, Handler, Args}} -> 365 {Reply, MSL1} = server_delete_handler(Handler, Args, MSL, 366 ServerName), 367 reply(Tag, Reply), 368 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, false); 369 {_From, Tag, {swap_handler, Handler1, Args1, Handler2, Args2}} -> 370 {Hib, Reply, MSL1} = server_swap_handler(Handler1, Args1, Handler2, 371 Args2, MSL, ServerName), 372 reply(Tag, Reply), 373 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, Hib); 374 {_From, Tag, {swap_sup_handler, Handler1, Args1, Handler2, Args2, 375 Sup}} -> 376 {Hib, Reply, MSL1} = server_swap_handler(Handler1, Args1, Handler2, 377 Args2, MSL, Sup, ServerName), 378 reply(Tag, Reply), 379 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, Hib); 380 {_From, Tag, stop} -> 381 catch terminate_server(normal, Parent, MSL, ServerName), 382 reply(Tag, ok); 383 {_From, Tag, which_handlers} -> 384 reply(Tag, the_handlers(MSL)), 385 loop(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, false); 386 {_From, Tag, get_modules} -> 387 reply(Tag, get_modules(MSL)), 388 loop(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, false); 389 Other -> 390 {Hib, MSL1} = server_notify(Other, handle_info, MSL, ServerName), 391 loop(Parent, ServerName, MSL1, HibernateAfterTimeout, Debug, Hib) 392 end. 393 394terminate_server(Reason, Parent, MSL, ServerName) -> 395 stop_handlers(MSL, ServerName), 396 do_unlink(Parent, MSL), 397 exit(Reason). 398 399reply({From, Ref}, Msg) -> 400 From ! {Ref, Msg}, 401 ok. 402 403%% unlink the supervisor process of all supervised handlers. 404%% We do not want a handler supervisor to EXIT due to the 405%% termination of the event manager (server). 406%% Do not unlink Parent ! 407do_unlink(Parent, MSL) -> 408 lists:foreach(fun(Handler) when Handler#handler.supervised =:= Parent -> 409 true; 410 (Handler) when is_pid(Handler#handler.supervised) -> 411 unlink(Handler#handler.supervised), 412 true; 413 (_) -> 414 true 415 end, 416 MSL). 417 418%% First terminate the supervised (if exists) handlers and 419%% then inform other handlers. 420%% We do not know if any handler really is interested but it 421%% may be so ! 422handle_exit(From, Reason, MSL, SName) -> 423 MSL1 = terminate_supervised(From, Reason, MSL, SName), 424 {_,MSL2}=server_notify({'EXIT', From, Reason}, handle_info, MSL1, SName), 425 MSL2. 426 427terminate_supervised(Pid, Reason, MSL, SName) -> 428 F = fun(Ha) when Ha#handler.supervised =:= Pid -> 429 do_terminate(Ha#handler.module, 430 Ha, 431 {stop,Reason}, 432 Ha#handler.state, 433 {parent_terminated, {Pid,Reason}}, 434 SName, 435 shutdown), 436 false; 437 (_) -> 438 true 439 end, 440 lists:filter(F, MSL). 441 442%%----------------------------------------------------------------- 443%% Callback functions for system messages handling. 444%%----------------------------------------------------------------- 445system_continue(Parent, Debug, [ServerName, MSL, HibernateAfterTimeout, Hib]) -> 446 loop(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, Hib). 447 448-spec system_terminate(_, _, _, [_]) -> no_return(). 449system_terminate(Reason, Parent, _Debug, [ServerName, MSL, _HibernateAfterTimeout, _Hib]) -> 450 terminate_server(Reason, Parent, MSL, ServerName). 451 452%%----------------------------------------------------------------- 453%% Module here is sent in the system msg change_code. It specifies 454%% which module should be changed. 455%%----------------------------------------------------------------- 456system_code_change([ServerName, MSL, HibernateAfterTimeout, Hib], Module, OldVsn, Extra) -> 457 MSL1 = lists:zf(fun(H) when H#handler.module =:= Module -> 458 {ok, NewState} = 459 Module:code_change(OldVsn, 460 H#handler.state, Extra), 461 {true, H#handler{state = NewState}}; 462 (_) -> true 463 end, 464 MSL), 465 {ok, [ServerName, MSL1, HibernateAfterTimeout, Hib]}. 466 467system_get_state([_ServerName, MSL, _HibernateAfterTimeout, _Hib]) -> 468 {ok, [{Mod,Id,State} || #handler{module=Mod, id=Id, state=State} <- MSL]}. 469 470system_replace_state(StateFun, [ServerName, MSL, HibernateAfterTimeout, Hib]) -> 471 {NMSL, NStates} = 472 lists:unzip([begin 473 Cur = {Mod,Id,State}, 474 try 475 NState = {Mod,Id,NS} = StateFun(Cur), 476 {HS#handler{state=NS}, NState} 477 catch 478 _:_ -> 479 {HS, Cur} 480 end 481 end || #handler{module=Mod, id=Id, state=State}=HS <- MSL]), 482 {ok, NStates, [ServerName, NMSL, HibernateAfterTimeout, Hib]}. 483 484%%----------------------------------------------------------------- 485%% Format debug messages. Print them as the call-back module sees 486%% them, not as the real erlang messages. Use trace for that. 487%%----------------------------------------------------------------- 488print_event(Dev, {in, Msg}, Name) -> 489 case Msg of 490 {notify, Event} -> 491 io:format(Dev, "*DBG* ~tp got event ~tp~n", [Name, Event]); 492 {_,_,{call, Handler, Query}} -> 493 io:format(Dev, "*DBG* ~tp(~tp) got call ~tp~n", 494 [Name, Handler, Query]); 495 _ -> 496 io:format(Dev, "*DBG* ~tp got ~tp~n", [Name, Msg]) 497 end; 498print_event(Dev, Dbg, Name) -> 499 io:format(Dev, "*DBG* ~tp : ~tp~n", [Name, Dbg]). 500 501 502%% server_add_handler(Handler, Args, MSL) -> {Ret, MSL'}. 503%% where MSL = [#handler{}] 504%% Ret goes to the top level MSL' is the new internal state of the 505%% event handler 506 507server_add_handler({Mod,Id}, Args, MSL) -> 508 Handler = #handler{module = Mod, 509 id = Id}, 510 server_add_handler(Mod, Handler, Args, MSL); 511server_add_handler(Mod, Args, MSL) -> 512 Handler = #handler{module = Mod}, 513 server_add_handler(Mod, Handler, Args, MSL). 514 515server_add_handler(Mod, Handler, Args, MSL) -> 516 case catch Mod:init(Args) of 517 {ok, State} -> 518 {false, ok, [Handler#handler{state = State}|MSL]}; 519 {ok, State, hibernate} -> 520 {true, ok, [Handler#handler{state = State}|MSL]}; 521 Other -> 522 {false, Other, MSL} 523 end. 524 525%% Set up a link to the supervising process. 526%% (Ought to be unidirected links here, Erl5.0 !!) 527%% NOTE: This link will not be removed then the 528%% handler is removed in case another handler has 529%% own link to this process. 530server_add_sup_handler({Mod,Id}, Args, MSL, Parent) -> 531 link(Parent), 532 Handler = #handler{module = Mod, 533 id = Id, 534 supervised = Parent}, 535 server_add_handler(Mod, Handler, Args, MSL); 536server_add_sup_handler(Mod, Args, MSL, Parent) -> 537 link(Parent), 538 Handler = #handler{module = Mod, 539 supervised = Parent}, 540 server_add_handler(Mod, Handler, Args, MSL). 541 542%% server_delete_handler(HandlerId, Args, MSL) -> {Ret, MSL'} 543 544server_delete_handler(HandlerId, Args, MSL, SName) -> 545 case split(HandlerId, MSL) of 546 {Mod, Handler, MSL1} -> 547 {do_terminate(Mod, Handler, Args, 548 Handler#handler.state, delete, SName, normal), 549 MSL1}; 550 error -> 551 {{error, module_not_found}, MSL} 552 end. 553 554%% server_swap_handler(Handler1, Args1, Handler2, Args2, MSL, SN) -> MSL' 555%% server_swap_handler(Handler1, Args1, Handler2, Args2, MSL, Sup, SN) -> MSL' 556 557server_swap_handler(Handler1, Args1, Handler2, Args2, MSL, SName) -> 558 {State2, Sup, MSL1} = split_and_terminate(Handler1, Args1, MSL, 559 SName, Handler2, false), 560 case s_s_h(Sup, Handler2, {Args2, State2}, MSL1) of 561 {Hib, ok, MSL2} -> 562 {Hib, ok, MSL2}; 563 {Hib, What, MSL2} -> 564 {Hib, {error, What}, MSL2} 565 end. 566 567server_swap_handler(Handler1, Args1, Handler2, Args2, MSL, Sup, SName) -> 568 {State2, _, MSL1} = split_and_terminate(Handler1, Args1, MSL, 569 SName, Handler2, Sup), 570 case s_s_h(Sup, Handler2, {Args2, State2}, MSL1) of 571 {Hib, ok, MSL2} -> 572 {Hib, ok, MSL2}; 573 {Hib, What, MSL2} -> 574 {Hib, {error, What}, MSL2} 575 end. 576 577s_s_h(false, Handler, Args, MSL) -> 578 server_add_handler(Handler, Args, MSL); 579s_s_h(Pid, Handler, Args, MSL) -> 580 server_add_sup_handler(Handler, Args, MSL, Pid). 581 582split_and_terminate(HandlerId, Args, MSL, SName, Handler2, Sup) -> 583 case split(HandlerId, MSL) of 584 {Mod, Handler, MSL1} -> 585 OldSup = Handler#handler.supervised, 586 NewSup = if 587 not Sup -> OldSup; 588 true -> Sup 589 end, 590 {do_terminate(Mod, Handler, Args, 591 Handler#handler.state, swapped, SName, 592 {swapped, Handler2, NewSup}), 593 OldSup, 594 MSL1}; 595 error -> 596 {error, false, MSL} 597 end. 598 599%% server_notify(Event, Func, MSL, SName) -> MSL' 600 601server_notify(Event, Func, [Handler|T], SName) -> 602 case server_update(Handler, Func, Event, SName) of 603 {ok, Handler1} -> 604 {Hib, NewHandlers} = server_notify(Event, Func, T, SName), 605 {Hib, [Handler1|NewHandlers]}; 606 {hibernate, Handler1} -> 607 {_Hib, NewHandlers} = server_notify(Event, Func, T, SName), 608 {true, [Handler1|NewHandlers]}; 609 no -> 610 server_notify(Event, Func, T, SName) 611 end; 612server_notify(_, _, [], _) -> 613 {false, []}. 614 615%% server_update(Handler, Func, Event, ServerName) -> Handler1 | no 616 617server_update(Handler1, Func, Event, SName) -> 618 Mod1 = Handler1#handler.module, 619 State = Handler1#handler.state, 620 case catch Mod1:Func(Event, State) of 621 {ok, State1} -> 622 {ok, Handler1#handler{state = State1}}; 623 {ok, State1, hibernate} -> 624 {hibernate, Handler1#handler{state = State1}}; 625 {swap_handler, Args1, State1, Handler2, Args2} -> 626 do_swap(Mod1, Handler1, Args1, State1, Handler2, Args2, SName); 627 remove_handler -> 628 do_terminate(Mod1, Handler1, remove_handler, State, 629 remove, SName, normal), 630 no; 631 {'EXIT', {undef, [{Mod1, handle_info, [_,_], _}|_]}} -> 632 ?LOG_WARNING(#{label=>{gen_event,no_handle_info}, 633 module=>Mod1, 634 message=>Event}, 635 #{domain=>[otp], 636 report_cb=>fun gen_event:format_log/2, 637 error_logger=> 638 #{tag=>warning_msg, % warningmap?? 639 report_cb=>fun gen_event:format_log/1}}), 640 {ok, Handler1}; 641 Other -> 642 do_terminate(Mod1, Handler1, {error, Other}, State, 643 Event, SName, crash), 644 no 645 end. 646 647do_swap(Mod1, Handler1, Args1, State1, Handler2, Args2, SName) -> 648 %% finalise the existing handler 649 State2 = do_terminate(Mod1, Handler1, Args1, State1, 650 swapped, SName, 651 {swapped, Handler2, Handler1#handler.supervised}), 652 {Mod2, Handler} = new_handler(Handler2, Handler1), 653 case catch Mod2:init({Args2, State2}) of 654 {ok, State2a} -> 655 {ok, Handler#handler{state = State2a}}; 656 Other -> 657 report_terminate(Handler, crash, {error, Other}, SName, false), 658 no 659 end. 660 661new_handler({Mod,Id}, Handler1) -> 662 {Mod, #handler{module = Mod, 663 id = Id, 664 supervised = Handler1#handler.supervised}}; 665new_handler(Mod, Handler1) -> 666 {Mod, #handler{module = Mod, 667 supervised = Handler1#handler.supervised}}. 668 669 670-spec split(handler(), [#handler{}]) -> 671 {atom(), #handler{}, [#handler{}]} | 'error'. 672 673split(Ha, MSL) -> split(Ha, MSL, []). 674 675split({Mod,Id}, [Ha|T], L) when Ha#handler.module =:= Mod, 676 Ha#handler.id =:= Id -> 677 {Mod, Ha, lists:reverse(L, T)}; 678split(Mod, [Ha|T], L) when Ha#handler.module =:= Mod, 679 not Ha#handler.id -> 680 {Mod, Ha, lists:reverse(L, T)}; 681split(Ha, [H|T], L) -> 682 split(Ha, T, [H|L]); 683split(_, [], _) -> 684 error. 685 686%% server_call(Handler, Query, MSL, ServerName) -> 687%% {Reply, MSL1} 688 689server_call(Handler, Query, MSL, SName) -> 690 case search(Handler, MSL) of 691 {ok, Ha} -> 692 case server_call_update(Ha, Query, SName) of 693 {no, Reply} -> 694 {false, Reply, delete(Handler, MSL)}; 695 {{ok, Ha1}, Reply} -> 696 {false, Reply, replace(Handler, MSL, Ha1)}; 697 {{hibernate, Ha1}, Reply} -> 698 {true, Reply, replace(Handler, MSL, Ha1)} 699 end; 700 false -> 701 {false, {error, bad_module}, MSL} 702 end. 703 704search({Mod, Id}, [Ha|_MSL]) when Ha#handler.module =:= Mod, 705 Ha#handler.id =:= Id -> 706 {ok, Ha}; 707search(Mod, [Ha|_MSL]) when Ha#handler.module =:= Mod, 708 not Ha#handler.id -> 709 {ok, Ha}; 710search(Handler, [_|MSL]) -> 711 search(Handler, MSL); 712search(_, []) -> 713 false. 714 715delete({Mod, Id}, [Ha|MSL]) when Ha#handler.module =:= Mod, 716 Ha#handler.id =:= Id -> 717 MSL; 718delete(Mod, [Ha|MSL]) when Ha#handler.module =:= Mod, 719 not Ha#handler.id -> 720 MSL; 721delete(Handler, [Ha|MSL]) -> 722 [Ha|delete(Handler, MSL)]; 723delete(_, []) -> 724 []. 725 726replace({Mod, Id}, [Ha|MSL], NewHa) when Ha#handler.module =:= Mod, 727 Ha#handler.id =:= Id -> 728 [NewHa|MSL]; 729replace(Mod, [Ha|MSL], NewHa) when Ha#handler.module =:= Mod, 730 not Ha#handler.id -> 731 [NewHa|MSL]; 732replace(Handler, [Ha|MSL], NewHa) -> 733 [Ha|replace(Handler, MSL, NewHa)]; 734replace(_, [], NewHa) -> 735 [NewHa]. 736 737%% server_call_update(Handler, Query, ServerName) -> 738%% {{Handler1, State1} | 'no', Reply} 739 740server_call_update(Handler1, Query, SName) -> 741 Mod1 = Handler1#handler.module, 742 State = Handler1#handler.state, 743 case catch Mod1:handle_call(Query, State) of 744 {ok, Reply, State1} -> 745 {{ok, Handler1#handler{state = State1}}, Reply}; 746 {ok, Reply, State1, hibernate} -> 747 {{hibernate, Handler1#handler{state = State1}}, 748 Reply}; 749 {swap_handler, Reply, Args1, State1, Handler2, Args2} -> 750 {do_swap(Mod1,Handler1,Args1,State1,Handler2,Args2,SName), Reply}; 751 {remove_handler, Reply} -> 752 do_terminate(Mod1, Handler1, remove_handler, State, 753 remove, SName, normal), 754 {no, Reply}; 755 Other -> 756 do_terminate(Mod1, Handler1, {error, Other}, State, 757 Query, SName, crash), 758 {no, {error, Other}} 759 end. 760 761do_terminate(Mod, Handler, Args, State, LastIn, SName, Reason) -> 762 case erlang:function_exported(Mod, terminate, 2) of 763 true -> 764 Res = (catch Mod:terminate(Args, State)), 765 report_terminate(Handler, Reason, Args, State, LastIn, SName, Res), 766 Res; 767 false -> 768 report_terminate(Handler, Reason, Args, State, LastIn, SName, ok), 769 ok 770 end. 771 772report_terminate(Handler, crash, {error, Why}, State, LastIn, SName, _) -> 773 report_terminate(Handler, Why, State, LastIn, SName); 774report_terminate(Handler, How, _, State, LastIn, SName, _) -> 775 %% How == normal | shutdown | {swapped, NewHandler, NewSupervisor} 776 report_terminate(Handler, How, State, LastIn, SName). 777 778report_terminate(Handler, Reason, State, LastIn, SName) -> 779 report_error(Handler, Reason, State, LastIn, SName), 780 case Handler#handler.supervised of 781 false -> 782 ok; 783 Pid -> 784 Pid ! {gen_event_EXIT,handler(Handler),Reason}, 785 ok 786 end. 787 788report_error(_Handler, normal, _, _, _) -> ok; 789report_error(_Handler, shutdown, _, _, _) -> ok; 790report_error(_Handler, {swapped,_,_}, _, _, _) -> ok; 791report_error(Handler, Reason, State, LastIn, SName) -> 792 ?LOG_ERROR(#{label=>{gen_event,terminate}, 793 handler=>handler(Handler), 794 name=>SName, 795 last_message=>LastIn, 796 state=>format_status(terminate,Handler#handler.module, 797 get(),State), 798 reason=>Reason}, 799 #{domain=>[otp], 800 report_cb=>fun gen_event:format_log/2, 801 error_logger=>#{tag=>error, 802 report_cb=>fun gen_event:format_log/1}}). 803 804%% format_log/1 is the report callback used by Logger handler 805%% error_logger only. It is kept for backwards compatibility with 806%% legacy error_logger event handlers. This function must always 807%% return {Format,Args} compatible with the arguments in this module's 808%% calls to error_logger prior to OTP-21.0. 809format_log(Report) -> 810 Depth = error_logger:get_format_depth(), 811 FormatOpts = #{chars_limit => unlimited, 812 depth => Depth, 813 single_line => false, 814 encoding => utf8}, 815 format_log_multi(limit_report(Report, Depth), FormatOpts). 816 817limit_report(Report, unlimited) -> 818 Report; 819limit_report(#{label:={gen_event,terminate}, 820 last_message:=LastIn, 821 state:=State, 822 reason:=Reason}=Report, 823 Depth) -> 824 Report#{last_message => io_lib:limit_term(LastIn, Depth), 825 state => io_lib:limit_term(State, Depth), 826 reason => io_lib:limit_term(Reason, Depth)}; 827limit_report(#{label:={gen_event,no_handle_info}, 828 message:=Msg}=Report, 829 Depth) -> 830 Report#{message => io_lib:limit_term(Msg, Depth)}. 831 832%% format_log/2 is the report callback for any Logger handler, except 833%% error_logger. 834format_log(Report, FormatOpts0) -> 835 Default = #{chars_limit => unlimited, 836 depth => unlimited, 837 single_line => false, 838 encoding => utf8}, 839 FormatOpts = maps:merge(Default, FormatOpts0), 840 IoOpts = 841 case FormatOpts of 842 #{chars_limit:=unlimited} -> 843 []; 844 #{chars_limit:=Limit} -> 845 [{chars_limit,Limit}] 846 end, 847 {Format,Args} = format_log_single(Report, FormatOpts), 848 io_lib:format(Format, Args, IoOpts). 849 850format_log_single(#{label:={gen_event,terminate}, 851 handler:=Handler, 852 name:=SName, 853 last_message:=LastIn, 854 state:=State, 855 reason:=Reason}, 856 #{single_line:=true, depth:=Depth}=FormatOpts) -> 857 P = p(FormatOpts), 858 Reason1 = fix_reason(Reason), 859 Format1 = lists:append(["Generic event handler ",P," crashed. " 860 "Installed: ",P,". Last event: ",P, 861 ". State: ",P,". Reason: ",P,"."]), 862 Args1 = 863 case Depth of 864 unlimited -> 865 [Handler,SName,Reason1,LastIn,State]; 866 _ -> 867 [Handler,Depth,SName,Depth,Reason1,Depth, 868 LastIn,Depth,State,Depth] 869 end, 870 {Format1, Args1}; 871format_log_single(#{label:={gen_event,no_handle_info}, 872 module:=Mod, 873 message:=Msg}, 874 #{single_line:=true,depth:=Depth}=FormatOpts) -> 875 P = p(FormatOpts), 876 Format = lists:append(["Undefined handle_info in ",P, 877 ". Unhandled message: ",P,"."]), 878 Args = 879 case Depth of 880 unlimited -> 881 [Mod,Msg]; 882 _ -> 883 [Mod,Depth,Msg,Depth] 884 end, 885 {Format,Args}; 886format_log_single(Report,FormatOpts) -> 887 format_log_multi(Report,FormatOpts). 888 889format_log_multi(#{label:={gen_event,terminate}, 890 handler:=Handler, 891 name:=SName, 892 last_message:=LastIn, 893 state:=State, 894 reason:=Reason}, 895 #{depth:=Depth}=FormatOpts) -> 896 Reason1 = fix_reason(Reason), 897 P = p(FormatOpts), 898 Format = 899 lists:append(["** gen_event handler ",P," crashed.\n", 900 "** Was installed in ",P,"\n", 901 "** Last event was: ",P,"\n", 902 "** When handler state == ",P,"\n", 903 "** Reason == ",P,"\n"]), 904 Args = 905 case Depth of 906 unlimited -> 907 [Handler,SName,LastIn,State,Reason1]; 908 _ -> 909 [Handler,Depth,SName,Depth,LastIn,Depth,State,Depth, 910 Reason1,Depth] 911 end, 912 {Format,Args}; 913format_log_multi(#{label:={gen_event,no_handle_info}, 914 module:=Mod, 915 message:=Msg}, 916 #{depth:=Depth}=FormatOpts) -> 917 P = p(FormatOpts), 918 Format = 919 "** Undefined handle_info in ~p\n" 920 "** Unhandled message: "++P++"\n", 921 Args = 922 case Depth of 923 unlimited -> 924 [Mod,Msg]; 925 _ -> 926 [Mod,Msg,Depth] 927 end, 928 {Format,Args}. 929 930fix_reason({'EXIT',{undef,[{M,F,A,_L}|_]=MFAs}=Reason}) -> 931 case code:is_loaded(M) of 932 false -> 933 {'module could not be loaded',MFAs}; 934 _ -> 935 case erlang:function_exported(M, F, length(A)) of 936 true -> 937 Reason; 938 false -> 939 {'function not exported',MFAs} 940 end 941 end; 942fix_reason({'EXIT',Reason}) -> 943 Reason; 944fix_reason(Reason) -> 945 Reason. 946 947p(#{single_line:=Single,depth:=Depth,encoding:=Enc}) -> 948 "~"++single(Single)++mod(Enc)++p(Depth); 949p(unlimited) -> 950 "p"; 951p(_Depth) -> 952 "P". 953 954single(true) -> "0"; 955single(false) -> "". 956 957mod(latin1) -> ""; 958mod(_) -> "t". 959 960handler(Handler) when not Handler#handler.id -> 961 Handler#handler.module; 962handler(Handler) -> 963 {Handler#handler.module, Handler#handler.id}. 964 965the_handlers(MSL) -> 966 [handler(Handler) || Handler <- MSL]. 967 968%% stop_handlers(MSL, ServerName) -> [] 969 970stop_handlers([Handler|T], SName) -> 971 Mod = Handler#handler.module, 972 do_terminate(Mod, Handler, stop, Handler#handler.state, 973 stop, SName, shutdown), 974 stop_handlers(T, SName); 975stop_handlers([], _) -> 976 []. 977 978%% Message from the release_handler. 979%% The list of modules got to be a set, i.e. no duplicate elements! 980get_modules(MSL) -> 981 Mods = [Handler#handler.module || Handler <- MSL], 982 ordsets:to_list(ordsets:from_list(Mods)). 983 984%%----------------------------------------------------------------- 985%% Status information 986%%----------------------------------------------------------------- 987format_status(Opt, StatusData) -> 988 [PDict, SysState, Parent, _Debug, [ServerName, MSL, _HibernateAfterTimeout, _Hib]] = StatusData, 989 Header = gen:format_status_header("Status for event handler", 990 ServerName), 991 FmtMSL = [MS#handler{state=format_status(Opt, Mod, PDict, State)} 992 || #handler{module = Mod, state = State} = MS <- MSL], 993 [{header, Header}, 994 {data, [{"Status", SysState}, 995 {"Parent", Parent}]}, 996 {items, {"Installed handlers", FmtMSL}}]. 997 998format_status(Opt, Mod, PDict, State) -> 999 case erlang:function_exported(Mod, format_status, 2) of 1000 true -> 1001 Args = [PDict, State], 1002 case catch Mod:format_status(Opt, Args) of 1003 {'EXIT', _} -> State; 1004 Else -> Else 1005 end; 1006 false -> 1007 State 1008 end. 1009