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