From c6bdd67b33b70d862e2a2d0f582106f2e930d970 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 6 Apr 2017 16:03:11 +0200 Subject: stdlib: Deprecate gen_fsm --- lib/stdlib/doc/src/gen_fsm.xml | 1091 +++++----------------------- lib/stdlib/doc/src/gen_server.xml | 1 - lib/stdlib/doc/src/gen_statem.xml | 11 +- lib/stdlib/doc/src/proc_lib.xml | 2 +- lib/stdlib/doc/src/supervisor.xml | 6 +- lib/stdlib/doc/src/sys.xml | 28 +- lib/stdlib/src/gen_fsm.erl | 20 + lib/stdlib/src/otp_internal.erl | 49 ++ system/doc/design_principles/fsm.xml | 338 --------- system/doc/design_principles/part.xml | 1 - system/doc/design_principles/spec_proc.xml | 86 +-- system/doc/design_principles/sup_princ.xml | 3 +- system/doc/design_principles/xmlfiles.mk | 1 - system/doc/reference_manual/modules.xml | 1 - 14 files changed, 298 insertions(+), 1340 deletions(-) delete mode 100644 system/doc/design_principles/fsm.xml diff --git a/lib/stdlib/doc/src/gen_fsm.xml b/lib/stdlib/doc/src/gen_fsm.xml index 719ab2b558..d74665060e 100644 --- a/lib/stdlib/doc/src/gen_fsm.xml +++ b/lib/stdlib/doc/src/gen_fsm.xml @@ -4,14 +4,14 @@
- 19962016 + 1996-2017 Ericsson AB. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software @@ -29,926 +29,177 @@
gen_fsm - Generic finite state machine behavior. - - -

- There is a new behaviour - gen_statem - that is intended to replace gen_fsm for new code. - gen_fsm will not be removed for the foreseeable future - to keep old state machine implementations running. -

-
-

This behavior module provides a finite state machine. - A generic finite state machine process (gen_fsm) implemented - using this module has a standard set of interface functions - and includes functionality for tracing and error reporting. It - also fits into an OTP supervision tree. For more information, see - OTP Design Principles. -

- -

A gen_fsm process assumes all specific parts to be located in a - callback module exporting a predefined set of functions. The relationship - between the behavior functions and the callback functions is as - follows:

- -
-gen_fsm module                    Callback module
---------------                    ---------------
-gen_fsm:start
-gen_fsm:start_link                -----> Module:init/1
-
-gen_fsm:stop                      -----> Module:terminate/3
-
-gen_fsm:send_event                -----> Module:StateName/2
-
-gen_fsm:send_all_state_event      -----> Module:handle_event/3
-
-gen_fsm:sync_send_event           -----> Module:StateName/3
-
-gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
-
--                                 -----> Module:handle_info/3
-
--                                 -----> Module:terminate/3
+  Deprecated and replaced by gen_statem 
 
--                                 -----> Module:code_change/4
- -

If a callback function fails or returns a bad value, the gen_fsm - process terminates.

- -

A gen_fsm process handles system messages as described in - sys(3). The sys module - can be used for debugging a gen_fsm process.

- -

Notice that a gen_fsm process does not trap exit signals - automatically, this must be explicitly initiated in the callback - module.

- -

Unless otherwise stated, all functions in this module fail if - the specified gen_fsm process does not exist or if bad arguments - are specified.

- -

The gen_fsm process can go into hibernation - (see - erlang:hibernate/3) if a callback function - specifies 'hibernate' instead of a time-out value. This - can be useful if the server is expected to be idle for a long - time. However, use this feature with care, as hibernation - implies at least two garbage collections (when hibernating and - shortly after waking up) and is not something you want to do - between each call to a busy state machine.

+ +

Deprecated and replaced by gen_statem

- - - - cancel_timer(Ref) -> RemainingTime | false - Cancel an internal timer in a generic FSM. - - Ref = reference() - RemainingTime = integer() - - -

Cancels an internal timer referred by Ref in the - gen_fsm process that calls this function.

-

Ref is a reference returned from - - send_event_after/2 or - start_timer/2.

-

If the timer has already timed out, but the event not yet - been delivered, it is cancelled as if it had not - timed out, so there is no false timer event after - returning from this function.

-

Returns the remaining time in milliseconds until the timer would - have expired if Ref referred to an active timer, otherwise - false.

-
-
- - - enter_loop(Module, Options, StateName, StateData) - enter_loop(Module, Options, StateName, StateData, FsmName) - enter_loop(Module, Options, StateName, StateData, Timeout) - enter_loop(Module, Options, StateName, StateData, FsmName, Timeout) - Enter the gen_fsm receive loop. - - Module = atom() - Options = [Option] -  Option = {debug,Dbgs} -   Dbgs = [Dbg] -    Dbg = trace | log | statistics -     | {log_to_file,FileName} | {install,{Func,FuncState}} - StateName = atom() - StateData = term() - FsmName = {local,Name} | {global,GlobalName} -   | {via,Module,ViaName} -  Name = atom() -  GlobalName = ViaName = term() - Timeout = int() | infinity - - -

Makes an existing process into a gen_fsm process. - Does not return, - instead the calling process enters the gen_fsm receive - loop and becomes a gen_fsm process. The process must - have been started using one of the start functions in - proc_lib(3). The user is - responsible for any initialization of the process, including - registering a name for it.

-

This function is useful when a more complex initialization - procedure is needed than the gen_fsm behavior provides.

-

Module, Options, and FsmName have - the same meanings as when calling - start[_link]/3,4. - However, if FsmName is specified, the process must have - been registered accordingly before this function is - called.

-

StateName, StateData, and Timeout have - the same meanings as in the return value of - Module:init/1. - The callback module Module does not need to - export an init/1 function.

-

The function fails if the calling process was not started by a - proc_lib start function, or if it is not registered - according to FsmName.

-
-
- - - reply(Caller, Reply) -> Result - Send a reply to a caller. - - Caller - see below - Reply = term() - Result = term() - - -

This function can be used by a gen_fsm process to - explicitly send a reply to a client process that called - - sync_send_event/2,3 or - - sync_send_all_state_event/2,3 - when the reply cannot be defined in the return value of - - Module:StateName/3 or - - Module:handle_sync_event/4.

-

Caller must be the From argument provided to - the callback function. Reply is any term - given back to the client as the return value of - sync_send_event/2,3 or - sync_send_all_state_event/2,3.

-

Return value Result is not further defined, and - is always to be ignored.

-
-
- - - send_all_state_event(FsmRef, Event) -> ok - Send an event asynchronously to a generic FSM. - - FsmRef = Name | {Name,Node} | {global,GlobalName} -   | {via,Module,ViaName} | pid() -  Name = Node = atom() -  GlobalName = ViaName = term() - Event = term() - - -

Sends an event asynchronously to the FsmRef of the - gen_fsm process and returns ok immediately. - The gen_fsm process calls - - Module:handle_event/3 to handle the event.

-

For a description of the arguments, see - send_event/2.

-

The difference between send_event/2 and - send_all_state_event/2 is which callback function is - used to handle the event. This function is useful when - sending events that are handled the same way in every state, - as only one handle_event clause is needed to handle - the event instead of one clause in each state name function.

-
-
- - - send_event(FsmRef, Event) -> ok - Send an event asynchronously to a generic FSM. - - FsmRef = Name | {Name,Node} | {global,GlobalName} -   | {via,Module,ViaName} | pid() -  Name = Node = atom() -  GlobalName = ViaName = term() - Event = term() - - -

Sends an event asynchronously to the FsmRef of the - gen_fsm process - and returns ok immediately. The gen_fsm process calls - - Module:StateName/2 to handle the event, where - StateName is the name of the current state of - the gen_fsm process.

-

FsmRef can be any of the following:

- - The pid - Name, if the gen_fsm process is locally - registered - {Name,Node}, if the gen_fsm process is locally - registered at another node - {global,GlobalName}, if the gen_fsm process is - globally registered - {via,Module,ViaName}, if the gen_fsm process is - registered through an alternative process registry - -

Event is any term that is passed as one of - the arguments to Module:StateName/2.

-
-
- - - send_event_after(Time, Event) -> Ref - Send a delayed event internally in a generic FSM. - - Time = integer() - Event = term() - Ref = reference() - - -

Sends a delayed event internally in the gen_fsm process - that calls this function after Time milliseconds. - Returns immediately a - reference that can be used to cancel the delayed send using - cancel_timer/1.

-

The gen_fsm process calls - - Module:StateName/2 to handle - the event, where StateName is the name of the current - state of the gen_fsm process at the time the delayed event is - delivered.

-

Event is any term that is passed as one of - the arguments to Module:StateName/2.

-
-
- - - start(Module, Args, Options) -> Result - start(FsmName, Module, Args, Options) -> Result - Create a standalone gen_fsm process. - - FsmName = {local,Name} | {global,GlobalName} -   | {via,Module,ViaName} -  Name = atom() -  GlobalName = ViaName = term() - Module = atom() - Args = term() - Options = [Option] -  Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts} -   Dbgs = [Dbg] -    Dbg = trace | log | statistics -     | {log_to_file,FileName} | {install,{Func,FuncState}} -   SOpts = [term()] - Result = {ok,Pid} | ignore | {error,Error} -  Pid = pid() -  Error = {already_started,Pid} | term() - - -

Creates a standalone gen_fsm process, that is, a process that - is not part of a supervision tree and thus has no supervisor.

-

For a description of arguments and return values, see - start_link/3,4.

-
-
- - - start_link(Module, Args, Options) -> Result - start_link(FsmName, Module, Args, Options) -> Result - Create a gen_fsm process in a supervision tree. - - - FsmName = {local,Name} | {global,GlobalName} -   | {via,Module,ViaName} -  Name = atom() -  GlobalName = ViaName = term() - Module = atom() - Args = term() - Options = [Option] -  Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts} -   Dbgs = [Dbg] -    Dbg = trace | log | statistics -     | {log_to_file,FileName} | {install,{Func,FuncState}} -   SOpts = [SOpt] -    SOpt - see erlang:spawn_opt/2,3,4,5 - Result = {ok,Pid} | ignore | {error,Error} -  Pid = pid() -  Error = {already_started,Pid} | term() - - -

Creates a gen_fsm process as part of a supervision tree. - The function is to be called, directly or indirectly, by - the supervisor. For example, it ensures that - the gen_fsm process is linked to the supervisor.

-

The gen_fsm process calls - Module:init/1 to - initialize. To ensure a synchronized startup procedure, - start_link/3,4 does not return until - Module:init/1 has returned.

- - -

If FsmName={local,Name}, the gen_fsm process is - registered locally as Name using register/2.

-
- -

If FsmName={global,GlobalName}, the gen_fsm process - is registered globally as GlobalName using - - global:register_name/2.

-
- -

If FsmName={via,Module,ViaName}, the gen_fsm - process registers with the registry represented by Module. - The Module callback is to export the functions - register_name/2, unregister_name/1, - whereis_name/1, and send/2, which are to behave - like the corresponding functions in - global. - Thus, {via,global,GlobalName} is a valid reference.

-
-
-

If no name is provided, the gen_fsm process is not - registered.

-

Module is the name of the callback module.

-

Args is any term that is passed as - the argument to Module:init/1.

-

If option {timeout,Time} is present, the gen_fsm - process is allowed to spend Time milliseconds initializing - or it terminates and the start function returns - {error,timeout}.

-

If option {debug,Dbgs} is present, the corresponding - sys function is called for each item in Dbgs; see - sys(3).

-

If option {spawn_opt,SOpts} is present, SOpts is - passed as option list to the spawn_opt BIF that is used to - spawn the gen_fsm process; see - - spawn_opt/2.

- -

Using spawn option monitor is not - allowed, it causes the function to fail with reason - badarg.

-
-

If the gen_fsm process is successfully created and - initialized, the function returns {ok,Pid}, where Pid - is the pid of the gen_fsm process. If a process with the - specified FsmName exists already, the function returns - {error,{already_started,Pid}}, where Pid is - the pid of that process.

-

If Module:init/1 fails with Reason, - the function returns {error,Reason}. If - Module:init/1 returns {stop,Reason} or - ignore, the process is terminated and the function - returns {error,Reason} or ignore, respectively.

-
-
- - - start_timer(Time, Msg) -> Ref - Send a time-out event internally in a generic FSM. - - Time = integer() - Msg = term() - Ref = reference() - - -

Sends a time-out event internally in the gen_fsm - process that calls this function after Time milliseconds. - Returns immediately a - reference that can be used to cancel the timer using - cancel_timer/1.

-

The gen_fsm process calls - - Module:StateName/2 to handle - the event, where StateName is the name of the current - state of the gen_fsm process at the time the time-out - message is delivered.

-

Msg is any term that is passed in the - time-out message, {timeout, Ref, Msg}, as one of - the arguments to Module:StateName/2.

-
-
- - - stop(FsmRef) -> ok - stop(FsmRef, Reason, Timeout) -> ok - Synchronously stop a generic FSM. - - FsmRef = Name | {Name,Node} | {global,GlobalName} -   | {via,Module,ViaName} | pid() -  Node = atom() -  GlobalName = ViaName = term() - Reason = term() - Timeout = int()>0 | infinity - - -

Orders a generic finite state machine to exit with the specified - Reason and waits for it to terminate. The gen_fsm - process calls - Module:terminate/3 before exiting.

-

The function returns ok if the generic finite state machine - terminates with the expected reason. Any other reason than - normal, shutdown, or {shutdown,Term} causes an - error report to be issued using - - error_logger:format/2. - The default Reason is normal.

-

Timeout is an integer greater than zero that - specifies how many milliseconds to wait for the generic FSM - to terminate, or the atom infinity to wait - indefinitely. The default value is infinity. If the - generic finite state machine has not terminated within the specified - time, a timeout exception is raised.

-

If the process does not exist, a noproc exception - is raised.

-
-
- - - sync_send_all_state_event(FsmRef, Event) -> Reply - sync_send_all_state_event(FsmRef, Event, Timeout) -> Reply - Send an event synchronously to a generic FSM. - - FsmRef = Name | {Name,Node} | {global,GlobalName} -   | {via,Module,ViaName} | pid() -  Name = Node = atom() -  GlobalName = ViaName = term() - Event = term() - Timeout = int()>0 | infinity - Reply = term() - - -

Sends an event to the FsmRef of the gen_fsm - process and waits until a reply arrives or a time-out occurs. - The gen_fsm process calls - - Module:handle_sync_event/4 to handle the event.

-

For a description of FsmRef and Event, see - send_event/2. - For a description of Timeout and Reply, see - - sync_send_event/3.

-

For a discussion about the difference between - sync_send_event and sync_send_all_state_event, see - - send_all_state_event/2.

-
-
- - - sync_send_event(FsmRef, Event) -> Reply - sync_send_event(FsmRef, Event, Timeout) -> Reply - Send an event synchronously to a generic FSM. - - FsmRef = Name | {Name,Node} | {global,GlobalName} -   | {via,Module,ViaName} | pid() -  Name = Node = atom() -  GlobalName = ViaName = term() - Event = term() - Timeout = int()>0 | infinity - Reply = term() - - -

Sends an event to the FsmRef of the gen_fsm - process and waits until a reply arrives or a time-out occurs. - The gen_fsm process calls - - Module:StateName/3 to handle the event, where - StateName is the name of the current state of - the gen_fsm process.

-

For a description of FsmRef and Event, see - send_event/2.

-

Timeout is an integer greater than zero that - specifies how many milliseconds to wait for a reply, or - the atom infinity to wait indefinitely. Defaults - to 5000. If no reply is received within the specified time, - the function call fails.

-

Return value Reply is defined in the return value - of Module:StateName/3.

-
-
-
- -
- Callback Functions -

The following functions are to be exported from a gen_fsm - callback module.

- -

state name denotes a state of the state machine.

- -

state data denotes the internal state of the Erlang process - that implements the state machine.

-
- - - - Module:code_change(OldVsn, StateName, StateData, Extra) -> {ok, NextStateName, NewStateData} - Update the internal state data during upgrade/downgrade. - - - OldVsn = Vsn | {down, Vsn} -   Vsn = term() - StateName = NextStateName = atom() - StateData = NewStateData = term() - Extra = term() - - -

This function is called by a gen_fsm process when it is to - update its internal state data during a release upgrade/downgrade, - that is, when instruction {update,Module,Change,...}, - where Change={advanced,Extra}, is given in - the appup file; see section - - Release Handling Instructions in OTP Design Principles.

-

For an upgrade, OldVsn is Vsn, and for a downgrade, - OldVsn is {down,Vsn}. Vsn is defined by the - vsn attribute(s) of the old version of the callback module - Module. If no such attribute is defined, the version is - the checksum of the Beam file.

-

StateName is the current state name and StateData the - internal state data of the gen_fsm process.

-

Extra is passed "as is" from the {advanced,Extra} - part of the update instruction.

-

The function is to return the new current state name and - updated internal data.

-
-
- - - Module:format_status(Opt, [PDict, StateData]) -> Status - Optional function for providing a term describing the - current gen_fsm process status. - - Opt = normal | terminate - PDict = [{Key, Value}] - StateData = term() - Status = term() - - - -

This callback is optional, so callback modules need not - export it. The gen_fsm module provides a default - implementation of this function that returns the callback - module state data.

-
-

This function is called by a gen_fsm process in the - following situations:

- - One of - sys:get_status/1,2 - is invoked to get the gen_fsm status. Opt is set to - the atom normal for this case. - The gen_fsm process terminates abnormally and logs an - error. Opt is set to the atom terminate for - this case. - -

This function is useful for changing the form and - appearance of the gen_fsm status for these cases. A callback - module wishing to change the sys:get_status/1,2 - return value as well as how its status appears in - termination error logs, exports an instance - of format_status/2 that returns a term describing the - current status of the gen_fsm process.

-

PDict is the current value of the process dictionary of the - gen_fsm process.

-

StateData is the internal state data of the - gen_fsm process.

-

The function is to return Status, a term that - change the details of the current state and status of - the gen_fsm process. There are no restrictions on the - form Status can take, but for - the sys:get_status/1,2 case (when Opt - is normal), the recommended form for - the Status value is [{data, [{"StateData", - Term}]}], where Term provides relevant details of - the gen_fsm state data. Following this recommendation is not - required, but it makes the callback module status - consistent with the rest of the sys:get_status/1,2 - return value.

-

One use for this function is to return compact alternative - state data representations to avoid that large state terms - are printed in log files.

-
-
- - - Module:handle_event(Event, StateName, StateData) -> Result - Handle an asynchronous event. - - Event = term() - StateName = atom() - StateData = term() - Result = {next_state,NextStateName,NewStateData} -   | {next_state,NextStateName,NewStateData,Timeout} -   | {next_state,NextStateName,NewStateData,hibernate} -   | {stop,Reason,NewStateData} -  NextStateName = atom() -  NewStateData = term() -  Timeout = int()>0 | infinity -  Reason = term() - - -

Whenever a gen_fsm process receives an event sent using - - send_all_state_event/2, - this function is called to handle the event.

-

StateName is the current state name of the gen_fsm - process.

-

For a description of the other arguments and possible return values, - see - Module:StateName/2.

-
-
- - - Module:handle_info(Info, StateName, StateData) -> Result - Handle an incoming message. - - Info = term() - StateName = atom() - StateData = term() - Result = {next_state,NextStateName,NewStateData} -   | {next_state,NextStateName,NewStateData,Timeout} -   | {next_state,NextStateName,NewStateData,hibernate} -   | {stop,Reason,NewStateData} -  NextStateName = atom() -  NewStateData = term() -  Timeout = int()>0 | infinity -  Reason = normal | term() - - -

This function is called by a gen_fsm process when it receives - any other message than a synchronous or asynchronous event (or a - system message).

-

Info is the received message.

-

For a description of the other arguments and possible return values, - see - Module:StateName/2.

-
-
- - - Module:handle_sync_event(Event, From, StateName, StateData) -> Result - Handle a synchronous event. - - Event = term() - From = {pid(),Tag} - StateName = atom() - StateData = term() - Result = {reply,Reply,NextStateName,NewStateData} -   | {reply,Reply,NextStateName,NewStateData,Timeout} -   | {reply,Reply,NextStateName,NewStateData,hibernate} -   | {next_state,NextStateName,NewStateData} -   | {next_state,NextStateName,NewStateData,Timeout} -   | {next_state,NextStateName,NewStateData,hibernate} -   | {stop,Reason,Reply,NewStateData} | {stop,Reason,NewStateData} -  Reply = term() -  NextStateName = atom() -  NewStateData = term() -  Timeout = int()>0 | infinity -  Reason = term() - - -

Whenever a gen_fsm process receives an event sent using - - sync_send_all_state_event/2,3, - this function is called to handle the event.

-

StateName is the current state name of the gen_fsm - process.

-

For a description of the other arguments and possible return values, - see - Module:StateName/3.

-
-
- - - Module:init(Args) -> Result - Initialize process and internal state name and state data. - - - Args = term() - Result = {ok,StateName,StateData} | {ok,StateName,StateData,Timeout} -   | {ok,StateName,StateData,hibernate} -   | {stop,Reason} | ignore -  StateName = atom() -  StateData = term() -  Timeout = int()>0 | infinity -  Reason = term() - - - -

Whenever a gen_fsm process is started using - start/3,4 or - start_link/3,4, - this function is called by the new process to initialize.

-

Args is the Args argument provided to the start - function.

-

If initialization is successful, the function is to return - {ok,StateName,StateData}, - {ok,StateName,StateData,Timeout}, or - {ok,StateName,StateData,hibernate}, where StateName - is the initial state name and StateData the initial - state data of the gen_fsm process.

-

If an integer time-out value is provided, a time-out occurs - unless an event or a message is received within Timeout - milliseconds. A time-out is represented by the atom - timeout and is to be handled by the - - Module:StateName/2 callback functions. The atom - infinity can be used to wait indefinitely, this is - the default value.

-

If hibernate is specified instead of a time-out value, the - process goes into hibernation when waiting for the next message - to arrive (by calling - proc_lib:hibernate/3).

-

If the initialization fails, the function returns - {stop,Reason}, where Reason is any term, - or ignore.

-
-
- - - Module:StateName(Event, StateData) -> Result - Handle an asynchronous event. - - Event = timeout | term() - StateData = term() - Result = {next_state,NextStateName,NewStateData} -   | {next_state,NextStateName,NewStateData,Timeout} -   | {next_state,NextStateName,NewStateData,hibernate} -   | {stop,Reason,NewStateData} -  NextStateName = atom() -  NewStateData = term() -  Timeout = int()>0 | infinity -  Reason = term() - - -

There is to be one instance of this function for each - possible state name. Whenever a gen_fsm process receives - an event sent using - send_event/2, - the instance of this function with the same name as - the current state name StateName is called to handle - the event. It is also called if a time-out occurs.

-

Event is either the atom timeout, if a time-out - has occurred, or the Event argument provided to - send_event/2.

-

StateData is the state data of the gen_fsm process.

-

If the function returns - {next_state,NextStateName,NewStateData}, - {next_state,NextStateName,NewStateData,Timeout}, or - {next_state,NextStateName,NewStateData,hibernate}, the - gen_fsm process continues executing with the current state - name set to NextStateName and with the possibly - updated state data NewStateData. For a description of - Timeout and hibernate, see - Module:init/1.

-

If the function returns {stop,Reason,NewStateData}, - the gen_fsm process calls - Module:terminate(Reason,StateName,NewStateData) and - terminates.

-
-
- - - Module:StateName(Event, From, StateData) -> Result - Handle a synchronous event. - - Event = term() - From = {pid(),Tag} - StateData = term() - Result = {reply,Reply,NextStateName,NewStateData} -   | {reply,Reply,NextStateName,NewStateData,Timeout} -   | {reply,Reply,NextStateName,NewStateData,hibernate} -   | {next_state,NextStateName,NewStateData} -   | {next_state,NextStateName,NewStateData,Timeout} -   | {next_state,NextStateName,NewStateData,hibernate} -   | {stop,Reason,Reply,NewStateData} | {stop,Reason,NewStateData} -  Reply = term() -  NextStateName = atom() -  NewStateData = term() -  Timeout = int()>0 | infinity -  Reason = normal | term() - - -

There is to be one instance of this function for each - possible state name. Whenever a gen_fsm process receives an - event sent using - sync_send_event/2,3, - the instance of this function with the same name as - the current state name StateName is called to handle - the event.

-

Event is the Event argument provided to - sync_send_event/2,3.

-

From is a tuple {Pid,Tag} where Pid is - the pid of the process that called sync_send_event/2,3 - and Tag is a unique tag.

-

StateData is the state data of the gen_fsm process.

- - -

If {reply,Reply,NextStateName,NewStateData}, - {reply,Reply,NextStateName,NewStateData,Timeout}, or - {reply,Reply,NextStateName,NewStateData,hibernate} is - returned, Reply is given back to From as the return - value of sync_send_event/2,3. The gen_fsm process - then continues executing with the current state name set to - NextStateName and with the possibly updated state data - NewStateData. For a description of Timeout and - hibernate, see - - Module:init/1.

-
- -

If {next_state,NextStateName,NewStateData}, - {next_state,NextStateName,NewStateData,Timeout}, or - {next_state,NextStateName,NewStateData,hibernate} is - returned, the gen_fsm process continues executing in - NextStateName with NewStateData. - Any reply to From must be specified explicitly using - reply/2.

-
- -

If the function returns - {stop,Reason,Reply,NewStateData}, Reply is - given back to From. If the function returns - {stop,Reason,NewStateData}, any reply to From - must be specified explicitly using reply/2. - The gen_fsm process then calls - Module:terminate(Reason,StateName,NewStateData) and - terminates.

-
-
-
-
- - - Module:terminate(Reason, StateName, StateData) - Clean up before termination. - - Reason = normal | shutdown | {shutdown,term()} | term() - StateName = atom() - StateData = term() - - -

This function is called by a gen_fsm process when it is about - to terminate. It is to be the opposite of - Module:init/1 - and do any necessary cleaning up. When it returns, the gen_fsm - process terminates with Reason. The return value is ignored. -

-

Reason is a term denoting the stop reason, - StateName is the current state name, and - StateData is the state data of the gen_fsm process.

-

Reason depends on why the gen_fsm process is - terminating. If - it is because another callback function has returned a stop - tuple {stop,..}, Reason has the value - specified in that tuple. If it is because of a failure, - Reason is the error reason.

-

If the gen_fsm process is part of a supervision tree and is - ordered by its supervisor to terminate, this function is called - with Reason=shutdown if the following conditions apply:

- - -

The gen_fsm process has been set to trap exit signals.

-
- -

The shutdown strategy as defined in the child specification of - the supervisor is an integer time-out value, not - brutal_kill.

-
-
-

Even if the gen_fsm process is not part of a - supervision tree, - this function is called if it receives an 'EXIT' - message from its parent. Reason is the same as in - the 'EXIT' message.

-

Otherwise, the gen_fsm process terminates immediately.

-

Notice that for any other reason than normal, - shutdown, or {shutdown,Term} the gen_fsm process - is assumed to terminate because of an error and an error report is - issued using - error_logger:format/2.

-
-
-
- +
- See Also -

gen_event(3), - gen_server(3), - gen_statem(3), - proc_lib(3), - supervisor(3), - sys(3)

+ + Migration to gen_statem + +

Here follows a simple example of turning a gen_fsm into + a gen_statem. The example comes + from the previous Users Guide for gen_fsm

+ + +-module(code_lock). +-define(NAME, code_lock). +%-define(BEFORE_REWRITE, true). + +-ifdef(BEFORE_REWRITE). +-behaviour(gen_fsm). +-else. +-behaviour(gen_statem). +-endif. + +-export([start_link/1, button/1, stop/0]). + +-ifdef(BEFORE_REWRITE). +-export([init/1, locked/2, open/2, handle_sync_event/4, handle_event/3, + handle_info/3, terminate/3, code_change/4]). +-else. +-export([init/1, callback_mode/0, locked/3, open/3, terminate/3, code_change/4]). +%% Add callback__mode/0 +%% Change arity of the state functions +%% Remove handle_info/3 +-endif. + +-ifdef(BEFORE_REWRITE). +start_link(Code) -> + gen_fsm:start_link({local, ?NAME}, ?MODULE, Code, []). +-else. +start_link(Code) -> + gen_statem:start_link({local,?NAME}, ?MODULE, Code, []). +-endif. + +-ifdef(BEFORE_REWRITE). +button(Digit) -> + gen_fsm:send_event(?NAME, {button, Digit}). +-else. +button(Digit) -> + gen_statem:cast(?NAME, {button,Digit}). + %% send_event is asynchronous and becomes a cast +-endif. + +-ifdef(BEFORE_REWRITE). +stop() -> + gen_fsm:sync_send_all_state_event(?NAME, stop). +-else. +stop() -> + gen_statem:call(?NAME, stop). + %% sync_send is synchronous and becomes call + %% all_state is handled by callback code in gen_statem +-endif. + +init(Code) -> + do_lock(), + Data = #{code => Code, remaining => Code}, + {ok, locked, Data}. + +-ifdef(BEFORE_REWRITE). +-else. +callback_mode() -> + state_functions. +%% state_functions mode is the mode most similar to +%% gen_fsm. There is also handle_event mode which is +%% a fairly different concept. +-endif. + +-ifdef(BEFORE_REWRITE). +locked({button, Digit}, Data0) -> + case analyze_lock(Digit, Data0) of + {open = StateName, Data} -> + {next_state, StateName, Data, 10000}; + {StateName, Data} -> + {next_state, StateName, Data} + end. +-else. +locked(cast, {button,Digit}, Data0) -> + case analyze_lock(Digit, Data0) of + {open = StateName, Data} -> + {next_state, StateName, Data, 10000}; + {StateName, Data} -> + {next_state, StateName, Data} + end; +locked({call, From}, Msg, Data) -> + handle_call(From, Msg, Data); +locked({info, Msg}, StateName, Data) -> + handle_info(Msg, StateName, Data). +%% Arity differs +%% All state events are dispatched to handle_call and handle_info help +%% functions. If you want to handle a call or cast event specifically +%% for this state you would add a special clause for it above. +-endif. + +-ifdef(BEFORE_REWRITE). +open(timeout, State) -> + do_lock(), + {next_state, locked, State}; +open({button,_}, Data) -> + {next_state, locked, Data}. +-else. +open(timeout, _, Data) -> + do_lock(), + {next_state, locked, Data}; +open(cast, {button,_}, Data) -> + {next_state, locked, Data}; +open({call, From}, Msg, Data) -> + handle_call(From, Msg, Data); +open(info, Msg, Data) -> + handle_info(Msg, open, Data). +%% Arity differs +%% All state events are dispatched to handle_call and handle_info help +%% functions. If you want to handle a call or cast event specifically +%% for this state you would add a special clause for it above. +-endif. + +-ifdef(BEFORE_REWRITE). +handle_sync_event(stop, _From, _StateName, Data) -> + {stop, normal, ok, Data}. + +handle_event(Event, StateName, Data) -> + {stop, {shutdown, {unexpected, Event, StateName}}, Data}. + +handle_info(Info, StateName, Data) -> + {stop, {shutdown, {unexpected, Info, StateName}}, StateName, Data}. +-else. +-endif. + +terminate(_Reason, State, _Data) -> + State =/= locked andalso do_lock(), + ok. +code_change(_Vsn, State, Data, _Extra) -> + {ok, State, Data}. + +%% Internal functions +-ifdef(BEFORE_REWRITE). +-else. +handle_call(From, stop, Data) -> + {stop_and_reply, normal, {reply, From, ok}, Data}. + +handle_info(Info, StateName, Data) -> + {stop, {shutdown, {unexpected, Info, StateName}}, StateName, Data}. +%% These are internal functions for handling all state events +%% and not behaviour callbacks as in gen_fsm +-endif. + +analyze_lock(Digit, #{code := Code, remaining := Remaining} = Data) -> + case Remaining of + [Digit] -> + do_unlock(), + {open, Data#{remaining := Code}}; + [Digit|Rest] -> % Incomplete + {locked, Data#{remaining := Rest}}; + _Wrong -> + {locked, Data#{remaining := Code}} + end. + +do_lock() -> + io:format("Lock~n", []). +do_unlock() -> + io:format("Unlock~n", []). +
diff --git a/lib/stdlib/doc/src/gen_server.xml b/lib/stdlib/doc/src/gen_server.xml index 662076b5f0..74fbfcc1bb 100644 --- a/lib/stdlib/doc/src/gen_server.xml +++ b/lib/stdlib/doc/src/gen_server.xml @@ -796,7 +796,6 @@ gen_server:abcast -----> Module:handle_cast/2
See Also

gen_event(3), - gen_fsm(3), gen_statem(3), proc_lib(3), supervisor(3), diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml index 5eb13db1aa..18089a8191 100644 --- a/lib/stdlib/doc/src/gen_statem.xml +++ b/lib/stdlib/doc/src/gen_statem.xml @@ -62,8 +62,8 @@

- The gen_statem behavior is intended to replace - gen_fsm for new code. + The gen_statem behavior replaces + gen_fsm in Erlang/OTP 20.0. It has the same features and adds some really useful:

@@ -78,8 +78,10 @@

The callback model(s) for gen_statem differs from the one for gen_fsm, - but it is still fairly easy to rewrite - from gen_fsm to gen_statem. + but it is still fairly easy to + + rewrite from + gen_fsm to gen_statem.

A generic state machine process (gen_statem) implemented @@ -945,7 +947,6 @@ handle_event(_, _, State, Data) -> state callback return value {next_state,NextState,NewData,Timeout} allowed like for gen_fsm's - Module:StateName/2.

timeout diff --git a/lib/stdlib/doc/src/proc_lib.xml b/lib/stdlib/doc/src/proc_lib.xml index e64b2ce18a..7939a0ef61 100644 --- a/lib/stdlib/doc/src/proc_lib.xml +++ b/lib/stdlib/doc/src/proc_lib.xml @@ -36,7 +36,7 @@ the OTP Design Principles. Specifically, the functions in this module are used by the OTP standard behaviors (for example, - gen_server, gen_fsm, and gen_statem) + gen_server and gen_statem) when starting new processes. The functions can also be used to start special processes, user-defined processes that comply to the OTP design principles. For an example, diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml index bb06d3645e..a42cfdd567 100644 --- a/lib/stdlib/doc/src/supervisor.xml +++ b/lib/stdlib/doc/src/supervisor.xml @@ -36,7 +36,6 @@ process can either be another supervisor or a worker process. Worker processes are normally implemented using one of the gen_event, - gen_fsm, gen_server, or gen_statem behaviors. A supervisor implemented using this module has @@ -237,8 +236,8 @@ child_spec() = #{id => child_id(), % mandatory

modules 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 - supervisor, gen_server, - gen_statem, or gen_fsm, + supervisor, gen_server or, + gen_statem, this is to be a list with one element [Module], where Module is the callback module. If the child process is an event manager (gen_event) with a @@ -706,7 +705,6 @@ child_spec() = #{id => child_id(), % mandatory

See Also

gen_event(3), - gen_fsm(3), gen_statem(3), gen_server(3), sys(3)

diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml index 45171f814d..78840aaaf3 100644 --- a/lib/stdlib/doc/src/sys.xml +++ b/lib/stdlib/doc/src/sys.xml @@ -166,12 +166,6 @@ process, the returned State is the state of the callback module.

- -

For a - gen_fsm - process, State is the tuple - {CurrentStateName, CurrentStateData}.

-

For a gen_statem @@ -222,7 +216,7 @@

Function system_get_state/1 is primarily useful for user-defined behaviors and modules that implement OTP special processes. - The gen_server, gen_fsm, + The gen_server, gen_statem, and gen_event OTP behavior modules export this function, so callback modules for those behaviors need not to supply their own.

@@ -245,11 +239,6 @@

A gen_server process returns the state of the callback module.

- -

A gen_fsm - process returns information, such as its current - state name and state data.

-

A gen_statem process returns information, such as its current @@ -262,14 +251,12 @@

Callback modules for gen_server, - gen_fsm, gen_statem, and gen_event + gen_statem, and gen_event can also change the value of Misc by exporting a function format_status/2, which contributes module-specific information. For details, see gen_server:format_status/2, - - gen_fsm:format_status/2, gen_statem:format_status/2, and @@ -372,13 +359,6 @@ module and NewState is a new instance of that state.

- -

For a gen_fsm process, - State is the tuple {CurrentStateName, - CurrentStateData}, and NewState is a - similar tuple, which can contain - a new state name, new state data, or both.

-

For a gen_statem process, State is the @@ -422,7 +402,7 @@ return its State argument.

If a StateFun function crashes or throws an exception, the original state of the process is unchanged for - gen_server, gen_fsm, and gen_statem processes. + gen_server, and gen_statem processes. For gen_event processes, a crashing or failing StateFun function means that only the state of the particular event handler it was @@ -462,7 +442,7 @@ user-defined behaviors and modules that implement OTP special processes. The OTP behavior modules gen_server, - gen_fsm, gen_statem, and gen_event + gen_statem, and gen_event export this function, so callback modules for those behaviors need not to supply their own.

diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl index e925a75fe8..0c76e97741 100644 --- a/lib/stdlib/src/gen_fsm.erl +++ b/lib/stdlib/src/gen_fsm.erl @@ -124,6 +124,26 @@ system_replace_state/2, format_status/2]). +-deprecated({start, 3, next_major_release}). +-deprecated({start, 4, next_major_release}). +-deprecated({start_link, 3, next_major_release}). +-deprecated({start_link, 4, next_major_release}). +-deprecated({stop, 1, next_major_release}). +-deprecated({stop, 3, next_major_release}). +-deprecated({send_event, 2, next_major_release}). +-deprecated({sync_send_event, 2, next_major_release}). +-deprecated({sync_send_event, 3, next_major_release}). +-deprecated({send_all_state_event, 2, next_major_release}). +-deprecated({sync_send_all_state_event, 2, next_major_release}). +-deprecated({sync_send_all_state_event, 3, next_major_release}). +-deprecated({reply, 2, next_major_release}). +-deprecated({start_timer, 2, next_major_release}). +-deprecated({send_event_after, 2, next_major_release}). +-deprecated({cancel_timer, 1, next_major_release}). +-deprecated({enter_loop, 4, next_major_release}). +-deprecated({enter_loop, 5, next_major_release}). +-deprecated({enter_loop, 6, next_major_release}). + -import(error_logger, [format/2]). %%% --------------------------------------------------- diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl index d89ff4a624..42094e3088 100644 --- a/lib/stdlib/src/otp_internal.erl +++ b/lib/stdlib/src/otp_internal.erl @@ -55,6 +55,55 @@ obsolete_1(erlang, now, 0) -> obsolete_1(calendar, local_time_to_universal_time, 1) -> {deprecated, {calendar, local_time_to_universal_time_dst, 1}}; +%% *** STDLIB added in OTP 20 *** + +obsolete_1(gen_fsm, start, 3) -> + {deprecated, {gen_statem, start, 3}}; +obsolete_1(gen_fsm, start, 4) -> + {deprecated, {gen_statem, start, 4}}; + +obsolete_1(gen_fsm, start_link, 3) -> + {deprecated, {gen_statem, start, 3}}; +obsolete_1(gen_fsm, start_link, 4) -> + {deprecated, {gen_statem, start, 4}}; + +obsolete_1(gen_fsm, stop, 1) -> + {deprecated, {gen_statem, stop, 1}}; +obsolete_1(gen_fsm, stop, 3) -> + {deprecated, {gen_statem, stop, 3}}; + +obsolete_1(gen_fsm, enter_loop, 4) -> + {deprecated, {gen_statem, enter_loop, 4}}; +obsolete_1(gen_fsm, enter_loop, 5) -> + {deprecated, {gen_statem, enter_loop, 5}}; +obsolete_1(gen_fsm, enter_loop, 6) -> + {deprecated, {gen_statem, enter_loop, 6}}; + +obsolete_1(gen_fsm, reply, 2) -> + {deprecated, {gen_statem, reply, 2}}; + +obsolete_1(gen_fsm, send_event, 2) -> + {deprecated, {gen_statem, cast, 1}}; +obsolete_1(gen_fsm, send_all_state_event, 2) -> + {deprecated, {gen_statem, cast, 1}}; + +obsolete_1(gen_fsm, sync_send_event, 2) -> + {deprecated, {gen_statem, call, 2}}; +obsolete_1(gen_fsm, sync_send_event, 3) -> + {deprecated, {gen_statem, call, 3}}; + +obsolete_1(gen_fsm, sync_send_all_state_event, 2) -> + {deprecated, {gen_statem, call, 2}}; +obsolete_1(gen_fsm, sync_send_all_state_event, 3) -> + {deprecated, {gen_statem, call, 3}}; + +obsolete_1(gen_fsm, start_timer, 2) -> + {deprecated, {erlang, start_timer, 2}}; +obsolete_1(gen_fsm, cancel_timer, 1) -> + {deprecated, {erlang, cancel_timer, 1}}; +obsolete_1(gen_fsm, send_event_after, 2) -> + {deprecated, {erlang, send_after, 2}}; + %% *** CRYPTO added in OTP 20 *** obsolete_1(crypto, rand_uniform, 2) -> diff --git a/system/doc/design_principles/fsm.xml b/system/doc/design_principles/fsm.xml deleted file mode 100644 index 4f2b75e6e8..0000000000 --- a/system/doc/design_principles/fsm.xml +++ /dev/null @@ -1,338 +0,0 @@ - - - - -
- - 19972016 - Ericsson AB. All Rights Reserved. - - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - - gen_fsm Behaviour - - - - - fsm.xml -
- - -

- There is a new behaviour - gen_statem - that is intended to replace gen_fsm for new code. - It has the same features and add some really useful. - This module will not be removed for the foreseeable future - to keep old state machine implementations running. -

-
-

This section is to be read with the gen_fsm(3) manual page - in STDLIB, where all interface functions and callback - functions are described in detail.

- -
- Finite-State Machines -

A Finite-State Machine (FSM) can be described as a set of - relations of the form:

-
-State(S) x Event(E) -> Actions(A), State(S')
-

These relations are interpreted as meaning:

- -

If we are in state S and event E occurs, we - are to perform actions A and make a transition to - state S'.

-
-

For an FSM implemented using the gen_fsm behaviour, - the state transition rules are written as a number of Erlang - functions, which conform to the following convention:

-
-StateName(Event, StateData) ->
-    .. code for actions here ...
-    {next_state, StateName', StateData'}
-
- -
- Example -

A door with a code lock can be viewed as an FSM. Initially, - the door is locked. Anytime someone presses a button, this - generates an event. Depending on what buttons have been pressed - before, the sequence so far can be correct, incomplete, or wrong.

-

If it is correct, the door is unlocked for 30 seconds (30,000 ms). - If it is incomplete, we wait for another button to be pressed. If - it is is wrong, we start all over, waiting for a new button - sequence.

-

Implementing the code lock FSM using gen_fsm results in - the following callback module:

- - - gen_fsm:start_link({local, code_lock}, code_lock, lists:reverse(Code), []). - -button(Digit) -> - gen_fsm:send_event(code_lock, {button, Digit}). - -init(Code) -> - {ok, locked, {[], Code}}. - -locked({button, Digit}, {SoFar, Code}) -> - case [Digit|SoFar] of - Code -> - do_unlock(), - {next_state, open, {[], Code}, 30000}; - Incomplete when length(Incomplete) - {next_state, locked, {Incomplete, Code}}; - _Wrong -> - {next_state, locked, {[], Code}} - end. - -open(timeout, State) -> - do_lock(), - {next_state, locked, State}.]]> -

The code is explained in the next sections.

-
- -
- Starting gen_fsm -

In the example in the previous section, the gen_fsm is - started by calling code_lock:start_link(Code):

- -start_link(Code) -> - gen_fsm:start_link({local, code_lock}, code_lock, lists:reverse(Code), []). - -

start_link calls the function gen_fsm:start_link/4, - which spawns and links to a new process, a gen_fsm.

- - -

The first argument, {local, code_lock}, specifies - the name. In this case, the gen_fsm is locally - registered as code_lock.

-

If the name is omitted, the gen_fsm is not registered. - Instead its pid must be used. The name can also be given - as {global, Name}, in which case the gen_fsm is - registered using global:register_name/2.

-
- -

The second argument, code_lock, is the name of - the callback module, that is, the module where the callback - functions are located.

-

The interface functions (start_link and button) - are then located in the same module as the callback - functions (init, locked, and open). This - is normally good programming practice, to have the code - corresponding to one process contained in one module.

-
- -

The third argument, Code, is a list of digits that - which is passed reversed to the callback function init. - Here, init - gets the correct code for the lock as indata.

-
- -

The fourth argument, [], is a list of options. See - the gen_fsm(3) manual page for available options.

-
-
-

If name registration succeeds, the new gen_fsm process calls - the callback function code_lock:init(Code). This function - is expected to return {ok, StateName, StateData}, where - StateName is the name of the initial state of the - gen_fsm. In this case locked, assuming the door is - locked to begin with. StateData is the internal state of - the gen_fsm. (For gen_fsm, the internal state is - often referred to 'state data' to - distinguish it from the state as in states of a state machine.) - In this case, the state data is the button sequence so far (empty - to begin with) and the correct code of the lock.

- -init(Code) -> - {ok, locked, {[], Code}}. -

gen_fsm:start_link is synchronous. It does not return until - the gen_fsm has been initialized and is ready to - receive notifications.

-

gen_fsm:start_link must be used if the gen_fsm is - part of a supervision tree, that is, started by a supervisor. There - is another function, gen_fsm:start, to start a standalone - gen_fsm, that is, a gen_fsm that is not part of a - supervision tree.

-
- -
- Notifying about Events -

The function notifying the code lock about a button event is - implemented using gen_fsm:send_event/2:

- -button(Digit) -> - gen_fsm:send_event(code_lock, {button, Digit}). -

code_lock is the name of the gen_fsm and must - agree with the name used to start it. - {button, Digit} is the actual event.

-

The event is made into a message and sent to the gen_fsm. - When the event is received, the gen_fsm calls - StateName(Event, StateData), which is expected to return a - tuple {next_state,StateName1,StateData1}. - StateName is the name of the current state and - StateName1 is the name of the next state to go to. - StateData1 is a new value for the state data of - the gen_fsm.

- - case [Digit|SoFar] of - Code -> - do_unlock(), - {next_state, open, {[], Code}, 30000}; - Incomplete when length(Incomplete) - {next_state, locked, {Incomplete, Code}}; - _Wrong -> - {next_state, locked, {[], Code}}; - end. - -open(timeout, State) -> - do_lock(), - {next_state, locked, State}.]]> -

If the door is locked and a button is pressed, the complete - button sequence so far is compared with the correct code for - the lock and, depending on the result, the door is either unlocked - and the gen_fsm goes to state open, or the door - remains in state locked.

-
- -
- Time-Outs -

When a correct code has been given, the door is unlocked and - the following tuple is returned from locked/2:

- -{next_state, open, {[], Code}, 30000}; -

30,000 is a time-out value in milliseconds. After this time, - that is, 30 seconds, a time-out occurs. Then, - StateName(timeout, StateData) is called. The time-out - then occurs when the door has been in state open for 30 - seconds. After that the door is locked again:

- -open(timeout, State) -> - do_lock(), - {next_state, locked, State}. -
- -
- All State Events -

Sometimes an event can arrive at any state of the gen_fsm. - Instead of sending the message with gen_fsm:send_event/2 - and writing one clause handling the event for each state function, - the message can be sent with gen_fsm:send_all_state_event/2 - and handled with Module:handle_event/3:

- --module(code_lock). -... --export([stop/0]). -... - -stop() -> - gen_fsm:send_all_state_event(code_lock, stop). - -... - -handle_event(stop, _StateName, StateData) -> - {stop, normal, StateData}. -
- -
- Stopping - -
- In a Supervision Tree -

If the gen_fsm is part of a supervision tree, no stop - function is needed. The gen_fsm is automatically - terminated by its supervisor. Exactly how this is done is - defined by a - shutdown strategy - set in the supervisor.

-

If it is necessary to clean up before termination, the shutdown - strategy must be a time-out value and the gen_fsm must be - set to trap exit signals in the init function. When ordered - to shutdown, the gen_fsm then calls the callback function - terminate(shutdown, StateName, StateData):

- -init(Args) -> - ..., - process_flag(trap_exit, true), - ..., - {ok, StateName, StateData}. - -... - -terminate(shutdown, StateName, StateData) -> - ..code for cleaning up here.. - ok. -
- -
- Standalone gen_fsm -

If the gen_fsm is not part of a supervision tree, a stop - function can be useful, for example:

- -... --export([stop/0]). -... - -stop() -> - gen_fsm:send_all_state_event(code_lock, stop). -... - -handle_event(stop, _StateName, StateData) -> - {stop, normal, StateData}. - -... - -terminate(normal, _StateName, _StateData) -> - ok. -

The callback function handling the stop event returns a - tuple, {stop,normal,StateData1}, where normal - specifies that it is a normal termination and StateData1 - is a new value for the state data of the gen_fsm. This - causes the gen_fsm to call - terminate(normal,StateName,StateData1) and then - it terminates gracefully:

-
-
- -
- Handling Other Messages -

If the gen_fsm is to be able to receive other messages - than events, the callback function - handle_info(Info, StateName, StateData) must be implemented - to handle them. Examples of - other messages are exit messages, if the gen_fsm is linked to - other processes (than the supervisor) and trapping exit signals.

- -handle_info({'EXIT', Pid, Reason}, StateName, StateData) -> - ..code to handle exits here.. - {next_state, StateName1, StateData1}. -

The code_change method must also be implemented.

- -code_change(OldVsn, StateName, StateData, Extra) -> - ..code to convert state (and more) during code change - {ok, NextStateName, NewStateData} -
-
- diff --git a/system/doc/design_principles/part.xml b/system/doc/design_principles/part.xml index 6495211e04..d52070a674 100644 --- a/system/doc/design_principles/part.xml +++ b/system/doc/design_principles/part.xml @@ -30,7 +30,6 @@ - diff --git a/system/doc/design_principles/spec_proc.xml b/system/doc/design_principles/spec_proc.xml index 5b156ac263..d663c5df79 100644 --- a/system/doc/design_principles/spec_proc.xml +++ b/system/doc/design_principles/spec_proc.xml @@ -45,61 +45,63 @@

The sys module has functions for simple debugging of processes implemented using behaviours. The code_lock example from - gen_fsm Behaviour + gen_statem Behaviour is used to illustrate this:

-% erl
-Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0]
+Erlang/OTP 20 [DEVELOPMENT] [erts-9.0] [source-5ace45e] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:10] [hipe] [kernel-poll:false]
 
-Eshell V5.2.3.6  (abort with ^G)
-1> code_lock:start_link([1,2,3,4]).
-{ok,<0.32.0>}
-2> sys:statistics(code_lock, true).
+Eshell V9.0  (abort with ^G)
+1>  code_lock:start_link([1,2,3,4]).
+Lock
+{ok,<0.63.0>}
+2> sys:statistics(code_lock, true).
 ok
-3> sys:trace(code_lock, true).
+3>  sys:trace(code_lock, true).
 ok
-4> code_lock:button(4).
-*DBG* code_lock got event {button,4} in state closed
+4>  code_lock:button(1).
+*DBG* code_lock receive cast {button,1} in state locked
 ok
-*DBG* code_lock switched to state closed
-5> code_lock:button(3).
-*DBG* code_lock got event {button,3} in state closed
+*DBG* code_lock consume cast {button,1} in state locked
+5>  code_lock:button(2).
+*DBG* code_lock receive cast {button,2} in state locked
 ok
-*DBG* code_lock switched to state closed
-6> code_lock:button(2).
-*DBG* code_lock got event {button,2} in state closed
+*DBG* code_lock consume cast {button,2} in state locked
+6>  code_lock:button(3).
+*DBG* code_lock receive cast {button,3} in state locked
 ok
-*DBG* code_lock switched to state closed
-7> code_lock:button(1).
-*DBG* code_lock got event {button,1} in state closed
+*DBG* code_lock consume cast {button,3} in state locked
+7>  code_lock:button(4).
+*DBG* code_lock receive cast {button,4} in state locked
 ok
-OPEN DOOR
-*DBG* code_lock switched to state open
-*DBG* code_lock got event timeout in state open
-CLOSE DOOR
-*DBG* code_lock switched to state closed
-8> sys:statistics(code_lock, get). 
-{ok,[{start_time,{{2003,6,12},{14,11,40}}},
-     {current_time,{{2003,6,12},{14,12,14}}},
-     {reductions,333},
+Unlock
+*DBG* code_lock consume cast {button,4} in state locked
+*DBG* code_lock receive state_timeout lock in state open
+Lock
+*DBG* code_lock consume state_timeout lock in state open
+8> sys:statistics(code_lock, get).
+{ok,[{start_time,{{2017,4,21},{16,8,7}}},
+     {current_time,{{2017,4,21},{16,9,42}}},
+     {reductions,2973},
      {messages_in,5},
      {messages_out,0}]}
-9> sys:statistics(code_lock, false).
+9> sys:statistics(code_lock, false).
 ok
-10> sys:trace(code_lock, false).     
+10> sys:trace(code_lock, false).
 ok
-11> sys:get_status(code_lock).
-{status,<0.32.0>,
-        {module,gen_fsm},
-        [[{'$ancestors',[<0.30.0>]},
-          {'$initial_call',{gen,init_it,
-                                [gen_fsm,<0.30.0>,<0.30.0>,
-                                 {local,code_lock},
-                                 code_lock,
-                                 [1,2,3,4],
-                                 []]}}],
-         running,<0.30.0>,[],
-         [code_lock,closed,{[],[1,2,3,4]},code_lock,infinity]]}
+11> sys:get_status(code_lock). +{status,<0.63.0>, + {module,gen_statem}, + [[{'$initial_call',{code_lock,init,1}}, + {'$ancestors',[<0.61.0>]}], + running,<0.61.0>,[], + [{header,"Status for state machine code_lock"}, + {data,[{"Status",running}, + {"Parent",<0.61.0>}, + {"Logged Events",[]}, + {"Postponed",[]}]}, + {data,[{"State", + {locked,#{code => [1,2,3,4],remaining => [1,2,3,4]}}}]}]]} +
diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml index 478d1bf714..4fd210aa48 100644 --- a/system/doc/design_principles/sup_princ.xml +++ b/system/doc/design_principles/sup_princ.xml @@ -276,7 +276,6 @@ child_spec() = #{id => child_id(), % mandatory supervisor:start_link gen_server:start_link - gen_fsm:start_link gen_statem:start_link gen_event:start_link A function compliant with these functions. For details, @@ -341,7 +340,7 @@ child_spec() = #{id => child_id(), % mandatory

modules are to be a list with one element [Module], where Module is the name of the callback module, if the child process is a supervisor, - gen_server, gen_fsm or gen_statem. + gen_server, gen_statem. If the child process is a gen_event, the value shall be dynamic.

This information is used by the release handler during diff --git a/system/doc/design_principles/xmlfiles.mk b/system/doc/design_principles/xmlfiles.mk index e476255d62..8877e94f39 100644 --- a/system/doc/design_principles/xmlfiles.mk +++ b/system/doc/design_principles/xmlfiles.mk @@ -24,7 +24,6 @@ DESIGN_PRINCIPLES_CHAPTER_FILES = \ des_princ.xml \ distributed_applications.xml \ events.xml \ - fsm.xml \ statem.xml \ gen_server_concepts.xml \ included_applications.xml \ diff --git a/system/doc/reference_manual/modules.xml b/system/doc/reference_manual/modules.xml index 96968b547e..6fe6680c84 100644 --- a/system/doc/reference_manual/modules.xml +++ b/system/doc/reference_manual/modules.xml @@ -143,7 +143,6 @@ fact(0) -> % | standard behaviours:

gen_server - gen_fsm gen_statem gen_event supervisor -- cgit v1.2.1