aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaimo Niskanen <[email protected]>2016-02-26 11:58:47 +0100
committerRaimo Niskanen <[email protected]>2016-02-26 11:58:47 +0100
commit07790dfcd4c5706878e8562365e2418021e67056 (patch)
treedc71f5386d27983eb01ee660e187a46f21b5f5c6
parentefda33e83f2bbc666f6ec261d54ad95c38acbc36 (diff)
downloadotp-07790dfcd4c5706878e8562365e2418021e67056.tar.gz
otp-07790dfcd4c5706878e8562365e2418021e67056.tar.bz2
otp-07790dfcd4c5706878e8562365e2418021e67056.zip
Optimize postponed handling
-rw-r--r--lib/stdlib/src/gen_statem.erl187
1 files changed, 101 insertions, 86 deletions
diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl
index 83de4114a7..8f058cc3a8 100644
--- a/lib/stdlib/src/gen_statem.erl
+++ b/lib/stdlib/src/gen_statem.erl
@@ -903,108 +903,63 @@ loop_event_result(
loop_event_actions(
Parent, Debug, S, Events, Event, State, NewState, NewData, Actions) ->
+ Postpone = false, % Shall we postpone this event, true or false
+ Hibernate = false,
+ Timeout = undefined,
+ NextEvents = [],
+ P = false, % The postponed list or false if unchanged
loop_event_actions(
Parent, Debug, S, Events, Event, State, NewState, NewData,
- false, false, undefined, [],
if
is_list(Actions) ->
Actions;
true ->
[Actions]
- end).
+ end,
+ Postpone, Hibernate, Timeout, NextEvents, P).
%%
loop_event_actions(
- Parent, Debug, #{postponed := P0} = S, Events, Event,
- State, NewState, NewData,
- Postpone, Hibernate, Timeout, NextEvents, []) ->
- P1 = % Move current event to postponed if Postpone
- case Postpone of
- true ->
- [Event|P0];
- false ->
- P0
- end,
- {Timer,Q1} =
- case Timeout of
- undefined ->
- {undefined,Events};
- {timeout,0,Msg} ->
- %% Pretend the timeout has just been received
- {undefined,Events ++ [{timeout,Msg}]};
- {timeout,Time,Msg} ->
- {erlang:start_timer(Time, self(), Msg),
- Events}
- end,
- {Q2,P} = % Move all postponed events to queue if state change
- if
- NewState =:= State ->
- {Q1,P1};
- true ->
- {lists:reverse(P1, Q1),[]}
- end,
- %% Place next events first in queue
- Q = lists:reverse(NextEvents, Q2),
- %%
- NewDebug =
- sys_debug(
- Debug, S,
- case Postpone of
- true ->
- {postpone,Event,NewState};
- false ->
- {consume,Event,NewState}
- end),
- %% Loop to top; process next event
- loop_events(
- Parent, NewDebug,
- S#{
- state := NewState,
- data := NewData,
- timer := Timer,
- hibernate := Hibernate,
- postponed := P},
- Q, Timer);
-loop_event_actions(
- Parent, Debug, S, Events, Event, State, NewState, NewData,
- Postpone, Hibernate, Timeout, NextEvents, [Action|Actions]) ->
+ Parent, Debug, S, Events, Event,
+ State, NewState, NewData, [Action|Actions],
+ Postpone, Hibernate, Timeout, NextEvents, P) ->
case Action of
%% Set options
postpone ->
loop_event_actions(
Parent, Debug, S, Events, Event,
- State, NewState, NewData,
- true, Hibernate, Timeout, NextEvents, Actions);
+ State, NewState, NewData, Actions,
+ true, Hibernate, Timeout, NextEvents, P);
{postpone,NewPostpone} when is_boolean(NewPostpone) ->
loop_event_actions(
Parent, Debug, S, Events, Event,
- State, NewState, NewData,
- NewPostpone, Hibernate, Timeout, NextEvents, Actions);
+ State, NewState, NewData, Actions,
+ NewPostpone, Hibernate, Timeout, NextEvents, P);
{postpone,_} ->
?TERMINATE(
error, {bad_action,Action}, Debug, S, [Event|Events]);
hibernate ->
loop_event_actions(
Parent, Debug, S, Events, Event,
- State, NewState, NewData,
- Postpone, true, Timeout, NextEvents, Actions);
+ State, NewState, NewData, Actions,
+ Postpone, true, Timeout, NextEvents, P);
{hibernate,NewHibernate} when is_boolean(NewHibernate) ->
loop_event_actions(
Parent, Debug, S, Events, Event,
- State, NewState, NewData,
- Postpone, NewHibernate, Timeout, NextEvents, Actions);
+ State, NewState, NewData, Actions,
+ Postpone, NewHibernate, Timeout, NextEvents, P);
{hibernate,_} ->
?TERMINATE(
error, {bad_action,Action}, Debug, S, [Event|Events]);
{timeout,infinity,_} -> % Clear timer - it will never trigger
loop_event_actions(
Parent, Debug, S, Events, Event,
- State, NewState, NewData,
- Postpone, Hibernate, undefined, NextEvents, Actions);
+ State, NewState, NewData, Actions,
+ Postpone, Hibernate, undefined, NextEvents, P);
{timeout,Time,_} = NewTimeout when is_integer(Time), Time >= 0 ->
loop_event_actions(
Parent, Debug, S, Events, Event,
- State, NewState, NewData,
- Postpone, Hibernate, NewTimeout, NextEvents, Actions);
+ State, NewState, NewData, Actions,
+ Postpone, Hibernate, NewTimeout, NextEvents, P);
{timeout,_,_} ->
?TERMINATE(
error, {bad_action,Action}, Debug, S, [Event|Events]);
@@ -1015,8 +970,8 @@ loop_event_actions(
NewDebug = do_reply(Debug, S, Caller, Reply),
loop_event_actions(
Parent, NewDebug, S, Events, Event,
- State, NewState, NewData,
- Postpone, Hibernate, Timeout, NextEvents, Actions);
+ State, NewState, NewData, Actions,
+ Postpone, Hibernate, Timeout, NextEvents, P);
false ->
?TERMINATE(
error, {bad_action,Action}, Debug, S, [Event|Events])
@@ -1026,9 +981,9 @@ loop_event_actions(
true ->
loop_event_actions(
Parent, Debug, S, Events, Event,
- State, NewState, NewData,
+ State, NewState, NewData, Actions,
Postpone, Hibernate, Timeout,
- [{Type,Content}|NextEvents], Actions);
+ [{Type,Content}|NextEvents], P);
false ->
?TERMINATE(
error, {bad_action,Action}, Debug, S, [Event|Events])
@@ -1039,33 +994,36 @@ loop_event_actions(
false ->
loop_event_actions(
Parent, Debug, S, Events, Event,
- State, NewState, NewData,
- Postpone, Hibernate, Timeout, NextEvents, Actions);
+ State, NewState, NewData, Actions,
+ Postpone, Hibernate, Timeout, NextEvents, P);
undefined ->
?TERMINATE(
error, {bad_action,Action}, Debug, S, [Event|Events]);
RemoveFun when is_function(RemoveFun, 2) ->
- #{postponed := P} = S,
- case remove_event(RemoveFun, Events, P) of
+ P0 =
+ case P of
+ false ->
+ maps:get(postponed, S);
+ _ ->
+ P
+ end,
+ case remove_event(RemoveFun, Events, P0) of
false ->
loop_event_actions(
Parent, Debug, S, Events, Event,
- State, NewState, NewData,
- Postpone, Hibernate, Timeout, NextEvents,
- Actions);
+ State, NewState, NewData, Actions,
+ Postpone, Hibernate, Timeout, NextEvents, P);
{NewEvents,false} ->
loop_event_actions(
Parent, Debug, S, NewEvents, Event,
- State, NewState, NewData,
- Postpone, Hibernate, Timeout, NextEvents,
- Actions);
+ State, NewState, NewData, Actions,
+ Postpone, Hibernate, Timeout, NextEvents, P);
{false,NewP} ->
- NewS = S#{postponed := NewP},
loop_event_actions(
- Parent, Debug, NewS, Events, Event,
- State, NewState, NewData,
+ Parent, Debug, S, Events, Event,
+ State, NewState, NewData, Actions,
Postpone, Hibernate, Timeout, NextEvents,
- Actions);
+ NewP);
[Class,Reason,Stacktrace] ->
terminate(
Class, Reason, Stacktrace,
@@ -1075,7 +1033,64 @@ loop_event_actions(
terminate(
Class, Reason, Stacktrace, Debug, S, [Event|Events])
end
- end.
+ end;
+loop_event_actions(
+ Parent, Debug, S, Events, Event, State, NewState, NewData, [],
+ Postpone, Hibernate, Timeout, NextEvents, P) ->
+ P0 =
+ case P of
+ false ->
+ maps:get(postponed, S);
+ _ ->
+ P
+ end,
+ P1 = % Move current event to postponed if Postpone
+ case Postpone of
+ true ->
+ [Event|P0];
+ false ->
+ P0
+ end,
+ {Timer,Q1} =
+ case Timeout of
+ undefined ->
+ {undefined,Events};
+ {timeout,0,Msg} ->
+ %% Pretend the timeout has just been received
+ {undefined,Events ++ [{timeout,Msg}]};
+ {timeout,Time,Msg} ->
+ {erlang:start_timer(Time, self(), Msg),
+ Events}
+ end,
+ {Q2,P2} = % Move all postponed events to queue if state change
+ if
+ NewState =:= State ->
+ {Q1,P1};
+ true ->
+ {lists:reverse(P1, Q1),[]}
+ end,
+ %% Place next events first in queue
+ Q3 = lists:reverse(NextEvents, Q2),
+ %%
+ NewDebug =
+ sys_debug(
+ Debug, S,
+ case Postpone of
+ true ->
+ {postpone,Event,NewState};
+ false ->
+ {consume,Event,NewState}
+ end),
+ %% Loop to top; process next event
+ loop_events(
+ Parent, NewDebug,
+ S#{
+ state := NewState,
+ data := NewData,
+ timer := Timer,
+ hibernate := Hibernate,
+ postponed := P2},
+ Q3, Timer).
%%---------------------------------------------------------------------------
%% Server helpers