A behaviour module for implementing a state machine. Two
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"...
The
The callback model(s) for
A generic state machine process (
A
gen_statem module Callback module ----------------- --------------- gen_statem:start gen_statem:start_link -----> Module:init/1 gen_statem:stop -----> Module:terminate/3 gen_statem:call gen_statem:cast erlang:send erlang:'!' -----> Module:StateName/3 Module:handle_event/4 - -----> Module:terminate/3 - -----> Module:code_change/4
Events are of different
If a callback function fails or returns a bad value,
the
The "state function" for a specific
When the
When the
The
The
The
Inserting an event replaces the trick of calling your own
state handling functions that you often would have to
resort to in for example
See the type
A
Note that a
Unless otherwise stated, all functions in this module fail if
the specified
The
This example shows a simple pushbutton model
for a toggling pushbutton implemented with
This is the complete callback module file
-module(pushbutton).
-behaviour(gen_statem).
-export([start/0,push/0,get_count/0,stop/0]).
-export([terminate/3,code_change/4,init/1]).
-export([on/3,off/3]).
name() -> pushbutton_statem. % The registered server name
callback_mode() -> state_functions.
%% API. This example uses a registered name name()
%% and does not link to the caller.
start() ->
gen_statem:start({local,name()}, ?MODULE, [], []).
push() ->
gen_statem:call(name(), push).
get_count() ->
gen_statem:call(name(), get_count).
stop() ->
gen_statem:stop(name()).
%% Mandatory callback functions
terminate(_Reason, _State, _Data) ->
void.
code_change(_Vsn, State, Data, _Extra) ->
{callback_mode(),State,Data}.
init([]) ->
%% Set the callback mode and initial state + data.
%% Data is used only as a counter.
State = off, Data = 0,
{callback_mode(),State,Data}.
%%% State functions
off({call,From}, push, Data) ->
%% Go to 'on', increment count and reply
%% that the resulting status is 'on'
{next_state,on,Data+1,[{reply,From,on}]};
off(EventType, EventContent, Data) ->
handle_event(EventType, EventContent, Data).
on({call,From}, push, Data) ->
%% Go to 'off' and reply that the resulting status is 'off'
{next_state,off,Data,[{reply,From,off}]};
on(EventType, EventContent, Data) ->
handle_event(EventType, EventContent, Data).
%% Handle events common to all states
handle_event({call,From}, get_count, Data) ->
%% Reply with the current count
{keep_state,Data,[{reply,From,Data}]};
handle_event(_, _, Data) ->
%% Ignore all other events
{keep_state,Data}.
And this is a shell session when running it:
1> pushbutton:start(). {ok,<0.36.0>} 2> pushbutton:get_count(). 0 3> pushbutton:push(). on 4> pushbutton:get_count(). 1 5> pushbutton:push(). off 6> pushbutton:get_count(). 1 7> pushbutton:stop(). ok 8> pushbutton:push(). ** exception exit: {noproc,{gen_statem,call,[pushbutton_statem,push,infinity]}} in function gen:do_for_proc/2 (gen.erl, line 261) in call from gen_statem:call/3 (gen_statem.erl, line 386)
And just to compare styles here is the same example using
init([]) ->
%% Set the callback mode and initial state + data.
%% Data is used only as a counter.
State = off, Data = 0,
{handle_event_function,State,Data}.
%%% Event handling
handle_event({call,From}, push, off, Data) ->
%% Go to 'on', increment count and reply
%% that the resulting status is 'on'
{next_state,on,Data+1,[{reply,From,on}]};
handle_event({call,From}, push, on, Data) ->
%% Go to 'off' and reply that the resulting status is 'off'
{next_state,off,Data,[{reply,From,off}]};
%%
%% Event handling common to all states
handle_event({call,From}, get_count, State, Data) ->
%% Reply with the current count
{next_state,State,Data,[{reply,From,Data}]};
handle_event(_, _, State, Data) ->
%% Ignore all other events
{next_state,State,Data}.
Name specification to use when starting
a
Server specification to use when addressing
a
It can be:
Debug option that can be used when starting
a
For every entry in
Options that can be used when starting
a
Return value from the start functions for_example
Destination to use when replying through for example the
After a state change (
If the
A term in which the state machine implementation
should store any server data it needs. The difference between
this and the
External events are of 3 different type:
The callback mode is selected when starting the
Transition options may be set by
If
If
Generate an event of
If the value is
If the value is
Note that it is not possible nor needed to cancel this timeout since it is cancelled automatically by any other event.
These state transition actions may be invoked by
returning them from the
Actions are executed in the containing list order.
Actions that set
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
An event of type
Reply to a caller waiting for a reply in
All these terms are tuples or atoms and this property
will hold in any future version of
All these terms are tuples or atoms and this property
will hold in any future version of
All these terms are tuples or atoms and this property
will hold in any future version of
Creates a
The
If the option
If the option
If the option
Using the spawn option
If the
If
Creates a stand-alone
See
The same as
Orders the
This function returns
If the process does not exist, a
Makes a synchronous call to the
A
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
The call may fail for example if the
Sends an asynchronous event to the
This function can be used by a
A reply sent with this function will not be visible
in
The same as
If
Otherwise the same as
Makes an the calling process become a
This function is useful when a more complex initialization
procedure is needed than
the
Failure: If the calling process was not started by a
The following functions should be exported from a
Whenever a
If the initialization is successful, the function should
return
The
If something goes wrong during the initialization
the function should return
This function may use
Whenever a
If
If this function returns with a next state that
does not match equal (
The only difference between
See
These functions may use
This function is called by a
If the
Even if the
Otherwise, the
Note that for any other reason than
This function may use
This function is called by a
In the case of an upgrade,
If you would dare to change
If successful, the function shall return the updated
internal state in an
If the function returns
This function may use
This callback is optional, so a callback module need not
export it. The
This function is called by a
This function is useful for customising the form and
appearance of the
The function should return
One use for this function is to return compact alternative state representations to avoid having large state terms printed in logfiles. Another is to hide sensitive data from being written to the error log.
This function may use