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 ++ 8 files changed, 253 insertions(+), 955 deletions(-) (limited to 'lib') 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) -> -- cgit v1.2.3