diff options
-rw-r--r-- | erts/emulator/beam/erl_alloc.types | 5 | ||||
-rw-r--r-- | erts/emulator/beam/erl_alloc_util.c | 30 | ||||
-rw-r--r-- | lib/common_test/test_server/ts_run.erl | 13 | ||||
-rw-r--r-- | lib/public_key/doc/src/using_public_key.xml | 2 | ||||
-rw-r--r-- | lib/stdlib/doc/src/binary.xml | 2 | ||||
-rw-r--r-- | lib/stdlib/doc/src/gen_statem.xml | 1723 | ||||
-rw-r--r-- | system/doc/design_principles/statem.xml | 696 |
7 files changed, 1278 insertions, 1193 deletions
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types index ad62a87326..ba216c7eb4 100644 --- a/erts/emulator/beam/erl_alloc.types +++ b/erts/emulator/beam/erl_alloc.types @@ -264,7 +264,6 @@ type PRTSD STANDARD SYSTEM port_specific_data type CPUDATA LONG_LIVED SYSTEM cpu_data type TMP_CPU_IDS SHORT_LIVED SYSTEM tmp_cpu_ids type EXT_TERM_DATA SHORT_LIVED PROCESSES external_term_data -type ZLIB STANDARD SYSTEM zlib type CPU_GRPS_MAP LONG_LIVED SYSTEM cpu_groups_map type AUX_WORK_TMO LONG_LIVED SYSTEM aux_work_timeouts type MISC_AUX_WORK_Q LONG_LIVED SYSTEM misc_aux_work_q @@ -297,8 +296,10 @@ type THR_Q_LL LONG_LIVED SYSTEM long_lived_thr_queue +if smp type ASYNC SHORT_LIVED SYSTEM async +type ZLIB STANDARD SYSTEM zlib +else -# sl_alloc is not thread safe in non smp build; therefore, we use driver_alloc +# sl/std_alloc is not thread safe in non smp build; therefore, we use driver_alloc +type ZLIB DRIVER SYSTEM zlib type ASYNC DRIVER SYSTEM async +endif diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c index be7c16cc05..2995f2f822 100644 --- a/erts/emulator/beam/erl_alloc_util.c +++ b/erts/emulator/beam/erl_alloc_util.c @@ -860,8 +860,9 @@ erts_alcu_literal_32_mseg_alloc(Allctr_t *allctr, Uint *size_p, Uint flags) { void* res; Uint sz = ERTS_SUPERALIGNED_CEILING(*size_p); - ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL - && !allctr->t && allctr->thread_safe); + ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL && + allctr->t == 0); + ERTS_SMP_LC_ASSERT(allctr->thread_safe); res = erts_alcu_mseg_alloc(allctr, &sz, flags); if (res) { @@ -877,8 +878,9 @@ erts_alcu_literal_32_mseg_realloc(Allctr_t *allctr, void *seg, { void* res; Uint new_sz = ERTS_SUPERALIGNED_CEILING(*new_size_p); - ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL - && !allctr->t && allctr->thread_safe); + ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL && + allctr->t == 0); + ERTS_SMP_LC_ASSERT(allctr->thread_safe); if (seg && old_size) clear_literal_range(seg, old_size); @@ -894,8 +896,9 @@ void erts_alcu_literal_32_mseg_dealloc(Allctr_t *allctr, void *seg, Uint size, Uint flags) { - ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL - && !allctr->t && allctr->thread_safe); + ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL && + allctr->t == 0); + ERTS_SMP_LC_ASSERT(allctr->thread_safe); erts_alcu_mseg_dealloc(allctr, seg, size, flags); @@ -1007,8 +1010,9 @@ erts_alcu_literal_32_sys_alloc(Allctr_t *allctr, Uint* size_p, int superalign) { void* res; Uint size = ERTS_SUPERALIGNED_CEILING(*size_p); - ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL - && !allctr->t && allctr->thread_safe); + ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL && + allctr->t == 0); + ERTS_SMP_LC_ASSERT(allctr->thread_safe); res = erts_alcu_sys_alloc(allctr, &size, 1); if (res) { @@ -1024,8 +1028,9 @@ erts_alcu_literal_32_sys_realloc(Allctr_t *allctr, void *ptr, Uint* size_p, Uint void* res; Uint size = ERTS_SUPERALIGNED_CEILING(*size_p); - ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL - && !allctr->t && allctr->thread_safe); + ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL && + allctr->t == 0); + ERTS_SMP_LC_ASSERT(allctr->thread_safe); if (ptr && old_size) clear_literal_range(ptr, old_size); @@ -1040,8 +1045,9 @@ erts_alcu_literal_32_sys_realloc(Allctr_t *allctr, void *ptr, Uint* size_p, Uint void erts_alcu_literal_32_sys_dealloc(Allctr_t *allctr, void *ptr, Uint size, int superalign) { - ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL - && !allctr->t && allctr->thread_safe); + ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL && + allctr->t == 0); + ERTS_SMP_LC_ASSERT(allctr->thread_safe); erts_alcu_sys_dealloc(allctr, ptr, size, 1); diff --git a/lib/common_test/test_server/ts_run.erl b/lib/common_test/test_server/ts_run.erl index a856fc6f8d..66db1ff9a7 100644 --- a/lib/common_test/test_server/ts_run.erl +++ b/lib/common_test/test_server/ts_run.erl @@ -261,7 +261,7 @@ run_batch(Vars, _Spec, State) -> Command = State#state.command ++ " -noinput -s erlang halt", ts_lib:progress(Vars, 1, "Command: ~ts~n", [Command]), io:format(user, "Command: ~ts~n",[Command]), - Port = open_port({spawn, Command}, [stream, in, eof]), + Port = open_port({spawn, Command}, [stream, in, eof, exit_status]), Timeout = 30000 * case os:getenv("TS_RUN_VALGRIND") of false -> 1; _ -> 100 @@ -284,7 +284,16 @@ tricky_print_data(Port, Timeout) -> ok after 1 -> % force context switch ok - end + end, + receive + {Port, {exit_status, 0}} -> + ok; + {Port, {exit_status, N}} -> + io:format(user, "Test run exited with status ~p~n", [N]) + after 1 -> + %% This shouldn't happen, but better safe then hanging + ok + end after Timeout -> case erl_epmd:names() of {ok,Names} -> diff --git a/lib/public_key/doc/src/using_public_key.xml b/lib/public_key/doc/src/using_public_key.xml index 86808adbea..e3a1eed4be 100644 --- a/lib/public_key/doc/src/using_public_key.xml +++ b/lib/public_key/doc/src/using_public_key.xml @@ -124,7 +124,7 @@ ...>>, not_encrypted}, {'Certificate',<<48,130,3,200,48,130,3,49,160,3,2,1,2,2,1, - 1,48,13,6,9,42,134,72,134,247,...>>>, + 1,48,13,6,9,42,134,72,134,247,...>>, not_encrypted}]</code> <p>Certificates can be decoded as usual:</p> diff --git a/lib/stdlib/doc/src/binary.xml b/lib/stdlib/doc/src/binary.xml index 5402fd0163..933157fc34 100644 --- a/lib/stdlib/doc/src/binary.xml +++ b/lib/stdlib/doc/src/binary.xml @@ -366,7 +366,7 @@ <code> 1> binary:matches(<<"abcde">>, - [<<"bcde">>,<<"bc">>>,<<"de">>],[]). + [<<"bcde">>,<<"bc">>,<<"de">>],[]). [{1,4}] </code> diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml index d83e17b177..be90488a1f 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,18 @@ </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 + 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> - for more information. + </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,37 +112,37 @@ 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 + 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 + 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. @@ -141,21 +150,21 @@ erlang:'!' -----> Module:StateName/3 <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>. 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 one 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,7 +172,7 @@ 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> @@ -173,73 +182,76 @@ erlang:'!' -----> Module:StateName/3 <c>action()</c> <c>next_event</c> </seealso> 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 + 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> that can be used for such events making them impossible + <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 + For the details of a state transition, see type <seealso marker="#type-transition_option"> - <c>transition_option()</c> - </seealso> - for the details of a state transition. + <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>. </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>. + <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> + <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> + <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>. @@ -247,7 +259,8 @@ erlang:'!' -----> Module:StateName/3 and you can ask for a count of how many times it has been pushed to 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 +318,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,<0.36.0>} @@ -326,12 +339,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,11 +376,11 @@ 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 + a <c>gen_statem</c> server. See <seealso marker="#start_link/3"> <c>start_link/3</c> </seealso> @@ -380,7 +392,7 @@ handle_event(_, _, State, Data) -> </desc> </datatype> <datatype> - <name name="server_ref" /> + <name name="server_ref"/> <desc> <p> Server specification to use when addressing @@ -393,75 +405,83 @@ handle_event(_, _, State, Data) -> </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()</c> | <c>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 through + 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 + Destination to use when replying through, for example, the <seealso marker="#type-action"> <c>action()</c> </seealso> @@ -472,178 +492,194 @@ 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> + <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> @@ -651,9 +687,9 @@ handle_event(_, _, State, Data) -> 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 + to prevent receiving any new event, an <seealso marker="erts:erlang#garbage_collect/0"> - <c>garbage_collect/0</c> + <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. @@ -661,39 +697,39 @@ handle_event(_, _, State, Data) -> </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> @@ -708,9 +744,9 @@ handle_event(_, _, State, Data) -> <seealso marker="#type-transition_option"> transition options </seealso> - overrides any previous of the same type, + override any previous of the same type, so the last in the containing list wins. - For example the last + For example, the last <seealso marker="#type-event_timeout"> <c>event_timeout()</c> </seealso> @@ -719,77 +755,87 @@ handle_event(_, _, State, Data) -> <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 + <seealso marker="gen_fsm#Module:StateName/2"> + <c>gen_fsm: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 + is to be used when you want to reliably distinguish an event inserted this way from any external event. </p> </item> @@ -797,294 +843,125 @@ 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 + <c><anno>From</anno></c> must be the term from argument <seealso marker="#type-event_type"> <c>{call,<anno>From</anno>}</c> </seealso> - argument to the + 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> @@ -1093,7 +970,7 @@ handle_event(_, _, State, Data) -> </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,33 +985,33 @@ 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 > 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> @@ -1144,7 +1021,7 @@ handle_event(_, _, State, Data) -> 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,44 +1031,8 @@ 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 @@ -1204,12 +1045,13 @@ handle_event(_, _, State, Data) -> </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 @@ -1228,34 +1070,35 @@ 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="#start_link/3"> + <c>start[_link]/3,4</c> + </seealso>. + However, the <seealso marker="#type-server_name"> <c>server_name()</c> </seealso> @@ -1263,265 +1106,260 @@ handle_event(_, _, State, Data) -> <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> - - - - <section> - <title>CALLBACK FUNCTIONS</title> - <p> - The following functions should be exported from a - <c>gen_statem</c> callback module. - </p> - </section> - <funcs> - <func> - <name>Module:init(Args) -> Result</name> - <fsummary>Initialize process and internal state</fsummary> - <type> - <v>Args = term()</v> - <v>Result = {CallbackMode,State,Data}</v> - <v> | {CallbackMode,State,Data,Actions}</v> - <v> | {stop,Reason} | ignore</v> - <v> - CallbackMode = - <seealso marker="#type-callback_mode">callback_mode()</seealso> - </v> - <v>State = <seealso marker="#type-state">state()</seealso></v> - <v> - Data = <seealso marker="#type-data">data()</seealso> - </v> - <v> - Actions = - [<seealso marker="#type-action">action()</seealso>] | - <seealso marker="#type-action">action()</seealso> - </v> - <v>Reason = term()</v> - </type> + <name name="reply" arity="1"/> + <name name="reply" arity="2"/> + <fsummary>Reply to a caller.</fsummary> <desc> - <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> - or - <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> - <c>Args</c> is the <c>Args</c> argument provided to the start - function. - </p> - <p> - If the initialization is successful, the function should - 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>. - of the <c>gen_statem</c>. - <c>State</c> is the initial - <seealso marker="#type-state"><c>state()</c></seealso> - and <c>Data</c> the initial server - <seealso marker="#type-data"><c>data()</c></seealso>. + 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> - The <seealso marker="#type-action"><c>Actions</c></seealso> - are executed when entering the first - <seealso marker="#type-state">state</seealso> just as for a + <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> - If something goes wrong during the initialization - the function should return <c>{stop,Reason}</c> - or <c>ignore</c>. See - <seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>. + 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> - This function may use - <seealso marker="erts:erlang#throw/1"><c>throw/1</c></seealso> - to return <c>Result</c>. + 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>Module:StateName(EventType, EventContent, Data) -> - StateFunctionResult - </name> - <name>Module:handle_event(EventType, EventContent, - State, Data) -> HandleEventResult - </name> - <fsummary>Handle an event</fsummary> - <type> - <v> - EventType = - <seealso marker="#type-event_type">event_type()</seealso> - </v> - <v>EventContent = term()</v> - <v> - State = - <seealso marker="#type-state">state()</seealso> - </v> - <v> - Data = NewData = - <seealso marker="#type-data">data()</seealso> - </v> - <v> - StateFunctionResult = - <seealso marker="#type-state_function_result"> - state_function_result() - </seealso> - </v> - <v> - HandleEventResult = - <seealso marker="#type-handle_event_result"> - handle_event_result() - </seealso> - </v> - </type> + <name name="start_link" arity="3"/> + <name name="start_link" arity="4"/> + <fsummary>Create a linked <c>gen_statem</c> process.</fsummary> <desc> <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="#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. + 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> - 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 - 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> - or by calling - <seealso marker="#reply/2"><c>reply(From, Reply)</c></seealso>. + 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> - 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. + <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> - 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> - there is no restriction on the next state. + <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 cause this function to fail with reason + <c>badarg</c>. + </p> + </note> <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. + 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> - These functions may use - <seealso marker="erts:erlang#throw/1"><c>throw/1</c></seealso>, - to return the result. + 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>Module:terminate(Reason, State, Data) -> Ignored</name> - <fsummary>Clean up before termination</fsummary> - <type> - <v>Reason = normal | shutdown | {shutdown,term()} | term()</v> - <v>State = <seealso marker="#type-state">state()</seealso></v> - <v>Data = <seealso marker="#type-data">data()</seealso></v> - <v>Ignored = term()</v> - </type> + <name name="stop" arity="1"/> + <fsummary>Synchronously stop a generic server.</fsummary> <desc> - <p> - This function is called by a <c>gen_statem</c> - when it is about to terminate. It should 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> - <c>Reason</c> is a term denoting the stop reason and - <seealso marker="#type-state"><c>State</c></seealso> - is the internal state of the <c>gen_statem</c>. - </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 - <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. + <p> + The same as + <seealso marker="#stop/3"> + <c>stop(<anno>ServerRef</anno>, normal, infinity)</c>. + </seealso> </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 - conditions apply:</p> - <list type="bulleted"> - <item> - the <c>gen_statem</c> has been set - to trap exit signals, and - </item> - <item> - the shutdown strategy as defined in the supervisor's - child specification is an integer timeout value, not - <c>brutal_kill</c>. - </item> - </list> - <p> - Even if the <c>gen_statem</c> is <em>not</em> - part of a supervision tree, this function will be called - if it receives an <c>'EXIT'</c> message from its parent. - <c>Reason</c> will be the same as - in the <c>'EXIT'</c> message. + </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> - Otherwise, the <c>gen_statem</c> will be immediately terminated. + <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> - 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 - and an error report is issued using - <seealso marker="kernel:error_logger#format/2"> - <c>error_logger:format/2</c>. - </seealso> + <p> + <c><anno>Timeout</anno></c> is an integer > 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> - This function may use - <seealso marker="erts:erlang#throw/1"><c>throw/1</c></seealso> - to return <c>Ignored</c>, which is ignored anyway. + If the process does not exist, a <c>noproc</c> exception + is raised. </p> </desc> </func> + </funcs> + <section> + <title>Callback Functions</title> + <p> + 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> + <fsummary>Update the internal state during upgrade/downgrade.</fsummary> <type> <v>OldVsn = Vsn | {down,Vsn}</v> <v> Vsn = term()</v> @@ -1544,24 +1382,23 @@ handle_event(_, _, State, Data) -> </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 + 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. See - <seealso marker="doc/design_principles:release_handling#instr"> + file. For more information, see + <seealso marker="doc/design_principles:release_handling#instr"> OTP Design Principles - </seealso> - for more information. + </seealso>. </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> + 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> @@ -1569,14 +1406,14 @@ handle_event(_, _, State, Data) -> <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> + 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 may also be possible to figure this out - from the <c>{down,Vsn}</c> argument since <c>Vsn</c> + 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> @@ -1584,32 +1421,102 @@ handle_event(_, _, State, Data) -> <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> + <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 + <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 will fail and roll back to the old release.</p> + upgrade fails and rolls back to the old release.</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> or <c>Reason</c>. </p> </desc> </func> <func> + <name>Module:init(Args) -> Result</name> + <fsummary>Initialize process and internal state.</fsummary> + <type> + <v>Args = term()</v> + <v>Result = {CallbackMode,State,Data}</v> + <v> | {CallbackMode,State,Data,Actions}</v> + <v> | {stop,Reason} | ignore</v> + <v> + CallbackMode = + <seealso marker="#type-callback_mode">callback_mode()</seealso> + </v> + <v>State = <seealso marker="#type-state">state()</seealso></v> + <v> + Data = <seealso marker="#type-data">data()</seealso> + </v> + <v> + Actions = + [<seealso marker="#type-action">action()</seealso>] | + <seealso marker="#type-action">action()</seealso> + </v> + <v>Reason = term()</v> + </type> + <desc> + <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> + or + <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> + <c>Args</c> is the <c>Args</c> argument provided to the start + function. + </p> + <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> + of the <c>gen_statem</c>. + <c>State</c> is the initial + <seealso marker="#type-state"><c>state()</c></seealso> + and <c>Data</c> the initial server + <seealso marker="#type-data"><c>data()</c></seealso>. + </p> + <p> + The <seealso marker="#type-action"><c>Actions</c></seealso> + are executed when entering the first + <seealso marker="#type-state">state</seealso> just as for a + <seealso marker="#state_function">state function</seealso>. + </p> + <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 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> + current <c>gen_statem</c> status.</fsummary> <type> <v>Opt = normal | terminate</v> <v>PDict = [{Key, Value}]</v> @@ -1627,58 +1534,59 @@ handle_event(_, _, State, Data) -> </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> + <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:</p> + <p>This function is called by a <c>gen_statem</c> process when + any of the following apply:</p> <list type="bulleted"> - <item> + <item> One of - <seealso marker="sys#get_status/1"> + <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. + 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> + <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> + </list> <p> - This function is useful for customising the form and + 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 customise the + callback module wishing to change the <seealso marker="sys#get_status/1"> <c>sys:get_status/1,2</c> </seealso> - return value as well as how + return value and how its status appears in termination error logs exports an - instance of <c>format_status/2</c> that returns a term + 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 <c>gen_statem</c>'s - process dictionary. + <p> + <c>PDict</c> is the current value of the process dictionary + of the <c>gen_statem</c>. </p> - <p> + <p> <seealso marker="#type-state"><c>State</c></seealso> is the internal state of the <c>gen_statem</c>. </p> - <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 + <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"> @@ -1687,38 +1595,197 @@ handle_event(_, _, State, Data) -> 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 + 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> + <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 + printed in log files. Another use 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> + 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 + </name> + <name>Module:handle_event(EventType, EventContent, + State, Data) -> HandleEventResult + </name> + <fsummary>Handle an event.</fsummary> + <type> + <v> + EventType = + <seealso marker="#type-event_type">event_type()</seealso> + </v> + <v>EventContent = term()</v> + <v> + State = + <seealso marker="#type-state">state()</seealso> + </v> + <v> + Data = NewData = + <seealso marker="#type-data">data()</seealso> + </v> + <v> + StateFunctionResult = + <seealso marker="#type-state_function_result"> + state_function_result() + </seealso> + </v> + <v> + HandleEventResult = + <seealso marker="#type-handle_event_result"> + handle_event_result() + </seealso> + </v> + </type> + <desc> + <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="#type-callback_mode"><em>callback mode</em></seealso> + 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 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>, + 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 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 must be an atom, but for <c>HandleEventResult</c> + there is no restriction on the next state. + </p> + <p> + 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 can use + <seealso marker="erts:erlang#throw/1"><c>erlang:throw/1</c></seealso>, + to return the result. + </p> + </desc> + </func> + + <func> + <name>Module:terminate(Reason, State, Data) -> Ignored</name> + <fsummary>Clean up before termination.</fsummary> + <type> + <v>Reason = normal | shutdown | {shutdown,term()} | term()</v> + <v>State = <seealso marker="#type-state">state()</seealso></v> + <v>Data = <seealso marker="#type-data">data()</seealso></v> + <v>Ignored = term()</v> + </type> + <desc> + <p> + This function is called by a <c>gen_statem</c> + 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> + <c>Reason</c> is a term denoting the stop reason and + <seealso marker="#type-state"><c>State</c></seealso> + is the internal state of the <c>gen_statem</c>. + </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 + <seealso marker="#type-action"><c>Actions</c></seealso>, + <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 is + called with <c>Reason = shutdown</c> if both the following + conditions apply:</p> + <list type="bulleted"> + <item> + <p> + The <c>gen_statem</c> has been set + to trap exit signals. + </p> + </item> + <item> + <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 is called + if it receives an <c>'EXIT'</c> message from its parent. + <c>Reason</c> is the same as + in the <c>'EXIT'</c> message. + </p> + <p> + Otherwise, the <c>gen_statem</c> is immediately terminated. + </p> + <p> + 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> + </p> + <p> + 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> </funcs> <section> - <title>SEE ALSO</title> + <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="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..8b0fbed7c0 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,60 @@ <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, makes + a state machine implemented with this behavior Turing complete. + But it feels mostly like an Event-Driven Mealy Machine. </p> </section> @@ -99,38 +96,40 @@ 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> + </item> + </list> <p> - Both these modes allow other return tuples - that you can find in the + Both these modes allow other return tuples; see <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 + <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,55 @@ 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 +196,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 +238,6 @@ start_link(Code) -> button(Digit) -> gen_statem:cast(?NAME, {button,Digit}). - init(Code) -> do_lock(), Data = #{code => Code, remaining => Code}, @@ -286,7 +282,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,63 +290,64 @@ start_link(Code) -> gen_statem:start_link({local,?NAME}, ?MODULE, Code, []). ]]></code> <p> - <c>start_link</c> calls the function + <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>. + </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"> @@ -360,14 +357,14 @@ start_link(Code) -> <seealso marker="stdlib:gen_statem#type-callback_mode"> <c>state_functions</c> </seealso> - through the macro <c>?CALLBACK_MODE</c> that is; each state + 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 +374,25 @@ init(Code) -> Data = #{code => Code, remaining => Code}, {?CALLBACK_MODE,locked,Data}. ]]></code> - <p> + <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> - has been initialized and is ready to receive events. + is synchronous. It does not return until the <c>gen_statem</c> + is initialized and is ready to receive events. </p> <p> + 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; + 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> - to start a standalone <c>gen_statem</c>, that is; + 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,7 +400,7 @@ 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"> @@ -415,9 +413,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 +450,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 +476,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 +494,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[ ... @@ -532,7 +530,7 @@ handle_event({call,From}, code_length, #{code := Code} = Data) -> This example uses <seealso marker="stdlib:gen_statem#call/2"> <c>gen_statem:call/2</c> - </seealso> + </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,9 +543,12 @@ 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[ @@ -596,19 +597,18 @@ 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>: + <c>process_flag(trap_exit, true)</c> + </seealso>. + When ordered to shut down, the <c>gen_statem</c> then calls + callback function <c>terminate(shutdown, State, Data)</c>: </p> <code type="erl"><![CDATA[ init(Args) -> @@ -617,9 +617,9 @@ 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. + 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) -> @@ -634,8 +634,8 @@ terminate(_Reason, State, _Data) -> 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> + <c>gen_statem:stop</c> + </seealso>, preferably through an API function: </p> <code type="erl"><![CDATA[ @@ -647,8 +647,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,15 +659,15 @@ 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 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 @@ -680,27 +680,28 @@ stop() -> </seealso> from the <seealso marker="stdlib:gen_statem#Module:StateName/3"> - callback function. - </seealso> + 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 + 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"> - reference manual + <c>gen_statem(3)</c> </seealso> - for details. You can for example actually reply to several callers + manual page. + You can, for example, reply to many callers and generate multiple next events to handle. </p> </section> @@ -710,16 +711,16 @@ stop() -> <section> <title>Event Types</title> <p> - So far we have mentioned a few + The previous sections mentioned a few <seealso marker="stdlib:gen_statem#type-event_type"> - event types. - </seealso> + 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> @@ -735,13 +736,13 @@ stop() -> Generated by <seealso marker="stdlib:gen_statem#call/2"> <c>gen_statem:call</c> - </seealso> + </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> + <c>gen_statem:reply</c> + </seealso>. </item> <tag><c>info</c></tag> <item> @@ -750,15 +751,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 be generated using <c>{next_event,EventType,EventContent}</c>. </item> </taglist> @@ -767,34 +768,34 @@ 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: + 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 +817,17 @@ open(cast, {button,_}, Data) -> ... ]]></code> <p> - If you need to cancel a timer due to some other event you can use + 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> - Note that a timeout message can not arrive after this, + <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,7 +840,7 @@ 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 @@ -850,8 +851,8 @@ open(cast, {button,_}, Data) -> </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[ ... @@ -860,17 +861,17 @@ 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. + 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>: + 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 +884,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 +893,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,16 +938,16 @@ 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> @@ -955,15 +956,15 @@ do_unlock() -> <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 + <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,9 +972,9 @@ 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"> @@ -984,30 +985,30 @@ do_unlock() -> <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, + 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 +1052,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 +1148,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 following clean first-dispatch-on-event approach + does not work that well because of the generated + entry actions: </p> <code type="erl"><![CDATA[ ... @@ -1195,7 +1197,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 +1208,33 @@ 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 + by implementing function <seealso marker="stdlib:gen_statem#Module:format_status/2"> <c>Module:format_status/2</c> - </seealso> - function, for example like this: + </seealso>, + for example like this: </p> <code type="erl"><![CDATA[ ... @@ -1260,9 +1262,9 @@ format_status(Opt, [_PDict,State,Data]) -> <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 + 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> @@ -1275,54 +1277,56 @@ format_status(Opt, [_PDict,State,Data]) -> <seealso marker="stdlib:gen_statem#type-callback_mode"> <c>handle_event_function</c> </seealso> - enables using a non-atom state as described in + 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. + 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 +1445,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 +1460,25 @@ 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 + 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[ @@ -1498,24 +1500,24 @@ handle_event( </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> |