aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/stdlib/doc/src/gen_statem.xml1769
-rw-r--r--system/doc/design_principles/statem.xml776
2 files changed, 1212 insertions, 1333 deletions
diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml
index d83e17b177..b1d9799917 100644
--- a/lib/stdlib/doc/src/gen_statem.xml
+++ b/lib/stdlib/doc/src/gen_statem.xml
@@ -29,39 +29,49 @@
<rev></rev>
</header>
<module>gen_statem</module>
- <modulesummary>Generic State Machine Behaviour</modulesummary>
+ <modulesummary>Generic state machine behavior.</modulesummary>
<description>
<p>
- A behaviour module for implementing a state machine. Two
+ This behavior module provides a state machine. Two
<seealso marker="#type-callback_mode"><em>callback modes</em></seealso>
- are supported. One for finite state machines
- (<seealso marker="gen_fsm"><c>gen_fsm</c></seealso> like)
- that requires the state to be an atom and uses that state as
- the name of the current callback function,
- and one without restriction on the state data type
- that uses one callback function for all states.
- </p>
- <p>
- This is a new behaviour in OTP-19.0.
- It has been thoroughly reviewed, is stable enough
- to be used by at least two heavy OTP applications, and is here to stay.
- But depending on user feedback, we do not expect
- but might find it necessary to make minor
- not backwards compatible changes into OTP-20.0,
- so its state can be designated as "not quite experimental"...
+ are supported:
</p>
+ <list type="bulleted">
+ <item>
+ <p>One for finite-state machines
+ (<seealso marker="gen_fsm"><c>gen_fsm</c></seealso> like),
+ which requires the state to be an atom and uses that state as
+ the name of the current callback function
+ </p>
+ </item>
+ <item>
+ <p>One without restriction on the state data type
+ that uses one callback function for all states
+ </p>
+ </item>
+ </list>
+ <note>
+ <p>
+ This is a new behavior in Erlang/OTP 19.0.
+ It has been thoroughly reviewed, is stable enough
+ to be used by at least two heavy OTP applications, and is here to stay.
+ Depending on user feedback, we do not expect
+ but can find it necessary to make minor
+ not backward compatible changes into Erlang/OTP 20.0.
+ </p>
+ </note>
<p>
- The <c>gen_statem</c> behaviour is intended to replace
+ The <c>gen_statem</c> behavior is intended to replace
<seealso marker="gen_fsm"><c>gen_fsm</c></seealso> for new code.
- It has the same features and add some really useful:
+ It has the same features and adds some really useful:
</p>
<list type="bulleted">
- <item>State code is gathered</item>
- <item>The state can be any term</item>
- <item>Events can be postponed</item>
- <item>Events can be self generated</item>
- <item>A reply can be sent from a later state</item>
- <item>There can be multiple sys traceable replies</item>
+ <item>State code is gathered.</item>
+ <item>The state can be any term.</item>
+ <item>Events can be postponed.</item>
+ <item>Events can be self-generated.</item>
+ <item>A reply can be sent from a later state.</item>
+ <item>There can be multiple <c>sys</c> traceable replies.</item>
</list>
<p>
The callback model(s) for <c>gen_statem</c> differs from
@@ -71,19 +81,16 @@
</p>
<p>
A generic state machine process (<c>gen_statem</c>) implemented
- using this module will have a standard set of interface functions
- and include functionality for tracing and error reporting.
- It will also fit into an OTP supervision tree. Refer to
- <seealso marker="doc/design_principles:statem">
- OTP Design Principles
- </seealso>
- for more information.
+ using this module has a standard set of interface functions
+ and includes functionality for tracing and error reporting.
+ It also fits into an OTP supervision tree. For more information, see
+ <seealso marker="doc/design_principles:statem">OTP Design Principles</seealso>.
</p>
<p>
A <c>gen_statem</c> assumes all specific parts to be located in a
- callback module exporting a pre-defined set of functions.
- The relationship between the behaviour functions and the callback
- functions can be illustrated as follows:</p>
+ callback module exporting a predefined set of functions.
+ The relationship between the behavior functions and the callback
+ functions is as follows:</p>
<pre>
gen_statem module Callback module
----------------- ---------------
@@ -103,59 +110,54 @@ erlang:'!' -----> Module:StateName/3
- -----> Module:code_change/4</pre>
<p>
Events are of different
- <seealso marker="#type-event_type">types</seealso>
+ <seealso marker="#type-event_type">types</seealso>,
so the callback functions can know the origin of an event
and how to respond.
</p>
<p>
If a callback function fails or returns a bad value,
- the <c>gen_statem</c> will terminate. An exception of class
- <seealso marker="erts:erlang#throw/1"><c>throw</c></seealso>,
- however, is not regarded as an error but as a valid return.
+ the <c>gen_statem</c> terminates. However, an exception of class
+ <seealso marker="erts:erlang#throw/1"><c>throw</c></seealso>
+ is not regarded as an error but as a valid return.
</p>
- <marker id="state_function" />
+ <marker id="state_function"/>
<p>
The "<em>state function</em>" for a specific
<seealso marker="#type-state">state</seealso>
in a <c>gen_statem</c> is the callback function that is called
- for all events in this state, and is selected depending on which
+ for all events in this state. It is selected depending on which
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
- that the implementation specifies when the the server starts.
+ that the implementation specifies when the server starts.
</p>
<p>
When the
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
- is <c>state_functions</c>, the state has to be an atom and
- is used as the state function name. See
- <seealso marker="#Module:StateName/3">
- <c>Module:StateName/3</c>
- </seealso>.
+ is <c>state_functions</c>, the state must be an atom and
+ is used as the state function name; see
+ <seealso marker="#Module:StateName/3"><c>Module:StateName/3</c></seealso>.
This gathers all code for a specific state
in one function and hence dispatches on state first.
- Note that in this mode the fact that there is
- a mandatory callback function
- <seealso marker="#Module:terminate/3">
- <c>Module:terminate/3</c>
- </seealso> makes the state name <c>terminate</c> unusable.
+ Notice that in this mode
+ the mandatory callback function
+ <seealso marker="#Module:terminate/3"><c>Module:terminate/3</c></seealso>
+ makes the state name <c>terminate</c> unusable.
</p>
<p>
When the
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
- is <c>handle_event_function</c> the state can be any term
+ is <c>handle_event_function</c>, the state can be any term
and the state function name is
- <seealso marker="#Module:handle_event/4">
- <c>Module:handle_event/4</c>
- </seealso>.
+ <seealso marker="#Module:handle_event/4"><c>Module:handle_event/4</c></seealso>.
This makes it easy to dispatch on state or on event as you desire.
Be careful about which events you handle in which
- states so you do not accidentally postpone one event
+ states so that you do not accidentally postpone an event
forever creating an infinite busy loop.
</p>
<p>
The <c>gen_statem</c> enqueues incoming events in order of arrival
and presents these to the
<seealso marker="#state_function">state function</seealso>
- in that order. The state function can postpone an event
+ in that order. The state function can postpone an event
so it is not retried in the current state.
After a state change the queue restarts with the postponed events.
</p>
@@ -163,91 +165,85 @@ erlang:'!' -----> Module:StateName/3
The <c>gen_statem</c> event queue model is sufficient
to emulate the normal process message queue with selective receive.
Postponing an event corresponds to not matching it
- in a receive statement and changing states corresponds
+ in a receive statement, and changing states corresponds
to entering a new receive statement.
</p>
<p>
The <seealso marker="#state_function">state function</seealso>
can insert events using the
- <seealso marker="#type-action">
- <c>action()</c> <c>next_event</c>
- </seealso>
+ <seealso marker="#type-action"><c>action()</c></seealso>
+ <c>next_event</c>
and such an event is inserted as the next to present
- to the state function. That is: as if it is
- the oldest incoming event. There is a dedicated
- <seealso marker="#type-event_type">
- <c>event_type()</c>
- </seealso>
- <c>internal</c> that can be used for such events making them impossible
+ to the state function. That is, as if it is
+ the oldest incoming event. A dedicated
+ <seealso marker="#type-event_type"><c>event_type()</c></seealso>
+ <c>internal</c> can be used for such events making them impossible
to mistake for external events.
</p>
<p>
Inserting an event replaces the trick of calling your own
state handling functions that you often would have to
- resort to in for example <seealso marker="gen_fsm"><c>gen_fsm</c></seealso>
+ resort to in, for example,
+ <seealso marker="gen_fsm"><c>gen_fsm</c></seealso>
to force processing an inserted event before others.
- A warning, though: if you in <c>gen_statem</c> for example
- postpone an event in one state and then call some other state function of yours,
- you have not changed states and hence the postponed event will not be retried,
- which is logical but might be confusing.
</p>
+ <note>
+ <p>If you in <c>gen_statem</c>, for example, postpone
+ an event in one state and then call another state function
+ of yours, you have not changed states and hence the postponed event
+ is not retried, which is logical but can be confusing.
+ </p>
+ </note>
<p>
- See the type
- <seealso marker="#type-transition_option">
- <c>transition_option()</c>
- </seealso>
- for the details of a state transition.
+ For the details of a state transition, see type
+ <seealso marker="#type-transition_option"><c>transition_option()</c></seealso>.
</p>
<p>
- A <c>gen_statem</c> handles system messages as documented in
+ A <c>gen_statem</c> handles system messages as described in
<seealso marker="sys"><c>sys</c></seealso>.
- The <c>sys</c>module can be used for debugging a <c>gen_statem</c>.
+ The <c>sys</c> module can be used for debugging a <c>gen_statem</c>.
</p>
<p>
- Note that a <c>gen_statem</c> does not trap exit signals
+ Notice that a <c>gen_statem</c> does not trap exit signals
automatically, this must be explicitly initiated in
the callback module (by calling
- <seealso marker="erts:erlang#process_flag/2">
- <c>process_flag(trap_exit, true)</c></seealso>.
+ <seealso marker="erts:erlang#process_flag/2"><c>process_flag(trap_exit, true)</c></seealso>.
</p>
<p>
Unless otherwise stated, all functions in this module fail if
the specified <c>gen_statem</c> does not exist or
- if bad arguments are given.
+ if bad arguments are specified.
</p>
<p>
The <c>gen_statem</c> process can go into hibernation; see
- <seealso marker="proc_lib#hibernate/3">
- <c>proc_lib:hibernate/3</c>.
- </seealso>
+ <seealso marker="proc_lib#hibernate/3"><c>proc_lib:hibernate/3</c></seealso>.
It is done when a
<seealso marker="#state_function">state function</seealso> or
<seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
specifies <c>hibernate</c> in the returned
<seealso marker="#type-action"><c>Actions</c></seealso>
- list. This feature might be useful to reclaim process heap memory
+ list. This feature can be useful to reclaim process heap memory
while the server is expected to be idle for a long time.
- However, use this feature with care
- since hibernation can be too costly
+ However, use this feature with care,
+ as hibernation can be too costly
to use after every event; see
- <seealso marker="erts:erlang#hibernate/3">
- <c>erlang:hibernate/3</c>.
- </seealso>
+ <seealso marker="erts:erlang#hibernate/3"><c>erlang:hibernate/3</c></seealso>.
</p>
</description>
<section>
- <title>EXAMPLE</title>
+ <title>Example</title>
<p>
- This example shows a simple pushbutton model
+ The following example shows a simple pushbutton model
for a toggling pushbutton implemented with
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
<c>state_functions</c>.
You can push the button and it replies if it went on or off,
and you can ask for a count of how many times it has been
- pushed to on.
+ pushed to switch on.
</p>
- <p>This is the complete callback module file <c>pushbutton.erl</c>:</p>
+ <p>The following is the complete callback module file
+ <c>pushbutton.erl</c>:</p>
<code type="erl">
-module(pushbutton).
-behaviour(gen_statem).
@@ -305,7 +301,7 @@ handle_event(_, _, Data) ->
%% Ignore all other events
{keep_state,Data}.
</code>
- <p>And this is a shell session when running it:</p>
+ <p>The following is a shell session when running it:</p>
<pre>
1> pushbutton:start().
{ok,&lt;0.36.0>}
@@ -326,12 +322,11 @@ ok
in function gen:do_for_proc/2 (gen.erl, line 261)
in call from gen_statem:call/3 (gen_statem.erl, line 386)
</pre>
-
<p>
- And just to compare styles here is the same example using
+ To compare styles, here follows the same example using
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
- <c>state_functions</c>, or rather here is code to replace
- from the <c>init/1</c> function of the <c>pushbutton.erl</c>
+ <c>state_functions</c>, or rather the code to replace
+ from function <c>init/1</c> of the <c>pushbutton.erl</c>
example file above:
</p>
<code type="erl">
@@ -364,107 +359,108 @@ handle_event(_, _, State, Data) ->
<datatypes>
<datatype>
- <name name="server_name" />
+ <name name="server_name"/>
<desc>
<p>
Name specification to use when starting
- a <c>gen_statem</c> server. See
- <seealso marker="#start_link/3">
- <c>start_link/3</c>
- </seealso>
+ a <c>gen_statem</c> server. See
+ <seealso marker="#start_link/3"><c>start_link/3</c></seealso>
and
- <seealso marker="#type-server_ref">
- <c>server_ref()</c>
- </seealso> below.
+ <seealso marker="#type-server_ref"><c>server_ref()</c></seealso>
+ below.
</p>
</desc>
</datatype>
<datatype>
- <name name="server_ref" />
+ <name name="server_ref"/>
<desc>
<p>
Server specification to use when addressing
a <c>gen_statem</c> server.
See <seealso marker="#call/2"><c>call/2</c></seealso> and
- <seealso marker="#type-server_name">
- <c>server_name()</c>
- </seealso>
+ <seealso marker="#type-server_name"><c>server_name()</c></seealso>
above.
</p>
<p>It can be:</p>
<taglist>
- <tag><c>pid()</c><br />
- <c>LocalName</c></tag>
- <item>The <c>gen_statem</c> is locally registered.</item>
+ <tag><c>pid() | LocalName</c></tag>
+ <item>
+ <p>
+ The <c>gen_statem</c> is locally registered.
+ </p>
+ </item>
<tag><c>{Name,Node}</c></tag>
<item>
- The <c>gen_statem</c> is locally registered
- on another node.
+ <p>
+ The <c>gen_statem</c> is locally registered
+ on another node.
+ </p>
</item>
<tag><c>{global,GlobalName}</c></tag>
<item>
- The <c>gen_statem</c> is globally registered
- in <seealso marker="kernel:global"><c>global</c></seealso>.
+ <p>
+ The <c>gen_statem</c> is globally registered in
+ <seealso marker="kernel:global"><c>kernel:global</c></seealso>.
+ </p>
</item>
<tag><c>{via,RegMod,ViaName}</c></tag>
<item>
- The <c>gen_statem</c> is registered through
- an alternative process registry.
- The registry callback module <c>RegMod</c>
- should export the functions
- <c>register_name/2</c>, <c>unregister_name/1</c>,
- <c>whereis_name/1</c> and <c>send/2</c>,
- which should behave like the corresponding functions
- in <seealso marker="kernel:global"><c>global</c></seealso>.
- Thus, <c>{via,global,GlobalName}</c> is the same as
- <c>{global,GlobalName}</c>.
+ <p>
+ The <c>gen_statem</c> is registered in
+ an alternative process registry.
+ The registry callback module <c>RegMod</c>
+ is to export functions
+ <c>register_name/2</c>, <c>unregister_name/1</c>,
+ <c>whereis_name/1</c>, and <c>send/2</c>,
+ which are to behave like the corresponding functions in
+ <seealso marker="kernel:global"><c>kernel:global</c></seealso>.
+ Thus, <c>{via,global,GlobalName}</c> is the same as
+ <c>{global,GlobalName}</c>.
+ </p>
</item>
</taglist>
</desc>
</datatype>
<datatype>
- <name name="debug_opt" />
+ <name name="debug_opt"/>
<desc>
<p>
Debug option that can be used when starting
- a <c>gen_statem</c> server through for example
+ a <c>gen_statem</c> server through, for example,
<seealso marker="#enter_loop/5"><c>enter_loop/5</c></seealso>.
</p>
<p>
- For every entry in <c><anno>Dbgs</anno></c>
+ For every entry in <c><anno>Dbgs</anno></c>,
the corresponding function in
- <seealso marker="sys"><c>sys</c></seealso> will be called.
+ <seealso marker="sys"><c>sys</c></seealso> is called.
</p>
</desc>
</datatype>
<datatype>
- <name name="start_opt" />
+ <name name="start_opt"/>
<desc>
<p>
Options that can be used when starting
- a <c>gen_statem</c> server through for example
+ a <c>gen_statem</c> server through, for example,
<seealso marker="#start_link/3"><c>start_link/3</c></seealso>.
</p>
</desc>
</datatype>
<datatype>
- <name name="start_ret" />
+ <name name="start_ret"/>
<desc>
<p>
- Return value from the start functions for_example
+ Return value from the start functions, for example,
<seealso marker="#start_link/3"><c>start_link/3</c></seealso>.
</p>
</desc>
</datatype>
-
<datatype>
- <name name="from" />
+ <name name="from"/>
<desc>
<p>
- Destination to use when replying through for example the
- <seealso marker="#type-action">
- <c>action()</c>
- </seealso>
+ Destination to use when replying through, for example, the
+ <seealso marker="#type-action"><c>action()</c></seealso>
<c>{reply,From,Reply}</c>
to a process that has called the <c>gen_statem</c> server using
<seealso marker="#call/2"><c>call/2</c></seealso>.
@@ -472,231 +468,228 @@ handle_event(_, _, State, Data) ->
</desc>
</datatype>
<datatype>
- <name name="state" />
+ <name name="state"/>
<desc>
<p>
- After a state change (<c>NextState =/= State</c>)
+ After a state change (<c>NextState =/= State</c>),
all postponed events are retried.
</p>
</desc>
</datatype>
<datatype>
- <name name="state_name" />
+ <name name="state_name"/>
<desc>
<p>
If the
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
is <c>state_functions</c>,
- the state has to be of this type.
+ the state must be of this type.
</p>
</desc>
</datatype>
<datatype>
- <name name="data" />
+ <name name="data"/>
<desc>
<p>
A term in which the state machine implementation
- should store any server data it needs. The difference between
+ is to store any server data it needs. The difference between
this and the <seealso marker="#type-state"><c>state()</c></seealso>
itself is that a change in this data does not cause
- postponed events to be retried. Hence if a change
+ postponed events to be retried. Hence, if a change
in this data would change the set of events that
- are handled than that data item should be made
+ are handled, then that data item is to be made
a part of the state.
</p>
</desc>
</datatype>
<datatype>
- <name name="event_type" />
+ <name name="event_type"/>
<desc>
<p>
- External events are of 3 different type:
- <c>{call,<anno>From</anno>}</c>, <c>cast</c> or <c>info</c>.
+ External events are of three types:
+ <c>{call,<anno>From</anno>}</c>, <c>cast</c>, or <c>info</c>.
<seealso marker="#call/2">Calls</seealso>
(synchronous) and
<seealso marker="#cast/2">casts</seealso>
originate from the corresponding API functions.
- For calls the event contain whom to reply to.
+ For calls, the event contains whom to reply to.
Type <c>info</c> originates from regular process messages sent
- to the <c>gen_statem</c>. It is also possible for the state machine
- implementation to generate events of types
+ to the <c>gen_statem</c>. Also, the state machine
+ implementation can generate events of types
<c>timeout</c> and <c>internal</c> to itself.
</p>
</desc>
</datatype>
<datatype>
- <name name="callback_mode" />
+ <name name="callback_mode"/>
<desc>
<p>
The <em>callback mode</em> is selected when starting the
<c>gen_statem</c> using the return value from
<seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
or when calling
- <seealso marker="#enter_loop/5"><c>enter_loop/5-7</c></seealso>,
+ <seealso marker="#enter_loop/5"><c>enter_loop/5,6,7</c></seealso>,
and with the return value from
- <seealso marker="#Module:code_change/4">
- <c>Module:code_change/4</c>.
- </seealso>
+ <seealso marker="#Module:code_change/4"><c>Module:code_change/4</c></seealso>.
</p>
<taglist>
<tag><c>state_functions</c></tag>
<item>
- The state has to be of type
- <seealso marker="#type-state_name"><c>state_name()</c></seealso>
- and one callback function per state that is
- <seealso marker="#Module:StateName/3">
- <c>Module:StateName/3</c>
- </seealso>
- is used.
+ <p>
+ The state must be of type
+ <seealso marker="#type-state_name"><c>state_name()</c></seealso>
+ and one callback function per state, that is,
+ <seealso marker="#Module:StateName/3"><c>Module:StateName/3</c></seealso>,
+ is used.
+ </p>
</item>
<tag><c>handle_event_function</c></tag>
<item>
- The state can be any term and the callback function
- <seealso marker="#Module:handle_event/4">
- <c>Module:handle_event/4</c>
- </seealso>
- is used for all states.
+ <p>
+ The state can be any term and the callback function
+ <seealso marker="#Module:handle_event/4"><c>Module:handle_event/4</c></seealso>
+ is used for all states.
+ </p>
</item>
</taglist>
</desc>
</datatype>
<datatype>
- <name name="transition_option" />
+ <name name="transition_option"/>
<desc>
<p>
- Transition options may be set by
+ Transition options can be set by
<seealso marker="#type-action">actions</seealso>
- and they modify some details below in how
+ and they modify the following in how
the state transition is done:
</p>
<list type="ordered">
<item>
- All
- <seealso marker="#type-action">actions</seealso>
- are processed in order of appearance.
+ <p>
+ All
+ <seealso marker="#type-action">actions</seealso>
+ are processed in order of appearance.
+ </p>
</item>
<item>
- If
- <seealso marker="#type-postpone">
- <c>postpone()</c>
- </seealso>
- is <c>true</c>
- the current event is postponed.
+ <p>
+ If
+ <seealso marker="#type-postpone"><c>postpone()</c></seealso>
+ is <c>true</c>,
+ the current event is postponed.
+ </p>
</item>
<item>
- If the state changes the queue of incoming events
- is reset to start with the oldest postponed.
+ <p>
+ If the state changes, the queue of incoming events
+ is reset to start with the oldest postponed.
+ </p>
</item>
<item>
- All events stored with
- <seealso marker="#type-action">
- <c>action()</c>
- </seealso>
- <c>next_event</c>
- are inserted in the queue to be processed before
- all other events.
+ <p>
+ All events stored with
+ <seealso marker="#type-action"><c>action()</c></seealso>
+ <c>next_event</c>
+ are inserted in the queue to be processed before
+ all other events.
+ </p>
</item>
<item>
- If an
- <seealso marker="#type-event_timeout">
- <c>event_timeout()</c>
- </seealso>
- is set through
- <seealso marker="#type-action">
- <c>action()</c>
- </seealso>
- <c>timeout</c>
- an event timer may be started or a timeout zero event
- may be enqueued.
+ <p>
+ If an
+ <seealso marker="#type-event_timeout"><c>event_timeout()</c></seealso>
+ is set through
+ <seealso marker="#type-action"><c>action()</c></seealso>
+ <c>timeout</c>,
+ an event timer can be started or a time-out zero event
+ can be enqueued.
+ </p>
</item>
<item>
- The (possibly new)
- <seealso marker="#state_function">state function</seealso>
- is called with the oldest enqueued event if there is any,
- otherwise the <c>gen_statem</c> goes into <c>receive</c>
- or hibernation
- (if
- <seealso marker="#type-hibernate">
- <c>hibernate()</c>
- </seealso>
- is <c>true</c>)
- to wait for the next message. In hibernation the next
- non-system event awakens the <c>gen_statem</c>, or rather
- the next incoming message awakens the <c>gen_statem</c>
- but if it is a system event
- it goes right back into hibernation.
+ <p>
+ The (possibly new)
+ <seealso marker="#state_function">state function</seealso>
+ is called with the oldest enqueued event if there is any,
+ otherwise the <c>gen_statem</c> goes into <c>receive</c>
+ or hibernation
+ (if
+ <seealso marker="#type-hibernate"><c>hibernate()</c></seealso>
+ is <c>true</c>)
+ to wait for the next message. In hibernation the next
+ non-system event awakens the <c>gen_statem</c>, or rather
+ the next incoming message awakens the <c>gen_statem</c>,
+ but if it is a system event
+ it goes right back into hibernation.
+ </p>
</item>
</list>
</desc>
</datatype>
<datatype>
- <name name="postpone" />
+ <name name="postpone"/>
<desc>
<p>
- If <c>true</c> postpone the current event and retry
+ If <c>true</c>, postpones the current event and retries
it when the state changes
(<c>NextState =/= State</c>).
</p>
</desc>
</datatype>
<datatype>
- <name name="hibernate" />
+ <name name="hibernate"/>
<desc>
<p>
- If <c>true</c> hibernate the <c>gen_statem</c>
+ If <c>true</c>, hibernates the <c>gen_statem</c>
by calling
- <seealso marker="proc_lib#hibernate/3">
- <c>proc_lib:hibernate/3</c>
- </seealso>
+ <seealso marker="proc_lib#hibernate/3"><c>proc_lib:hibernate/3</c></seealso>
before going into <c>receive</c>
to wait for a new external event.
If there are enqueued events,
- to prevent receiving any new event; a
- <seealso marker="erts:erlang#garbage_collect/0">
- <c>garbage_collect/0</c>
- </seealso> is done instead to simulate
+ to prevent receiving any new event, an
+ <seealso marker="erts:erlang#garbage_collect/0"><c>erlang:garbage_collect/0</c></seealso>
+ is done instead to simulate
that the <c>gen_statem</c> entered hibernation
and immediately got awakened by the oldest enqueued event.
</p>
</desc>
</datatype>
<datatype>
- <name name="event_timeout" />
+ <name name="event_timeout"/>
<desc>
<p>
- Generate an event of
+ Generates an event of
<seealso marker="#type-event_type"><c>event_type()</c></seealso>
<c>timeout</c>
- after this time (in milliseconds) unless some other
- event arrives in which case this timeout is cancelled.
- Note that a retried or inserted event
- counts just like a new in this respect.
+ after this time (in milliseconds) unless another
+ event arrives in which case this time-out is cancelled.
+ Notice that a retried or inserted event
+ counts like a new in this respect.
</p>
<p>
- If the value is <c>infinity</c> no timer is started since
- it will never trigger anyway.
+ If the value is <c>infinity</c>, no timer is started, as
+ it never triggers anyway.
</p>
<p>
- If the value is <c>0</c> the timeout event is immediately enqueued
- unless there already are enqueued events since then the
- timeout is immediately cancelled.
- This is a feature ensuring that a timeout <c>0</c> event
- will be processed before any not yet received external event.
+ If the value is <c>0</c>, the time-out event is immediately enqueued
+ unless there already are enqueued events, as the
+ time-out is then immediately cancelled.
+ This is a feature ensuring that a time-out <c>0</c> event
+ is processed before any not yet received external event.
</p>
<p>
- Note that it is not possible nor needed to cancel this timeout
- since it is cancelled automatically by any other event.
+ Notice that it is not possible or needed to cancel this time-out,
+ as it is cancelled automatically by any other event.
</p>
</desc>
</datatype>
<datatype>
- <name name="action" />
+ <name name="action"/>
<desc>
<p>
- These state transition actions may be invoked by
+ These state transition actions can be invoked by
returning them from the
- <seealso marker="#state_function">state function</seealso>,
- from <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
+ <seealso marker="#state_function">state function</seealso>, from
+ <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
or by giving them to
<seealso marker="#enter_loop/6"><c>enter_loop/6,7</c></seealso>.
</p>
@@ -705,91 +698,81 @@ handle_event(_, _, State, Data) ->
</p>
<p>
Actions that set
- <seealso marker="#type-transition_option">
- transition options
- </seealso>
- overrides any previous of the same type,
+ <seealso marker="#type-transition_option">transition options</seealso>
+ override any previous of the same type,
so the last in the containing list wins.
- For example the last
- <seealso marker="#type-event_timeout">
- <c>event_timeout()</c>
- </seealso>
+ For example, the last
+ <seealso marker="#type-event_timeout"><c>event_timeout()</c></seealso>
overrides any other <c>event_timeout()</c> in the list.
</p>
<taglist>
<tag><c>postpone</c></tag>
<item>
- Set the
- <seealso marker="#type-transition_option">
- <c>transition_option()</c>
- </seealso>
- <seealso marker="#type-postpone">
- <c>postpone()</c>
- </seealso>
- for this state transition.
- This action is ignored when returned from
- <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
- or given to
- <seealso marker="#enter_loop/5"><c>enter_loop/5,6</c></seealso>
- since there is no event to postpone in those cases.
+ <p>
+ Sets the
+ <seealso marker="#type-transition_option"><c>transition_option()</c></seealso>
+ <seealso marker="#type-postpone"><c>postpone()</c></seealso>
+ for this state transition.
+ This action is ignored when returned from
+ <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
+ or given to
+ <seealso marker="#enter_loop/5"><c>enter_loop/5,6</c></seealso>,
+ as there is no event to postpone in those cases.
+ </p>
</item>
<tag><c>hibernate</c></tag>
<item>
- Set the
- <seealso marker="#type-transition_option">
- <c>transition_option()</c>
- </seealso>
- <seealso marker="#type-hibernate">
- <c>hibernate()</c>
- </seealso>
- for this state transition.
+ <p>
+ Sets the
+ <seealso marker="#type-transition_option"><c>transition_option()</c></seealso>
+ <seealso marker="#type-hibernate"><c>hibernate()</c></seealso>
+ for this state transition.
+ </p>
</item>
<tag><c>Timeout</c></tag>
<item>
- Short for <c>{timeout,Timeout,Timeout}</c> that is
- the timeout message is the timeout time.
- This form exists to make the
- <seealso marker="#state_function">state function</seealso>
- return value <c>{next_state,NextState,NewData,Timeout}</c>
- allowed like for
- <seealso marker="gen_fsm#Module:StateName/2">
- <c>gen_fsm Module:StateName/2</c>.
- </seealso>
+ <p>
+ Short for <c>{timeout,Timeout,Timeout}</c>, that is,
+ the time-out message is the time-out time.
+ This form exists to make the
+ <seealso marker="#state_function">state function</seealso>
+ return value <c>{next_state,NextState,NewData,Timeout}</c>
+ allowed like for <c>gen_fsm</c>'s
+ <seealso marker="gen_fsm#Module:StateName/2"><c>Module:StateName/2</c></seealso>.
+ </p>
</item>
<tag><c>timeout</c></tag>
<item>
- Set the
- <seealso marker="#type-transition_option">
- <c>transition_option()</c>
- </seealso>
- <seealso marker="#type-event_timeout">
- <c>event_timeout()</c>
- </seealso>
- to <c><anno>Time</anno></c> with <c><anno>EventContent</anno></c>.
+ <p>
+ Sets the
+ <seealso marker="#type-transition_option"><c>transition_option()</c></seealso>
+ <seealso marker="#type-event_timeout"><c>event_timeout()</c></seealso>
+ to <c><anno>Time</anno></c> with <c><anno>EventContent</anno></c>.
+ </p>
</item>
<tag><c>reply_action()</c></tag>
- <item>Reply to a caller.</item>
+ <item>
+ <p>
+ Replies to a caller.
+ </p>
+ </item>
<tag><c>next_event</c></tag>
<item>
- Store the given <c><anno>EventType</anno></c>
+ <p>
+ Stores the specified <c><anno>EventType</anno></c>
and <c><anno>EventContent</anno></c> for insertion after all
actions have been executed.
- </item>
- <item>
+ </p>
<p>
The stored events are inserted in the queue as the next to process
- before any already queued events. The order of these stored events
- is preserved so the first <c>next_event</c> in the containing list
- will become the first to process.
+ before any already queued events. The order of these stored events
+ is preserved, so the first <c>next_event</c> in the containing
+ list becomes the first to process.
</p>
- </item>
- <item>
<p>
An event of type
- <seealso marker="#type-event_type">
- <c>internal</c>
- </seealso>
- should be used when you want to reliably distinguish
+ <seealso marker="#type-event_type"><c>internal</c></seealso>
+ is to be used when you want to reliably distinguish
an event inserted this way from any external event.
</p>
</item>
@@ -797,303 +780,126 @@ handle_event(_, _, State, Data) ->
</desc>
</datatype>
<datatype>
- <name name="reply_action" />
+ <name name="reply_action"/>
<desc>
<p>
- Reply to a caller waiting for a reply in
+ Replies to a caller waiting for a reply in
<seealso marker="#call/2"><c>call/2</c></seealso>.
- <c><anno>From</anno></c> must be the term from the
- <seealso marker="#type-event_type">
- <c>{call,<anno>From</anno>}</c>
- </seealso>
- argument to the
+ <c><anno>From</anno></c> must be the term from argument
+ <seealso marker="#type-event_type"><c>{call,<anno>From</anno>}</c></seealso>
+ to the
<seealso marker="#state_function">state function</seealso>.
</p>
</desc>
</datatype>
<datatype>
- <name name="state_function_result" />
+ <name name="state_function_result"/>
<desc>
<taglist>
<tag><c>next_state</c></tag>
<item>
- The <c>gen_statem</c> will do a state transition to
- <c><anno>NextStateName</anno></c>
- (which may be the same as the current state),
- set <c><anno>NewData</anno></c>
- and execute all <c><anno>Actions</anno></c>
+ <p>
+ The <c>gen_statem</c> does a state transition to
+ <c><anno>NextStateName</anno></c>
+ (which can be the same as the current state),
+ sets <c><anno>NewData</anno></c>,
+ and executes all <c><anno>Actions</anno></c>.
+ </p>
</item>
</taglist>
<p>
All these terms are tuples or atoms and this property
- will hold in any future version of <c>gen_statem</c>,
- just in case you need such a promise.
+ will hold in any future version of <c>gen_statem</c>.
</p>
</desc>
</datatype>
<datatype>
- <name name="handle_event_result" />
+ <name name="handle_event_result"/>
<desc>
<taglist>
<tag><c>next_state</c></tag>
<item>
- The <c>gen_statem</c> will do a state transition to
- <c><anno>NextState</anno></c>
- (which may be the same as the current state),
- set <c><anno>NewData</anno></c>
- and execute all <c><anno>Actions</anno></c>
+ <p>
+ The <c>gen_statem</c> does a state transition to
+ <c><anno>NextState</anno></c>
+ (which can be the same as the current state),
+ sets <c><anno>NewData</anno></c>,
+ and executes all <c><anno>Actions</anno></c>.
+ </p>
</item>
</taglist>
<p>
All these terms are tuples or atoms and this property
- will hold in any future version of <c>gen_statem</c>,
- just in case you need such a promise.
+ will hold in any future version of <c>gen_statem</c>.
</p>
</desc>
</datatype>
<datatype>
- <name name="common_state_callback_result" />
+ <name name="common_state_callback_result"/>
<desc>
<taglist>
<tag><c>stop</c></tag>
<item>
- Terminate the <c>gen_statem</c> by calling
- <seealso marker="#Module:terminate/3">
- <c>Module:terminate/3</c>
- </seealso>
- with <c>Reason</c> and
- <c><anno>NewData</anno></c>, if given.
+ <p>
+ Terminates the <c>gen_statem</c> by calling
+ <seealso marker="#Module:terminate/3"><c>Module:terminate/3</c></seealso>
+ with <c>Reason</c> and
+ <c><anno>NewData</anno></c>, if specified.
+ </p>
</item>
<tag><c>stop_and_reply</c></tag>
<item>
- Send all <c><anno>Replies</anno></c>
- then terminate the <c>gen_statem</c> by calling
- <seealso marker="#Module:terminate/3">
- <c>Module:terminate/3</c>
- </seealso>
- with <c>Reason</c> and
- <c><anno>NewData</anno></c>, if given.
+ <p>
+ Sends all <c><anno>Replies</anno></c>,
+ then terminates the <c>gen_statem</c> by calling
+ <seealso marker="#Module:terminate/3"><c>Module:terminate/3</c></seealso>
+ with <c>Reason</c> and
+ <c><anno>NewData</anno></c>, if specified.
+ </p>
</item>
<tag><c>keep_state</c></tag>
<item>
- The <c>gen_statem</c> will keep the current state, or
- do a state transition to the current state if you like,
- set <c><anno>NewData</anno></c>
- and execute all <c><anno>Actions</anno></c>.
- This is the same as
- <c>{next_state,CurrentState,<anno>NewData</anno>,<anno>Actions</anno>}</c>.
+ <p>
+ The <c>gen_statem</c> keeps the current state, or
+ does a state transition to the current state if you like,
+ sets <c><anno>NewData</anno></c>,
+ and executes all <c><anno>Actions</anno></c>.
+ This is the same as
+ <c>{next_state,CurrentState,<anno>NewData</anno>,<anno>Actions</anno>}</c>.
+ </p>
</item>
<tag><c>keep_state_and_data</c></tag>
<item>
- The <c>gen_statem</c> will keep the current state or
- do a state transition to the current state if you like,
- keep the current server data,
- and execute all <c><anno>Actions</anno></c>.
- This is the same as
- <c>{next_state,CurrentState,CurrentData,<anno>Actions</anno>}</c>.
+ <p>
+ The <c>gen_statem</c> keeps the current state or
+ does a state transition to the current state if you like,
+ keeps the current server data,
+ and executes all <c><anno>Actions</anno></c>.
+ This is the same as
+ <c>{next_state,CurrentState,CurrentData,<anno>Actions</anno>}</c>.
+ </p>
</item>
</taglist>
<p>
All these terms are tuples or atoms and this property
- will hold in any future version of <c>gen_statem</c>,
- just in case you need such a promise.
+ will hold in any future version of <c>gen_statem</c>.
</p>
</desc>
</datatype>
</datatypes>
<funcs>
-
- <func>
- <name name="start_link" arity="3" />
- <name name="start_link" arity="4" />
- <fsummary>Create a linked <c>gen_statem</c> process</fsummary>
- <desc>
- <p>
- Creates a <c>gen_statem</c> process according
- to OTP design principles
- (using
- <seealso marker="proc_lib"><c>proc_lib</c></seealso>
- primitives)
- that is linked to the calling process.
- This is essential when the <c>gen_statem</c> shall be part of
- a supervision tree so it gets linked to its supervisor.
- </p>
- <p>
- The <c>gen_statem</c> process calls
- <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
- to initialize the server. To ensure a synchronized start-up
- procedure, <c>start_link/3,4</c> does not return until
- <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
- has returned.
- </p>
- <p>
- <c><anno>ServerName</anno></c> specifies the
- <seealso marker="#type-server_name">
- <c>server_name()</c>
- </seealso>
- to register for the <c>gen_statem</c>.
- If the <c>gen_statem</c> is started with <c>start_link/3</c>
- no <c><anno>ServerName</anno></c> is provided and
- the <c>gen_statem</c> is not registered.
- </p>
- <p><c><anno>Module</anno></c> is the name of the callback module.</p>
- <p>
- <c><anno>Args</anno></c> is an arbitrary term which is passed as
- the argument to
- <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>.
- </p>
- <p>
- If the option <c>{timeout,Time}</c> is present in
- <c><anno>Opts</anno></c>, the <c>gen_statem</c>
- is allowed to spend <c>Time</c> milliseconds initializing
- or it will be terminated and the start function will return
- <seealso marker="#type-start_ret"><c>{error,timeout}</c></seealso>.
- </p>
- <p>
- If the option
- <seealso marker="#type-debug_opt"><c>{debug,Dbgs}</c></seealso>
- is present in <c><anno>Opts</anno></c>, debugging through
- <seealso marker="sys"><c>sys</c></seealso> is activated.
- </p>
- <p>
- If the option <c>{spawn_opt,SpawnOpts}</c> is present in
- <c><anno>Opts</anno></c>, <c>SpawnOpts</c> will be passed
- as option list to
- <seealso marker="erts:erlang#spawn_opt/2"><c>spawn_opt/2</c></seealso>
- which is used to spawn the <c>gen_statem</c> process.
- </p>
- <note>
- <p>
- Using the spawn option <c>monitor</c> is currently not
- allowed, but will cause this function to fail with reason
- <c>badarg</c>.
- </p>
- </note>
- <p>
- If the <c>gen_statem</c> is successfully created
- and initialized this function returns
- <seealso marker="#type-start_ret">
- <c>{ok,Pid}</c>,
- </seealso>
- where <c>Pid</c> is the <c>pid()</c>
- of the <c>gen_statem</c>.
- If there already exists a process with the specified
- <c><anno>ServerName</anno></c> this function returns
- <seealso marker="#type-start_ret"><c>{error,{already_started,Pid}}</c></seealso>,
- where <c>Pid</c> is the <c>pid()</c> of that process.
- </p>
- <p>
- If <c>Module:init/1</c> fails with <c>Reason</c>,
- this function returns
- <seealso marker="#type-start_ret"><c>{error,Reason}</c></seealso>.
- If <c>Module:init/1</c> returns
- <seealso marker="#type-start_ret">
- <c>{stop,Reason}</c>
- </seealso>
- or
- <seealso marker="#type-start_ret"><c>ignore</c></seealso>,
- the process is terminated and this function
- returns
- <seealso marker="#type-start_ret">
- <c>{error,Reason}</c>
- </seealso>
- or
- <seealso marker="#type-start_ret"><c>ignore</c></seealso>,
- respectively.
- </p>
- </desc>
- </func>
-
-
- <func>
- <name name="start" arity="3" />
- <name name="start" arity="4" />
- <fsummary>Create a stand-alone <c>gen_statem</c> process</fsummary>
- <desc>
- <p>
- Creates a stand-alone <c>gen_statem</c> process according to
- OTP design principles (using
- <seealso marker="proc_lib"><c>proc_lib</c></seealso>
- primitives).
- Since it does not get linked to the calling process
- this start function can not be used by a supervisor
- to start a child.
- </p>
- <p>
- See <seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>
- for a description of arguments and return values.
- </p>
- </desc>
- </func>
-
- <func>
- <name name="stop" arity="1" />
- <fsummary>Synchronously stop a generic server</fsummary>
- <desc>
- <p>
- The same as
- <seealso marker="#stop/3">
- <c>stop(<anno>ServerRef</anno>, normal, infinity)</c>.
- </seealso>
- </p>
- </desc>
- </func>
- <func>
- <name name="stop" arity="3" />
- <fsummary>Synchronously stop a generic server</fsummary>
- <desc>
- <p>
- Orders the <c>gen_statem</c>
- <seealso marker="#type-server_ref">
- <c><anno>ServerRef</anno></c>
- </seealso>
- to exit with the given <c><anno>Reason</anno></c>
- and waits for it to terminate.
- The <c>gen_statem</c> will call
- <seealso marker="#Module:terminate/3">
- <c>Module:terminate/3</c>
- </seealso>
- before exiting.
- </p>
- <p>
- This function returns <c>ok</c> if the server terminates
- with the expected reason. Any other reason than <c>normal</c>,
- <c>shutdown</c>, or <c>{shutdown,Term}</c> will cause an
- error report to be issued through
- <seealso marker="kernel:error_logger#format/2">
- <c>error_logger:format/2</c>.
- </seealso>
- The default <c><anno>Reason</anno></c> is <c>normal</c>.
- </p>
- <p>
- <c><anno>Timeout</anno></c> is an integer greater than zero
- which specifies how many milliseconds to wait for the server to
- terminate, or the atom <c>infinity</c> to wait indefinitely.
- The default value is <c>infinity</c>.
- If the server has not terminated within the specified time,
- a <c>timeout</c> exception is raised.
- </p>
- <p>
- If the process does not exist, a <c>noproc</c> exception
- is raised.
- </p>
- </desc>
- </func>
-
<func>
- <name name="call" arity="2" />
- <name name="call" arity="3" />
- <fsummary>Make a synchronous call to a <c>gen_statem</c></fsummary>
+ <name name="call" arity="2"/>
+ <name name="call" arity="3"/>
+ <fsummary>Make a synchronous call to a <c>gen_statem</c>.</fsummary>
<desc>
<p>
Makes a synchronous call to the <c>gen_statem</c>
- <seealso marker="#type-server_ref">
- <c><anno>ServerRef</anno></c>
- </seealso>
+ <seealso marker="#type-server_ref"><c><anno>ServerRef</anno></c></seealso>
by sending a request
and waiting until its reply arrives.
- The <c>gen_statem</c> will call the
+ The <c>gen_statem</c> calls the
<seealso marker="#state_function">state function</seealso> with
<seealso marker="#type-event_type"><c>event_type()</c></seealso>
<c>{call,From}</c> and event content
@@ -1108,43 +914,41 @@ handle_event(_, _, State, Data) ->
and that <c><anno>Reply</anno></c> becomes the return value
of this function.
</p>
- <p>
- <c><anno>Timeout</anno></c> is an integer greater than zero
+ <p>
+ <c><anno>Timeout</anno></c> is an integer &gt; 0,
which specifies how many milliseconds to wait for a reply,
or the atom <c>infinity</c> to wait indefinitely,
- which is the default. If no reply is received within
+ which is the default. If no reply is received within
the specified time, the function call fails.
</p>
<note>
<p>
To avoid getting a late reply in the caller's
- inbox this function spawns a proxy process that
- does the call. A late reply gets delivered to the
- dead proxy process hence gets discarded. This is
+ inbox, this function spawns a proxy process that
+ does the call. A late reply gets delivered to the
+ dead proxy process, hence gets discarded. This is
less efficient than using
<c><anno>Timeout</anno> =:= infinity</c>.
</p>
</note>
- <p>
- The call may fail for example if the <c>gen_statem</c> dies
+ <p>
+ The call can fail, for example, if the <c>gen_statem</c> dies
before or during this function call.
</p>
</desc>
</func>
<func>
- <name name="cast" arity="2" />
- <fsummary>Send an asynchronous event to a <c>gen_statem</c></fsummary>
+ <name name="cast" arity="2"/>
+ <fsummary>Send an asynchronous event to a <c>gen_statem</c>.</fsummary>
<desc>
<p>
Sends an asynchronous event to the <c>gen_statem</c>
- <seealso marker="#type-server_ref">
- <c><anno>ServerRef</anno></c>
- </seealso>
+ <seealso marker="#type-server_ref"><c><anno>ServerRef</anno></c></seealso>
and returns <c>ok</c> immediately,
ignoring if the destination node or <c>gen_statem</c>
does not exist.
- The <c>gen_statem</c> will call the
+ The <c>gen_statem</c> calls the
<seealso marker="#state_function">state function</seealso> with
<seealso marker="#type-event_type"><c>event_type()</c></seealso>
<c>cast</c> and event content
@@ -1154,68 +958,29 @@ handle_event(_, _, State, Data) ->
</func>
<func>
- <name name="reply" arity="1" />
- <name name="reply" arity="2" />
- <fsummary>Reply to a caller</fsummary>
- <desc>
- <p>
- This function can be used by a <c>gen_statem</c>
- to explicitly send a reply to a process that waits in
- <seealso marker="#call/2"><c>call/2</c></seealso>
- when the reply cannot be defined in
- the return value of a
- <seealso marker="#state_function">state function</seealso>.
- </p>
- <p>
- <c><anno>From</anno></c> must be the term from the
- <seealso marker="#type-event_type">
- <c>{call,<anno>From</anno>}</c>
- </seealso>
- argument to the
- <seealso marker="#state_function">state function</seealso>.
- <c><anno>From</anno></c> and <c><anno>Reply</anno></c>
- can also be specified using a
- <seealso marker="#type-reply_action">
- <c>reply_action()</c>
- </seealso>
- and multiple replies with a list of them.
- </p>
- <note>
- <p>
- A reply sent with this function will not be visible
- in <seealso marker="sys"><c>sys</c></seealso> debug output.
- </p>
- </note>
- </desc>
- </func>
-
- <func>
- <name name="enter_loop" arity="5" />
- <fsummary>Enter the <c>gen_statem</c> receive loop</fsummary>
+ <name name="enter_loop" arity="5"/>
+ <fsummary>Enter the <c>gen_statem</c> receive loop.</fsummary>
<desc>
<p>
The same as
<seealso marker="#enter_loop/7"><c>enter_loop/7</c></seealso>
except that no
- <seealso marker="#type-server_name">
- <c>server_name()</c>
- </seealso>
+ <seealso marker="#type-server_name"><c>server_name()</c></seealso>
must have been registered.
</p>
</desc>
</func>
+
<func>
- <name name="enter_loop" arity="6" />
- <fsummary>Enter the <c>gen_statem</c> receive loop</fsummary>
+ <name name="enter_loop" arity="6"/>
+ <fsummary>Enter the <c>gen_statem</c> receive loop.</fsummary>
<desc>
<p>
- If <c><anno>Server_or_Actions</anno></c> is a <c>list()</c>
+ If <c><anno>Server_or_Actions</anno></c> is a <c>list()</c>,
the same as
<seealso marker="#enter_loop/7"><c>enter_loop/7</c></seealso>
except that no
- <seealso marker="#type-server_name">
- <c>server_name()</c>
- </seealso>
+ <seealso marker="#type-server_name"><c>server_name()</c></seealso>
must have been registered and
<c>Actions = <anno>Server_or_Actions</anno></c>.
</p>
@@ -1228,73 +993,350 @@ handle_event(_, _, State, Data) ->
</p>
</desc>
</func>
+
<func>
- <name name="enter_loop" arity="7" />
- <fsummary>Enter the <c>gen_statem</c> receive loop</fsummary>
+ <name name="enter_loop" arity="7"/>
+ <fsummary>Enter the <c>gen_statem</c> receive loop.</fsummary>
<desc>
- <p>
- Makes an the calling process become a <c>gen_statem</c>.
- Does not return, instead the calling process will enter
- the <c>gen_statem</c> receive loop and become
+ <p>
+ Makes the calling process become a <c>gen_statem</c>.
+ Does not return, instead the calling process enters
+ the <c>gen_statem</c> receive loop and becomes
a <c>gen_statem</c> server.
The process <em>must</em> have been started
using one of the start functions in
- <seealso marker="proc_lib"><c>proc_lib</c></seealso>.
+ <seealso marker="proc_lib"><c>proc_lib</c></seealso>.
The user is responsible for any initialization of the process,
including registering a name for it.
</p>
- <p>
+ <p>
This function is useful when a more complex initialization
- procedure is needed than
- the <c>gen_statem</c> behaviour provides.
+ procedure is needed than
+ the <c>gen_statem</c> behavior provides.
</p>
- <p>
- <c><anno>Module</anno></c>, <c><anno>Opts</anno></c> and
+ <p>
+ <c><anno>Module</anno></c>, <c><anno>Opts</anno></c>, and
<c><anno>Server</anno></c> have the same meanings
as when calling
- <seealso marker="#start_link/3">
- <c>gen_statem:start[_link]/3,4</c>.
- </seealso>
- However, the
- <seealso marker="#type-server_name">
- <c>server_name()</c>
- </seealso>
+ <seealso marker="#start_link/3"><c>start[_link]/3,4</c></seealso>.
+ However, the
+ <seealso marker="#type-server_name"><c>server_name()</c></seealso>
name must have been registered accordingly
<em>before</em> this function is called.</p>
<p>
<c><anno>CallbackMode</anno></c>, <c><anno>State</anno></c>,
- <c><anno>Data</anno></c> and <c><anno>Actions</anno></c>
+ <c><anno>Data</anno></c>, and <c><anno>Actions</anno></c>
have the same meanings as in the return value of
- <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>.
- Also, the callback module <c><anno>Module</anno></c>
+ <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>.
+ Also, the callback module <c><anno>Module</anno></c>
does not need to export an <c>init/1</c> function.
</p>
<p>
- Failure: If the calling process was not started by a
- <seealso marker="proc_lib"><c>proc_lib</c></seealso>
+ The function fails if the calling process was not started by a
+ <seealso marker="proc_lib"><c>proc_lib</c></seealso>
start function, or if it is not registered
- according to
+ according to
<seealso marker="#type-server_name"><c>server_name()</c></seealso>.
</p>
</desc>
</func>
- </funcs>
+ <func>
+ <name name="reply" arity="1"/>
+ <name name="reply" arity="2"/>
+ <fsummary>Reply to a caller.</fsummary>
+ <desc>
+ <p>
+ This function can be used by a <c>gen_statem</c>
+ to explicitly send a reply to a process that waits in
+ <seealso marker="#call/2"><c>call/2</c></seealso>
+ when the reply cannot be defined in
+ the return value of a
+ <seealso marker="#state_function">state function</seealso>.
+ </p>
+ <p>
+ <c><anno>From</anno></c> must be the term from argument
+ <seealso marker="#type-event_type"><c>{call,<anno>From</anno>}</c></seealso>
+ to the
+ <seealso marker="#state_function">state function</seealso>.
+ <c><anno>From</anno></c> and <c><anno>Reply</anno></c>
+ can also be specified using a
+ <seealso marker="#type-reply_action"><c>reply_action()</c></seealso>
+ and multiple replies with a list of them.
+ </p>
+ <note>
+ <p>
+ A reply sent with this function is not visible
+ in <seealso marker="sys"><c>sys</c></seealso> debug output.
+ </p>
+ </note>
+ </desc>
+ </func>
+ <func>
+ <name name="start" arity="3"/>
+ <name name="start" arity="4"/>
+ <fsummary>Create a standalone <c>gen_statem</c> process.</fsummary>
+ <desc>
+ <p>
+ Creates a standalone <c>gen_statem</c> process according to
+ OTP design principles (using
+ <seealso marker="proc_lib"><c>proc_lib</c></seealso>
+ primitives).
+ As it does not get linked to the calling process,
+ this start function cannot be used by a supervisor
+ to start a child.
+ </p>
+ <p>
+ For a description of arguments and return values, see
+ <seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="start_link" arity="3"/>
+ <name name="start_link" arity="4"/>
+ <fsummary>Create a linked <c>gen_statem</c> process.</fsummary>
+ <desc>
+ <p>
+ Creates a <c>gen_statem</c> process according
+ to OTP design principles
+ (using
+ <seealso marker="proc_lib"><c>proc_lib</c></seealso>
+ primitives)
+ that is linked to the calling process.
+ This is essential when the <c>gen_statem</c> must be part of
+ a supervision tree so it gets linked to its supervisor.
+ </p>
+ <p>
+ The <c>gen_statem</c> process calls
+ <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
+ to initialize the server. To ensure a synchronized startup
+ procedure, <c>start_link/3,4</c> does not return until
+ <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
+ has returned.
+ </p>
+ <p>
+ <c><anno>ServerName</anno></c> specifies the
+ <seealso marker="#type-server_name"><c>server_name()</c></seealso>
+ to register for the <c>gen_statem</c>.
+ If the <c>gen_statem</c> is started with <c>start_link/3</c>,
+ no <c><anno>ServerName</anno></c> is provided and
+ the <c>gen_statem</c> is not registered.
+ </p>
+ <p><c><anno>Module</anno></c> is the name of the callback module.</p>
+ <p>
+ <c><anno>Args</anno></c> is an arbitrary term that is passed as
+ the argument to
+ <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>.
+ </p>
+ <list type="bulleted">
+ <item>
+ <p>
+ If option <c>{timeout,Time}</c> is present in
+ <c><anno>Opts</anno></c>, the <c>gen_statem</c>
+ is allowed to spend <c>Time</c> milliseconds initializing
+ or it terminates and the start function returns
+ <seealso marker="#type-start_ret"><c>{error,timeout}</c></seealso>.
+ </p>
+ </item>
+ <item>
+ <p>
+ If option
+ <seealso marker="#type-debug_opt"><c>{debug,Dbgs}</c></seealso>
+ is present in <c><anno>Opts</anno></c>, debugging through
+ <seealso marker="sys"><c>sys</c></seealso> is activated.
+ </p>
+ </item>
+ <item>
+ <p>
+ If option <c>{spawn_opt,SpawnOpts}</c> is present in
+ <c><anno>Opts</anno></c>, <c>SpawnOpts</c> is passed
+ as option list to
+ <seealso marker="erts:erlang#spawn_opt/2"><c>erlang:spawn_opt/2</c></seealso>,
+ which is used to spawn the <c>gen_statem</c> process.
+ </p>
+ </item>
+ </list>
+ <note>
+ <p>
+ Using spawn option <c>monitor</c> is not
+ allowed, it causes this function to fail with reason
+ <c>badarg</c>.
+ </p>
+ </note>
+ <p>
+ If the <c>gen_statem</c> is successfully created
+ and initialized, this function returns
+ <seealso marker="#type-start_ret"><c>{ok,Pid}</c></seealso>,
+ where <c>Pid</c> is the <c>pid()</c>
+ of the <c>gen_statem</c>.
+ If a process with the specified <c><anno>ServerName</anno></c>
+ exists already, this function returns
+ <seealso marker="#type-start_ret"><c>{error,{already_started,Pid}}</c></seealso>,
+ where <c>Pid</c> is the <c>pid()</c> of that process.
+ </p>
+ <p>
+ If <c>Module:init/1</c> fails with <c>Reason</c>,
+ this function returns
+ <seealso marker="#type-start_ret"><c>{error,Reason}</c></seealso>.
+ If <c>Module:init/1</c> returns
+ <seealso marker="#type-start_ret"><c>{stop,Reason}</c></seealso>
+ or
+ <seealso marker="#type-start_ret"><c>ignore</c></seealso>,
+ the process is terminated and this function
+ returns
+ <seealso marker="#type-start_ret"><c>{error,Reason}</c></seealso>
+ or
+ <seealso marker="#type-start_ret"><c>ignore</c></seealso>,
+ respectively.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="stop" arity="1"/>
+ <fsummary>Synchronously stop a generic server.</fsummary>
+ <desc>
+ <p>
+ The same as
+ <seealso marker="#stop/3"><c>stop(<anno>ServerRef</anno>, normal, infinity)</c></seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="stop" arity="3"/>
+ <fsummary>Synchronously stop a generic server.</fsummary>
+ <desc>
+ <p>
+ Orders the <c>gen_statem</c>
+ <seealso marker="#type-server_ref"><c><anno>ServerRef</anno></c></seealso>
+ to exit with the specified <c><anno>Reason</anno></c>
+ and waits for it to terminate.
+ The <c>gen_statem</c> calls
+ <seealso marker="#Module:terminate/3"><c>Module:terminate/3</c></seealso>
+ before exiting.
+ </p>
+ <p>
+ This function returns <c>ok</c> if the server terminates
+ with the expected reason. Any other reason than <c>normal</c>,
+ <c>shutdown</c>, or <c>{shutdown,Term}</c> causes an
+ error report to be issued through
+ <seealso marker="kernel:error_logger#format/2"><c>error_logger:format/2</c></seealso>.
+ The default <c><anno>Reason</anno></c> is <c>normal</c>.
+ </p>
+ <p>
+ <c><anno>Timeout</anno></c> is an integer &gt; 0,
+ which specifies how many milliseconds to wait for the server to
+ terminate, or the atom <c>infinity</c> to wait indefinitely.
+ Defaults to <c>infinity</c>.
+ If the server does not terminate within the specified time,
+ a <c>timeout</c> exception is raised.
+ </p>
+ <p>
+ If the process does not exist, a <c>noproc</c> exception
+ is raised.
+ </p>
+ </desc>
+ </func>
+ </funcs>
<section>
- <title>CALLBACK FUNCTIONS</title>
+ <title>Callback Functions</title>
<p>
- The following functions should be exported from a
+ The following functions are to be exported from a
<c>gen_statem</c> callback module.
</p>
</section>
+
<funcs>
+ <func>
+ <name>Module:code_change(OldVsn, OldState, OldData, Extra) ->
+ Result
+ </name>
+ <fsummary>Update the internal state during upgrade/downgrade.</fsummary>
+ <type>
+ <v>OldVsn = Vsn | {down,Vsn}</v>
+ <v>&nbsp;&nbsp;Vsn = term()</v>
+ <v>OldState = NewState = term()</v>
+ <v>Extra = term()</v>
+ <v>Result = {NewCallbackMode,NewState,NewData} | Reason</v>
+ <v>
+ NewCallbackMode =
+ <seealso marker="#type-callback_mode">callback_mode()</seealso>
+ </v>
+ <v>
+ OldState = NewState =
+ <seealso marker="#type-state">state()</seealso>
+ </v>
+ <v>
+ OldData = NewData =
+ <seealso marker="#type-data">data()</seealso>
+ </v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>
+ This function is called by a <c>gen_statem</c> when it is to
+ update its internal state during a release upgrade/downgrade,
+ that is, when the instruction <c>{update,Module,Change,...}</c>,
+ where <c>Change={advanced,Extra}</c>, is specified in the
+ <seealso marker="sasl:appup"><c>appup</c></seealso>
+ file. For more information, see
+ <seealso marker="doc/design_principles:release_handling#instr">OTP Design Principles</seealso>.
+ </p>
+ <p>
+ For an upgrade, <c>OldVsn</c> is <c>Vsn</c>, and
+ for a downgrade, <c>OldVsn</c> is
+ <c>{down,Vsn}</c>. <c>Vsn</c> is defined by the <c>vsn</c>
+ attribute(s) of the old version of the callback module
+ <c>Module</c>. If no such attribute is defined, the version
+ is the checksum of the Beam file.
+ </p>
+ <note>
+ <p>
+ If you would dare to change
+ <seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
+ during release upgrade/downgrade, the upgrade is no problem,
+ as the new code surely knows what <em>callback mode</em>
+ it needs. However, for a downgrade this function must
+ know from argument <c>Extra</c> that comes from the
+ <seealso marker="sasl:appup"><c>sasl:appup</c></seealso>
+ file what <em>callback mode</em> the old code did use.
+ It can also be possible to figure this out
+ from argument <c>{down,Vsn}</c>, as <c>Vsn</c>
+ in effect defines the old callback module version.
+ </p>
+ </note>
+ <p>
+ <c>OldState</c> and <c>OldData</c> is the internal state
+ of the <c>gen_statem</c>.
+ </p>
+ <p>
+ <c>Extra</c> is passed "as is" from the <c>{advanced,Extra}</c>
+ part of the update instruction.
+ </p>
+ <p>
+ If successful, the function must return the updated
+ internal state in an
+ <c>{NewCallbackMode,NewState,NewData}</c> tuple.
+ </p>
+ <p>
+ If the function returns <c>Reason</c>, the ongoing
+ upgrade fails and rolls back to the old release.</p>
+ <p>
+ This function can use
+ <seealso marker="erts:erlang#throw/1"><c>erlang:throw/1</c></seealso>
+ to return <c>Result</c> or <c>Reason</c>.
+ </p>
+ </desc>
+ </func>
<func>
<name>Module:init(Args) -> Result</name>
- <fsummary>Initialize process and internal state</fsummary>
+ <fsummary>Initialize process and internal state.</fsummary>
<type>
<v>Args = term()</v>
<v>Result = {CallbackMode,State,Data}</v>
@@ -1316,25 +1358,25 @@ handle_event(_, _, State, Data) ->
<v>Reason = term()</v>
</type>
<desc>
- <marker id="Module:init-1" />
- <p>
+ <marker id="Module:init-1"/>
+ <p>
Whenever a <c>gen_statem</c> is started using
- <seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>
+ <seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>
or
- <seealso marker="#start/3"><c>start/3,4</c></seealso>,
- this function is called by the new process to initialize
+ <seealso marker="#start/3"><c>start/3,4</c></seealso>,
+ this function is called by the new process to initialize
the implementation state and server data.
</p>
- <p>
+ <p>
<c>Args</c> is the <c>Args</c> argument provided to the start
- function.
+ function.
</p>
- <p>
- If the initialization is successful, the function should
- return <c>{CallbackMode,State,Data}</c> or
+ <p>
+ If the initialization is successful, the function is to
+ return <c>{CallbackMode,State,Data}</c> or
<c>{CallbackMode,State,Data,Actions}</c>.
<c>CallbackMode</c> selects the
- <seealso marker="#type-callback_mode"><em>callback mode</em></seealso>.
+ <seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
of the <c>gen_statem</c>.
<c>State</c> is the initial
<seealso marker="#type-state"><c>state()</c></seealso>
@@ -1347,28 +1389,127 @@ handle_event(_, _, State, Data) ->
<seealso marker="#type-state">state</seealso> just as for a
<seealso marker="#state_function">state function</seealso>.
</p>
- <p>
- If something goes wrong during the initialization
- the function should return <c>{stop,Reason}</c>
- or <c>ignore</c>. See
+ <p>
+ If the initialization fails,
+ the function is to return <c>{stop,Reason}</c>
+ or <c>ignore</c>; see
<seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>.
</p>
<p>
- This function may use
- <seealso marker="erts:erlang#throw/1"><c>throw/1</c></seealso>
+ This function can use
+ <seealso marker="erts:erlang#throw/1"><c>erlang:throw/1</c></seealso>
to return <c>Result</c>.
</p>
</desc>
</func>
<func>
+ <name>Module:format_status(Opt, [PDict,State,Data]) ->
+ Status
+ </name>
+ <fsummary>Optional function for providing a term describing the
+ current <c>gen_statem</c> status.</fsummary>
+ <type>
+ <v>Opt = normal | terminate</v>
+ <v>PDict = [{Key, Value}]</v>
+ <v>
+ State =
+ <seealso marker="#type-state">state()</seealso>
+ </v>
+ <v>
+ Data =
+ <seealso marker="#type-data">data()</seealso>
+ </v>
+ <v>Key = term()</v>
+ <v>Value = term()</v>
+ <v>Status = term()</v>
+ </type>
+ <desc>
+ <note>
+ <p>
+ This callback is optional, so a callback module does not need
+ to export it. The <c>gen_statem</c> module provides a default
+ implementation of this function that returns
+ <c>{State,Data}</c>. If this callback fails, the default
+ function returns <c>{State,Info}</c>,
+ where <c>Info</c> informs of the crash but no details,
+ to hide possibly sensitive data.
+ </p>
+ </note>
+ <p>This function is called by a <c>gen_statem</c> process when
+ any of the following apply:</p>
+ <list type="bulleted">
+ <item>
+ One of
+ <seealso marker="sys#get_status/1"><c>sys:get_status/1,2</c></seealso>
+ is invoked to get the <c>gen_statem</c> status. <c>Opt</c> is set
+ to the atom <c>normal</c> for this case.
+ </item>
+ <item>
+ The <c>gen_statem</c> terminates abnormally and logs an error.
+ <c>Opt</c> is set to the atom <c>terminate</c> for this case.
+ </item>
+ </list>
+ <p>
+ This function is useful for changing the form and
+ appearance of the <c>gen_statem</c> status for these cases. A
+ callback module wishing to change the
+ <seealso marker="sys#get_status/1"><c>sys:get_status/1,2</c></seealso>
+ return value and how
+ its status appears in termination error logs exports an
+ instance of <c>format_status/2</c>, which returns a term
+ describing the current status of the <c>gen_statem</c>.
+ </p>
+ <p>
+ <c>PDict</c> is the current value of the process dictionary
+ of the <c>gen_statem</c>.
+ </p>
+ <p>
+ <seealso marker="#type-state"><c>State</c></seealso>
+ is the internal state of the <c>gen_statem</c>.
+ </p>
+ <p>
+ <seealso marker="#type-data"><c>Data</c></seealso>
+ is the internal server data of the <c>gen_statem</c>.
+ </p>
+ <p>
+ The function is to return <c>Status</c>, a term that
+ changes the details of the current state and status of
+ the <c>gen_statem</c>. There are no restrictions on the
+ form <c>Status</c> can take, but for the
+ <seealso marker="sys#get_status/1"><c>sys:get_status/1,2</c></seealso>
+ case (when <c>Opt</c>
+ is <c>normal</c>), the recommended form for
+ the <c>Status</c> value is <c>[{data, [{"State",
+ Term}]}]</c>, where <c>Term</c> provides relevant details of
+ the <c>gen_statem</c> state. Following this recommendation is not
+ required, but it makes the callback module status
+ consistent with the rest of the
+ <seealso marker="sys#get_status/1"><c>sys:get_status/1,2</c></seealso>
+ return value.
+ </p>
+ <p>
+ One use for this function is to return compact alternative
+ state representations to avoid having large state terms
+ printed in log files. Another use is to hide sensitive data from
+ being written to the error log.
+ </p>
+ <p>
+ This function can use
+ <seealso marker="erts:erlang#throw/1"><c>erlang:throw/1</c></seealso>
+ to return <c>Status</c>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
<name>Module:StateName(EventType, EventContent, Data) ->
- StateFunctionResult
+ StateFunctionResult
</name>
<name>Module:handle_event(EventType, EventContent,
- State, Data) -> HandleEventResult
+ State, Data) -> HandleEventResult
</name>
- <fsummary>Handle an event</fsummary>
+ <fsummary>Handle an event.</fsummary>
<type>
<v>
EventType =
@@ -1385,59 +1526,55 @@ handle_event(_, _, State, Data) ->
</v>
<v>
StateFunctionResult =
- <seealso marker="#type-state_function_result">
- state_function_result()
- </seealso>
+ <seealso marker="#type-state_function_result">state_function_result()</seealso>
</v>
<v>
HandleEventResult =
- <seealso marker="#type-handle_event_result">
- handle_event_result()
- </seealso>
+ <seealso marker="#type-handle_event_result">handle_event_result()</seealso>
</v>
</type>
<desc>
- <p>
+ <p>
Whenever a <c>gen_statem</c> receives an event from
- <seealso marker="#call/2"><c>call/2</c></seealso>,
- <seealso marker="#cast/2"><c>cast/2</c></seealso> or
- as a normal process message one of these functions is called. If
+ <seealso marker="#call/2"><c>call/2</c></seealso>,
+ <seealso marker="#cast/2"><c>cast/2</c></seealso>, or
+ as a normal process message, one of these functions is called. If
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
- is <c>state_functions</c> then <c>Module:StateName/3</c> is called,
- and if it is <c>handle_event_function</c>
- then <c>Module:handle_event/4</c> is called.
+ is <c>state_functions</c>, <c>Module:StateName/3</c> is called,
+ and if it is <c>handle_event_function</c>,
+ <c>Module:handle_event/4</c> is called.
</p>
<p>
If <c>EventType</c> is
- <seealso marker="#type-event_type"><c>{call,From}</c></seealso>
- the caller is waiting for a reply. The reply can be sent
+ <seealso marker="#type-event_type"><c>{call,From}</c></seealso>,
+ the caller waits for a reply. The reply can be sent
from this or from any other
<seealso marker="#state_function">state function</seealso>
by returning with <c>{reply,From,Reply}</c> in
<seealso marker="#type-action"><c>Actions</c></seealso>, in
- <seealso marker="#type-reply_action"><c>Replies</c></seealso>
+ <seealso marker="#type-reply_action"><c>Replies</c></seealso>,
or by calling
<seealso marker="#reply/2"><c>reply(From, Reply)</c></seealso>.
</p>
<p>
If this function returns with a next state that
- does not match equal (<c>=/=</c>) to the current state
- all postponed events will be retried in the next state.
+ does not match equal (<c>=/=</c>) to the current state,
+ all postponed events are retried in the next state.
</p>
<p>
The only difference between <c>StateFunctionResult</c> and
<c>HandleEventResult</c> is that for <c>StateFunctionResult</c>
- the next state has to be an atom but for <c>HandleEventResult</c>
+ the next state must be an atom, but for <c>HandleEventResult</c>
there is no restriction on the next state.
</p>
<p>
- See <seealso marker="#type-action"><c>action()</c></seealso>
- for options that can be set and actions that can be done
- by <c>gen_statem</c> after returning from this function.
+ For options that can be set and actions that can be done
+ by <c>gen_statem</c> after returning from this function,
+ see <seealso marker="#type-action"><c>action()</c></seealso>.
</p>
<p>
- These functions may use
- <seealso marker="erts:erlang#throw/1"><c>throw/1</c></seealso>,
+ These functions can use
+ <seealso marker="erts:erlang#throw/1"><c>erlang:throw/1</c></seealso>,
to return the result.
</p>
</desc>
@@ -1445,7 +1582,7 @@ handle_event(_, _, State, Data) ->
<func>
<name>Module:terminate(Reason, State, Data) -> Ignored</name>
- <fsummary>Clean up before termination</fsummary>
+ <fsummary>Clean up before termination.</fsummary>
<type>
<v>Reason = normal | shutdown | {shutdown,term()} | term()</v>
<v>State = <seealso marker="#type-state">state()</seealso></v>
@@ -1453,272 +1590,82 @@ handle_event(_, _, State, Data) ->
<v>Ignored = term()</v>
</type>
<desc>
- <p>
+ <p>
This function is called by a <c>gen_statem</c>
- when it is about to terminate. It should be the opposite of
+ when it is about to terminate. It is to be the opposite of
<seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
- and do any necessary cleaning up. When it returns,
- the <c>gen_statem</c> terminates with <c>Reason</c>. The return
- value is ignored.</p>
- <p>
+ and do any necessary cleaning up. When it returns,
+ the <c>gen_statem</c> terminates with <c>Reason</c>. The return
+ value is ignored.</p>
+ <p>
<c>Reason</c> is a term denoting the stop reason and
- <seealso marker="#type-state"><c>State</c></seealso>
+ <seealso marker="#type-state"><c>State</c></seealso>
is the internal state of the <c>gen_statem</c>.
</p>
- <p>
+ <p>
<c>Reason</c> depends on why the <c>gen_statem</c>
is terminating.
- If it is because another callback function has returned a
- stop tuple <c>{stop,Reason}</c> in
+ If it is because another callback function has returned, a
+ stop tuple <c>{stop,Reason}</c> in
<seealso marker="#type-action"><c>Actions</c></seealso>,
- <c>Reason</c> will have the value specified in that tuple.
- If it is due to a failure, <c>Reason</c> is the error reason.
+ <c>Reason</c> has the value specified in that tuple.
+ If it is because of a failure, <c>Reason</c> is the error reason.
</p>
<p>
If the <c>gen_statem</c> is part of a supervision tree and is
- ordered by its supervisor to terminate, this function will be
- called with <c>Reason = shutdown</c> if the following
+ ordered by its supervisor to terminate, this function is
+ called with <c>Reason = shutdown</c> if both the following
conditions apply:</p>
<list type="bulleted">
<item>
- the <c>gen_statem</c> has been set
- to trap exit signals, and
+ <p>
+ The <c>gen_statem</c> has been set
+ to trap exit signals.
+ </p>
</item>
<item>
- the shutdown strategy as defined in the supervisor's
- child specification is an integer timeout value, not
- <c>brutal_kill</c>.
+ <p>
+ The shutdown strategy as defined in the supervisor's
+ child specification is an integer time-out value, not
+ <c>brutal_kill</c>.
+ </p>
</item>
</list>
<p>
Even if the <c>gen_statem</c> is <em>not</em>
- part of a supervision tree, this function will be called
+ part of a supervision tree, this function is called
if it receives an <c>'EXIT'</c> message from its parent.
- <c>Reason</c> will be the same as
+ <c>Reason</c> is the same as
in the <c>'EXIT'</c> message.
</p>
<p>
- Otherwise, the <c>gen_statem</c> will be immediately terminated.
+ Otherwise, the <c>gen_statem</c> is immediately terminated.
</p>
<p>
- Note that for any other reason than <c>normal</c>,
- <c>shutdown</c>, or <c>{shutdown,Term}</c>
- the <c>gen_statem</c> is assumed to terminate due to an error
+ Notice that for any other reason than <c>normal</c>,
+ <c>shutdown</c>, or <c>{shutdown,Term}</c>,
+ the <c>gen_statem</c> is assumed to terminate because of an error
and an error report is issued using
- <seealso marker="kernel:error_logger#format/2">
- <c>error_logger:format/2</c>.
- </seealso>
+ <seealso marker="kernel:error_logger#format/2"><c>error_logger:format/2</c></seealso>.
</p>
<p>
- This function may use
- <seealso marker="erts:erlang#throw/1"><c>throw/1</c></seealso>
+ This function can use
+ <seealso marker="erts:erlang#throw/1"><c>erlang:throw/1</c></seealso>
to return <c>Ignored</c>, which is ignored anyway.
</p>
</desc>
</func>
-
- <func>
- <name>Module:code_change(OldVsn, OldState, OldData, Extra) ->
- Result
- </name>
- <fsummary>Update the internal state during upgrade/downgrade</fsummary>
- <type>
- <v>OldVsn = Vsn | {down,Vsn}</v>
- <v>&nbsp;&nbsp;Vsn = term()</v>
- <v>OldState = NewState = term()</v>
- <v>Extra = term()</v>
- <v>Result = {NewCallbackMode,NewState,NewData} | Reason</v>
- <v>
- NewCallbackMode =
- <seealso marker="#type-callback_mode">callback_mode()</seealso>
- </v>
- <v>
- OldState = NewState =
- <seealso marker="#type-state">state()</seealso>
- </v>
- <v>
- OldData = NewData =
- <seealso marker="#type-data">data()</seealso>
- </v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>
- This function is called by a <c>gen_statem</c> when it should
- update its internal state during a release upgrade/downgrade,
- that is when the instruction <c>{update,Module,Change,...}</c>
- where <c>Change={advanced,Extra}</c> is given in the
- <seealso marker="sasl:appup"><c>appup</c></seealso>
- file. See
- <seealso marker="doc/design_principles:release_handling#instr">
- OTP Design Principles
- </seealso>
- for more information.
- </p>
- <p>
- In the case of an upgrade, <c>OldVsn</c> is <c>Vsn</c>, and
- in the case of a downgrade, <c>OldVsn</c> is
- <c>{down,Vsn}</c>. <c>Vsn</c> is defined by the <c>vsn</c>
- attribute(s) of the old version of the callback module
- <c>Module</c>. If no such attribute is defined, the version
- is the checksum of the BEAM file.
- </p>
- <note>
- <p>
- If you would dare to change
- <seealso marker="#type-callback_mode">
- <em>callback mode</em>
- </seealso>
- during release upgrade/downgrade, the upgrade is no problem
- since the new code surely knows what <em>callback mode</em>
- it needs, but for a downgrade this function will have to
- know from the <c>Extra</c> argument that comes from the
- <seealso marker="sasl:appup"><c>appup</c></seealso>
- file what <em>callback mode</em> the old code did use.
- It may also be possible to figure this out
- from the <c>{down,Vsn}</c> argument since <c>Vsn</c>
- in effect defines the old callback module version.
- </p>
- </note>
- <p>
- <c>OldState</c> and <c>OldData</c> is the internal state
- of the <c>gen_statem</c>.
- </p>
- <p>
- <c>Extra</c> is passed as-is from the <c>{advanced,Extra}</c>
- part of the update instruction.
- </p>
- <p>
- If successful, the function shall return the updated
- internal state in an
- <c>{NewCallbackMode,NewState,NewData}</c> tuple.
- </p>
- <p>
- If the function returns <c>Reason</c>, the ongoing
- upgrade will fail and roll back to the old release.</p>
- <p>
- This function may use
- <seealso marker="erts:erlang#throw/1"><c>throw/1</c></seealso>
- to return <c>Result</c> or <c>Reason</c>.
- </p>
- </desc>
- </func>
-
- <func>
- <name>Module:format_status(Opt, [PDict,State,Data]) ->
- Status
- </name>
- <fsummary>Optional function for providing a term describing the
- current <c>gen_statem</c> status</fsummary>
- <type>
- <v>Opt = normal | terminate</v>
- <v>PDict = [{Key, Value}]</v>
- <v>
- State =
- <seealso marker="#type-state">state()</seealso>
- </v>
- <v>
- Data =
- <seealso marker="#type-data">data()</seealso>
- </v>
- <v>Key = term()</v>
- <v>Value = term()</v>
- <v>Status = term()</v>
- </type>
- <desc>
- <note>
- <p>
- This callback is optional, so a callback module need not
- export it. The <c>gen_statem</c> module provides a default
- implementation of this function that returns
- <c>{State,Data}</c>. If this callback fails the default
- function will return <c>{State,Info}</c>
- where <c>Info</c> informs of the crash but no details,
- to hide possibly sensitive data.
- </p>
- </note>
- <p>This function is called by a <c>gen_statem</c> process when:</p>
- <list type="bulleted">
- <item>
- One of
- <seealso marker="sys#get_status/1">
- <c>sys:get_status/1,2</c>
- </seealso>
- is invoked to get the <c>gen_statem</c> status. <c>Opt</c> is set
- to the atom <c>normal</c> for this case.
- </item>
- <item>
- The <c>gen_statem</c> terminates abnormally and logs an error.
- <c>Opt</c> is set to the atom <c>terminate</c> for this case.
- </item>
- </list>
- <p>
- This function is useful for customising the form and
- appearance of the <c>gen_statem</c> status for these cases. A
- callback module wishing to customise the
- <seealso marker="sys#get_status/1">
- <c>sys:get_status/1,2</c>
- </seealso>
- return value as well as how
- its status appears in termination error logs exports an
- instance of <c>format_status/2</c> that returns a term
- describing the current status of the <c>gen_statem</c>.
- </p>
- <p>
- <c>PDict</c> is the current value of the <c>gen_statem</c>'s
- process dictionary.
- </p>
- <p>
- <seealso marker="#type-state"><c>State</c></seealso>
- is the internal state of the <c>gen_statem</c>.
- </p>
- <p>
- <seealso marker="#type-data"><c>Data</c></seealso>
- is the internal server data of the <c>gen_statem</c>.
- </p>
- <p>
- The function should return <c>Status</c>, a term that
- customises the details of the current state and status of
- the <c>gen_statem</c>. There are no restrictions on the
- form <c>Status</c> can take, but for the
- <seealso marker="sys#get_status/1">
- <c>sys:get_status/1,2</c>
- </seealso>
- case (when <c>Opt</c>
- is <c>normal</c>), the recommended form for
- the <c>Status</c> value is <c>[{data, [{"State",
- Term}]}]</c> where <c>Term</c> provides relevant details of
- the <c>gen_statem</c> state. Following this recommendation isn't
- required, but doing so will make the callback module status
- consistent with the rest of the
- <seealso marker="sys#get_status/1">
- <c>sys:get_status/1,2</c>
- </seealso>
- return value.
- </p>
- <p>
- One use for this function is to return compact alternative
- state representations to avoid having large state terms
- printed in logfiles. Another is to hide sensitive data from
- being written to the error log.
- </p>
- <p>
- This function may use
- <seealso marker="erts:erlang#throw/1"><c>throw/1</c></seealso>
- to return <c>Status</c>.
- </p>
- </desc>
- </func>
-
</funcs>
<section>
- <title>SEE ALSO</title>
- <p><seealso marker="gen_event"><c>gen_event(3)</c></seealso>,
+ <title>See Also</title>
+ <p>
+ <seealso marker="gen_event"><c>gen_event(3)</c></seealso>,
<seealso marker="gen_fsm"><c>gen_fsm(3)</c></seealso>,
<seealso marker="gen_server"><c>gen_server(3)</c></seealso>,
- <seealso marker="supervisor"><c>supervisor(3)</c></seealso>,
<seealso marker="proc_lib"><c>proc_lib(3)</c></seealso>,
- <seealso marker="sys"><c>sys(3)</c></seealso></p>
+ <seealso marker="supervisor"><c>supervisor(3)</c></seealso>,
+ <seealso marker="sys"><c>sys(3)</c></seealso>.
+ </p>
</section>
</erlref>
diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml
index ca0fce55e2..585b1a35f5 100644
--- a/system/doc/design_principles/statem.xml
+++ b/system/doc/design_principles/statem.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,7 +22,7 @@
</legalnotice>
- <title>gen_statem Behaviour</title>
+ <title>gen_statem Behavior</title>
<prepared></prepared>
<docno></docno>
<date></date>
@@ -33,63 +33,61 @@
<p>
This section is to be read with the
<seealso marker="stdlib:gen_statem"><c>gen_statem(3)</c></seealso>
- manual page in STDLIB, where all interface functions and callback
+ manual page in <c>STDLIB</c>, where all interface functions and callback
functions are described in detail.
</p>
- <p>
- This is a new behaviour in OTP-19.0.
- It has been thoroughly reviewed, is stable enough
- to be used by at least two heavy OTP applications, and is here to stay.
- But depending on user feedback, we do not expect
- but might find it necessary to make minor
- not backwards compatible changes into OTP-20.0,
- so its state can be designated as "not quite experimental"...
- </p>
+ <note>
+ <p>
+ This is a new behavior in Erlang/OTP 19.0.
+ It has been thoroughly reviewed, is stable enough
+ to be used by at least two heavy OTP applications, and is here to stay.
+ Depending on user feedback, we do not expect
+ but can find it necessary to make minor
+ not backward compatible changes into Erlang/OTP 20.0.
+ </p>
+ </note>
<!-- =================================================================== -->
<section>
- <title>Event Driven State Machines</title>
+ <title>Event-Driven State Machines</title>
<p>
Established Automata theory does not deal much with
how a state transition is triggered,
- but in general assumes that the output is a function
+ but assumes that the output is a function
of the input (and the state) and that they are
some kind of values.
</p>
<p>
- For an Event Driven State Machine the input is an event
+ For an Event-Driven State Machine, the input is an event
that triggers a state transition and the output
is actions executed during the state transition.
It can analogously to the mathematical model of a
- Finite State Machine be described as
- a set of relations of the form:
+ Finite-State Machine be described as
+ a set of relations of the following form:
</p>
<pre>
State(S) x Event(E) -> Actions(A), State(S')</pre>
- <p>These relations are interpreted as meaning:</p>
- <p>
- If we are in state <c>S</c> and event <c>E</c> occurs, we
+ <p>These relations are interpreted as follows:
+ if we are in state <c>S</c> and event <c>E</c> occurs, we
are to perform actions <c>A</c> and make a transition to
- state <c>S'</c>.
- </p>
- <p>
- Note that <c>S'</c> may be equal to <c>S</c>.
+ state <c>S'</c>. Notice that <c>S'</c> can be equal to <c>S</c>.
</p>
<p>
- Since <c>A</c> and <c>S'</c> depend only on
- <c>S</c> and <c>E</c> the kind of state machine described
- here is a Mealy Machine.
- (See for example the corresponding Wikipedia article)
+ As <c>A</c> and <c>S'</c> depend only on
+ <c>S</c> and <c>E</c>, the kind of state machine described
+ here is a Mealy Machine
+ (see, for example, the corresponding Wikipedia article).
</p>
<p>
- Like most <c>gen_</c> behaviours, <c>gen_statem</c> keeps
- a server <c>Data</c> besides the state. This and the fact that
+ Like most <c>gen_</c> behaviors, <c>gen_statem</c> keeps
+ a server <c>Data</c> besides the state. Because of this, and as
there is no restriction on the number of states
- (assuming enough virtual machine memory)
- or on the number of distinct input events actually makes
- a state machine implemented with this behaviour Turing complete.
- But it feels mostly like an Event Driven Mealy Machine.
+ (assuming that there is enough virtual machine memory)
+ or on the number of distinct input events,
+ a state machine implemented with this behavior
+ is in fact Turing complete.
+ But it feels mostly like an Event-Driven Mealy Machine.
</p>
</section>
@@ -99,38 +97,39 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
<marker id="callback_modes" />
<title>Callback Modes</title>
<p>
- The <c>gen_statem</c> behaviour supports two different callback modes.
- In the mode
- <seealso marker="stdlib:gen_statem#type-callback_mode">
- <c>state_functions</c>,
- </seealso>
- the state transition rules are written as a number of Erlang
- functions, which conform to the following convention:
+ The <c>gen_statem</c> behavior supports two callback modes:
</p>
- <pre>
+ <list type="bulleted">
+ <item>
+ <p>
+ In mode
+ <seealso marker="stdlib:gen_statem#type-callback_mode"><c>state_functions</c></seealso>,
+ the state transition rules are written as some Erlang
+ functions, which conform to the following convention:
+ </p>
+ <pre>
StateName(EventType, EventContent, Data) ->
.. code for actions here ...
{next_state, NewStateName, NewData}.</pre>
- <p>
- In the mode
- <seealso marker="stdlib:gen_statem#type-callback_mode">
- <c>handle_event_function</c>
- </seealso>
- there is only one
- Erlang function that implements all state transition rules:
- </p>
- <pre>
+ </item>
+ <item>
+ <p>
+ In mode
+ <seealso marker="stdlib:gen_statem#type-callback_mode"><c>handle_event_function</c></seealso>,
+ only one Erlang function provides all state transition rules:
+ </p>
+ <pre>
handle_event(EventType, EventContent, State, Data) ->
.. code for actions here ...
- {next_state, State', Data'}</pre>
- <p>
- Both these modes allow other return tuples
- that you can find in the
- <seealso marker="stdlib:gen_statem#Module:StateName/3">
- reference manual.
- </seealso>
- These other return tuples can for example stop the machine,
- execute state transition actions on the machine engine itself
+ {next_state, NewState, NewData}</pre>
+ </item>
+ </list>
+ <p>
+ Both these modes allow other return tuples; see
+ <seealso marker="stdlib:gen_statem#Module:StateName/3"><c>Module:StateName/3</c></seealso>
+ in the <c>gen_statem</c> manual page.
+ These other return tuples can, for example, stop the machine,
+ execute state transition actions on the machine engine itself,
and send replies.
</p>
@@ -139,54 +138,54 @@ handle_event(EventType, EventContent, State, Data) ->
<p>
The two
<seealso marker="#callback_modes">callback modes</seealso>
- gives different possibilities
+ give different possibilities
and restrictions, but one goal remains:
you want to handle all possible combinations of
events and states.
</p>
<p>
- You can for example do this by focusing on one state at the time
- and for every state ensure that all events are handled,
- or the other way around focus on one event at the time
- and ensure that it is handled in every state,
- or mix these strategies.
+ This can be done, for example, by focusing on one state at the time
+ and for every state ensure that all events are handled.
+ Alternatively, you can focus on one event at the time
+ and ensure that it is handled in every state.
+ You can also use a mix of these strategies.
</p>
<p>
- With <c>state_functions</c> you are restricted to use
- atom only states, and the <c>gen_statem</c> engine dispatches
- on state name for you. This encourages the callback module
+ With <c>state_functions</c>, you are restricted to use
+ atom-only states, and the <c>gen_statem</c> engine dispatches
+ on state name for you. This encourages the callback module
to gather the implementation of all event actions particular
- to one state in the same place in the code
+ to one state in the same place in the code,
hence to focus on one state at the time.
</p>
<p>
- This mode fits well when you have a regular state diagram
- like the ones in this chapter that describes all events and actions
+ This mode fits well when you have a regular state diagram,
+ like the ones in this chapter, which describes all events and actions
belonging to a state visually around that state,
and each state has its unique name.
</p>
<p>
- With <c>handle_event_function</c> you are free to mix strategies
- as you like because all events and states
- are handled in the the same callback function.
+ With <c>handle_event_function</c>, you are free to mix strategies,
+ as all events and states are handled in the same callback function.
</p>
<p>
This mode works equally well when you want to focus on
- one event at the time or when you want to focus on
- one state at the time, but the <c>handle_event/4</c> function
+ one event at the time or on
+ one state at the time, but function
+ <seealso marker="stdlib:gen_statem#Module:handle_event/4"><c>Module:handle_event/4</c></seealso>
quickly grows too large to handle without introducing dispatching.
</p>
<p>
- The mode enables the use of non-atom states for example
- complex states or even hiearchical states.
+ The mode enables the use of non-atom states, for example,
+ complex states or even hierarchical states.
If, for example, a state diagram is largely alike
- for the client and for the server side of a protocol;
- then you can have a state <c>{StateName,server}</c> or
- <c>{StateName,client}</c> and since you do the dispatching
- yourself you make <c>StateName</c> decide where in the code
+ for the client side and the server side of a protocol,
+ you can have a state <c>{StateName,server}</c> or
+ <c>{StateName,client}</c>. Also, as you do the dispatching
+ yourself, you make <c>StateName</c> decide where in the code
to handle most events in the state.
- The second element of the tuple is then used to select
- whether to handle special client side or server side events.
+ The second element of the tuple is then used to select
+ whether to handle special client-side or server-side events.
</p>
</section>
</section>
@@ -196,31 +195,28 @@ handle_event(EventType, EventContent, State, Data) ->
<section>
<title>Example</title>
<p>
- This is an example starting off as equivalent to the the example in the
- <seealso marker="fsm"><c>gen_fsm</c> behaviour</seealso>
- description. In later chapters additions and tweaks are made
+ This example starts off as equivalent to the example in section
+ <seealso marker="fsm"><c>gen_fsm</c> Behavior</seealso>.
+ In later sections, additions and tweaks are made
using features in <c>gen_statem</c> that <c>gen_fsm</c> does not have.
- At the end of this section you can find the example again
+ The end of this chapter provides the example again
with all the added features.
</p>
<p>
- A door with a code lock can be viewed as a state machine.
- Initially, the door is locked. Anytime someone presses a button,
- this generates an event.
+ A door with a code lock can be seen as a state machine.
+ Initially, the door is locked. When someone presses a button,
+ an event is generated.
Depending on what buttons have been pressed before,
the sequence so far can be correct, incomplete, or wrong.
- </p>
- <p>
- If it is correct, the door is unlocked for 10 seconds (10000 ms).
- If it is incomplete, we wait for another button to be pressed. If
- it is is wrong, we start all over,
- waiting for a new button sequence.
+ If correct, the door is unlocked for 10 seconds (10,000 milliseconds).
+ If incomplete, we wait for another button to be pressed. If
+ wrong, we start all over, waiting for a new button sequence.
</p>
<image file="../design_principles/code_lock.png">
- <icaption>Code lock state diagram</icaption>
+ <icaption>Code Lock State Diagram</icaption>
</image>
<p>
- We can implement such a code lock state machine using
+ This code lock state machine can be implemented using
<c>gen_statem</c> with the following callback module:
</p>
<marker id="ex"></marker>
@@ -241,7 +237,6 @@ start_link(Code) ->
button(Digit) ->
gen_statem:cast(?NAME, {button,Digit}).
-
init(Code) ->
do_lock(),
Data = #{code => Code, remaining => Code},
@@ -286,7 +281,7 @@ code_change(_Vsn, State, Data, _Extra) ->
<section>
<title>Starting gen_statem</title>
<p>
- In the example in the previous section, the <c>gen_statem</c> is
+ In the example in the previous section, <c>gen_statem</c> is
started by calling <c>code_lock:start_link(Code)</c>:
</p>
<code type="erl"><![CDATA[
@@ -294,80 +289,71 @@ start_link(Code) ->
gen_statem:start_link({local,?NAME}, ?MODULE, Code, []).
]]></code>
<p>
- <c>start_link</c> calls the function
- <seealso marker="stdlib:gen_statem#start_link/4">
- <c>gen_statem:start_link/4</c>
- </seealso>
- which spawns and links to a new process; a <c>gen_statem</c>.
+ <c>start_link</c> calls function
+ <seealso marker="stdlib:gen_statem#start_link/4"><c>gen_statem:start_link/4</c></seealso>,
+ which spawns and links to a new process, a <c>gen_statem</c>.
</p>
<list type="bulleted">
<item>
<p>
- The first argument, <c>{local,?NAME}</c>, specifies
- the name. In this case, the <c>gen_statem</c> is locally
- registered as <c>code_lock</c> through the macro <c>?NAME</c>.
- </p>
+ The first argument, <c>{local,?NAME}</c>, specifies
+ the name. In this case, the <c>gen_statem</c> is locally
+ registered as <c>code_lock</c> through the macro <c>?NAME</c>.
+ </p>
<p>
- If the name is omitted, the <c>gen_statem</c> is not registered.
- Instead its pid must be used. The name can also be given
- as <c>{global,Name}</c>, in which case the <c>gen_statem</c> is
- registered using
- <seealso marker="kernel:global#register_name/2">
- <c>global:register_name/2</c>.
- </seealso>
- </p>
+ If the name is omitted, the <c>gen_statem</c> is not registered.
+ Instead its pid must be used. The name can also be specified
+ as <c>{global,Name}</c>, then the <c>gen_statem</c> is
+ registered using
+ <seealso marker="kernel:global#register_name/2"><c>global:register_name/2</c></seealso>
+ in <c>Kernel</c>.
+ </p>
</item>
<item>
<p>
- The second argument, <c>?MODULE</c>, is the name of
- the callback module, that is; the module where the callback
+ The second argument, <c>?MODULE</c>, is the name of
+ the callback module, that is, the module where the callback
functions are located, which is this module.
- </p>
+ </p>
<p>
- The interface functions (<c>start_link/1</c> and <c>button/1</c>)
- are located in the same module as the callback functions
- (<c>init/1</c>, <c>locked/3</c>, and <c>open/3</c>).
- It is normally good programming practice to have the client
- side and the server side code contained in one module.
- </p>
+ The interface functions (<c>start_link/1</c> and <c>button/1</c>)
+ are located in the same module as the callback functions
+ (<c>init/1</c>, <c>locked/3</c>, and <c>open/3</c>).
+ It is normally good programming practice to have the client-side
+ code and the server-side code contained in one module.
+ </p>
</item>
<item>
<p>
- The third argument, <c>Code</c>, is a list of digits that
- is the correct unlock code which is passsed
- to the callback function <c>init/1</c>.
+ The third argument, <c>Code</c>, is a list of digits, which
+ is the correct unlock code that is passed
+ to callback function <c>init/1</c>.
</p>
</item>
<item>
<p>
- The fourth argument, <c>[]</c>, is a list of options. See the
- <seealso marker="stdlib:gen_statem#start_link/3">
- <c>gen_statem:start_link/3</c>
- </seealso>
- manual page for available options.
+ The fourth argument, <c>[]</c>, is a list of options.
+ For the available options, see
+ <seealso marker="stdlib:gen_statem#start_link/3"><c>gen_statem:start_link/3</c></seealso>.
</p>
</item>
</list>
<p>
If name registration succeeds, the new <c>gen_statem</c> process
- calls the callback function <c>code_lock:init(Code)</c>.
+ calls callback function <c>code_lock:init(Code)</c>.
This function is expected to return <c>{CallbackMode,State,Data}</c>,
where
- <seealso marker="#callback_modes">
- <c>CallbackMode</c>
- </seealso>
+ <seealso marker="#callback_modes"><c>CallbackMode</c></seealso>
selects callback module state function mode, in this case
- <seealso marker="stdlib:gen_statem#type-callback_mode">
- <c>state_functions</c>
- </seealso>
- through the macro <c>?CALLBACK_MODE</c> that is; each state
+ <seealso marker="stdlib:gen_statem#type-callback_mode"><c>state_functions</c></seealso>
+ through macro <c>?CALLBACK_MODE</c>. That is, each state
has got its own handler function.
<c>State</c> is the initial state of the <c>gen_statem</c>,
- in this case <c>locked</c>; assuming the door is locked to begin with.
- <c>Data</c> is the internal server data of the <c>gen_statem</c>.
+ in this case <c>locked</c>; assuming that the door is locked to begin
+ with. <c>Data</c> is the internal server data of the <c>gen_statem</c>.
Here the server data is a <seealso marker="stdlib:maps">map</seealso>
- with the key <c>code</c> that stores
- the correct button sequence and the key <c>remaining</c>
+ with key <c>code</c> that stores
+ the correct button sequence, and key <c>remaining</c>
that stores the remaining correct button sequence
(the same as the <c>code</c> to begin with).
</p>
@@ -377,24 +363,19 @@ init(Code) ->
Data = #{code => Code, remaining => Code},
{?CALLBACK_MODE,locked,Data}.
]]></code>
- <p>
- <seealso marker="stdlib:gen_statem#start_link/3">
- <c>gen_statem:start_link</c>
- </seealso>
- is synchronous. It does not return until the <c>gen_statem</c>
- has been initialized and is ready to receive events.
+ <p>Function
+ <seealso marker="stdlib:gen_statem#start_link/3"><c>gen_statem:start_link</c></seealso>
+ is synchronous. It does not return until the <c>gen_statem</c>
+ is initialized and is ready to receive events.
</p>
<p>
- <seealso marker="stdlib:gen_statem#start_link/3">
- <c>gen_statem:start_link</c>
- </seealso>
+ Function
+ <seealso marker="stdlib:gen_statem#start_link/3"><c>gen_statem:start_link</c></seealso>
must be used if the <c>gen_statem</c>
- is part of a supervision tree, that is; started by a supervisor.
- There is another function;
- <seealso marker="stdlib:gen_statem#start/3">
- <c>gen_statem:start</c>
- </seealso>
- to start a standalone <c>gen_statem</c>, that is;
+ is part of a supervision tree, that is, started by a supervisor.
+ Another function,
+ <seealso marker="stdlib:gen_statem#start/3"><c>gen_statem:start</c></seealso>
+ can be used to start a standalone <c>gen_statem</c>, that is,
a <c>gen_statem</c> that is not part of a supervision tree.
</p>
</section>
@@ -402,12 +383,10 @@ init(Code) ->
<!-- =================================================================== -->
<section>
- <title>Events and Handling them</title>
+ <title>Handling Events</title>
<p>The function notifying the code lock about a button event is
implemented using
- <seealso marker="stdlib:gen_statem#cast/2">
- <c>gen_statem:cast/2</c>:
- </seealso>
+ <seealso marker="stdlib:gen_statem#cast/2"><c>gen_statem:cast/2</c></seealso>:
</p>
<code type="erl"><![CDATA[
button(Digit) ->
@@ -415,9 +394,9 @@ button(Digit) ->
]]></code>
<p>
The first argument is the name of the <c>gen_statem</c> and must
- agree with the name used to start it so therefore we use the
+ agree with the name used to start it. So, we use the
same macro <c>?NAME</c> as when starting.
- <c>{button,Digit}</c> is the actual event content.
+ <c>{button,Digit}</c> is the event content.
</p>
<p>
The event is made into a message and sent to the <c>gen_statem</c>.
@@ -452,19 +431,19 @@ open(cast, {button,_}, Data) ->
]]></code>
<p>
If the door is locked and a button is pressed, the pressed
- button is compared with the next correct button and,
- depending on the result, the door is either unlocked
+ button is compared with the next correct button.
+ Depending on the result, the door is either unlocked
and the <c>gen_statem</c> goes to state <c>open</c>,
or the door remains in state <c>locked</c>.
</p>
<p>
- If the pressed button is incorrect the server data
+ If the pressed button is incorrect, the server data
restarts from the start of the code sequence.
</p>
<p>
- In state <c>open</c> any button locks the door since
- any event cancels the event timer so we will not get
- a timeout event after a button event.
+ In state <c>open</c>, any button locks the door, as
+ any event cancels the event timer, so no
+ time-out event occurs after a button event.
</p>
</section>
@@ -478,11 +457,11 @@ open(cast, {button,_}, Data) ->
{next_state,open,Data#{remaining := Code},10000};
]]></code>
<p>
- 10000 is a time-out value in milliseconds.
- After this time, that is; 10 seconds, a time-out occurs.
+ 10,000 is a time-out value in milliseconds.
+ After this time (10 seconds), a time-out occurs.
Then, <c>StateName(timeout, 10000, Data)</c> is called.
The time-out occurs when the door has been in state <c>open</c>
- for 10 seconds. After that the door is locked again:
+ for 10 seconds. After that the door is locked again:
</p>
<code type="erl"><![CDATA[
open(timeout, _, Data) ->
@@ -496,16 +475,16 @@ open(timeout, _, Data) ->
<section>
<title>All State Events</title>
<p>
- Sometimes an event can arrive in any state of the <c>gen_statem</c>.
+ Sometimes events can arrive in any state of the <c>gen_statem</c>.
It is convenient to handle these in a common state handler function
that all state functions call for events not specific to the state.
</p>
<p>
- Let's introduce a <c>code_length/0</c> function that returns
+ Consider a <c>code_length/0</c> function that returns
the length of the correct code
- (that should not be sensitive to reveal...).
- We'll dispatch all events that are not state specific
- to the common function <c>handle_event/3</c>.
+ (that should not be sensitive to reveal).
+ We dispatch all events that are not state-specific
+ to the common function <c>handle_event/3</c>:
</p>
<code type="erl"><![CDATA[
...
@@ -530,9 +509,7 @@ handle_event({call,From}, code_length, #{code := Code} = Data) ->
]]></code>
<p>
This example uses
- <seealso marker="stdlib:gen_statem#call/2">
- <c>gen_statem:call/2</c>
- </seealso>
+ <seealso marker="stdlib:gen_statem#call/2"><c>gen_statem:call/2</c></seealso>,
which waits for a reply from the server.
The reply is sent with a <c>{reply,From,Reply}</c> tuple
in an action list in the <c>{keep_state,...}</c> tuple
@@ -545,14 +522,15 @@ handle_event({call,From}, code_length, #{code := Code} = Data) ->
<section>
<title>One Event Handler</title>
<p>
- If you use the mode <c>handle_event_function</c>
- all events are handled in <c>handle_event/4</c> and we
- may (but do not have to) use an event-centered approach
+ If mode <c>handle_event_function</c> is used,
+ all events are handled in
+ <seealso marker="stdlib:gen_statem#Module:handle_event/4"><c>Module:handle_event/4</c></seealso>
+ and we can (but do not have to) use an event-centered approach
where we dispatch on event first and then state:
</p>
<code type="erl"><![CDATA[
...
--define(CALLBACK_MODE, state_functions).
+-define(CALLBACK_MODE, handle_event_function).
...
-export([handle_event/4]).
@@ -596,19 +574,14 @@ handle_event(timeout, _, open, Data) ->
The <c>gen_statem</c> is automatically 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.
+ set in the supervisor.
</p>
<p>
If it is necessary to clean up before termination, the shutdown
- strategy must be a time-out value and the <c>gen_statem</c> must
- in the <c>init/1</c> function set itself to trap exit signals
+ strategy must be a time-out value and the <c>gen_statem</c> must
+ in function <c>init/1</c> set itself to trap exit signals
by calling
- <seealso marker="erts:erlang#process_flag/2">
- <c>process_flag(trap_exit, true)</c>.
- </seealso>
- When ordered to shutdown, the <c>gen_statem</c> then calls
- the callback function
- <c>terminate(shutdown, State, Data)</c>:
+ <seealso marker="erts:erlang#process_flag/2"><c>process_flag(trap_exit, true)</c></seealso>:
</p>
<code type="erl"><![CDATA[
init(Args) ->
@@ -617,9 +590,13 @@ init(Args) ->
...
]]></code>
<p>
- In this example we let the <c>terminate/3</c> function
- lock the door if it is open so we do not accidentally leave the door
- open when the supervision tree terminates.
+ When ordered to shut down, the <c>gen_statem</c> then calls
+ callback function <c>terminate(shutdown, State, Data)</c>.
+ </p>
+ <p>
+ In the following example, function <c>terminate/3</c>
+ locks the door if it is open, so we do not accidentally leave the door
+ open when the supervision tree terminates:
</p>
<code type="erl"><![CDATA[
terminate(_Reason, State, _Data) ->
@@ -633,9 +610,7 @@ terminate(_Reason, State, _Data) ->
<p>
If the <c>gen_statem</c> is not part of a supervision tree,
it can be stopped using
- <seealso marker="stdlib:gen_statem#stop/1">
- <c>gen_statem:stop</c>,
- </seealso>
+ <seealso marker="stdlib:gen_statem#stop/1"><c>gen_statem:stop</c></seealso>,
preferably through an API function:
</p>
<code type="erl"><![CDATA[
@@ -647,8 +622,8 @@ stop() ->
gen_statem:stop(?NAME).
]]></code>
<p>
- This makes the <c>gen_statem</c> call the <c>terminate/3</c>
- callback function just like for a supervised server
+ This makes the <c>gen_statem</c> call callback function
+ <c>terminate/3</c> just like for a supervised server
and waits for the process to terminate.
</p>
</section>
@@ -659,48 +634,41 @@ stop() ->
<section>
<title>Actions</title>
<p>
- In the first chapters we mentioned actions as a part of
- the general state machine model, and these actions
- are implemented with the code the <c>gen_statem</c>
- callback module executes in an event handling
+ In the first sections actions were mentioned as a part of
+ the general state machine model. These general actions
+ are implemented with the code that callback module
+ <c>gen_statem</c> executes in an event-handling
callback function before returning
to the <c>gen_statem</c> engine.
</p>
<p>
- There are more specific state transition actions
+ There are more specific state-transition actions
that a callback function can order the <c>gen_statem</c>
engine to do after the callback function return.
These are ordered by returning a list of
- <seealso marker="stdlib:gen_statem#type-action">
- actions
- </seealso>
+ <seealso marker="stdlib:gen_statem#type-action">actions</seealso>
in the
- <seealso marker="stdlib:gen_statem#type-state_function_result">
- return tuple
- </seealso>
+ <seealso marker="stdlib:gen_statem#type-state_function_result">return tuple</seealso>
from the
- <seealso marker="stdlib:gen_statem#Module:StateName/3">
- callback function.
- </seealso>
+ <seealso marker="stdlib:gen_statem#Module:StateName/3">callback function</seealso>.
These state transition actions affect the <c>gen_statem</c>
- engine itself. They can:
+ engine itself and can do the following:
</p>
<list type="bulleted">
- <item>Postpone the current event.</item>
- <item>Hibernate the <c>gen_statem</c>.</item>
- <item>Start an event timeout.</item>
- <item>Reply to a caller.</item>
- <item>Generate the next event to handle.</item>
+ <item>Postpone the current event</item>
+ <item>Hibernate the <c>gen_statem</c></item>
+ <item>Start an event time-out</item>
+ <item>Reply to a caller</item>
+ <item>Generate the next event to handle</item>
</list>
<p>
- We have mentioned the event timeout
- and replying to a caller in the example above.
- An example of event postponing comes in later in this chapter.
- See the
- <seealso marker="stdlib:gen_statem#type-action">
- reference manual
- </seealso>
- for details. You can for example actually reply to several callers
+ In the example earlier was mentioned the event time-out
+ and replying to a caller.
+ An example of event postponing is included later in this chapter.
+ For details, see the
+ <seealso marker="stdlib:gen_statem#type-action"><c>gen_statem(3)</c></seealso>
+ manual page.
+ You can, for example, reply to many callers
and generate multiple next events to handle.
</p>
</section>
@@ -710,38 +678,30 @@ stop() ->
<section>
<title>Event Types</title>
<p>
- So far we have mentioned a few
- <seealso marker="stdlib:gen_statem#type-event_type">
- event types.
- </seealso>
+ The previous sections mentioned a few
+ <seealso marker="stdlib:gen_statem#type-event_type">event types</seealso>.
Events of all types are handled in the same callback function,
for a given state, and the function gets
<c>EventType</c> and <c>EventContent</c> as arguments.
</p>
<p>
- Here is the complete list of event types and where
+ The following is a complete list of event types and where
they come from:
</p>
<taglist>
<tag><c>cast</c></tag>
<item>
Generated by
- <seealso marker="stdlib:gen_statem#cast/2">
- <c>gen_statem:cast</c>.
- </seealso>
+ <seealso marker="stdlib:gen_statem#cast/2"><c>gen_statem:cast</c></seealso>.
</item>
<tag><c>{call,From}</c></tag>
<item>
Generated by
- <seealso marker="stdlib:gen_statem#call/2">
- <c>gen_statem:call</c>
- </seealso>
+ <seealso marker="stdlib:gen_statem#call/2"><c>gen_statem:call</c></seealso>,
where <c>From</c> is the reply address to use
when replying either through the state transition action
<c>{reply,From,Msg}</c> or by calling
- <seealso marker="stdlib:gen_statem#reply/1">
- <c>gen_statem:reply</c>.
- </seealso>
+ <seealso marker="stdlib:gen_statem#reply/1"><c>gen_statem:reply</c></seealso>.
</item>
<tag><c>info</c></tag>
<item>
@@ -750,15 +710,15 @@ stop() ->
</item>
<tag><c>timeout</c></tag>
<item>
- Generated by the state transition action
+ Generated by state transition action
<c>{timeout,Time,EventContent}</c> (or its short form <c>Time</c>)
timer timing out.
</item>
<tag><c>internal</c></tag>
<item>
- Generated by the state transition action
+ Generated by state transition action
<c>{next_event,internal,EventContent}</c>.
- In fact all event types above can be generated using
+ All event types above can also be generated using
<c>{next_event,EventType,EventContent}</c>.
</item>
</taglist>
@@ -767,34 +727,32 @@ stop() ->
<!-- =================================================================== -->
<section>
- <title>State Timeouts</title>
+ <title>State Time-Outs</title>
<p>
- The timeout event generated by the state transition action
- <c>{timeout,Time,EventContent}</c> is an event timeout,
- that is; if an event arrives the timer is cancelled.
- You get either an event or a timeout but not both.
+ The time-out event generated by state transition action
+ <c>{timeout,Time,EventContent}</c> is an event time-out,
+ that is, if an event arrives the timer is cancelled.
+ You get either an event or a time-out, but not both.
</p>
<p>
- Often you want a timer to not be cancelled by any event
+ Often you want a timer not to be cancelled by any event
or you want to start a timer in one state and respond
- to the timeout in another. This can be accomplished
- with a regular erlang timer:
- <seealso marker="erts:erlang#start_timer/4">
- <c>erlang:start_timer</c>.
- </seealso>
+ to the time-out in another. This can be accomplished
+ with a regular Erlang timer:
+ <seealso marker="erts:erlang#start_timer/4"><c>erlang:start_timer</c></seealso>.
</p>
<p>
- Looking at the example in this chapter so far; using the
+ For the example so far in this chapter: using the
<c>gen_statem</c> event timer has the consequence that
if a button event is generated while in the <c>open</c> state,
- the timeout is cancelled and the button event is delivered.
- Therefore we chose to lock the door if this happended.
+ the time-out is cancelled and the button event is delivered.
+ So, we choose to lock the door if this occurred.
</p>
<p>
- Suppose we do not want a button to lock the door,
+ Suppose that we do not want a button to lock the door,
instead we want to ignore button events in the <c>open</c> state.
Then we start a timer when entering the <c>open</c> state
- and wait for it to expire while ignoring button events:
+ and waits for it to expire while ignoring button events:
</p>
<code type="erl"><![CDATA[
...
@@ -816,17 +774,15 @@ open(cast, {button,_}, Data) ->
...
]]></code>
<p>
- If you need to cancel a timer due to some other event you can use
- <seealso marker="erts:erlang#cancel_timer/2">
- <c>erlang:cancel_timer(Tref)</c>.
- </seealso>
- Note that a timeout message can not arrive after this,
+ If you need to cancel a timer because of some other event, you can use
+ <seealso marker="erts:erlang#cancel_timer/2"><c>erlang:cancel_timer(Tref)</c></seealso>.
+ Notice that a time-out message cannot arrive after this,
unless you have postponed it (see the next section) before,
- so make sure you do not accidentally postpone such messages.
+ so ensure that you do not accidentally postpone such messages.
</p>
<p>
- Another way to cancel a timer is to not cancel it,
- but instead to ignore it if it arrives in a state
+ Another way to cancel a timer is not to cancel it,
+ but to ignore it if it arrives in a state
where it is known to be late.
</p>
</section>
@@ -839,19 +795,17 @@ open(cast, {button,_}, Data) ->
If you want to ignore a particular event in the current state
and handle it in a future state, you can postpone the event.
A postponed event is retried after the state has
- changed i.e <c>OldState =/= NewState</c>.
+ changed, that is, <c>OldState =/= NewState</c>.
</p>
<p>
Postponing is ordered by the state transition
- <seealso marker="stdlib:gen_statem#type-action">
- action
- </seealso>
+ <seealso marker="stdlib:gen_statem#type-action">action</seealso>
<c>postpone</c>.
</p>
<p>
In this example, instead of ignoring button events
- while in the <c>open</c> state we can postpone them
- and they will be queued and later handled in the <c>locked</c> state:
+ while in the <c>open</c> state, we can postpone them
+ and they are queued and later handled in the <c>locked</c> state:
</p>
<code type="erl"><![CDATA[
...
@@ -861,16 +815,16 @@ open(cast, {button,_}, Data) ->
]]></code>
<p>
The fact that a postponed event is only retried after a state change
- translates into a requirement on the event and state space:
- if you have a choice between storing a state data item
- in the <c>State</c> or in the <c>Data</c>;
- should a change in the item value affect which events that
- are handled, then this item ought to be part of the state.
+ translates into a requirement on the event and state space.
+ If you have a choice between storing a state data item
+ in the <c>State</c> or in the <c>Data</c>:
+ if a change in the item value affects which events that
+ are handled, then this item is to be part of the state.
</p>
<p>
- What you want to avoid is that you maybe much later decide
- to postpone an event in one state and by misfortune it is never retried
- because the code only changes the <c>Data</c> but not the <c>State</c>.
+ You want to avoid that you maybe much later decide
+ to postpone an event in one state and by misfortune it is never retried,
+ as the code only changes the <c>Data</c> but not the <c>State</c>.
</p>
<section>
@@ -883,7 +837,7 @@ open(cast, {button,_}, Data) ->
or from the context.
</p>
<p>
- Possible actions may be; ignore as in drop the event
+ Possible actions: ignore as in drop the event
(maybe log it) or deal with the event in some other state
as in postpone it.
</p>
@@ -892,10 +846,10 @@ open(cast, {button,_}, Data) ->
<section>
<title>Selective Receive</title>
<p>
- Erlang's selective receive statement is often used to
- describe simple state machine examples in straightforward
- Erlang code. Here is a possible implementation of
- the first example:
+ Erlang's selective receive statement is often used to
+ describe simple state machine examples in straightforward
+ Erlang code. The following is a possible implementation of
+ the first example:
</p>
<code type="erl"><![CDATA[
-module(code_lock).
@@ -937,33 +891,31 @@ do_unlock() ->
io:format("Open~n", []).
]]></code>
<p>
- The selective receive in this case causes <c>open</c>
- to implicitly postpone any events to the <c>locked</c> state.
+ The selective receive in this case causes implicitly <c>open</c>
+ to postpone any events to the <c>locked</c> state.
</p>
<p>
- A selective receive can not be used from a <c>gen_statem</c>
- behaviour just as for any <c>gen_*</c> behavior
- since the receive statement is within the <c>gen_*</c> engine itself.
- It has to be there because all
+ A selective receive cannot be used from a <c>gen_statem</c>
+ behavior as for any <c>gen_*</c> behavior,
+ as the receive statement is within the <c>gen_*</c> engine itself.
+ It must be there because all
<seealso marker="stdlib:sys"><c>sys</c></seealso>
- compatible behaviours must respond to system messages and therefore
+ compatible behaviors must respond to system messages and therefore
do that in their engine receive loop,
passing non-system messages to the callback module.
</p>
<p>
The state transition
- <seealso marker="stdlib:gen_statem#type-action">
- action
- </seealso>
- <c>postpone</c> is designed to be able to model
- selective receives. A selective receive implicitly postpones
+ <seealso marker="stdlib:gen_statem#type-action">action</seealso>
+ <c>postpone</c> is designed to model
+ selective receives. A selective receive implicitly postpones
any not received events, but the <c>postpone</c>
state transition action explicitly postpones one received event.
</p>
<p>
- Other than that both mechanisms have got the same theoretical
+ Both mechanisms have the same theoretical
time and memory complexity, while the selective receive
- language construct has got smaller constant factors.
+ language construct has smaller constant factors.
</p>
</section>
</section>
@@ -971,43 +923,39 @@ do_unlock() ->
<!-- =================================================================== -->
<section>
- <title>Self Generated Events</title>
+ <title>Self-Generated Events</title>
<p>
- It may be beneficial in some cases to be able to generate events
+ It can sometimes be beneficial to be able to generate events
to your own state machine.
This can be done with the state transition
- <seealso marker="stdlib:gen_statem#type-action">
- action
- </seealso>
+ <seealso marker="stdlib:gen_statem#type-action">action</seealso>
<c>{next_event,EventType,EventContent}</c>.
</p>
<p>
You can generate events of any existing
- <seealso marker="stdlib:gen_statem#type-action">
- type,
- </seealso>
- but the <c>internal</c> type can only be generated through the
- <c>next_event</c> action and hence can not come from an external source,
+ <seealso marker="stdlib:gen_statem#type-action">type</seealso>,
+ but the <c>internal</c> type can only be generated through action
+ <c>next_event</c>. Hence, it cannot come from an external source,
so you can be certain that an <c>internal</c> event is an event
from your state machine to itself.
</p>
<p>
- One example of using self generated events may be when you have
+ One example of using self-generated events can be when you have
a state machine specification that uses state entry actions.
- That you could code using a dedicated function
- to do the state transition. But if you want that code to be
- visible besides the other state logic you can insert
+ You can code that using a dedicated function
+ to do the state transition. But if you want that code to be
+ visible besides the other state logic, you can insert
an <c>internal</c> event that does the entry actions.
This has the same unfortunate consequence as using
- state transition functions that everywhere you go to
- the state in question you will have to explicitly
+ state transition functions: everywhere you go to
+ the state, you must explicitly
insert the <c>internal</c> event
- or use state transition function.
+ or use a state transition function.
</p>
<p>
- Here is an implementation of entry actions
+ The following is an implementation of entry actions
using <c>internal</c> events with content <c>enter</c>
- utilizing a helper function <c>enter/3</c> for state entry:
+ using a helper function <c>enter/3</c> for state entry:
</p>
<code type="erl"><![CDATA[
...
@@ -1051,20 +999,20 @@ enter(Tag, State, Data) ->
<section>
<title>Example Revisited</title>
<p>
- Here is the example after all mentioned modifications
- and some more utilizing the entry actions,
+ This section includes the example after all mentioned modifications
+ and some more using the entry actions,
which deserves a new state diagram:
</p>
<image file="../design_principles/code_lock_2.png">
- <icaption>Code lock state diagram revisited</icaption>
+ <icaption>Code Lock State Diagram Revisited</icaption>
</image>
<p>
- Note that this state diagram does not specify how to handle
- a button event in the state <c>open</c>, so you will have to
- read some other place that is here that unspecified events
- shall be ignored as in not consumed but handled in some other state.
- Nor does it show that the <c>code_length/0</c> call shall be
- handled in every state.
+ Notice that this state diagram does not specify how to handle
+ a button event in the state <c>open</c>. So, you need to
+ read somewhere else that unspecified events
+ must be ignored as in not consumed but handled in some other state.
+ Also, the state diagram does not show that the <c>code_length/0</c>
+ call must be handled in every state.
</p>
<section>
@@ -1147,10 +1095,11 @@ code_change(_Vsn, State, Data, _Extra) ->
<section>
<title>Callback Mode: handle_event_function</title>
<p>
- What to change to use one <c>handle_event/4</c> function.
- Here a clean first-dispatch-on-event approach
- does not work that well due to the generated
- entry actions:
+ This section describes what to change in the example
+ to use one <c>handle_event/4</c> function.
+ The previously used clean first-dispatch-on-event approach
+ does not work that well here because of the generated
+ entry actions so this example dispatches on state first:
</p>
<code type="erl"><![CDATA[
...
@@ -1195,7 +1144,7 @@ handle_event({call,From}, code_length, _State, #{code := Code}) ->
]]></code>
</section>
<p>
- Note that postponing buttons from the <c>locked</c> state
+ Notice that postponing buttons from the <c>locked</c> state
to the <c>open</c> state feels like the wrong thing to do
for a code lock, but it at least illustrates event postponing.
</p>
@@ -1206,33 +1155,29 @@ handle_event({call,From}, code_length, _State, #{code := Code}) ->
<section>
<title>Filter the State</title>
<p>
- The example servers so far in this chapter will for example
- when killed by an exit signal or due to an internal error
- print out the full internal state in the error log.
+ The example servers so far in this chapter
+ print the full internal state in the error log, for example,
+ when killed by an exit signal or because of an internal error.
This state contains both the code lock code
- and which digits that remains to unlock.
+ and which digits that remain to unlock.
</p>
<p>
This state data can be regarded as sensitive,
and maybe not what you want in the error log
- because of something unpredictable happening.
+ because of some unpredictable event.
</p>
<p>
Another reason to filter the state can be
- that the state is too big to print out since it fills
+ that the state is too large to print, as it fills
the error log with uninteresting details.
</p>
<p>
- To avoid this you can format the internal state
+ To avoid this, you can format the internal state
that gets in the error log and gets returned from
- <seealso marker="stdlib:sys#get_status/1">
- <c>sys:get_status/1,2</c>
- </seealso>
- by implementing the
- <seealso marker="stdlib:gen_statem#Module:format_status/2">
- <c>Module:format_status/2</c>
- </seealso>
- function, for example like this:
+ <seealso marker="stdlib:sys#get_status/1"><c>sys:get_status/1,2</c></seealso>
+ by implementing function
+ <seealso marker="stdlib:gen_statem#Module:format_status/2"><c>Module:format_status/2</c></seealso>,
+ for example like this:
</p>
<code type="erl"><![CDATA[
...
@@ -1257,12 +1202,10 @@ format_status(Opt, [_PDict,State,Data]) ->
]]></code>
<p>
It is not mandatory to implement a
- <seealso marker="stdlib:gen_statem#Module:format_status/2">
- <c>Module:format_status/2</c>
- </seealso>
- function. If you do not a default implementation is used that
+ <seealso marker="stdlib:gen_statem#Module:format_status/2"><c>Module:format_status/2</c></seealso>
+ function. If you do not, a default implementation is used that
does the same as this example function without filtering
- the <c>Data</c> term that is: <c>StateData = {State,Data}</c>.
+ the <c>Data</c> term, that is, <c>StateData = {State,Data}</c>.
</p>
</section>
@@ -1272,57 +1215,54 @@ format_status(Opt, [_PDict,State,Data]) ->
<title>Complex State</title>
<p>
The callback mode
- <seealso marker="stdlib:gen_statem#type-callback_mode">
- <c>handle_event_function</c>
- </seealso>
- enables using a non-atom state as described in
- <seealso marker="#callback_modes">
- Callback Modes,
- </seealso>
- for example a complex state term like a tuple.
+ <seealso marker="stdlib:gen_statem#type-callback_mode"><c>handle_event_function</c></seealso>
+ enables using a non-atom state as described in section
+ <seealso marker="#callback_modes">Callback Modes</seealso>,
+ for example, a complex state term like a tuple.
</p>
<p>
One reason to use this is when you have
- a state item that affects the event handling
- in particular when combining that with postponing events.
- Let us complicate the previous example
+ a state item that affects the event handling,
+ in particular in combination with postponing events.
+ We complicate the previous example
by introducing a configurable lock button
- (this is the state item in question)
- that in the <c>open</c> state immediately locks the door,
+ (this is the state item in question),
+ which in the <c>open</c> state immediately locks the door,
and an API function <c>set_lock_button/1</c> to set the lock button.
</p>
<p>
Suppose now that we call <c>set_lock_button</c>
while the door is open,
and have already postponed a button event
- that up until now was not the lock button;
- the sensible thing might be to say that
- the button was pressed too early so it should
- not be recognized as the lock button,
- but then it might be surprising that a button event
+ that until now was not the lock button.
+ The sensible thing can be to say that
+ the button was pressed too early so it is
+ not to be recognized as the lock button.
+ However, then it can be surprising that a button event
that now is the lock button event arrives (as retried postponed)
immediately after the state transits to <c>locked</c>.
</p>
<p>
- So let us make the <c>button/1</c> function synchronous
- by using <c>gen_statem:call</c>,
+ So we make the <c>button/1</c> function synchronous
+ by using
+ <seealso marker="stdlib:gen_statem#call/2"><c>gen_statem:call</c></seealso>
and still postpone its events in the <c>open</c> state.
Then a call to <c>button/1</c> during the <c>open</c>
- state will not return until the state transits to <c>locked</c>
- since it is there the event is handled and the reply is sent.
+ state does not return until the state transits to <c>locked</c>,
+ as it is there the event is handled and the reply is sent.
</p>
<p>
- If now one process calls <c>set_lock_button/1</c>
- to change the lock button while some other process
- hangs in <c>button/1</c> with the new lock button
- it could be expected that the hanging lock button call
+ If a process now calls <c>set_lock_button/1</c>
+ to change the lock button while another process
+ hangs in <c>button/1</c> with the new lock button,
+ it can be expected that the hanging lock button call
immediately takes effect and locks the lock.
- Therefore we make the current lock button a part of the state
- so when we change the lock button the state will change
- and all postponed events will be retried.
+ Therefore, we make the current lock button a part of the state,
+ so that when we change the lock button, the state changes
+ and all postponed events are retried.
</p>
<p>
- We define the state as <c>{StateName,LockButton}</c>
+ We define the state as <c>{StateName,LockButton}</c>,
where <c>StateName</c> is as before
and <c>LockButton</c> is the current lock button:
</p>
@@ -1441,10 +1381,9 @@ format_status(Opt, [_PDict,State,Data]) ->
end.
]]></code>
<p>
- It may be an ill-fitting model for a physical code lock
- that the <c>button/1</c> call might hang until the lock
- is locked. But for an API in general it is really not
- that strange.
+ It can be an ill-fitting model for a physical code lock
+ that the <c>button/1</c> call can hang until the lock
+ is locked. But for an API in general it is not that strange.
</p>
</section>
@@ -1457,26 +1396,21 @@ format_status(Opt, [_PDict,State,Data]) ->
and they have some state(s) in their lifetime in which
the servers can be expected to idle for a while,
and the amount of heap memory all these servers need
- is a problem; then it is possible to minimize
- the memory footprint of a server by hibernating it through
- <seealso marker="stdlib:proc_lib#hibernate/3">
- <c>proc_lib:hibernate/3</c>.
- </seealso>
+ is a problem, then the memory footprint of a server
+ can be mimimized by hibernating it through
+ <seealso marker="stdlib:proc_lib#hibernate/3"><c>proc_lib:hibernate/3</c></seealso>.
</p>
<note>
<p>
- To hibernate a process is rather costly. See
- <seealso marker="erts:erlang#hibernate/3">
- <c>erlang:hibernate/3</c>.
- </seealso>
- It is in general not something you want to do
- after every event.
+ It is rather costly to hibernate a process; see
+ <seealso marker="erts:erlang#hibernate/3"><c>erlang:hibernate/3</c></seealso>.
+ It is not something you want to do after every event.
</p>
</note>
<p>
- We can in this example hibernate in the <c>{open,_}</c> state
- since what normally happens in that state is that
- the state timeout after a while
+ We can in this example hibernate in the <c>{open,_}</c> state,
+ because what normally occurs in that state is that
+ the state time-out after a while
triggers a transition to <c>{locked,_}</c>:
</p>
<code type="erl"><![CDATA[
@@ -1493,29 +1427,27 @@ handle_event(
]]></code>
<p>
The
- <seealso marker="stdlib:gen_statem#type-hibernate">
- <c>[hibernate]</c>
- </seealso>
+ <seealso marker="stdlib:gen_statem#type-hibernate"><c>[hibernate]</c></seealso>
action list on the last line
when entering the <c>{open,_}</c> state is the only change.
- If any event arrives in the <c>{open,_},</c> state we
- do not bother to re-hibernate, so the server stays
+ If any event arrives in the <c>{open,_},</c> state, we
+ do not bother to rehibernate, so the server stays
awake after any event.
</p>
<p>
To change that we would need to insert
- the <c>hibernate</c> action in more places,
- for example for the state independent <c>set_lock_button</c>
+ action <c>hibernate</c> in more places.
+ For example, for the state-independent <c>set_lock_button</c>
and <c>code_length</c> operations that then would have to
be aware of using <c>hibernate</c> while in the
- <c>{open,_}</c> state which would clutter the code.
+ <c>{open,_}</c> state, which would clutter the code.
</p>
<p>
- This server probably does not use an amount of
+ This server probably does not use
heap memory worth hibernating for.
- To gain anything from hibernation your server would
- have to actually produce some garbage during callback execution,
- for which this example server may serve as a bad example.
+ To gain anything from hibernation, your server would
+ have to produce some garbage during callback execution,
+ for which this example server can serve as a bad example.
</p>
</section>