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 --- system/doc/design_principles/fsm.xml | 338 ----------------------------------- 1 file changed, 338 deletions(-) delete mode 100644 system/doc/design_principles/fsm.xml (limited to 'system/doc/design_principles/fsm.xml') 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} -
-
- -- cgit v1.2.3