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