From 30cdfe871577f9622297fb5ed792b117894ef1f2 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
When the
@@ -138,9 +142,9 @@ erlang:'!' -----> Module:StateName/3
This gathers all code for a specific state
in one function as the
When the
@@ -249,11 +253,10 @@ erlang:'!' -----> Module:StateName/3
-behaviour(gen_statem).
-export([start/0,push/0,get_count/0,stop/0]).
--export([terminate/3,code_change/4,init/1]).
+-export([terminate/3,code_change/4,init/1,callback_mode/0]).
-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.
@@ -270,15 +273,14 @@ stop() ->
terminate(_Reason, _State, _Data) ->
void.
code_change(_Vsn, State, Data, _Extra) ->
- {callback_mode(),State,Data}.
+ {ok,State,Data}.
init([]) ->
- %% Set the callback mode and initial state + data.
- %% Data is used only as a counter.
+ %% Set the initial state + data. Data is used only as a counter.
State = off, Data = 0,
- {callback_mode(),State,Data}.
-
+ {ok,State,Data}.
+callback_mode() -> state_functions.
-%%% State functions
+%%% State function(s)
off({call,From}, push, Data) ->
%% Go to 'on', increment count and reply
@@ -326,18 +328,13 @@ ok
To compare styles, here follows 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}.
-
+callback_mode() -> handle_event_function.
-%%% Event handling
+%%% State function(s)
handle_event({call,From}, push, off, Data) ->
%% Go to 'on', increment count and reply
@@ -426,8 +423,8 @@ handle_event(_, _, State, Data) ->
Debug option that can be used when starting
- a gen_statem server through, for example,
- enter_loop/5 .
+ a gen_statem server through,
+ enter_loop/4-6 .
For every entry in Dbgs ,
@@ -525,12 +522,9 @@ handle_event(_, _, State, Data) ->
The callback mode is selected when starting the
- gen_statem using the return value from
- Module:init/1
- or when calling
- enter_loop/5,6,7 ,
- and with the return value from
- Module:code_change/4 .
+ gen_statem and after code change
+ using the return value from
+ Module:callback_mode/0 .
state_functions
@@ -691,7 +685,7 @@ handle_event(_, _, State, Data) ->
state function , from
Module:init/1
or by giving them to
- enter_loop/6,7 .
+ enter_loop/5,6 .
Actions are executed in the containing list order.
@@ -958,35 +952,36 @@ handle_event(_, _, State, Data) ->
-
+
Enter the gen_statem receive loop.
The same as
- enter_loop/7
- except that no
+ enter_loop/6
+ with Actions = [] except that no
server_name()
- must have been registered.
+ must have been registered. This creates an anonymous server.
-
+
Enter the gen_statem receive loop.
If Server_or_Actions is a list() ,
the same as
- enter_loop/7
+ enter_loop/6
except that no
server_name()
must have been registered and
Actions = Server_or_Actions .
+ This creates an anonymous server.
Otherwise the same as
- enter_loop/7
+ enter_loop/6
with
Server = Server_or_Actions and
Actions = [] .
@@ -995,7 +990,7 @@ handle_event(_, _, State, Data) ->
-
+
Enter the gen_statem receive loop.
@@ -1015,21 +1010,31 @@ handle_event(_, _, State, Data) ->
the gen_statem behavior provides.
- Module , Opts , and
- Server have the same meanings
- as when calling
+ Module , Opts
+ have the same meaning as when calling
start[_link]/3,4 .
+
+
+ If Server is self() an anonymous
+ server is created just as when using
+ start[_link]/3 .
+ If Server is a
+ server_name()
+ a named server is created just as when using
+ start[_link]/4 .
However, the
server_name()
name must have been registered accordingly
- before this function is called.
+ before this function is called.
+
- CallbackMode , State ,
- Data , and Actions
+ State , Data ,
+ and Actions
have the same meanings as in the return value of
Module:init/1 .
- Also, the callback module Module
- does not need to export an init/1 function.
+ Also, the callback module does not need to export a
+ Module:init/1
+ function.
The function fails if the calling process was not started by a
@@ -1252,6 +1257,54 @@ handle_event(_, _, State, Data) ->
+
+ Module:callback_mode() -> CallbackMode
+ Update the internal state during upgrade/downgrade.
+
+
+ CallbackMode =
+ callback_mode()
+
+
+
+
+ This function is called by a gen_statem
+ when it needs to find out the
+ callback mode
+ of the callback module. The value is cached by gen_statem
+ for efficiency reasons, so this function is only called
+ once after server start and after code change,
+ but before the first
+ state function
+ is called. More occasions may be added in future versions
+ of gen_statem .
+
+
+ Server start happens either when
+ Module:init/1
+ returns or when
+ enter_loop/4-6
+ is called. Code change happens when
+ Module:code_change/4
+ returns.
+
+
+ This function can use
+ erlang:throw/1
+ to return CallbackMode , just for symmetry reasons.
+ There should be no actual reason to use this.
+
+
+
+ If this function's body does not consist of solely one of two
+ possible
+ atoms
+ the callback module is doing something strange.
+
+
+
+
+
Module:code_change(OldVsn, OldState, OldData, Extra) ->
Result
@@ -1262,11 +1315,7 @@ handle_event(_, _, State, Data) ->
Vsn = term()
OldState = NewState = term()
Extra = term()
- Result = {CallbackMode,NewState,NewData} | Reason
-
- CallbackMode =
- callback_mode()
-
+ Result = {ok,NewState,NewData} | Reason
OldState = NewState =
state()
@@ -1295,21 +1344,6 @@ handle_event(_, _, State, Data) ->
Module . If no such attribute is defined, the version
is the checksum of the Beam file.
-
-
- If you would dare to change
- callback mode
- during release upgrade/downgrade, the upgrade is no problem,
- as the new code surely knows what callback mode
- it needs. However, for a downgrade this function must
- know from argument Extra that comes from the
- sasl:appup
- file what callback mode the old code did use.
- It can also be possible to figure this out
- from argument {down,Vsn} , as Vsn
- in effect defines the old callback module version.
-
-
OldState and OldData is the internal state
of the gen_statem .
@@ -1321,16 +1355,16 @@ handle_event(_, _, State, Data) ->
If successful, the function must return the updated
internal state in an
- {CallbackMode,NewState,NewData} tuple.
+ {ok,NewState,NewData} tuple.
If the function returns a failure Reason , the ongoing
upgrade fails and rolls back to the old release.
- Note that Reason can not be a 3-tuple since that
- will be regarded as a
- {CallbackMode,NewState,NewData} tuple,
+ Note that Reason can not be an {ok,_,_} tuple
+ since that will be regarded as a
+ {ok,NewState,NewData} tuple,
and that a tuple matching {ok,_}
- is an invalid failure Reason .
+ is an also invalid failure Reason .
It is recommended to use an atom as Reason since
it will be wrapped in an {error,Reason} tuple.
@@ -1344,16 +1378,14 @@ handle_event(_, _, State, Data) ->
Module:init(Args) -> Result
- Initialize process and internal state.
+
+ Optional function for initializing process and internal state.
+
Args = term()
- Result = {CallbackMode,State,Data}
- | {CallbackMode,State,Data,Actions}
+ Result = {ok,State,Data}
+ | {ok,State,Data,Actions}
| {stop,Reason} | ignore
-
- CallbackMode =
- callback_mode()
-
State = state()
Data = data()
@@ -1372,7 +1404,7 @@ handle_event(_, _, State, Data) ->
start_link/3,4
or
start/3,4 ,
- this function is called by the new process to initialize
+ this optional function is called by the new process to initialize
the implementation state and server data.
@@ -1381,11 +1413,8 @@ handle_event(_, _, State, Data) ->
If the initialization is successful, the function is to
- return {CallbackMode,State,Data} or
- {CallbackMode,State,Data,Actions} .
- CallbackMode selects the
- callback mode
- of the gen_statem .
+ return {ok,State,Data} or
+ {ok,State,Data,Actions} .
State is the initial
state()
and Data the initial server
@@ -1408,6 +1437,16 @@ handle_event(_, _, State, Data) ->
erlang:throw/1
to return Result .
+
+
+ This callback is optional, so a callback module does not need
+ to export it, but most do. If this function is not exported,
+ the gen_statem should be started through
+ proc_lib
+ and
+ enter_loop/4-6 .
+
+
--
cgit v1.2.3
From 3a60545091d3075e23c4a7af8c18b3641bb084e2 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Tue, 9 Aug 2016 08:59:51 +0200
Subject: Doc fixes
---
lib/stdlib/doc/src/gen_statem.xml | 56 ++++++++++++++-------------------------
lib/stdlib/src/gen_statem.erl | 8 +++---
2 files changed, 24 insertions(+), 40 deletions(-)
(limited to 'lib/stdlib')
diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml
index f18c1087ab..3322571b2c 100644
--- a/lib/stdlib/doc/src/gen_statem.xml
+++ b/lib/stdlib/doc/src/gen_statem.xml
@@ -119,9 +119,11 @@ erlang:'!' -----> Module:StateName/3
If a callback function fails or returns a bad value,
- the gen_statem terminates. However, an exception of class
+ the gen_statem terminates, unless otherwise stated.
+ However, an exception of class
throw
- is not regarded as an error but as a valid return.
+ is not regarded as an error but as a valid return
+ from all callback functions.
@@ -917,7 +919,8 @@ handle_event(_, _, State, Data) ->
- To avoid getting a late reply in the caller's
+ For Timeout =/= infinity ,
+ 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
@@ -1288,12 +1291,6 @@ handle_event(_, _, State, Data) ->
Module:code_change/4
returns.
-
- This function can use
- erlang:throw/1
- to return CallbackMode , just for symmetry reasons.
- There should be no actual reason to use this.
-
If this function's body does not consist of solely one of two
@@ -1368,11 +1365,6 @@ handle_event(_, _, State, Data) ->
It is recommended to use an atom as Reason since
it will be wrapped in an {error,Reason} tuple.
-
- This function can use
- erlang:throw/1
- to return Result or Reason .
-
@@ -1432,11 +1424,6 @@ handle_event(_, _, State, Data) ->
or ignore ; see
start_link/3,4 .
-
- This function can use
- erlang:throw/1
- to return Result .
-
This callback is optional, so a callback module does not need
@@ -1477,10 +1464,14 @@ handle_event(_, _, State, Data) ->
This callback is optional, so a callback module does not need
to export it. The gen_statem module provides a default
implementation of this function that returns
- {State,Data} . If this callback fails, the default
- function returns {State,Info} ,
- where Info informs of the crash but no details,
- to hide possibly sensitive data.
+ {State,Data} .
+
+
+ If this callback is exported but fails,
+ to hide possibly sensitive data,
+ the default function will instead return {State,Info} ,
+ where Info says nothing but the fact that
+ format_status/2 has crashed.
This function is called by a gen_statem process when
@@ -1541,11 +1532,6 @@ handle_event(_, _, State, Data) ->
printed in log files. Another use is to hide sensitive data from
being written to the error log.
-
- This function can use
- erlang:throw/1
- to return Status .
-
@@ -1620,9 +1606,12 @@ handle_event(_, _, State, Data) ->
see action() .
- These functions can use
- erlang:throw/1 ,
- to return the result.
+ Note the fact that you can use
+ throw
+ to return the result, which can be useful.
+ For example to bail out with throw(keep_state_and_data)
+ from deep within complex code that is in no position to
+ return {next_state,State,Data} .
@@ -1695,11 +1684,6 @@ handle_event(_, _, State, Data) ->
and an error report is issued using
error_logger:format/2 .
-
- This function can use
- erlang:throw/1
- to return Ignored , which is ignored anyway.
-
diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl
index 6d7b461ee3..a39503cb6b 100644
--- a/lib/stdlib/src/gen_statem.erl
+++ b/lib/stdlib/src/gen_statem.erl
@@ -1295,7 +1295,7 @@ format_status(Opt, PDict, #{module := Module}, State, Data) ->
_:_ ->
format_status_default(
Opt, State,
- "Module:format_status/2 crashed")
+ atom_to_list(Module) ++ ":format_status/2 crashed")
end;
false ->
format_status_default(Opt, State, Data)
@@ -1303,10 +1303,10 @@ format_status(Opt, PDict, #{module := Module}, State, Data) ->
%% The default Module:format_status/2
format_status_default(Opt, State, Data) ->
- SSD = {State,Data},
+ StateData = {State,Data},
case Opt of
terminate ->
- SSD;
+ StateData;
_ ->
- [{data,[{"State",SSD}]}]
+ [{data,[{"State",StateData}]}]
end.
--
cgit v1.2.3
From a47d47ac92d080c6f8e4fcba1dd8b8575c5a3f96 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Wed, 17 Aug 2016 10:42:58 +0200
Subject: Clarify error values
---
lib/stdlib/src/gen_statem.erl | 38 +++++++++++++++++++++++++-----------
lib/stdlib/test/gen_statem_SUITE.erl | 8 ++++----
2 files changed, 31 insertions(+), 15 deletions(-)
(limited to 'lib/stdlib')
diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl
index a39503cb6b..7e4fab5365 100644
--- a/lib/stdlib/src/gen_statem.erl
+++ b/lib/stdlib/src/gen_statem.erl
@@ -582,7 +582,7 @@ init_result(Starter, Parent, ServerRef, Module, Result, Opts) ->
proc_lib:init_ack(Starter, ignore),
exit(normal);
_ ->
- Error = {bad_return_value,Result},
+ Error = {bad_return_from_init,Result},
proc_lib:init_ack(Starter, {error,Error}),
exit(Error)
end.
@@ -656,11 +656,11 @@ format_status(
print_event(Dev, {in,Event}, {Name,_}) ->
io:format(
- Dev, "*DBG* ~p received ~s~n",
+ Dev, "*DBG* ~p receive ~s~n",
[Name,event_string(Event)]);
print_event(Dev, {out,Reply,{To,_Tag}}, {Name,_}) ->
io:format(
- Dev, "*DBG* ~p sent ~p to ~p~n",
+ Dev, "*DBG* ~p send ~p to ~p~n",
[Name,Reply,To]);
print_event(Dev, {Tag,Event,NextState}, {Name,State}) ->
StateString =
@@ -992,7 +992,9 @@ loop_event_result(
State, Data, P, Event, State, Actions);
_ ->
terminate(
- error, {bad_return_value,Result}, ?STACKTRACE(),
+ error,
+ {bad_return_from_state_function,Result},
+ ?STACKTRACE(),
Debug, S, [Event|Events], State, Data, P)
end.
@@ -1029,7 +1031,9 @@ loop_event_actions(
Postpone, Hibernate, Timeout, NextEvents);
false ->
terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
+ error,
+ {bad_action_from_state_function,Action},
+ ?STACKTRACE(),
Debug, S, [Event|Events], State, NewData, P)
end;
{next_event,Type,Content} ->
@@ -1042,7 +1046,9 @@ loop_event_actions(
[{Type,Content}|NextEvents]);
false ->
terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
+ error,
+ {bad_action_from_state_function,Action},
+ ?STACKTRACE(),
Debug, S, [Event|Events], State, NewData, P)
end;
%% Actions that set options
@@ -1053,7 +1059,9 @@ loop_event_actions(
NewPostpone, Hibernate, Timeout, NextEvents);
{postpone,_} ->
terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
+ error,
+ {bad_action_from_state_function,Action},
+ ?STACKTRACE(),
Debug, S, [Event|Events], State, NewData, P);
postpone ->
loop_event_actions(
@@ -1067,7 +1075,9 @@ loop_event_actions(
Postpone, NewHibernate, Timeout, NextEvents);
{hibernate,_} ->
terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
+ error,
+ {bad_action_from_state_function,Action},
+ ?STACKTRACE(),
Debug, S, [Event|Events], State, NewData, P);
hibernate ->
loop_event_actions(
@@ -1086,7 +1096,9 @@ loop_event_actions(
Postpone, Hibernate, NewTimeout, NextEvents);
{timeout,_,_} ->
terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
+ error,
+ {bad_action_from_state_function,Action},
+ ?STACKTRACE(),
Debug, S, [Event|Events], State, NewData, P);
infinity -> % Clear timer - it will never trigger
loop_event_actions(
@@ -1101,7 +1113,9 @@ loop_event_actions(
Postpone, Hibernate, NewTimeout, NextEvents);
_ ->
terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
+ error,
+ {bad_action_from_state_function,Action},
+ ?STACKTRACE(),
Debug, S, [Event|Events], State, NewData, P)
end;
%%
@@ -1173,7 +1187,9 @@ do_reply_then_terminate(
NewDebug, S, Q, State, Data, P, Rs);
_ ->
terminate(
- error, {bad_action,R}, ?STACKTRACE(),
+ error,
+ {bad_reply_action_from_state_function,R},
+ ?STACKTRACE(),
Debug, S, Q, State, Data, P)
end.
diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl
index d90119de54..1d1417c2e6 100644
--- a/lib/stdlib/test/gen_statem_SUITE.erl
+++ b/lib/stdlib/test/gen_statem_SUITE.erl
@@ -460,10 +460,10 @@ abnormal2(Config) ->
{ok,Pid} = gen_statem:start_link(?MODULE, start_arg(Config, []), []),
%% bad return value in the gen_statem loop
- {{bad_return_value,badreturn},_} =
+ {{bad_return_from_state_function,badreturn},_} =
?EXPECT_FAILURE(gen_statem:call(Pid, badreturn), Reason),
receive
- {'EXIT',Pid,{bad_return_value,badreturn}} -> ok
+ {'EXIT',Pid,{bad_return_from_state_function,badreturn}} -> ok
after 5000 ->
ct:fail(gen_statem_did_not_die)
end,
@@ -709,7 +709,7 @@ error_format_status(Config) ->
gen_statem:start(
?MODULE, start_arg(Config, {data,Data}), []),
%% bad return value in the gen_statem loop
- {{bad_return_value,badreturn},_} =
+ {{bad_return_from_state_function,badreturn},_} =
?EXPECT_FAILURE(gen_statem:call(Pid, badreturn), Reason),
receive
{error,_,
@@ -717,7 +717,7 @@ error_format_status(Config) ->
"** State machine"++_,
[Pid,{{call,_},badreturn},
{formatted,idle,Data},
- error,{bad_return_value,badreturn}|_]}} ->
+ error,{bad_return_from_state_function,badreturn}|_]}} ->
ok;
Other when is_tuple(Other), element(1, Other) =:= error ->
error_logger_forwarder:unregister(),
--
cgit v1.2.3
From b6541d133f166a3f28cc3b2daf14c59024312c60 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Wed, 17 Aug 2016 14:29:43 +0200
Subject: Handle exceptions in init/1 and callback_mode/0
---
lib/stdlib/src/gen_statem.erl | 119 +++++++++++++++++++++++++-----------------
1 file changed, 72 insertions(+), 47 deletions(-)
(limited to 'lib/stdlib')
diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl
index 7e4fab5365..eee7d60e9d 100644
--- a/lib/stdlib/src/gen_statem.erl
+++ b/lib/stdlib/src/gen_statem.erl
@@ -557,9 +557,15 @@ init_it(Starter, Parent, ServerRef, Module, Args, Opts) ->
Result ->
init_result(Starter, Parent, ServerRef, Module, Result, Opts);
Class:Reason ->
+ Stacktrace = erlang:get_stacktrace(),
+ Name = gen:get_proc_name(ServerRef),
gen:unregister_name(ServerRef),
proc_lib:init_ack(Starter, {error,Reason}),
- erlang:raise(Class, Reason, erlang:get_stacktrace())
+ error_info(
+ Class, Reason, Stacktrace,
+ #{name => Name, callback_mode => undefined},
+ [], [], undefined),
+ erlang:raise(Class, Reason, Stacktrace)
end.
%%---------------------------------------------------------------------------
@@ -582,8 +588,14 @@ init_result(Starter, Parent, ServerRef, Module, Result, Opts) ->
proc_lib:init_ack(Starter, ignore),
exit(normal);
_ ->
+ Name = gen:get_proc_name(ServerRef),
+ gen:unregister_name(ServerRef),
Error = {bad_return_from_init,Result},
proc_lib:init_ack(Starter, {error,Error}),
+ error_info(
+ error, Error, ?STACKTRACE(),
+ #{name => Name, callback_mode => undefined},
+ [], [], undefined),
exit(Error)
end.
@@ -835,31 +847,6 @@ loop_events_done(Parent, Debug, S, Timer, State, Data, P, Hibernate) ->
timer := Timer},
loop(Parent, Debug, NewS).
-loop_event(
- Parent, Debug,
- #{callback_mode := undefined,
- module := Module} = S,
- Events,
- State, Data, P, Event, Hibernate) ->
- %% Cache the callback_mode() value
- case
- try Module:callback_mode()
- catch
- Result -> Result
- end
- of
- CallbackMode ->
- case callback_mode(CallbackMode) of
- true ->
- loop_event(
- Parent, Debug,
- S#{callback_mode := CallbackMode},
- Events,
- State, Data, P, Event, Hibernate);
- false ->
- error({callback_mode,CallbackMode})
- end
- end;
loop_event(
Parent, Debug,
#{callback_mode := CallbackMode,
@@ -878,22 +865,36 @@ loop_event(
%%
try
case CallbackMode of
+ undefined ->
+ Module:callback_mode();
state_functions ->
- Module:State(Type, Content, Data);
+ erlang:apply(Module, State, [Type,Content,Data]);
handle_event_function ->
Module:handle_event(Type, Content, State, Data)
- end of
+ end
+ of
+ Result when CallbackMode =:= undefined ->
+ loop_event_callback_mode(
+ Parent, Debug, S, Events, State, Data, P, Event, Result);
Result ->
loop_event_result(
Parent, Debug, S, Events, State, Data, P, Event, Result)
catch
+ Result when CallbackMode =:= undefined ->
+ loop_event_callback_mode(
+ Parent, Debug, S, Events, State, Data, P, Event, Result);
Result ->
loop_event_result(
Parent, Debug, S, Events, State, Data, P, Event, Result);
- error:badarg when CallbackMode =:= state_functions ->
+ error:badarg ->
case erlang:get_stacktrace() of
- [{erlang,apply,[Module,State,_],_}|Stacktrace] ->
- Args = [Type,Content,Data],
+ [{erlang,apply,
+ [Module,State,[Type,Content,Data]=Args],
+ _}
+ |Stacktrace]
+ when CallbackMode =:= state_functions ->
+ %% We get here e.g if apply fails
+ %% due to State not being an atom
terminate(
error,
{undef_state_function,{Module,State,Args}},
@@ -905,24 +906,29 @@ loop_event(
Debug, S, [Event|Events], State, Data, P)
end;
error:undef ->
- %% Process an undef to check for the simple mistake
+ %% Process undef to check for the simple mistake
%% of calling a nonexistent state function
+ %% to make the undef more precise
case erlang:get_stacktrace() of
- [{Module,State,
- [Type,Content,Data]=Args,
- _}
+ [{Module,callback_mode,[]=Args,_}
|Stacktrace]
- when CallbackMode =:= state_functions ->
+ when CallbackMode =:= undefined ->
+ terminate(
+ error,
+ {undef_callback,{Module,callback_mode,Args}},
+ Stacktrace,
+ Debug, S, [Event|Events], State, Data, P);
+ [{Module,State,[Type,Content,Data]=Args,_}
+ |Stacktrace]
+ when CallbackMode =:= state_functions ->
terminate(
error,
{undef_state_function,{Module,State,Args}},
Stacktrace,
Debug, S, [Event|Events], State, Data, P);
- [{Module,handle_event,
- [Type,Content,State,Data]=Args,
- _}
+ [{Module,handle_event,[Type,Content,State,Data]=Args,_}
|Stacktrace]
- when CallbackMode =:= handle_event_function ->
+ when CallbackMode =:= handle_event_function ->
terminate(
error,
{undef_state_function,{Module,handle_event,Args}},
@@ -940,6 +946,25 @@ loop_event(
Debug, S, [Event|Events], State, Data, P)
end.
+%% Interpret callback_mode() result
+loop_event_callback_mode(
+ Parent, Debug, S, Events, State, Data, P, Event, CallbackMode) ->
+ case callback_mode(CallbackMode) of
+ true ->
+ Hibernate = false, % We have already GC:ed recently
+ loop_event(
+ Parent, Debug,
+ S#{callback_mode := CallbackMode},
+ Events,
+ State, Data, P, Event, Hibernate);
+ false ->
+ terminate(
+ error,
+ {bad_return_from_callback_mode,CallbackMode},
+ ?STACKTRACE(),
+ Debug, S, [Event|Events], State, Data, P)
+ end.
+
%% Interpret all callback return variants
loop_event_result(
Parent, Debug, S, Events, State, Data, P, Event, Result) ->
@@ -1208,8 +1233,9 @@ terminate(
C:R ->
ST = erlang:get_stacktrace(),
error_info(
- C, R, ST, Debug, S, Q, P,
+ C, R, ST, S, Q, P,
format_status(terminate, get(), S, State, Data)),
+ sys:print_log(Debug),
erlang:raise(C, R, ST)
end,
case Reason of
@@ -1218,8 +1244,9 @@ terminate(
{shutdown,_} -> ok;
_ ->
error_info(
- Class, Reason, Stacktrace, Debug, S, Q, P,
- format_status(terminate, get(), S, State, Data))
+ Class, Reason, Stacktrace, S, Q, P,
+ format_status(terminate, get(), S, State, Data)),
+ sys:print_log(Debug)
end,
case Stacktrace of
[] ->
@@ -1229,7 +1256,7 @@ terminate(
end.
error_info(
- Class, Reason, Stacktrace, Debug,
+ Class, Reason, Stacktrace,
#{name := Name, callback_mode := CallbackMode},
Q, P, FmtData) ->
{FixedReason,FixedStacktrace} =
@@ -1296,9 +1323,7 @@ error_info(
case FixedStacktrace of
[] -> [];
_ -> [FixedStacktrace]
- end),
- sys:print_log(Debug),
- ok.
+ end).
%% Call Module:format_status/2 or return a default value
--
cgit v1.2.3
From 9b1179d8c8c411a245c59fc7092e4a7a98f76663 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Thu, 18 Aug 2016 11:18:37 +0200
Subject: Improve sys debug
---
lib/stdlib/src/gen_statem.erl | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
(limited to 'lib/stdlib')
diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl
index eee7d60e9d..3b3477b282 100644
--- a/lib/stdlib/src/gen_statem.erl
+++ b/lib/stdlib/src/gen_statem.erl
@@ -666,14 +666,14 @@ format_status(
%% them, not as the real erlang messages. Use trace for that.
%%---------------------------------------------------------------------------
-print_event(Dev, {in,Event}, {Name,_}) ->
+print_event(Dev, {in,Event}, {Name,State}) ->
io:format(
- Dev, "*DBG* ~p receive ~s~n",
- [Name,event_string(Event)]);
-print_event(Dev, {out,Reply,{To,_Tag}}, {Name,_}) ->
+ Dev, "*DBG* ~p receive ~s in state ~p~n",
+ [Name,event_string(Event),State]);
+print_event(Dev, {out,Reply,{To,_Tag}}, {Name,State}) ->
io:format(
- Dev, "*DBG* ~p send ~p to ~p~n",
- [Name,Reply,To]);
+ Dev, "*DBG* ~p send ~p to ~p from state ~p~n",
+ [Name,Reply,To,State]);
print_event(Dev, {Tag,Event,NextState}, {Name,State}) ->
StateString =
case NextState of
@@ -1064,8 +1064,10 @@ loop_event_actions(
{next_event,Type,Content} ->
case event_type(Type) of
true ->
+ NewDebug =
+ sys_debug(Debug, S, State, {in,{Type,Content}}),
loop_event_actions(
- Parent, Debug, S, Events,
+ Parent, NewDebug, S, Events,
State, NewData, P, Event, NextState, Actions,
Postpone, Hibernate, Timeout,
[{Type,Content}|NextEvents]);
--
cgit v1.2.3