aboutsummaryrefslogtreecommitdiffstats
path: root/system/doc/design_principles/events.xml
diff options
context:
space:
mode:
Diffstat (limited to 'system/doc/design_principles/events.xml')
-rw-r--r--system/doc/design_principles/events.xml221
1 files changed, 221 insertions, 0 deletions
diff --git a/system/doc/design_principles/events.xml b/system/doc/design_principles/events.xml
new file mode 100644
index 0000000000..5579f1e459
--- /dev/null
+++ b/system/doc/design_principles/events.xml
@@ -0,0 +1,221 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Gen_Event Behaviour</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>events.xml</file>
+ </header>
+ <marker id="gen_event"></marker>
+ <p>This chapter should be read in conjunction with
+ <c>gen_event(3)</c>, where all interface functions and callback
+ functions are described in detail.</p>
+
+ <section>
+ <title>Event Handling Principles</title>
+ <p>In OTP, an <em>event manager</em> is a named object to which
+ events can be sent. An <em>event</em> could be, for example,
+ an error, an alarm or some information that should be logged.</p>
+ <p>In the event manager, zero, one or several <em>event handlers</em> are installed. When the event manager is notified
+ about an event, the event will be processed by all the installed
+ event handlers. For example, an event manager for handling errors
+ can by default have a handler installed which writes error
+ messages to the terminal. If the error messages during a certain
+ period should be saved to a file as well, the user adds another
+ event handler which does this. When logging to file is no longer
+ necessary, this event handler is deleted.</p>
+ <p>An event manager is implemented as a process and each event
+ handler is implemented as a callback module.</p>
+ <p>The event manager essentially maintains a list of
+ <c>{Module, State}</c> pairs, where each <c>Module</c> is an
+ event handler, and <c>State</c> the internal state of that event
+ handler.</p>
+ </section>
+
+ <section>
+ <title>Example</title>
+ <p>The callback module for the event handler writing error messages
+ to the terminal could look like:</p>
+ <code type="none">
+-module(terminal_logger).
+-behaviour(gen_event).
+
+-export([init/1, handle_event/2, terminate/2]).
+
+init(_Args) ->
+ {ok, []}.
+
+handle_event(ErrorMsg, State) ->
+ io:format("***Error*** ~p~n", [ErrorMsg]),
+ {ok, State}.
+
+terminate(_Args, _State) ->
+ ok.</code>
+ <p>The callback module for the event handler writing error messages
+ to a file could look like:</p>
+ <code type="none">
+-module(file_logger).
+-behaviour(gen_event).
+
+-export([init/1, handle_event/2, terminate/2]).
+
+init(File) ->
+ {ok, Fd} = file:open(File, read),
+ {ok, Fd}.
+
+handle_event(ErrorMsg, Fd) ->
+ io:format(Fd, "***Error*** ~p~n", [ErrorMsg]),
+ {ok, Fd}.
+
+terminate(_Args, Fd) ->
+ file:close(Fd).</code>
+ <p>The code is explained in the next sections.</p>
+ </section>
+
+ <section>
+ <marker id="mgr"></marker>
+ <title>Starting an Event Manager</title>
+ <p>To start an event manager for handling errors, as described in
+ the example above, call the following function:</p>
+ <code type="none">
+gen_event:start_link({local, error_man})</code>
+ <p>This function spawns and links to a new process, an event
+ manager.</p>
+ <p>The argument, <c>{local, error_man}</c> specifies the name. In
+ this case, the event manager will be locally registered as
+ <c>error_man</c>.</p>
+ <p>If the name is omitted, the event manager is not registered.
+ Instead its pid must be used. The name could also be given
+ as <c>{global, Name}</c>, in which case the event manager is
+ registered using <c>global:register_name/2</c>.</p>
+ <p><c>gen_event:start_link</c> must be used if the event manager is
+ part of a supervision tree, i.e. is started by a supervisor.
+ There is another function <c>gen_event:start</c> to start a
+ stand-alone event manager, i.e. an event manager which is not
+ part of a supervision tree.</p>
+ </section>
+
+ <section>
+ <title>Adding an Event Handler</title>
+ <p>Here is an example using the shell on how to start an event
+ manager and add an event handler to it:</p>
+ <pre>
+1> <input>gen_event:start({local, error_man}).</input>
+{ok,&lt;0.31.0>}
+2> <input>gen_event:add_handler(error_man, terminal_logger, []).</input>
+ok</pre>
+ <p>This function sends a message to the event manager registered as
+ <c>error_man</c>, telling it to add the event handler
+ <c>terminal_logger</c>. The event manager will call the callback
+ function <c>terminal_logger:init([])</c>, where the argument []
+ is the third argument to <c>add_handler</c>. <c>init</c> is
+ expected to return <c>{ok, State}</c>, where <c>State</c> is
+ the internal state of the event handler.</p>
+ <code type="none">
+init(_Args) ->
+ {ok, []}.</code>
+ <p>Here, <c>init</c> does not need any input data and ignores its
+ argument. Also, for <c>terminal_logger</c> the internal state is
+ not used. For <c>file_logger</c>, the internal state is used
+ to save the open file descriptor.</p>
+ <code type="none">
+init(File) ->
+ {ok, Fd} = file:open(File, read),
+ {ok, Fd}.</code>
+ </section>
+
+ <section>
+ <title>Notifying About Events</title>
+ <pre>
+3> <input>gen_event:notify(error_man, no_reply).</input>
+***Error*** no_reply
+ok</pre>
+ <p><c>error_man</c> is the name of the event manager and
+ <c>no_reply</c> is the event.</p>
+ <p>The event is made into a message and sent to the event manager.
+ When the event is received, the event manager calls
+ <c>handle_event(Event, State)</c> for each installed event
+ handler, in the same order as they were added. The function is
+ expected to return a tuple <c>{ok, State1}</c>, where
+ <c>State1</c> is a new value for the state of the event handler.</p>
+ <p>In <c>terminal_logger</c>:</p>
+ <code type="none">
+handle_event(ErrorMsg, State) ->
+ io:format("***Error*** ~p~n", [ErrorMsg]),
+ {ok, State}.</code>
+ <p>In <c>file_logger</c>:</p>
+ <code type="none">
+handle_event(ErrorMsg, Fd) ->
+ io:format(Fd, "***Error*** ~p~n", [ErrorMsg]),
+ {ok, Fd}.</code>
+ </section>
+
+ <section>
+ <title>Deleting an Event Handler</title>
+ <pre>
+4> <input>gen_event:delete_handler(error_man, terminal_logger, []).</input>
+ok</pre>
+ <p>This function sends a message to the event manager registered as
+ <c>error_man</c>, telling it to delete the event handler
+ <c>terminal_logger</c>. The event manager will call the callback
+ function <c>terminal_logger:terminate([], State)</c>, where
+ the argument [] is the third argument to <c>delete_handler</c>.
+ <c>terminate</c> should be the opposite of <c>init</c> and do any
+ necessary cleaning up. Its return value is ignored.</p>
+ <p>For <c>terminal_logger</c>, no cleaning up is necessary:</p>
+ <code type="none">
+terminate(_Args, _State) ->
+ ok.</code>
+ <p>For <c>file_logger</c>, the file descriptor opened in <c>init</c>
+ needs to be closed:</p>
+ <code type="none">
+terminate(_Args, Fd) ->
+ file:close(Fd).</code>
+ </section>
+
+ <section>
+ <title>Stopping</title>
+ <p>When an event manager is stopped, it will give each of
+ the installed event handlers the chance to clean up by calling
+ <c>terminate/2</c>, the same way as when deleting a handler.</p>
+
+ <section>
+ <title>In a Supervision Tree</title>
+ <p>If the event manager is part of a supervision tree, no stop
+ function is needed. The event manager will automatically be
+ terminated by its supervisor. Exactly how this is done is
+ defined by a <seealso marker="sup_princ#shutdown">shutdown strategy</seealso> set in the supervisor.</p>
+ </section>
+
+ <section>
+ <title>Stand-Alone Event Managers</title>
+ <p>An event manager can also be stopped by calling:</p>
+ <pre>
+> <input>gen_event:stop(error_man).</input>
+ok</pre>
+ </section>
+ </section>
+</chapter>
+