diff options
Diffstat (limited to 'lib/stdlib')
-rw-r--r-- | lib/stdlib/src/gen_statem.erl | 187 |
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 |