gen_fsm:send_after | start_timer

Sean Hinde <>
Mon Jul 9 14:20:39 CEST 2001


Hi,

Anyone else think it would be useful to extend gen_fsm to have it's own
state aware timer functionality?

At the moment all timers sent with erlang:send_after or erlang:start_timer
arrive in handle_info rather than in the callback for the current state. I
find that handle_info becomes very large and unwieldy with more than a
couple of timers running and 4 or more states..

Usage would be something like:

%%----------------------------------------------------------------------
%% Func: init/1
%% Returns: {ok, StateName, StateData}          |
%%          {ok, StateName, StateData, Timeout} |
%%          ignore                              |
%%          {stop, StopReason}                   
%%----------------------------------------------------------------------
init([]) ->
    gen_fsm:start_timer(2000, "Hello from init"),
    {ok, state1, #state{}}.

%%----------------------------------------------------------------------
%% Func: StateName/2
%% Returns: {next_state, NextStateName, NextStateData}          |
%%          {next_state, NextStateName, NextStateData, Timeout} |
%%          {stop, Reason, NewStateData}                         
%%----------------------------------------------------------------------
state1(Event, StateData) ->
    gen_fsm:start_timer(2000, "Hello from state 1"),
    io:format("SH:~p~n",[Event]),
    {next_state, state2, StateData}.

state2(Event, StateData) ->
    io:format("SH:~p~n",[Event]),
    gen_fsm:send_after(2000, "Hello from state 2"),
    {next_state, state1, StateData}.

Possible implementation follows as a diff -c:

*** /opt/rcs/5.0.2.5/lib/stdlib-1.9.4/src/gen_fsm.erl   Thu Jun  7 15:04:40
2001
--- gen_fsm.erl Mon Jul  9 13:14:09 2001

***************

*** 110,115 ****

--- 110,117 ----

         sync_send_all_state_event/2, sync_send_all_state_event/3,

         reply/2]).

 

+ -export([start_timer/2, send_after/2]).

+

  %% Internal exports

  -export([init_it/6, print_event/3,

         system_continue/3,

***************

*** 199,204 ****

--- 201,217 ----

                           [Name, Event, Timeout]}})

      end.

 

+ %% Designed to be only callable within one of the callbacks

+ %% hence using the self() of this instance of the process.

+ %% This is to ensure that timers don't go astray in global

+ %% e.g. when straddling a failover, or turn up in a restarted

+ %% instance of the process.

+ start_timer(Time, Msg) ->

+     erlang:start_timer(Time, self(), {'$gen_fsm_timer', Msg}).

+

+ send_after(Time, Msg) ->

+     erlang:send_after(Time, self(), {'$gen_fsm_timer', Msg}).

+

  %%% ---------------------------------------------------

  %%% Initiate the new process.

  %%% Register the name using the Rfunc function

***************

*** 288,293 ****

--- 301,314 ----

            io:format(Dev,

                      "*DBG* ~p got all_state_event ~p in state ~w~n",

                      [Name, Event, StateName]);

+       {'$gen_fsm_timer', Msg} ->

+           io:format(Dev,

+                     "*DBG* ~p got timer ~p in state ~w~n",

+                     [Name, Msg, StateName]);

+       {timeout, Ref, {'$gen_fsm_timer', Msg}} ->

+           io:format(Dev,

+                     "*DBG* ~p got timer ~p in state ~w~n",

+                     [Name, {timeout, Ref, Msg}, StateName]);

        _ ->

            io:format(Dev, "*DBG* ~p got ~p in state ~w~n",

                      [Name, Msg, StateName])

***************

*** 367,372 ****

--- 388,397 ----

  dispatch({'$gen_sync_all_state_event', From, Event},

         Mod, StateName, StateData) ->

      apply(Mod, handle_sync_event, [Event, From, StateName, StateData]);

+ dispatch({'$gen_fsm_timer', Msg}, Mod, StateName, StateData) ->

+     apply(Mod, StateName, [Msg, StateData]);

+ dispatch({timeout, Ref, {'$gen_fsm_timer', Msg}}, Mod, StateName,
StateData) -
>

+     apply(Mod, StateName, [{timeout, Ref, Msg}, StateData]);

  dispatch(Info, Mod, StateName, StateData) ->

      apply(Mod, handle_info, [Info, StateName, StateData]).

 

***************

*** 423,428 ****

--- 448,457 ----

      "** Last event in was ~p (for all states)~n";

  get_msg_str({'$gen_sync_all_state_event', Event}) ->

      "** Last sync event in was ~p (for all states)~n";

+ get_msg_str({'$gen_fsm_timer', Msg}) ->

+     "** Last timer event in was ~p~n";

+ get_msg_str({timeout, Ref, {'$gen_fsm_timer', Msg}}) ->

+     "** Last timer event in was ~p~n";

  get_msg_str(Msg) ->

      "** Last message in was ~p~n".

 

***************

*** 430,435 ****

--- 459,466 ----

  get_msg({'$gen_sync_event', Event}) -> Event;

  get_msg({'$gen_all_state_event', Event}) -> Event;

  get_msg({'$gen_sync_all_state_event', Event}) -> Event;

+ get_msg({'$gen_fsm_timer', Msg}) -> Msg;

+ get_msg({timeout, Ref, {'$gen_fsm_timer', Msg}}) -> {timeout, Ref, Msg};

  get_msg(Msg) -> Msg.

 

  %%-----------------------------------------------------------------



                  


- Sean



NOTICE AND DISCLAIMER:
This email (including attachments) is confidential.  If you have received
this email in error please notify the sender immediately and delete this
email from your system without copying or disseminating it or placing any
reliance upon its contents.  We cannot accept liability for any breaches of
confidence arising through use of email.  Any opinions expressed in this
email (including attachments) are those of the author and do not necessarily
reflect our opinions.  We will not accept responsibility for any commitments
made by our employees outside the scope of our business.  We do not warrant
the accuracy or completeness of such information.





More information about the erlang-questions mailing list