diff options
Diffstat (limited to 'lib/stdlib')
-rw-r--r-- | lib/stdlib/doc/src/gen_statem.xml | 87 | ||||
-rw-r--r-- | lib/stdlib/doc/src/proc_lib.xml | 8 | ||||
-rw-r--r-- | lib/stdlib/doc/src/supervisor.xml | 10 | ||||
-rw-r--r-- | lib/stdlib/doc/src/sys.xml | 31 | ||||
-rw-r--r-- | lib/stdlib/src/gen_statem.erl | 93 |
5 files changed, 153 insertions, 76 deletions
diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml index 01be3099c1..db6a4e03ea 100644 --- a/lib/stdlib/doc/src/gen_statem.xml +++ b/lib/stdlib/doc/src/gen_statem.xml @@ -407,7 +407,7 @@ ok <name name="state" /> <desc> <p> - After a state change (<c>NewState =/= State</c>) + After a state change (<c>NextState =/= State</c>) all postponed events are retried. </p> </desc> @@ -566,7 +566,7 @@ ok <p> If <c>true</c> postpone the current event and retry it when the state changes that is: - <c>NewState =/= State</c>. + <c>NextState =/= State</c>. </p> </desc> </datatype> @@ -701,7 +701,47 @@ ok </desc> </datatype> <datatype> - <name name="state_callback_result" /> + <name name="state_function_result" /> + <desc> + <taglist> + <tag><c>next_state</c></tag> + <item> + The <c>gen_statem</c> will do a state transition to + <c><anno>NextStateName</anno></c> + (which may be the same as the current state), + set <c><anno>NewData</anno></c> + and execute all <c><anno>Actions</anno></c> + </item> + </taglist> + <p> + All these terms are tuples or atoms and this property + will hold in any future version of <c>gen_statem</c>, + just in case you need such a promise. + </p> + </desc> + </datatype> + <datatype> + <name name="handle_event_result" /> + <desc> + <taglist> + <tag><c>next_state</c></tag> + <item> + The <c>gen_statem</c> will do a state transition to + <c><anno>NextState</anno></c> + (which may be the same as the current state), + set <c><anno>NewData</anno></c> + and execute all <c><anno>Actions</anno></c> + </item> + </taglist> + <p> + All these terms are tuples or atoms and this property + will hold in any future version of <c>gen_statem</c>, + just in case you need such a promise. + </p> + </desc> + </datatype> + <datatype> + <name name="common_state_callback_result" /> <desc> <taglist> <tag><c>stop</c></tag> @@ -723,14 +763,6 @@ ok with <c>Reason</c> and <c><anno>NewData</anno></c>, if given. </item> - <tag><c>next_state</c></tag> - <item> - The <c>gen_statem</c> will do a state transition to - <c><anno>NewState</anno></c> - (which may be the same as the current state), - set <c><anno>NewData</anno></c> - and execute all <c><anno>Actions</anno></c> - </item> <tag><c>keep_state</c></tag> <item> The <c>gen_statem</c> will keep the current state, or @@ -1209,10 +1241,11 @@ ok </func> <func> - <name>Module:StateName(EventType, EventContent, Data) -> Result + <name>Module:StateName(EventType, EventContent, Data) -> + StateFunctionResult </name> <name>Module:handle_event(EventType, EventContent, - State, Data) -> Result + State, Data) -> HandleEventResult </name> <fsummary>Handle an event</fsummary> <type> @@ -1222,7 +1255,7 @@ ok </v> <v>EventContent = term()</v> <v> - State = NewState = + State = <seealso marker="#type-state">state()</seealso> </v> <v> @@ -1230,9 +1263,15 @@ ok <seealso marker="#type-data">data()</seealso> </v> <v> - Result = - <seealso marker="#type-state_callback_result"> - state_callback_result() + StateFunctionResult = + <seealso marker="#type-state_function_result"> + state_function_result() + </seealso> + </v> + <v> + HandleEventResult = + <seealso marker="#type-handle_event_result"> + handle_event_result() </seealso> </v> </type> @@ -1260,9 +1299,15 @@ ok <seealso marker="#reply/2"><c>reply(Caller, Reply)</c></seealso>. </p> <p> - If this function returns with a new state that + If this function returns with a next state that does not match equal (<c>=/=</c>) to the current state - all postponed events will be retried in the new state. + all postponed events will be retried in the next state. + </p> + <p> + The only difference between <c>StateFunctionResult</c> and + <c>HandleEventResult</c> is that for <c>StateFunctionResult</c> + the next state has to be an atom but for <c>HandleEventResult</c> + there is no restriction on the next state. </p> <p> See <seealso marker="#type-action">action()</seealso> @@ -1272,7 +1317,7 @@ ok <p> These functions may use <seealso marker="erts:erlang#throw/1"><c>throw</c></seealso>, - to return <c>Result</c>. + to return the result. </p> </desc> </func> @@ -1401,7 +1446,7 @@ ok <p> If successful, the function shall return the updated internal state in an - <c>{ok,{NewState,NewData}}</c> tuple. + <c>{ok,NewState,NewData}</c> tuple. </p> <p> If the function returns <c>Reason</c>, the ongoing diff --git a/lib/stdlib/doc/src/proc_lib.xml b/lib/stdlib/doc/src/proc_lib.xml index 85f0c0c908..245580b1ba 100644 --- a/lib/stdlib/doc/src/proc_lib.xml +++ b/lib/stdlib/doc/src/proc_lib.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2014</year> + <year>1996</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -34,9 +34,9 @@ <p>This module is used to start processes adhering to the <seealso marker="doc/design_principles:des_princ">OTP Design Principles</seealso>. Specifically, the functions in this module are used by the OTP standard behaviors (<c>gen_server</c>, - <c>gen_fsm</c>, ...) when starting new processes. The functions - can also be used to start <em>special processes</em>, user - defined processes which comply to the OTP design principles. See + <c>gen_fsm</c>, <c>gen_statem</c>, ...) when starting new processes. + The functions can also be used to start <em>special processes</em>, + user defined processes which comply to the OTP design principles. See <seealso marker="doc/design_principles:spec_proc">Sys and Proc_Lib</seealso> in OTP Design Principles for an example.</p> <p>Some useful information is initialized when a process starts. The registered names, or the process identifiers, of the parent diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml index 24ff251ce3..9d81fb0db7 100644 --- a/lib/stdlib/doc/src/supervisor.xml +++ b/lib/stdlib/doc/src/supervisor.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2014</year> + <year>1996</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -34,8 +34,8 @@ <p>A behaviour module for implementing a supervisor, a process which supervises other processes called child processes. A child process can either be another supervisor or a worker process. - Worker processes are normally implemented using one of - the <c>gen_event</c>, <c>gen_fsm</c>, or <c>gen_server</c> + Worker processes are normally implemented using one of the + <c>gen_event</c>, <c>gen_fsm</c>, <c>gen_statem</c> or <c>gen_server</c> behaviours. A supervisor implemented using this module will have a standard set of interface functions and include functionality for tracing and error reporting. Supervisors are used to build a @@ -221,7 +221,8 @@ <p><c>modules</c> is used by the release handler during code replacement to determine which processes are using a certain module. As a rule of thumb, if the child process is a - <c>supervisor</c>, <c>gen_server</c>, or <c>gen_fsm</c>, + <c>supervisor</c>, <c>gen_server</c>, + <c>gen_fsm</c> or <c>gen_statem</c> this should be a list with one element <c>[Module]</c>, where <c>Module</c> is the callback module. If the child process is an event manager (<c>gen_event</c>) with a @@ -633,6 +634,7 @@ <title>SEE ALSO</title> <p><seealso marker="gen_event">gen_event(3)</seealso>, <seealso marker="gen_fsm">gen_fsm(3)</seealso>, + <seealso marker="gen_statem">gen_statem(3)</seealso>, <seealso marker="gen_server">gen_server(3)</seealso>, <seealso marker="sys">sys(3)</seealso></p> </section> diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml index d400f72e1d..2255395f46 100644 --- a/lib/stdlib/doc/src/sys.xml +++ b/lib/stdlib/doc/src/sys.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2014</year> + <year>1996</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -217,14 +217,18 @@ processes. For example, a <c>gen_server</c> process returns the callback module's state, a <c>gen_fsm</c> process returns information such as its current state name and state data, - and a <c>gen_event</c> process returns information about each of its + a <c>gen_statem</c> process returns information about + its current state and data, and a <c>gen_event</c> process + returns information about each of its registered handlers. Callback modules for <c>gen_server</c>, - <c>gen_fsm</c>, and <c>gen_event</c> can also customise the value + <c>gen_fsm</c>, <c>gen_statem</c> and <c>gen_event</c> + can also customise the value of <c><anno>Misc</anno></c> by exporting a <c>format_status/2</c> function that contributes module-specific information; - see <seealso marker="gen_server#Module:format_status/2">gen_server:format_status/2</seealso>, - <seealso marker="gen_fsm#Module:format_status/2">gen_fsm:format_status/2</seealso>, and - <seealso marker="gen_event#Module:format_status/2">gen_event:format_status/2</seealso> + see <seealso marker="gen_server#Module:format_status/2">gen_server format_status/2</seealso>, + <seealso marker="gen_fsm#Module:format_status/2">gen_fsm format_status/2</seealso>, + <seealso marker="gen_statem#Module:format_status/2">gen_statem format_status/2</seealso>, and + <seealso marker="gen_event#Module:format_status/2">gen_event format_status/2</seealso> for more details.</p> </desc> </func> @@ -245,6 +249,8 @@ processes. For a <c>gen_server</c> process, the returned <c><anno>State</anno></c> is simply the callback module's state. For a <c>gen_fsm</c> process, <c><anno>State</anno></c> is the tuple <c>{CurrentStateName, CurrentStateData}</c>. + For a <c>gen_statem</c> process <c><anno>State</anno></c> is + the tuple <c>{CurrentState,CurrentData}.</c> For a <c>gen_event</c> process, <c><anno>State</anno></c> a list of tuples, where each tuple corresponds to an event handler registered in the process and contains <c>{Module, Id, HandlerState}</c>, where <c>Module</c> is the event handler's module name, @@ -263,8 +269,9 @@ details of the exception.</p> <p>The <c>system_get_state/1</c> function is primarily useful for user-defined behaviours and modules that implement OTP <seealso marker="#special_process">special - processes</seealso>. The <c>gen_server</c>, <c>gen_fsm</c>, and <c>gen_event</c> OTP - behaviour modules export this function, and so callback modules for those behaviours + processes</seealso>. The <c>gen_server</c>, <c>gen_fsm</c>, + <c>gen_statem</c> and <c>gen_event</c> OTP + behaviour modules export this function, so callback modules for those behaviours need not supply their own.</p> <p>To obtain more information about a process, including its state, see <seealso marker="#get_status-1">get_status/1</seealso> and @@ -290,6 +297,8 @@ <c>gen_fsm</c> process, <c><anno>State</anno></c> is the tuple <c>{CurrentStateName, CurrentStateData}</c>, and <c><anno>NewState</anno></c> is a similar tuple that may contain a new state name, new state data, or both. + The same applies for a <c>gen_statem</c> process but + it names the tuple fields <c>{CurrentState,CurrentData}</c>. For a <c>gen_event</c> process, <c><anno>State</anno></c> is the tuple <c>{Module, Id, HandlerState}</c> where <c>Module</c> is the event handler's module name, <c>Id</c> is the handler's ID (which is the value <c>false</c> if it was registered without @@ -304,7 +313,8 @@ state, then regardless of process type, it may simply return its <c><anno>State</anno></c> argument.</p> <p>If a <c><anno>StateFun</anno></c> function crashes or throws an exception, then - for <c>gen_server</c> and <c>gen_fsm</c> processes, the original state of the process is + for <c>gen_server</c>, <c>gen_fsm</c> or <c>gen_statem</c> processes, + the original state of the process is unchanged. For <c>gen_event</c> processes, a crashing or failing <c><anno>StateFun</anno></c> function means that only the state of the particular event handler it was working on when it failed or crashed is unchanged; it can still succeed in changing the states of other event @@ -329,7 +339,8 @@ <c>{callback_failed, StateFun, {Class, Reason}}</c>.</p> <p>The <c>system_replace_state/2</c> function is primarily useful for user-defined behaviours and modules that implement OTP <seealso marker="#special_process">special processes</seealso>. The - <c>gen_server</c>, <c>gen_fsm</c>, and <c>gen_event</c> OTP behaviour modules export this function, + <c>gen_server</c>, <c>gen_fsm</c>, <c>gen_statem</c> and + <c>gen_event</c> OTP behaviour modules export this function, and so callback modules for those behaviours need not supply their own.</p> </desc> </func> diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl index cc09efc140..438c366f8e 100644 --- a/lib/stdlib/src/gen_statem.erl +++ b/lib/stdlib/src/gen_statem.erl @@ -44,8 +44,16 @@ -export( [wakeup_from_hibernate/3]). +%% Type exports for templates +-export_type( + [event_type/0, + callback_mode/0, + state_function_result/0, + handle_event_result/0, + action/0]). + %% Fix problem for doc build --export_type([transition_option/0,state_callback_result/0]). +-export_type([transition_option/0]). %%%========================================================================== %%% Interface functions. @@ -84,7 +92,7 @@ -type action() :: %% During a state change: - %% * NewState and NewData are set. + %% * NextState and NewData are set. %% * All action()s are executed in order of apperance. %% * Postponing the current event is performed %% iff 'postpone' is 'true'. @@ -119,7 +127,25 @@ {'reply', % Reply to a caller Caller :: caller(), Reply :: term()}. --type state_callback_result() :: +-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()} | + common_state_callback_result(). +-type handle_event_result() :: + {'next_state', % {next_state,NextState,NewData,[]} + NextState :: state(), + NewData :: data()} | + {'next_state', % State transition, maybe to the same state + NextState :: state(), + NewData :: data(), + Actions :: [action()] | action()} | + common_state_callback_result(). +-type common_state_callback_result() :: 'stop' | % {stop,normal} {'stop', % Stop the server Reason :: term()} | @@ -133,13 +159,6 @@ Reason :: term(), Replies :: [reply_action()] | reply_action(), NewData :: data()} | - {'next_state', % {next_state,NewState,NewData,[]} - NewState :: state(), - NewData :: data()} | - {'next_state', % State transition, maybe to the same state - NewState :: state(), - NewData :: data(), - Actions :: [action()] | action()} | {'keep_state', % {keep_state,NewData,[]} NewData :: data()} | {'keep_state', % Keep state, change data @@ -171,7 +190,7 @@ event_type(), EventContent :: term(), Data :: data()) -> - state_callback_result(). + state_function_result(). %% %% State callback for callback_mode() =:= handle_event_function. %% @@ -182,7 +201,7 @@ EventContent :: term(), State :: state(), % Current state Data :: data()) -> - state_callback_result(). + handle_event_result(). %% Clean up before the server terminates. -callback terminate( @@ -514,7 +533,7 @@ enter(Module, Opts, CallbackMode, State, Data, Server, Actions, Parent) -> %% The values should already have been type checked Name = gen:get_proc_name(Server), Debug = gen:debug_options(Name, Opts), - OldState = make_ref(), % Will be discarded by loop_event_actions/9 + PrevState = make_ref(), % Will be discarded by loop_event_actions/9 NewActions = if is_list(Actions) -> @@ -526,7 +545,7 @@ enter(Module, Opts, CallbackMode, State, Data, Server, Actions, Parent) -> callback_mode => CallbackMode, module => Module, name => Name, - state => OldState, + state => PrevState, data => Data, timer => undefined, postponed => [], @@ -534,7 +553,7 @@ enter(Module, Opts, CallbackMode, State, Data, Server, Actions, Parent) -> loop_event_actions( Parent, Debug, S, [], {event,undefined}, % Will be discarded thanks to {postpone,false} - OldState, State, Data, NewActions). + PrevState, State, Data, NewActions). %%%========================================================================== %%% gen callbacks @@ -868,18 +887,18 @@ loop_event_result( exit, Reason, ?STACKTRACE(), Debug, NewS, Q, Replies), %% Since we got back here Replies was bad terminate(Class, NewReason, Stacktrace, NewDebug, NewS, Q); - {next_state,NewState,NewData} - when CallbackMode =:= state_functions, is_atom(NewState); + {next_state,NextState,NewData} + when CallbackMode =:= state_functions, is_atom(NextState); CallbackMode =/= state_functions -> loop_event_actions( Parent, Debug, S, Events, Event, - State, NewState, NewData, []); - {next_state,NewState,NewData,Actions} - when CallbackMode =:= state_functions, is_atom(NewState); + State, NextState, NewData, []); + {next_state,NextState,NewData,Actions} + when CallbackMode =:= state_functions, is_atom(NextState); CallbackMode =/= state_functions -> loop_event_actions( Parent, Debug, S, Events, Event, - State, NewState, NewData, Actions); + State, NextState, NewData, Actions); {keep_state,NewData} -> loop_event_actions( Parent, Debug, S, Events, Event, @@ -902,13 +921,13 @@ loop_event_result( end. loop_event_actions( - Parent, Debug, S, Events, Event, State, NewState, NewData, Actions) -> + Parent, Debug, S, Events, Event, State, NextState, NewData, Actions) -> Postpone = false, % Shall we postpone this event, true or false Hibernate = false, Timeout = undefined, NextEvents = [], loop_event_actions( - Parent, Debug, S, Events, Event, State, NewState, NewData, + Parent, Debug, S, Events, Event, State, NextState, NewData, if is_list(Actions) -> Actions; @@ -920,19 +939,19 @@ loop_event_actions( %% Process all action()s loop_event_actions( Parent, Debug, S, Events, Event, - State, NewState, NewData, [Action|Actions], + State, NextState, NewData, [Action|Actions], Postpone, Hibernate, Timeout, NextEvents) -> case Action of %% Actions that set options postpone -> loop_event_actions( Parent, Debug, S, Events, Event, - State, NewState, NewData, Actions, + State, NextState, NewData, Actions, true, Hibernate, Timeout, NextEvents); {postpone,NewPostpone} when is_boolean(NewPostpone) -> loop_event_actions( Parent, Debug, S, Events, Event, - State, NewState, NewData, Actions, + State, NextState, NewData, Actions, NewPostpone, Hibernate, Timeout, NextEvents); {postpone,_} -> ?TERMINATE( @@ -940,12 +959,12 @@ loop_event_actions( hibernate -> loop_event_actions( Parent, Debug, S, Events, Event, - State, NewState, NewData, Actions, + State, NextState, NewData, Actions, Postpone, true, Timeout, NextEvents); {hibernate,NewHibernate} when is_boolean(NewHibernate) -> loop_event_actions( Parent, Debug, S, Events, Event, - State, NewState, NewData, Actions, + State, NextState, NewData, Actions, Postpone, NewHibernate, Timeout, NextEvents); {hibernate,_} -> ?TERMINATE( @@ -953,12 +972,12 @@ loop_event_actions( {timeout,infinity,_} -> % Clear timer - it will never trigger loop_event_actions( Parent, Debug, S, Events, Event, - State, NewState, NewData, Actions, + State, NextState, NewData, Actions, Postpone, Hibernate, undefined, NextEvents); {timeout,Time,_} = NewTimeout when is_integer(Time), Time >= 0 -> loop_event_actions( Parent, Debug, S, Events, Event, - State, NewState, NewData, Actions, + State, NextState, NewData, Actions, Postpone, Hibernate, NewTimeout, NextEvents); {timeout,_,_} -> ?TERMINATE( @@ -970,7 +989,7 @@ loop_event_actions( NewDebug = do_reply(Debug, S, Caller, Reply), loop_event_actions( Parent, NewDebug, S, Events, Event, - State, NewState, NewData, Actions, + State, NextState, NewData, Actions, Postpone, Hibernate, Timeout, NextEvents); false -> ?TERMINATE( @@ -981,7 +1000,7 @@ loop_event_actions( true -> loop_event_actions( Parent, Debug, S, Events, Event, - State, NewState, NewData, Actions, + State, NextState, NewData, Actions, Postpone, Hibernate, Timeout, [{Type,Content}|NextEvents]); false -> @@ -996,7 +1015,7 @@ loop_event_actions( %% End of actions list loop_event_actions( Parent, Debug, #{postponed := P0} = S, Events, Event, - State, NewState, NewData, [], + State, NextState, NewData, [], Postpone, Hibernate, Timeout, NextEvents) -> %% %% All options have been collected and next_events are buffered. @@ -1011,7 +1030,7 @@ loop_event_actions( end, {Q2,P} = % Move all postponed events to queue if state change if - NewState =:= State -> + NextState =:= State -> {Events,P1}; true -> {lists:reverse(P1, Events),[]} @@ -1024,9 +1043,9 @@ loop_event_actions( Debug, S, case Postpone of true -> - {postpone,Event,NewState}; + {postpone,Event,NextState}; false -> - {consume,Event,NewState} + {consume,Event,NextState} end), %% Have a peek on the event queue so we can avoid starting %% the state timer unless we have to @@ -1057,7 +1076,7 @@ loop_event_actions( loop_events( Parent, NewDebug, S#{ - state := NewState, + state := NextState, data := NewData, timer := Timer, postponed := P, |