diff options
author | Raimo Niskanen <[email protected]> | 2015-10-26 11:52:17 +0100 |
---|---|---|
committer | Raimo Niskanen <[email protected]> | 2016-02-09 10:07:56 +0100 |
commit | 6ace96d3e5c9ac8ace3d8967bcafb3e6a081d9be (patch) | |
tree | 2a5dc8326bf0a52a23ac3c00de0ea365d91866e4 /lib/stdlib/doc | |
parent | adcc726c36555434204dd0fccd13ed984741a7fb (diff) | |
download | otp-6ace96d3e5c9ac8ace3d8967bcafb3e6a081d9be.tar.gz otp-6ace96d3e5c9ac8ace3d8967bcafb3e6a081d9be.tar.bz2 otp-6ace96d3e5c9ac8ace3d8967bcafb3e6a081d9be.zip |
New state machine
Diffstat (limited to 'lib/stdlib/doc')
-rw-r--r-- | lib/stdlib/doc/src/Makefile | 3 | ||||
-rw-r--r-- | lib/stdlib/doc/src/gen_statem.xml | 1131 | ||||
-rw-r--r-- | lib/stdlib/doc/src/ref_man.xml | 3 | ||||
-rw-r--r-- | lib/stdlib/doc/src/specs.xml | 1 |
4 files changed, 1136 insertions, 2 deletions
diff --git a/lib/stdlib/doc/src/Makefile b/lib/stdlib/doc/src/Makefile index 196c86748f..26602764a6 100644 --- a/lib/stdlib/doc/src/Makefile +++ b/lib/stdlib/doc/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2015. All Rights Reserved. +# Copyright Ericsson AB 1997-2016. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -68,6 +68,7 @@ XML_REF3_FILES = \ gen_event.xml \ gen_fsm.xml \ gen_server.xml \ + gen_statem.xml \ io.xml \ io_lib.xml \ lib.xml \ diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml new file mode 100644 index 0000000000..885021f61c --- /dev/null +++ b/lib/stdlib/doc/src/gen_statem.xml @@ -0,0 +1,1131 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2016</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>gen_statem</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>gen_statem</module> + <modulesummary>Generic State Machine Behaviour</modulesummary> + <description> + <p>A behaviour module for implementing a state machine, primarily + a finite state machine, but an infinite state space is possible. + A generic state machine process (gen_statem) implemented using + this module will have a standard set of interface functions + and include functionality for tracing and error reporting. + It will also fit into an OTP supervision tree. Refer to + <seealso marker="doc/design_principles:gen_server_concepts"> + OTP Design Principles</seealso> for more information. + </p> + <p>A gen_statem 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> + <pre> +gen_statem module Callback module +----------------- --------------- +gen_statem:start +gen_statem:start_link -----> Module:init/1 + +gen_statem:stop -----> Module:terminate/2 + +gen_statem:call +gen_statem:cast +erlang:send +erlang:'!' -----> Module:State/5 + Module:handle_event/5 + +- -----> Module:terminate/3 + +- -----> Module:code_change/3</pre> + <p>Events are of different + <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 gen_statem 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. + </p> + <marker id="state_function" /> + <p>The "<em>state function</em>" for a specific + <seealso marker="#type-state">state</seealso> + in a gen_statem is the callback function that is called + for all events in this state. + An event can can be postponed causing it to be retried + after the state has changed, or more precisely; + after a state change all postponed events are retried + in the new state. + </p> + <p>The state machine + <seealso marker="#type-state"><c>State</c></seealso> + is normally an atom in which case the + <seealso marker="#state_function">state function</seealso> + that will be called is + <seealso marker="#Module:State/5"><c>Module:State/5</c></seealso>. + For a + <seealso marker="#type-state"><c>State</c></seealso> + that is <em>not</em> an atom the + <seealso marker="#state_function">state function</seealso> + <seealso marker="#Module:handle_event/5"> + <c>Module:handle_event/5</c> + </seealso> will be called. + If you use <c>handle_event</c> as a + <seealso marker="#type-state">state</seealso> and later + decides to use non-atom states you will then have to + rewrite your code to stop using that state. + </p> + <p>When the using an atom-only + <seealso marker="#type-state">State</seealso> + it becomes fairly obvious in the implementation code + which events are handled in which state + since there are different callback functions for different states. + </p> + <p> + When using a non-atom <seealso marker="#type-state">State</seealso> + all events are handled in the callback function + <seealso marker="#Module:handle_event/5"> + <c>Module:handle_event/5</c> + </seealso> + so it may require more coding discipline to ensure what events + are handled in which state. Therefore it might be a wee bit + easier to accidentally postpone an event in two or more states + and not handling it in any of them causing a tight infinite + loop when the event bounces to be retried between the states. + </p> + <p>A gen_statem handles system messages as documented in + <seealso marker="sys">sys</seealso>. + The <seealso marker="sys">sys</seealso> module + can be used for debugging a gen_statem. + </p> + <p>Note that a gen_statem does not trap exit signals automatically, + this must be explicitly initiated by the callback module. + </p> + <p>Unless otherwise stated, all functions in this module fail if + the specified gen_statem does not exist or if bad arguments are given. + </p> + <p>The gen_statem process can go into hibernation (see + <seealso marker="erts:erlang#hibernate/3"> + <c>erlang:hibernate/3</c> + </seealso>) if 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-state_op"><c>StateOps</c></seealso> list. + This might be useful if the server is expected to be idle + for a long time. However use this feature with care + since hibernation implies at least two garbage collections + (when hibernating and shortly after waking up) and that is not + something you'd want to do between each event on a busy server. + </p> + </description> + + <datatypes> + <datatype> + <name name="server_name" /> + <desc> + <p>Name specification to use when starting a gen_statem server. + See <seealso marker="#start_link/3"> + <c>start_link/3</c> + </seealso> and + <seealso marker="#type-server_ref"> + <c>server_ref()</c> + </seealso> below. + </p> + </desc> + </datatype> + <datatype> + <name name="server_ref" /> + <desc> + <p>Server specification to use when addressing a gen_statem server. + See <seealso marker="#call/2">call/2</seealso> and + <seealso marker="#type-server_name"> + <c>server_name()</c> + </seealso> above. + </p> + <p>It can be:</p> + <list type="bulleted"> + <item>the <c>pid()</c>,</item> + <item><c><anno>Name</anno></c>, + if the gen_statem is locally registered, + </item> + <item><c>{<anno>Name</anno>,<anno>Node</anno>}</c>, + if the gen_statem is locally registered at another node, or + </item> + <item><c>{global,<anno>GlobalName</anno>}</c>, + if the gen_statem is globally registered. + </item> + <item><c>{via,<anno>RegMod</anno>,<anno>ViaName</anno>}</c>, + if the gen_statem 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>. + </item> + </list> + </desc> + </datatype> + <datatype> + <name name="debug_opt" /> + <desc> + <p>Debug option that can be used when starting + a gen_statem server through for example + <seealso marker="#enter_loop/4">enter_loop/4</seealso>. + </p> + <p>For every entry in <c><anno>Dbgs</anno></c> + the corresponding function in + <seealso marker="sys"><c>sys</c></seealso> will be called. + </p> + </desc> + </datatype> + <datatype> + <name name="start_opt" /> + <desc> + <p>Options that can be used when starting + a gen_statem server through for example + <seealso marker="#start_link/3">start_link/3</seealso>. + </p> + </desc> + </datatype> + <datatype> + <name name="start_ret" /> + <desc> + <p>Return value from the start functions for_example + <seealso marker="#start_link/3">start_link/3</seealso>. + </p> + </desc> + </datatype> + + <datatype> + <name name="client" /> + <desc> + <p>Client address to use when replying through for example the + <seealso marker="#type-state_op">state_op()</seealso> + <c>{reply,Client,Reply}</c> to a client + that has called the gen_statem server using + <seealso marker="#call/2">call/2</seealso>. + </p> + </desc> + </datatype> + <datatype> + <name name="state" /> + <desc> + <p>If the gen_statem <c>State</c> is an <c>atom()</c>, the + <seealso marker="#state_function">state function</seealso> is + <seealso marker="#Module:State/5">Module:State/5</seealso>. + If it is any other <c>term()</c> the + <seealso marker="#state_function">state function</seealso> is + <seealso marker="#Module:handle_event/5"> + Module:handle_event/5 + </seealso>. After a state change (<c>NewState =/= State</c>) + all postponed events are retried. + </p> + </desc> + </datatype> + <datatype> + <name name="state_data" /> + <desc> + <p>A <c>term()</c> in which the state machine implementation + should store any state data it needs. The difference between + this data and the + <seealso marker="#type-state">state()</seealso> + itself is that a change in this data does not cause + postponed events to be retried. + </p> + </desc> + </datatype> + <datatype> + <name name="event_type" /> + <desc> + <p>External events are of 3 different type: + <c>{call,<anno>Client</anno>}</c>, <c>cast</c> or <c>info</c>. + Calls (synchronous) and casts (asynchronous) + originate from the corresponding API functions. + For calls the event contain whom to reply to. + Type <c>info</c> originates from normal messages sent + to the gen_statem process. + It is also possible for the state machine + implementation to insert events to itself, + in particular of types + <c>timeout</c> and <c>internal</c>. + </p> + </desc> + </datatype> + <datatype> + <name name="event_predicate" /> + <desc> + <p>A <c>fun()</c> of arity 2 that takes an event + and returns a boolean. + When used in <c>{remove_event,RemoveEventPredicate}</c> + from <seealso marker="#type-state_op">state_op()</seealso>. + The event for which the predicate returns <c>true</c> will + be removed. + </p> + <p> + The predicate may <em>not</em> use a throw exception + to return its result. + </p> + </desc> + </datatype> + <datatype> + <name name="state_op" /> + <desc> + <p>Either a + <seealso marker="#type-state_option"> + <c>state_option()</c> + </seealso> of which the first occurence + in the containing list takes precedence, or a + <seealso marker="#type-state_operation"> + <c>state_operation()</c> + </seealso> that are performed in order of + the containing list. + </p> + <p>These may be returned from the + <seealso marker="#state_function">state function</seealso> + or from <seealso marker="#Module:init/1">Module:init/1</seealso>. + </p> + <p>The gen_statem enqueues postponed events and + not yet processed events in order of arrival, except for + an event that a callback function inserts with + <c>{insert_event,EventType,EventContent}</c> that is inserted + as the next event to process. + </p> + <p>When the state machine changes states all enqueued events + becomes not yet processed to be processed before the old + not yet processed events. In other words; the order of arrival + is retained. + </p> + <p>The processing order is:</p> + <list type="ordered"> + <item>If the option <c>retry</c> is <c>true</c> + the current event is enqueued as postponed to be retried. + </item> + <item>If the state changes all postponed events + are transferred to not yet processed to be processed + before other not yet processed events. + </item> + <item>All operations are processed in order of appearance. + </item> + <item>The <c>timeout</c> option is processed if present. + So a state timer may be started or a timeout zero event + may be inserted as if just received. + </item> + <item>The (possibly new) + <seealso marker="#state_function">state function</seealso> + is called with the next not yet processed event + if there is any, otherwise the gen_statem goes into <c>receive</c> + or hibernation (if the option <c>hibernate</c> is <c>true</c>) + to wait for the next message. In hibernation the next + non-system event awakens the gen_statem. + </item> + </list> + </desc> + </datatype> + <datatype> + <name name="state_option" /> + <desc> + <taglist> + <tag><c>retry</c></tag> + <tag><c>{retry,<anno>Retry</anno>}</c></tag> + <item>If <c><anno>Retry</anno> =:= true</c> + or plain <c>retry</c> postpone the current event + to be retried after a state change. + </item> + <tag><c>hibernate</c></tag> + <tag><c>{hibernate,<anno>Hibernate</anno>}</c></tag> + <item>If <c><anno>Hibernate</anno> =:= true</c> + or plain <c>hibernate</c> hibernate the gen_statem by calling + <seealso marker="proc_lib#hibernate/3"> + <c>proc_lib:hibernate/3</c> + </seealso> before <c>receive</c> to wait for a new event. + If there are not yet processed events the + <c>hibernate</c> operation is ignored as if an event + just arrived and awakened the gen_statem. + </item> + <tag> + <c>{timeout,<anno>Time</anno>,<anno>Msg</anno>}</c> + </tag> + <item>Generate an event of + <seealso marker="#type-event_type">type <c>timeout</c></seealso> + after <c><anno>Time</anno></c> milliseconds unless some other + event is received before that time. Note that a retried + event counts just like a new in this respect. + If <c>Time =:= infinity</c> or <c>Time =:= 0</c> + no timer is started but for zero time the timeout + event is enqued as just received after all + other already received events. + Also note that it is not possible + to cancel this timeout using the + <seealso marker="#type-state_operation"> + <c>state_operation()</c> + </seealso> <c>cancel_timer</c>. + This timeout is cancelled automatically by any event. + </item> + </taglist> + </desc> + </datatype> + <datatype> + <name name="state_operation" /> + <desc> + <taglist> + <tag> + <c>{reply,<anno>Client</anno>,<anno>Reply</anno>}</c> + </tag> + <item>Reply to a client that called + <seealso marker="#call/2"><c>call/2</c></seealso>. + <c><anno>Client</anno></c> must be the term from the + <seealso marker="#type-event_type"> + <c>{call,<anno>Client</anno>}</c> + </seealso> argument to the + <seealso marker="#state_function">state function</seealso>. + </item> + <tag><c>{stop,<anno>Reason</anno>}</c></tag> + <item>The gen_statem will call + <seealso marker="#Module:terminate/3"> + <c>Module:terminate/3</c> + </seealso> with <c><anno>Reason</anno></c> and terminate. + </item> + <tag> + <c> + {insert_event,<anno>EventType</anno>,<anno>EventContent</anno>} + </c> + </tag> + <item>Insert the given event as the next to process + before any other not yet processed events. + An event of type + <seealso marker="#type-event_type"> + <c>internal</c> + </seealso> should be used when you want to reliably distinguish + an event inserted this way from any external event. + </item> + <tag> + <c> + {remove_event,<anno>EventType</anno>,<anno>EventContent</anno>} + </c> + </tag> + <item>Remove the oldest queued event + that matches equal to the given event. + </item> + <tag> + <c> + {remove_event,<anno>EventPredicate</anno>} + </c> + </tag> + <item>Remove the oldest queued event for which + the <c><anno>EventPredicate</anno></c> returns <c>true</c>. + </item> + <tag><c>{cancel_timer,<anno>TimerRef</anno>}</c></tag> + <item>Uses <c><anno>TimerRef</anno></c> when calling + <seealso marker="erts:erlang#cancel_timer/2"> + <c>erlang:cancel_timer/2</c> + </seealso> to cancel a timer, cleans the gen_statem's + message queue from any late timeout message from + the timer, and removes any late timeout message + from the queued events using + <c>{remove_event,<anno>EventPredicate</anno>}</c> above. + This is a convenience function that saves quite some + lines of code and testing time over doing it from + the primitives mentioned above. + </item> + <tag><c>{demonitor,<anno>MonitorRef</anno>}</c></tag> + <item>Like <c>{cancel_timer,_}</c> above but for + <seealso marker="erts:erlang#demonitor/2"> + <c>demonitor/2</c> + </seealso>. + </item> + <tag><c>{unlink,<anno>Id</anno>}</c></tag> + <item>Like <c>{cancel_timer,_}</c> above but for + <seealso marker="erts:erlang#unlink/1"> + <c>unlink/1</c> + </seealso>. + </item> + </taglist> + </desc> + </datatype> + </datatypes> + + <funcs> + + <func> + <name name="start_link" arity="3" /> + <name name="start_link" arity="4" /> + <fsummary>Create a linked gen_statem process</fsummary> + <desc> + <p>Creates a gen_statem 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 gen_statem shall be part of + a supervision tree so it gets linked to its supervisor. + </p> + <p>The gen_statem 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 gen_statem. + If the gen_statem is started with <c>start_link/3</c> + no <c><anno>ServerName</anno></c> is provided and + the gen_statem 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>Options</anno></c>, the gen_statem 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>Options</anno></c>, debugging through + <seealso marker="sys"><c>sys</c></seealso> is activated. + </p> + <p>If the option <c>{spawn_opt,SOpts}</c> is present in + <c><anno>Options</anno></c>, <c>SOpts</c> will be passed + as option list to the <c>spawn_opt</c> BIF + which is used to + <seealso marker="erts:erlang#spawn_opt/2">spawn</seealso> + the gen_statem. + </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 gen_statem 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 gen_statem. + 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 gen_statem process</fsummary> + <desc> + <p>Creates a stand-alone gen_statem 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">start_link/3,4</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 gen_statem + <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 gen_statem will call + <seealso marker="#Module:terminate/3"> + Module:terminate/3 + </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"> + error_logger:format/2 + </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 gen_statem</fsummary> + <desc> + <p>Makes a synchronous call to the gen_statem + <seealso marker="#type-server_ref"> + <c><anno>ServerRef</anno></c> + </seealso> by sending a request + and waiting until its reply arrives. + The gen_statem will call the + <seealso marker="#state_function">state function</seealso> with + <seealso marker="#type-event_type"><c>event_type()</c></seealso> + <c>{call,Client}</c> and event content + <c><anno>Request</anno></c>. + </p> + <p>A <c><anno>Reply</anno></c> is generated when a + <seealso marker="#state_function">state function</seealso> + returns with + <c>{reply,Client,<anno>Reply</anno>}</c> as one + <seealso marker="#type-state_op"><c>state_op()</c></seealso>, + 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 + 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 + the specified time, the function call fails. + <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 + less efficient than using + <c><anno>Timeout</anno> =:= infinity</c>. + </p> + </note> + </p> + <p>The call may fail for example if the gen_statem dies + before or during this function call. + </p> + </desc> + </func> + + <func> + <name name="cast" arity="2" /> + <fsummary>Send an asynchronous event to a gen_statem</fsummary> + <desc> + <p>Sends an asynchronous event to the gen_statem + <seealso marker="#type-server_ref"> + <c><anno>ServerRef</anno></c> + </seealso> and returns <c>ok</c> immediately, + ignoring if the destination node or gen_statem does not exist. + The gen_statem will call 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 + <c><anno>Msg</anno></c>. + </p> + </desc> + </func> + + <func> + <name name="reply" arity="2" /> + <fsummary>Send a reply to a client</fsummary> + <desc> + <p>This function can be used by a gen_statem to explicitly send + a reply to a client that called + <seealso marker="#call/2"><c>call/2</c></seealso> + when the reply cannot be defined in + the return value of the + <seealso marker="#state_function">state function</seealso>. + </p> + <p><c><anno>Client</anno></c> must be the term from the + <seealso marker="#type-event_type"> + <c>{call,<anno>Client</anno>}</c> + </seealso> argument to the + <seealso marker="#state_function">state function</seealso>. + </p> + <note> + <p>A reply sent with this function will not be visible + in <seealso marker="sys">sys</seealso> debug output. + </p> + </note> + </desc> + </func> + + <func> + <name name="enter_loop" arity="4" /> + <fsummary>Enter the gen_statem receive loop</fsummary> + <desc> + <p>The same as + <seealso marker="#enter_loop/6"><c>enter_loop/6</c></seealso> + except that no + <seealso marker="#type-server_name"> + <c>server_name()</c> + </seealso> must have been registered. + </p> + </desc> + </func> + <func> + <name name="enter_loop" arity="5" /> + <fsummary>Enter the gen_statem receive loop</fsummary> + <desc> + <p>If <c><anno>Server_or_StateOps</anno></c> is a <c>list()</c> + the same as + <seealso marker="#enter_loop/6"><c>enter_loop/6</c></seealso> + except that no + <seealso marker="#type-server_name"> + <c>server_name()</c> + </seealso> must have been registered and + <c>StateOps = <anno>Server_or_StateOps</anno></c>. + </p> + <p>Otherwise the same as + <seealso marker="#enter_loop/6"><c>enter_loop/6</c></seealso> + with + <c>Server = <anno>Server_or_StateOps</anno></c> and + <c>StateOps = []</c>. + </p> + </desc> + </func> + <func> + <name name="enter_loop" arity="6" /> + <fsummary>Enter the gen_statem receive loop</fsummary> + <desc> + <p>Makes an the calling process become a gen_statem. Does not return, + instead the calling process will enter the gen_statem receive + loop and become a gen_statem 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>. + The user is responsible for any initialization of the process, + including registering a name for it. + </p> + <p>This function is useful when a more complex initialization + procedure is needed than the gen_statem behaviour provides. + </p> + <p><c><anno>Module</anno></c>, <c><anno>Options</anno></c> and + <c><anno>Server</anno></c> have the same meanings + as when calling + <seealso marker="#start_link/3">gen_statem:start[_link]/3,4</seealso>. + However, the + <seealso marker="#type-server_name"> + <c>server_name()</c> + </seealso> name must have been registered accordingly + <em>before</em> this function is called.</p> + <p><c><anno>State</anno></c> and <c><anno>StateData</anno></c> + have the same meanings as in the return value of + <seealso marker="#Module:init/1">Module:init/1</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> + start function, or if it is not registered + 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 = {ok,State,StateData}</v> + <v> | {ok,State,StateData,StateOps}</v> + <v> | {stop,Reason} | ignore</v> + <v>State = <seealso marker="#type-state">state()</seealso></v> + <v>StateData = <seealso marker="#type-state_data">state_data()</seealso></v> + <v>StateOps = [<seealso marker="#type-state_op">state_op()</seealso>]</v> + <v>Reason = term()</v> + </type> + <desc> + <marker id="Module:init-1" /> + <p>Whenever a gen_statem is started using + <seealso marker="#start_link/3">gen_statem:start_link/3,4</seealso> + or + <seealso marker="#start/3">gen_statem:start/3,4</seealso>, + this function is called by the new process to initialize + the implementation loop 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>{ok,State,StateData}</c> or + <c>{ok,State,StateData,StateOps}</c>. + <c>State</c> is the <seealso marker="#type-state">state</seealso> + of the gen_statem. + </p> + <p>The <seealso marker="#type-state_op"><c>StateOps</c></seealso> + are executed before entering the first + <seealso marker="#type-state">state</seealso> just as for a + <seealso marker="#state_function">state function</seealso>. + </p> + <p>If something goes wrong during the initialization + the function should return <c>{stop,Reason}</c> + or <c>ignore</c>. See + <seealso marker="#start_link/3">gen_statem:start_link/3,4</seealso>. + </p> + </desc> + </func> + + <func> + <name>Module:handle_event(EventType, EventContent, + PrevState, State, StateData) -> Result + </name> + <name>Module:State(EventType, EventContent, + PrevState, State, StateData) -> Result + </name> + <fsummary>Handle an event</fsummary> + <type> + <v>EventType = + <seealso marker="#type-event_type">event_type()</seealso> + </v> + <v>EventContent = term()</v> + <v>Result = {NewState,NewStateData,StateOps}</v> + <v> | {NewState,NewStateData}</v> + <d> The same as <c>{NewState,NewStateData,[]}</c></d> + <v> | {NewStateData}</v> + <d> The same as <c>{State,NewStateData,[retry]}</c></d> + <v> | {}</v> + <d> The same as <c>{State,StateData,[]}</c></d> + <v> | StateOps</v> + <d> The same as <c>{State,StateData,StateOps}</c></d> + + <v>PrevState = State = NewState = + <seealso marker="#type-state">state()</seealso> + </v> + <v>StateData = NewStateData = + <seealso marker="#type-state_data">state_data()</seealso> + </v> + <v>StateOps = + [<seealso marker="#type-state_op">state_op()</seealso>] + </v> + </type> + <desc> + <p>Whenever a gen_statem receives an event from + <seealso marker="#call/2">gen_statem:call/2</seealso>, + <seealso marker="#cast/2">gen_statem:cast/2</seealso> or + as a normal process message this function is called. + If the <c>EventType</c> is + <seealso marker="#type-event_type"><c>{call,Client}</c></seealso> + the client 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,Client,Reply}</c> in + <seealso marker="#type-state_op">StateOps</seealso> + or by calling + <seealso marker="#reply/2"> + <c>gen_statem:reply(Client, Reply)</c> + </seealso>. + </p> + <p><seealso marker="#type-state"><c>State</c></seealso> + is the internal state of the gen_statem which + when <c>State</c> is an <c>atom()</c> + is the same as this function's name, so it is seldom useful, + except for example when comparing with <c>PrevState</c> + that is the gen_statem's previous state, or in + <seealso marker="#Module:handle_event/5"> + Module:handle_event/5 + </seealso> since that function is common for all states + that are not an <c>atom()</c>. + </p> + <p>If this function returns with + <seealso marker="#type-state"><c>NewState =/= State</c></seealso> + all postponed events will be retried in the new state. + </p> + <p>See <seealso marker="#type-state_op">state_op()</seealso> + for the operations that can be done by gen_statem + after returning from this function. + </p> + </desc> + </func> + + <func> + <name>Module:terminate(Reason, State, StateData)</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>StateData = + <seealso marker="#type-state_data"> + state_data() + </seealso> + </v> + </type> + <desc> + <p>This function is called by a gen_statem 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 gen_statem 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">State</seealso> + is the internal state of the gen_statem. + </p> + <p><c>Reason</c> depends on why the gen_statem is terminating. + If it is because another callback function has returned a + stop tuple <c>{stop,Reason}</c> in + <seealso marker="#type-state_op">StateOps</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> + <p>If the gen_statem 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 gen_statem 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 gen_statem 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. + </p> + <p>Otherwise, the gen_statem will be immediately terminated. + </p> + <p>Note that for any other reason than <c>normal</c>, + <c>shutdown</c>, or <c>{shutdown,Term}</c> the gen_statem is + assumed to terminate due to an error and + an error report is issued using + <seealso marker="kernel:error_logger#format/2"> + error_logger:format/2 + </seealso>. + </p> + </desc> + </func> + + <func> + <name>Module:code_change(OldVsn, OldState, OldStateData, Extra) -> + Result + </name> + <fsummary>Update the internal state during upgrade/downgrade</fsummary> + <type> + <v>OldVsn = Vsn | {down,Vsn}</v> + <v> Vsn = term()</v> + <v>OldState = NewState = term()</v> + <v>Extra = term()</v> + <v>Result = {ok,{NewState,NewStateData}} | Reason</v> + <v>OldState = NewState = + <seealso marker="#type-state">state()</seealso> + </v> + <v>OldStateData = NewStateData = + <seealso marker="#type-state_data">state_data()</seealso> + </v> + <v>Reason = term()</v> + </type> + <desc> + <p>This function is called by a gen_statem when it should + update its internal state during a release upgrade/downgrade, + i.e. when the instruction <c>{update,Module,Change,...}</c> + where <c>Change={advanced,Extra}</c> is given in + the <c>appup</c> file. See + <seealso marker="doc/design_principles:release_handling#instr"> + OTP Design Principles + </seealso> + for more information. + </p> + <p>In the case of an upgrade, <c>OldVsn</c> is <c>Vsn</c>, and + in the case of a downgrade, <c>OldVsn</c> is + <c>{down,Vsn}</c>. <c>Vsn</c> is defined by the <c>vsn</c> + attribute(s) of the old version of the callback module + <c>Module</c>. If no such attribute is defined, the version + is the checksum of the BEAM file. + </p> + <p><c>OldState</c> and <c>OldStateData</c> is the internal state + of the gen_statem. + </p> + <p><c>Extra</c> is passed as-is from the <c>{advanced,Extra}</c> + part of the update instruction. + </p> + <p>If successful, the function shall return the updated + internal state in an + <c>{ok,{NewState,NewStateData}}</c> tuple. + </p> + <p>If the function returns <c>Reason</c>, the ongoing + upgrade will fail and roll back to the old release.</p> + </desc> + </func> + + <func> + <name>Module:format_status(Opt, [PDict,State,StateData]) -> + Status + </name> + <fsummary>Optional function for providing a term describing the + current gen_statem status</fsummary> + <type> + <v>Opt = normal | terminate</v> + <v>PDict = [{Key, Value}]</v> + <v>State = + <seealso marker="#type-state">state()</seealso> + </v> + <v>StateData = + <seealso marker="#type-state_data">state_data()</seealso> + </v> + <v>Key = term()</v> + <v>Value = term()</v> + <v>Status = term()</v> + </type> + <desc> + <note> + <p>This callback is optional, so callback modules need not + export it. The gen_statem module provides a default + implementation of this function that returns the callback + module state. + </p> + </note> + <p>This function is called by a gen_statem process when:</p> + <list type="bulleted"> + <item>One of + <seealso marker="sys#get_status/1"> + <c>sys:get_status/1,2</c> + </seealso> + is invoked to get the gen_statem status. <c>Opt</c> is set + to the atom <c>normal</c> for this case. + </item> + <item>The gen_statem terminates abnormally and logs an error. + <c>Opt</c> is set to the atom <c>terminate</c> for this case. + </item> + </list> + <p>This function is useful for customising the form and + appearance of the gen_statem status for these cases. A + callback module wishing to customise the + <seealso marker="sys#get_status/1"> + <c>sys:get_status/1,2</c> + </seealso> return value as well as how + its status appears in termination error logs exports an + instance of <c>format_status/2</c> that returns a term + describing the current status of the gen_statem. + </p> + <p><c>PDict</c> is the current value of the gen_statem's + process dictionary. + </p> + <p><seealso marker="#type-state"><c>State</c></seealso> + is the internal state of the gen_statem. + </p> + <p>The function should return <c>Status</c>, a term that + customises the details of the current state and status of + the gen_statem. There are no restrictions on the + form <c>Status</c> can take, but for the + <seealso marker="sys#get_status/1"> + <c>sys:get_status/1,2</c> + </seealso> case (when <c>Opt</c> + is <c>normal</c>), the recommended form for + the <c>Status</c> value is <c>[{data, [{"State", + Term}]}]</c> where <c>Term</c> provides relevant details of + the gen_statem state. Following this recommendation isn't + required, but doing so will make the callback module status + consistent with the rest of the + <seealso marker="sys#get_status/1"> + <c>sys:get_status/1,2</c> + </seealso> return value. + </p> + <p>One use for this function is to return compact alternative + state representations to avoid having large state terms + printed in logfiles. + </p> + </desc> + </func> + + </funcs> + + <section> + <title>SEE ALSO</title> + <p><seealso marker="gen_event">gen_event</seealso>, + <seealso marker="gen_fsm">gen_fsm</seealso>, + <seealso marker="gen_server">gen_server</seealso>, + <seealso marker="supervisor">supervisor</seealso>, + <seealso marker="proc_lib">proc_lib</seealso>, + <seealso marker="sys">sys</seealso></p> + </section> +</erlref> diff --git a/lib/stdlib/doc/src/ref_man.xml b/lib/stdlib/doc/src/ref_man.xml index 82ad78e675..404873ea32 100644 --- a/lib/stdlib/doc/src/ref_man.xml +++ b/lib/stdlib/doc/src/ref_man.xml @@ -4,7 +4,7 @@ <application xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>1996</year><year>2015</year> + <year>1996</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -66,6 +66,7 @@ <xi:include href="gen_event.xml"/> <xi:include href="gen_fsm.xml"/> <xi:include href="gen_server.xml"/> + <xi:include href="gen_statem.xml"/> <xi:include href="io.xml"/> <xi:include href="io_lib.xml"/> <xi:include href="lib.xml"/> diff --git a/lib/stdlib/doc/src/specs.xml b/lib/stdlib/doc/src/specs.xml index 0418bf7b22..45b207b13d 100644 --- a/lib/stdlib/doc/src/specs.xml +++ b/lib/stdlib/doc/src/specs.xml @@ -30,6 +30,7 @@ <xi:include href="../specs/specs_gen_event.xml"/> <xi:include href="../specs/specs_gen_fsm.xml"/> <xi:include href="../specs/specs_gen_server.xml"/> + <xi:include href="../specs/specs_gen_statem.xml"/> <xi:include href="../specs/specs_io.xml"/> <xi:include href="../specs/specs_io_lib.xml"/> <xi:include href="../specs/specs_lib.xml"/> |