Multiple behaviour processes

Vance Shipley vances@REDACTED
Thu Jan 6 14:08:53 CET 2005


On Thu, Jan 06, 2005 at 02:25:09PM +0200, Yoel Jacobsen wrote:
some icky html stuff


What I do is to create a my_fsm.erl bahaviour module which exports
the same interface as gen_fsm.  You create a function for each of
the exports and have it call gen_fsm's functions.

send_event(FsmRef, Event) ->
   gen_fsm:send_event(FsmRef, Event).

So now you have a new my_fsm which behaves identically to 
gen_fsm.  It should also export behaviour_info:

behaviour_info(callbacks) ->
   gen_fsm:behaviour_info(callbacks);
behaviour_info(Other) ->
   gen_fsm:behaviour_info(Other).


You can use this in the same way as gen_fsm so if you have a
gen_fsm behaviour module named foo_fsm.erl you can just change
the -behaviour(gen_fsm) to -behaviour(my_fsm) and start it using
my_fsm:

   my_fsm:start(foo_fsm, Args, Options)

Now you modify it's behaviour to suit.  Firstly let's have
it keep it's own state.  We'll modify the start functions:

start(Module, Args, Options) ->
   gen_fsm:start(?MODULE, [Module, Args], Options).

init(init([Module, Args]) ->
   case Module:init(Args) of
      {ok, StateName, StateData} ->
          {ok, statename, #state{module = Module, data = StateData}};
      {ok, StateName, StateData, Timeout} ->
          {ok, statename, #state{module = Module, data = StateData}, Timeout};
      {stop, Reason} ->
         {stop, Reason};
      ignore ->
         ignore;
      Other ->
         Other
   end.

And we'll have one or more private states.  Here I made just 
one named statename.  You create specific state handlers to handle 
just the events you're interested in and the rest are passed through:

statename(Event, From, State) ->
   Module = State#state.module,
   StateName = State#state.statename,
   case Module:StateName(Event, From, State#state.statedata) of
      {reply, Reply, NextStateName, NewStateData} ->
         NewState = State#state{statename = NextStateName,
               statedata = NewStateData},
         {reply, Reply, statename, NewState};
      {reply, Reply, NextStateName, NewStateData, Timeout} ->
         NewState = State#state{statename = NextStateName,
               statedata = NewStateData},
         {reply, Reply, statename, NewState, Timeout};
      {next_state, NextStateName, NewStateData} ->
         NewState = State#state{statename = NextStateName,
               statedata = NewStateData},
         {next_state, statename, NewState};
      {next_state, NextStateName, NewStateData, Timeout} ->
         NewState = State#state{statename = NextStateName,
               statedata = NewStateData},
         {next_state, statename, NewState, Timeout};
      {stop, Reason, Reply, NewStateData} ->
         NewState = State#state{statedata = NewStateData},
         {stop, Reason, Reply, NewState};
      {stop, Reason, NewStateData} ->
         NewState = State#state{statedata = NewStateData},
         {stop, Reason, NewState};
      Other ->
         Other
   end.



I use this method in my LAPD protocol stack to allow users to
easily adapt the lapd_mux_fsm to different layer 1 implementations.

	http://www.motivity.ca/lapd/lapd_mux_fsm.html


	-Vance

Vance Shipley
Motivity Telecom Inc.
vances@REDACTED




More information about the erlang-questions mailing list