From 26a7af61fbffae90c0968d945ae8b146582ba068 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Thu, 18 Feb 2016 16:38:57 +0100 Subject: Change initial PrevState to 'undefined' --- lib/stdlib/doc/src/gen_statem.xml | 27 ++++++++++++++++++++++++--- lib/stdlib/src/gen_statem.erl | 7 ++++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml index 5fbedb12f8..9d98763973 100644 --- a/lib/stdlib/doc/src/gen_statem.xml +++ b/lib/stdlib/doc/src/gen_statem.xml @@ -110,6 +110,14 @@ erlang:'!' -----> Module:StateName/5 states so you do not accidentally postpone one event forever creating an infinite busy loop.

+

Any state name or any state value (depending on + callback_mode) + is permitted with a small gotcha regarding the state + undefined that is used as the previous state when + the first gen_statem state function is called. + You might need to know about this faked state if you + inspect the previous state argument in your state functions. +

The gen_statem enqueues incoming events in order of arrival and presents these to the state function @@ -118,6 +126,12 @@ erlang:'!' -----> Module:StateName/5 After a state change all enqueued events (including postponed) are again presented to the state function.

+

The gen_statem event queue model is sufficient to emulate + the normal process message queue and selective receive + with postponing an event corresponding to not matching + it in a receive statement and changing states corresponding + to entering a new receive statement. +

The state function can insert events using the @@ -133,6 +147,15 @@ erlang:'!' -----> Module:StateName/5 that can be used for such events making it impossible to mistake for an external event.

+

Inserting an event replaces the trick of calling your own + state handling functions that you often would have to + resort to in e.g gen_fsm + to force processing a faked event before others. + If you for example in gen_statem postpone an event + in one state and then call some other state function of yours, + you have not changed states and hence the postponed event + will not be retried, which is logical but might be confusing. +

A gen_statem handles system messages as documented in sys. The sys module @@ -1011,7 +1034,6 @@ erlang:'!' -----> Module:StateName/5 EventContent = term() PrevStateName = state_name() - | reference() StateName = state_name() @@ -1060,8 +1082,7 @@ erlang:'!' -----> Module:StateName/5 in some odd cases for example when you want to do something only at the first event in a state. Note that when gen_statem enters its first state - this is set to a reference() - since that can not match equal to any state. + this is set to undefined.

If this function returns with a new state that does not match equal (=/=) to the current state diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl index 486f61b1ed..e03e22b087 100644 --- a/lib/stdlib/src/gen_statem.erl +++ b/lib/stdlib/src/gen_statem.erl @@ -459,13 +459,13 @@ do_send(Proc, Msg) -> enter(Module, Options, State, StateData, Server, InitOps, Parent) -> Name = gen:get_proc_name(Server), Debug = gen:debug_options(Name, Options), - PrevState = make_ref(), + PrevState = undefined, S = #{ callback_mode => state_functions, module => Module, name => Name, prev_state => PrevState, - state => PrevState, + state => PrevState, % Will be discarded by loop_event_state_ops state_data => StateData, timer => undefined, postponed => [], @@ -475,7 +475,8 @@ enter(Module, Options, State, StateData, Server, InitOps, Parent) -> loop_event_state_ops( Parent, Debug, S#{callback_mode := CallbackMode}, - [], {event,undefined}, + [], + {event,undefined}, % Will be discarded by {postpone,false} State, StateData, StateOps++[{postpone,false}]); [Reason] -> -- cgit v1.2.3