From f986565050ac30075ef3c0a451bf6dad91c7c446 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
- For
- The call can fail, for example, if the
+ If you combine catching exceptions from this function
+ with
+ The call can also fail, for example, if the
+ The
If you in
+ The state entry mode is selected when starting the
+
+ If
+
+ If
+
+ If the state changes or is the initial state, and the
+
If an
@@ -1288,7 +1333,9 @@ handle_event(_, _, State, Data) ->
+ The
+ If the atom
+ No state entry event will be inserted after a
+
- If this function's body does not consist of solely one of two
- possible
-
+ No state entry event will be inserted after a
+
+ Note that a state entry event will be inserted
+ when entering the initial state even though this formally
+ is not a state change. In this case
- If the atom
- No state entry event will be inserted after a
-
If this function's body does not return an inline constant
--
cgit v1.2.3
From 04d40c5cd18aca449606c19608e8044f593ee99e Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
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.
+ 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.
@@ -70,7 +71,7 @@
- The If you in
+ This is the return type from
+
- The state entry mode is selected when starting the
-
If
If
- No state entry event will be inserted after a
+ If
- Note that a state entry event will be inserted
- when entering the initial state even though this formally
- is not a state change. In this case
Transition options can be set by
- If the state changes or is the initial state, and the
-
- Notice that it is not possible or needed to cancel this time-out, + Note that it is not possible or needed to cancel this time-out, as it is cancelled automatically by any other event.
@@ -743,7 +771,10 @@ handle_event(_, _, State, Data) ->
These state transition actions can be invoked by
returning them from the
-
+ Stores the specified
+ 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
+
+ These state transition actions can be invoked by
+ returning them from the
+
+ Actions are executed in the containing list order. +
+
+ Actions that set
+
@@ -805,32 +883,6 @@ handle_event(_, _, State, Data) ->
to
- Replies to a caller. -
-
- Stores the specified
- 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
-
- Replies to a caller waiting for a reply in
+ This state transition action can be invoked by
+ returning it from the
+
+ It replies to a caller waiting for a reply in
+ Note that using this action from
+
+ The
+ All these terms are tuples or atoms and this property
+ will hold in any future version of
+ The
+ All these terms are tuples or atoms and this property
+ will hold in any future version of
@@ -1362,7 +1475,8 @@ handle_event(_, _, State, Data) ->
once after server start and after code change,
but before the first
@@ -1380,7 +1494,7 @@ handle_event(_, _, State, Data) ->
or a list containing
@@ -1601,7 +1715,8 @@ handle_event(_, _, State, Data) ->
The function is to return
@@ -1694,6 +1823,24 @@ handle_event(_, _, State, Data) ->
by
+ When the
Note the fact that you can use
- Terminates the
- Sends all
+ All these terms are tuples or atoms and this property
+ will hold in any future version of
@@ -1053,6 +1070,36 @@ handle_event(_, _, State, Data) ->
+ Terminates the
+ Sends all
+ All these terms are tuples or atoms and this property
+ will hold in any future version of
The
- If an
-
- The (possibly new)
+ Timeout timers
+
+ Otherwise the
If the value is
- If the value is
Note that it is not possible or needed to cancel this time-out, @@ -768,6 +772,34 @@ handle_event(_, _, State, Data) ->
+
+ Generates an event of
+
+ If the value is
+ If the value is
+ Setting this timer while it is running will restart it with
+ the new time-out value. Therefore it is possible to cancel
+ this timeout by setting it to
+ Sets the
+
- The "state function" for a specific
+ The "state callback" for a specific
The
- The
The
If you in
callback_mode() -> handle_event_function.
-%%% State function(s)
+%%% state callback(s)
handle_event({call,From}, push, off, Data) ->
%% Go to 'on', increment count and reply
@@ -482,6 +482,10 @@ handle_event(_, _, State, Data) ->
+ If the
+ callback mode
+ is handle_event_function ,
+ the state can be any term.
After a state change (NextState =/= State ),
all postponed events are retried.
@@ -495,6 +499,8 @@ handle_event(_, _, State, Data) ->
callback mode
is state_functions ,
the state must be of this type.
+ After a state change (NextState =/= State ),
+ all postponed events are retried.
@@ -592,11 +598,11 @@ handle_event(_, _, State, Data) ->
returns a list containing state_enter ,
the gen_statem engine will, at every state change,
call the
- state function
+ state callback
with arguments (enter, OldState, Data) .
This may look like an event but is really a call
- performed after the previous state function returned
- and before any event is delivered to the new state function.
+ performed after the previous state callback returned
+ and before any event is delivered to the new state callback.
See
Module:StateName/3
and
@@ -666,19 +672,19 @@ handle_event(_, _, State, Data) ->
If the state changes or is the initial state, and
state enter calls
are used, the gen_statem calls
- the new state function with arguments
+ the new state callback with arguments
(enter, OldState, Data) .
Any
actions
returned from this call are handled as if they were
appended to the actions
- returned by the state function that changed states.
+ returned by the state callback that changed states.
-
If there are enqueued events the (possibly new)
- state function
+ state callback
is called with the oldest enqueued event,
and we start again from the top of this list.
@@ -691,7 +697,7 @@ handle_event(_, _, State, Data) ->
event_timeout()
are handled. This may lead to a time-out zero event
being generated to the
- state function
+ state callback
and we start again from the top of this list.
@@ -707,7 +713,7 @@ handle_event(_, _, State, Data) ->
the next incoming message awakens the gen_statem ,
but if it is a system event it goes right back into hibernation.
When a new message arrives the
- state function
+ state callback
is called with the corresponding event,
and we start again from the top of this list.
@@ -806,7 +812,7 @@ handle_event(_, _, State, Data) ->
These state transition actions can be invoked by
returning them from the
- state function
+ state callback
when it is called with an
event ,
from
@@ -870,7 +876,7 @@ handle_event(_, _, State, Data) ->
These state transition actions can be invoked by
returning them from the
- state function , from
+ state callback , from
Module:init/1
or by giving them to
enter_loop/5,6 .
@@ -903,7 +909,7 @@ handle_event(_, _, State, Data) ->
Short for {timeout,Timeout,Timeout} , that is,
the time-out message is the time-out time.
This form exists to make the
- state function
+ state callback
return value {next_state,NextState,NewData,Timeout}
allowed like for gen_fsm 's
Module:StateName/2 .
@@ -936,7 +942,7 @@ handle_event(_, _, State, Data) ->
This state transition action can be invoked by
returning it from the
- state function , from
+ state callback , from
Module:init/1
or by giving it to
enter_loop/5,6 .
@@ -947,7 +953,7 @@ handle_event(_, _, State, Data) ->
From must be the term from argument
{call,From }
in a call to a
- state function .
+ state callback .
Note that using this action from
@@ -956,77 +962,48 @@ handle_event(_, _, State, Data) ->
enter_loop/5,6
would be weird on the border of whichcraft
since there has been no earlier call to a
- state function
+ state callback
in this server.
-
+
-
- next_state
- -
-
- The gen_statem does a state transition to
- NextStateName
- (which can be the same as the current state),
- sets NewData ,
- and executes all Actions .
-
-
-
- All these terms are tuples or atoms and this property
- will hold in any future version of gen_statem .
+ State is the current state
+ and it can not be changed since the state callback
+ was called with a
+ state enter call .
-
-
-
-
-
next_state
-
The gen_statem does a state transition to
- NextStateName
- (which can be the same as the current state),
+ State , which has to be
+ the current state,
sets NewData ,
and executes all Actions .
-
- All these terms are tuples or atoms and this property
- will hold in any future version of gen_statem .
-
-
+
-
- next_state
- -
-
- The gen_statem does a state transition to
- NextState
- (which can be the same as the current state),
- sets NewData ,
- and executes all Actions .
-
-
-
- All these terms are tuples or atoms and this property
- will hold in any future version of gen_statem .
+ StateType is
+ state_name()
+ if
+ callback mode
+ is state_functions , or
+ state()
+ if
+ callback mode
+ is handle_event_function .
-
-
-
-
-
next_state
-
@@ -1039,48 +1016,20 @@ handle_event(_, _, State, Data) ->
-
- All these terms are tuples or atoms and this property
- will hold in any future version of gen_statem .
-
-
+
-
- keep_state
- -
-
- The gen_statem keeps the current state, or
- does a state transition to the current state if you like,
- sets NewData ,
- and executes all Actions .
- This is the same as
- {next_state,CurrentState,NewData ,Actions } .
-
-
- keep_state_and_data
- -
-
- The gen_statem keeps the current state or
- does a state transition to the current state if you like,
- keeps the current server data,
- and executes all Actions .
- This is the same as
- {next_state,CurrentState,CurrentData,Actions } .
-
-
-
- All these terms are tuples or atoms and this property
- will hold in any future version of gen_statem .
+ ActionType is
+ enter_action()
+ if the state callback was called with a
+ state enter call
+ and
+ action()
+ if the state callback was called with an event.
-
-
-
-
-
keep_state
-
@@ -1104,17 +1053,6 @@ handle_event(_, _, State, Data) ->
{next_state,CurrentState,CurrentData,Actions } .
-
-
- All these terms are tuples or atoms and this property
- will hold in any future version of gen_statem .
-
-
-
-
-
-
-
stop
-
@@ -1155,14 +1093,14 @@ handle_event(_, _, State, Data) ->
by sending a request
and waiting until its reply arrives.
The gen_statem calls the
- state function with
+ state callback with
event_type()
{call,From} and event content
Request .
A Reply is generated when a
- state function
+ state callback
returns with
{reply,From,Reply } as one
action() ,
@@ -1227,7 +1165,7 @@ handle_event(_, _, State, Data) ->
ignoring if the destination node or gen_statem
does not exist.
The gen_statem calls the
- state function with
+ state callback with
event_type()
cast and event content
Msg .
@@ -1341,18 +1279,18 @@ handle_event(_, _, State, Data) ->
call/2
when the reply cannot be defined in
the return value of a
- state function .
+ state callback .
From must be the term from argument
{call,From }
to the
- state function .
+ state callback .
A reply or multiple replies canalso be sent
using one or several
reply_action() s
from a
- state function .
+ state callback .
@@ -1562,7 +1500,7 @@ handle_event(_, _, State, Data) ->
for efficiency reasons, so this function is only called
once after server start and after code change,
but before the first
- state function
+ state callback
in the current code version is called.
More occasions may be added in future versions
of gen_statem .
@@ -1707,7 +1645,7 @@ handle_event(_, _, State, Data) ->
The Actions
are executed when entering the first
state just as for a
- state function .
+ state callback .
If the initialization fails,
@@ -1829,13 +1767,13 @@ handle_event(_, _, State, Data) ->
Module:StateName(enter, OldState, Data) ->
- StateFunctionEnterResult
+ StateEnterResult(StateName)
Module:StateName(EventType, EventContent, Data) ->
StateFunctionResult
Module:handle_event(enter, OldState, State, Data) ->
- HandleEventResult
+ StateEnterResult
Module:handle_event(EventType, EventContent, State, Data) ->
HandleEventResult
@@ -1856,20 +1794,20 @@ handle_event(_, _, State, Data) ->
data()
- StateFunctionResult =
- state_function_result()
+ StateEnterResult(StateName) =
+ state_enter_result(StateName)
- StateFunctionEnterResult =
- state_function_enter_result()
+ StateFunctionResult =
+ event_handler_result (state_name() )
- HandleEventResult =
- handle_event_result()
+ StateEnterResult =
+ state_enter_result (state() )
- HandleEventEnterResult =
- handle_event_enter_result()
+ HandleEventResult =
+ event_handler_result (state() )
@@ -1888,7 +1826,7 @@ handle_event(_, _, State, Data) ->
{call,From} ,
the caller waits for a reply. The reply can be sent
from this or from any other
- state function
+ state callback
by returning with {reply,From,Reply} in
Actions , in
Replies ,
diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl
index bc33be22a2..5c750cb93d 100644
--- a/lib/stdlib/src/gen_statem.erl
+++ b/lib/stdlib/src/gen_statem.erl
@@ -44,18 +44,20 @@
-export(
[wakeup_from_hibernate/3]).
-%% Type exports for templates
+%% Type exports for templates and callback modules
-export_type(
[event_type/0,
- state_name/0,
+ init_result/0,
callback_mode_result/0,
state_function_result/0,
- state_function_enter_result/0,
handle_event_result/0,
- handle_event_enter_result/0,
+ state_enter_result/1,
+ event_handler_result/1,
+ reply_action/0,
+ enter_action/0,
action/0]).
-%% Fix problem for doc build
+%% Type that is exported just to be documented
-export_type([transition_option/0]).
%%%==========================================================================
@@ -66,7 +68,7 @@
{To :: pid(), Tag :: term()}. % Reply-to specifier for call
-type state() ::
- state_name() | % For StateName/3 callback functios
+ state_name() | % For StateName/3 callback functions
term(). % For handle_event/4 callback function
-type state_name() :: atom().
@@ -140,67 +142,45 @@
{'reply', % Reply to a caller
From :: from(), Reply :: term()}.
--type state_function_result() ::
- {'next_state', % {next_state,NextStateName,NewData,[]}
- NextStateName :: state_name(),
- NewData :: data()} |
- {'next_state', % State transition, maybe to the same state
- NextStateName :: state_name(),
- NewData :: data(),
- Actions :: [action()] | action()} |
- keep_state_callback_result().
--type state_function_enter_result() ::
- {'next_state', % {next_state,NextStateName,NewData,[]}
- NextStateName :: state_name(),
- NewData :: data()} |
- {'next_state', % State transition, maybe to the same state
- NextStateName :: state_name(),
- NewData :: data(),
- Actions :: [enter_action()] | enter_action()} |
- keep_state_callback_enter_result().
+-type init_result() ::
+ {ok, state(), data()} |
+ {ok, state(), data(), [action()] | action()} |
+ 'ignore' |
+ {'stop', Reason :: term()}.
+%% Old, not advertised
+-type state_function_result() ::
+ event_handler_result(state_name()).
-type handle_event_result() ::
+ event_handler_result(state()).
+%%
+-type state_enter_result(StateType) ::
{'next_state', % {next_state,NextState,NewData,[]}
- NextState :: state(),
+ State :: StateType,
NewData :: data()} |
{'next_state', % State transition, maybe to the same state
- NextState :: state(),
+ State :: StateType,
NewData :: data(),
- Actions :: [action()] | action()} |
- keep_state_callback_result().
--type handle_event_enter_result() ::
+ Actions :: [enter_action()] | enter_action()} |
+ state_callback_result(enter_action()).
+-type event_handler_result(StateType) ::
{'next_state', % {next_state,NextState,NewData,[]}
- NextState :: state(),
+ NextState :: StateType,
NewData :: data()} |
{'next_state', % State transition, maybe to the same state
- NextState :: state(),
+ NextState :: StateType,
NewData :: data(),
- Actions :: [enter_action()] | enter_action()} |
- keep_state_callback_enter_result().
-
--type keep_state_callback_result() ::
- {'keep_state', % {keep_state,NewData,[]}
- NewData :: data()} |
- {'keep_state', % Keep state, change data
- NewData :: data(),
- Actions :: [action()] | action()} |
- 'keep_state_and_data' | % {keep_state_and_data,[]}
- {'keep_state_and_data', % Keep state and data -> only actions
Actions :: [action()] | action()} |
- common_state_callback_result().
-
--type keep_state_callback_enter_result() ::
+ state_callback_result(action()).
+-type state_callback_result(ActionType) ::
{'keep_state', % {keep_state,NewData,[]}
NewData :: data()} |
{'keep_state', % Keep state, change data
NewData :: data(),
- Actions :: [enter_action()] | enter_action()} |
+ Actions :: [ActionType] | ActionType} |
'keep_state_and_data' | % {keep_state_and_data,[]}
{'keep_state_and_data', % Keep state and data -> only actions
- Actions :: [enter_action()] | enter_action()} |
- common_state_callback_result().
-
--type common_state_callback_result() ::
+ Actions :: [ActionType] | ActionType} |
'stop' | % {stop,normal}
{'stop', % Stop the server
Reason :: term()} |
@@ -220,11 +200,7 @@
%% the server is not running until this function has returned
%% an {ok, ...} tuple. Thereafter the state callbacks are called
%% for all events to this server.
--callback init(Args :: term()) ->
- {ok, state(), data()} |
- {ok, state(), data(), [action()] | action()} |
- 'ignore' |
- {'stop', Reason :: term()}.
+-callback init(Args :: term()) -> init_result().
%% This callback shall return the callback mode of the callback module.
%%
@@ -244,11 +220,11 @@
'enter',
OldStateName :: state_name(),
Data :: data()) ->
- state_function_enter_result();
+ state_enter_result('state_name');
(event_type(),
EventContent :: term(),
Data :: data()) ->
- state_function_result().
+ event_handler_result(state_name()).
%%
%% State callback for all states
%% when callback_mode() =:= handle_event_function.
@@ -257,12 +233,12 @@
OldState :: state(),
State :: state(), % Current state
Data :: data()) ->
- handle_event_enter_result();
+ state_enter_result(state());
(event_type(),
EventContent :: term(),
State :: state(), % Current state
Data :: data()) ->
- handle_event_result().
+ event_handler_result(state()).
%% Clean up before the server terminates.
-callback terminate(
--
cgit v1.2.3
From 5e2d802e29f0a8f81de297f9a3e3922f2d6cd6c0 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Fri, 14 Oct 2016 10:08:49 +0200
Subject: Fix race condition in cancel_timer/1
---
lib/stdlib/src/gen_statem.erl | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
(limited to 'lib/stdlib')
diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl
index 5c750cb93d..17d1ebecec 100644
--- a/lib/stdlib/src/gen_statem.erl
+++ b/lib/stdlib/src/gen_statem.erl
@@ -1609,13 +1609,14 @@ cancel_timer(undefined) ->
ok;
cancel_timer(TRef) ->
case erlang:cancel_timer(TRef) of
- TimeLeft when is_integer(TimeLeft) ->
- ok;
false ->
+ %% We have to assume that TRef is the ref of a running timer
+ %% and if so the timer has expired
+ %% hence we must wait for the timeout message
receive
{timeout,TRef,_} ->
ok
- after 0 ->
- ok
- end
+ end;
+ _TimeLeft ->
+ ok
end.
--
cgit v1.2.3