gen_fsm(3)

MODULE
gen_fsm - A Finite State Machine Behaviour

DESCRIPTION

This module provides a standard way of writing Finite State Machine (FSM) processes. All FSMs written as gen_fsms share a common set of interface functions. The generic parts of the FSM contains functions for debugging, for handling the termination of the parent process, and for presentation of illustrative error information if something goes wrong in the process.

The state of the FSM is defined by two parameters, the StateName and the StateData. For each StateName, there must be a corresponding function exported from the call-back module. When an event is received, and the current state of the FSM is StateName, Module:StateName(Event, StateData) is called. This function should return the next state, which is the next StateName.

It is also possible to define a function Module:handle_event(Event, StateName, StateData) to take care of events which should always be handled, regardless of their state. This function is called when gen_fsm:send_all_state_event/2 is used to generate an event.

Events can be handled synchronously as well. This means that the caller waits for a reply to the event.

The relationship between the generic interface functions (and received messages) and the callback functions can be illustrated as follows:
Callback module                            gen_fsm
----------------                            -------
gen_fsm:start_link                 ----->   start a new fsm process
Module:init/1                     <-----
                                            looping
gen_fsm:send_event                ----->
Module:StateName/2                <-----
gen_fsm:sync_send_event           ----->
Module:StateName/3                <-----
gen_fsm:send_all_state_event      ----->
Module:handle_event/3             <-----
gen_fsm:sync_send_all_state_event ----->
Module:handle_sync_event/4        <-----
Module:handle_info/3              <-----     other message
                                             received.
Module:terminate/3                <-----     clean up before
                                             termination.

  Note:

Trapping of exits, if required, must be done explicitly.

An instance of the gen_fsm behaviour can be debugged by using the module sys.

EXPORTS

start(Module, StartArgs, Options) -> StartRet
start_link(Module, StartArgs, Options) -> StartRet
start(Name, Module, StartArgs, Options) -> StartRet
start_link(Name, Module, StartArgs, Options) -> StartRet

    Types
        Name = {local, atom()} | {global, atom()}
        Module = atom()
        StartArgs = term()
        Options = [Opt]
        Opt = {debug, [Dbg]} | {timeout, Time}
        Dbg = trace | log | statistics | {log_to_file, FileName} | {install, {Func, FuncState}}
        StartRet = {ok, Pid} | ignore | {error, Reason}
        Pid = pid()
        Reason = {already_started, Pid} | term()

    Starts an FSM process. An anonymous process is started if Name is not specified. This process can only be called by using the returned Pid identifier.

    A process which is started with start does not care about the parent, which means that the parent is not handled explicitly in the generic process part. If started in this manner, this function must not be used if the FSM is a worker in a supervision tree.

    A process started with start_link is initially linked to the caller - the parent - and will terminate whenever the parent process terminates, and with the same reason as the parent. If started in this manner, this function should be used if the FSM is a worker in a supervision tree.

    The function Module:init(StartArgs) is called (see below).

    Time specifies how long time, in milliseconds, the server is allowed to initialize itself.

    The debug options are described in sys(3).

send_event(ProcessRef,Event) -> void()

    Types
        ProcessRef = Name | {Name, Node} | {global, Name} | pid()
        Name = atom()
        Node = atom()
        Event = term()

    Sends an event asynchronously to the FSM process. In the callback module, the function StateName/2 is called, where StateName is the name of the current state.

send_all_state_event(ProcessRef,Event) -> void()

    Types
        ProcessRef = Name | {Name, Node} | {global, Name} | pid()
        Name = atom()
        Node = atom()
        Event = term()

    An event, which can be handled in all states, is sent asynchronously to the FSM process. In the callback module, handle_event/3 is called.

sync_send_event(ProcessRef,Event) -> Reply
sync_send_event(ProcessRef,Event, Timeout) -> Reply

    Types
        ProcessRef = Name | {Name, Node} | {global, Name} | pid()
        Name = atom()
        Node = atom()
        Event = term()
        Timeout = int() > 0 | infinity
        Reply = term()

    Sends an event synchronously to the FSM process and waits for the answer. In the callback module, the function StateName/3 is called, where StateName is the name of the current state.

    Timeout should be set to some reasonable value. The special value infinity can be used if the user has no idea how long the request is supposed to take. The default is 5000.

    If Timeout has an integer value and if no response has been delivered within Timeout milliseconds, the client will terminate with reason {timeout, {gen_fsm, sync_send_event, [ProcessRef, Event, Timeout]}}.

sync_send_all_state_event(ProcessRef,Event) -> Reply
sync_send_all_state_event(ProcessRef,Event,Timeout) -> Reply

    Types
        ProcessRef = Name | {Name, Node} | {global, Name} | pid()
        Name = atom()
        Node = atom()
        Event = term()
        Timeout = int() > 0 | infinity
        Reply = term()

    An event, which can be handled in all states, is sent synchronously to the FSM process. In the callback module, handle_event/4 is called.

    Timeout should be set to some reasonable value. The special value infinity can be used if the user has no idea how long the request is supposed to take. The default is 5000.

    If Timeout has an integer value and no response has been delivered within Timeout milliseconds, the client will terminate with reason {timeout, {gen_fsm, sync_send_all_state_event, [ProcessRef, Event, Timeout]}}.

reply(To, Reply) -> true

    Types
        To = {pid(), Tag}
        Tag = term()
        Reply = term()

    If a reply can not be returned immediately - as the return value of Module:StateName/3 or Module:handle_sync_event/4 - this function can be used to make an explicit reply. To has the same value as the From argument in these functions.

Callback Functions

The following functions should be exported from a gen_fsm callback module.

EXPORTS

Module:init(StartArgs) -> Return

    Types
        StartArgs = term()
        StateName = atom()
        StateData = term()
        Timeout = int() > 0 | infinity
        StopReason = term()
        Return = {ok, StateName, StateData} | {ok, StateName, StateData, Timeout} | ignore | {stop, StopReason}

    This function initializes the FSM process and returns the initial state. The Timeout variable specifies that the process shall wait for Timeout milliseconds for the first message. If no message has arrived within the specified time, Module:StateName(timeout, StateData) is called.

    The StartArgs argument supplied to the init/1 function is the same as the argument supplied to the gen_fsm:start functions.

    If the process should trap exits, this has to be explicitly expressed here with process_flag(trap_exit, true).

    The representation of the FSM StateData is an implementation specific detail which has to be decided by the designer of the FSM. It can be any Erlang term. StateData will be visible as an argument to all callback functions. To change something in StateData, a new value is returned from the callback function using the terms described below.

    If the initializing procedure fails, the reason is supplied as StopReason with the {stop, StopReason} return value.

    This function can return ignore in order to inform the parent, especially if it is a supervisor, that the FSM, as an example, has not started in accordance with the configuration data.

Module:StateName(Event, StateData) -> Return

    Types
        Event = term()
        StateData = term()
        Return = {next_state, NextStateName, NextStateData} | {next_state, NextStateName, NextStateData, Timeout} | {stop, Reason, NewStateData}
        NextStateName = atom()
        NextStateData = term()
        Reason = normal | shutdown | term()

    Handles events in the state StateName. The Timeout variable is as in Module:init/1 above.

    Whenever the function gen_fsm:send_event is called, this function is called to handle the event. If the FSM times out, this function is also called with Event = timeout.

    Event is the same term as supplied in the above client call.

    If the FSM decides to terminate, this function should return {stop, Reason, NewStateData}, and the function Module:terminate(Reason, StateName, NewStateData) is called. If Reason is something other than normal or shutdown, the FSM is assumed to have terminated with a runtime failure. In this case, a lot of information about the failure is reported. The atom normal causes a normal termination while shutdown causes an abnormal, but faultless, termination of the process.

Module:StateName(Event, From, StateData) -> Return

    Types
        Event = term()
        From = {pid(), Tag}
        StateData = term()
        Return = {next_state, NextStateName, NextStateData} | {next_state, NextStateName, NextStateData, Timeout} | {reply, Reply, NextStateName, NextStateData} | {reply, Reply, NextStateName, NextStateData, Timeout} | {stop, Reason, NewStateData} | {stop, Reason, Reply, NewStateData}
        NextStateName = atom()
        NextStateData = term()
        Reply = term()
        Reason = normal | shutdown | term()

    Handles synchronous events in the state StateName. The Timeout variable is as in Module:init/1 above.

    Whenever the function gen_fsm:sync_send_event/2, 3 is called, this function is called to handle the event.

    Event is the same as the term supplied with the above client call.

    The FSM decides if a reply is sent to the caller directly ({reply, ...}), indirectly ({next_state, ...}), or if the FSM has to terminate ({stop, ...}) as a result of the request. If {next_state, ...} is returned, a reply can be sent to the caller using the reply/2 function.

    If the FSM decides to terminate, this function returns {stop, Reason, NewStateData} or {stop, Reason, Reply, NewStateData}, and the function Module:terminate(Reason, StateName, NewStateData) is called. If Reason is something other than normal or shutdown, the FSM is assumed to have terminated with a runtime failure. In this case, a lot of information about the failure is reported. The atom normal causes a normal termination while shutdown causes an abnormal, but faultless, termination of the process.

Module:handle_event(Event, StateName, StateData) -> Return

    Types
        Event = term()
        StateName = atom()
        StateData = term()

    Handles events generated with the function gen_fsm:send_all_state_event/2.

    The Return value is the same as for Module:StateName/2.

Module:handle_sync_event(Event, From, StateName, StateData) -> Return

    Types
        Event = term()
        From = {pid(), Tag}
        StateName = atom()
        StateData = term()

    Handles events generated with the function gen_fsm:sync_send_all_state_event/2, 3.

    The Return value is the same as for Module:StateName/3.

Module:handle_info(Info, StateName, StateData) -> Return

    Types
        Info = term()
        StateName = atom()
        StateData = term()

    This function receives all messages sent to this process which are not generated by gen_fsm:send_event/2, gen_fsm:send_all_state_event/2, gen_fsm:sync_send_event/2, 3, or gen_fsm:sync_send_all_state_event/2, 3. Typical messages handled here include:

        {'EXIT', Pid, Reason}:
            If the process traps exit signals, the corresponding messages are handled here.

        {nodedown, Node}:
            If another Erlang node is monitored, the corresponding nodedown message is handled here.

        Msg:
            All other messages sent to the process using Fsm ! Msg are also handled here.

  Note:

Communication with the FSM should always go through the interface functions described above.

The Return value is the same as for Module:StateName/2.

Module:terminate(Reason, StateName, StateData) -> void()

    Types
        Reason = term()
        StateName = atom()
        StateData = term()

    This callback function is called whenever the FSM is about to terminate. Either one of the above callback functions have returned {stop, StopReason, ...}, in which case Reason is equal to StopReason; or some other fault has been caught. Reason is any term which describes the termination reason. If the FSM traps exits, the terminate function is called if the FSM's parent (normally a supervisor) dies or orders the FSM to die. If the FSM does not trap exits, it dies immediately if the parent dies.

    With this function, the FSM can clean up before the process terminates. It can, for example, de-allocate external resources.

    The termination reason cannot be changed here. The FSM will terminate due toReason regardless of what was returned from this function.

Module:code_change(OldVsn, StateName, StateData, Extra) -> {ok, NewState, NewStateData}

    Types
        OldVsn = undefined | term()
        StateName = atom()
        StateData = term()
        Extra = term()
        NewStateName = atom()
        NewStateData = term()

    This function is called when a code change is performed, which implies that the internal data structures of the FSM have changed. The function is supposed to convert the old state to the new one. OldVsn is the vsn attribute of the old version of the module. If no such attribute was defined, the atom undefined is sent. Extra is an optional term, typically defined in the release upgrade script.

System events

The gen_fsm behaviour generates the following system events, handled by the sys module:

    *   {in, Msg} when a message is received.

    *   {out, Msg, To, StateName} when a message is sent.

    *   return when an event handling callback function returns.

See Also

sys(3)

AUTHOR
Martin Bjorklund - mbj@erlang.ericsson.se