123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- -module(ebb_par_fsm).
- -behaviour(gen_fsm).
- -include("../include/ebb_prim.hrl").
- %% API
- -export([start_link/3]).
- %% gen_fsm callbacks
- -export([init/1, handle_event/3, handle_sync_event/4, handle_info/3,
- terminate/3, code_change/4]).
- -export([forwarding/2]).
- -define(DICT, orddict).
- -record(state, {par, in_map, input}).
- %%====================================================================
- %% API
- %%====================================================================
- %%--------------------------------------------------------------------
- %% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
- %% Description:Creates a gen_fsm process which calls Module:init/1 to
- %% initialize. To ensure a synchronized start-up procedure, this function
- %% does not return until Module:init/1 has returned.
- %%--------------------------------------------------------------------
- start_link(Par = #par{}, Run, Receiver) when is_pid(Receiver) ->
- gen_fsm:start_link(?MODULE, {Par, Run, Receiver}, []).
- %%====================================================================
- %% gen_fsm callbacks
- %%====================================================================
- %%--------------------------------------------------------------------
- %% Function: init(Args) -> {ok, StateName, State} |
- %% {ok, StateName, State, Timeout} |
- %% ignore |
- %% {stop, StopReason}
- %% Description:Whenever a gen_fsm is started using gen_fsm:start/[3,4] or
- %% gen_fsm:start_link/3,4, this function is called by the new process to
- %% initialize.
- %%--------------------------------------------------------------------
- init({Par, Run, Receiver}) ->
- Fsms = run_ops(Par, Run, Receiver),
- State = #state{par=Par, in_map=build_in_map(Par, Fsms), input=?DICT:new()},
- {ok, forwarding, State}.
- %%--------------------------------------------------------------------
- %% Function:
- %% state_name(Event, State) -> {next_state, NextStateName, NextState}|
- %% {next_state, NextStateName,
- %% NextState, Timeout} |
- %% {stop, Reason, NewState}
- %% Description:There should be one instance of this function for each possible
- %% state name. Whenever a gen_fsm receives an event sent using
- %% gen_fsm: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 timeout occurs.
- %%--------------------------------------------------------------------
- forwarding({in, N, Val},
- State = #state{par=#par{in=In}, input=Input, in_map=Map})
- when N > 0, N =< In ->
- State2 = State#state{input=?DICT:store(N, Val, Input)},
- {N2, Receiver} = ?DICT:fetch(N, Map),
- ebb_event:in(Receiver, N2, Val),
- case is_done(State2) of
- true -> {stop, normal, State2};
- false -> {next_state, forwarding, State2}
- end.
- %%--------------------------------------------------------------------
- %% Function:
- %% state_name(Event, From, State) -> {next_state, NextStateName, NextState} |
- %% {next_state, NextStateName,
- %% NextState, Timeout} |
- %% {reply, Reply, NextStateName, NextState}|
- %% {reply, Reply, NextStateName,
- %% NextState, Timeout} |
- %% {stop, Reason, NewState}|
- %% {stop, Reason, Reply, NewState}
- %% Description: There should be one instance of this function for each
- %% possible state name. Whenever a gen_fsm receives an event sent using
- %% gen_fsm: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.
- %%--------------------------------------------------------------------
- %%--------------------------------------------------------------------
- %% Function:
- %% handle_event(Event, StateName, State) -> {next_state, NextStateName,
- %% NextState} |
- %% {next_state, NextStateName,
- %% NextState, Timeout} |
- %% {stop, Reason, NewState}
- %% Description: Whenever a gen_fsm receives an event sent using
- %% gen_fsm:send_all_state_event/2, this function is called to handle
- %% the event.
- %%--------------------------------------------------------------------
- handle_event(_Event, StateName, State) ->
- {next_state, StateName, State}.
- %%--------------------------------------------------------------------
- %% Function:
- %% handle_sync_event(Event, From, StateName,
- %% State) -> {next_state, NextStateName, NextState} |
- %% {next_state, NextStateName, NextState,
- %% Timeout} |
- %% {reply, Reply, NextStateName, NextState}|
- %% {reply, Reply, NextStateName, NextState,
- %% Timeout} |
- %% {stop, Reason, NewState} |
- %% {stop, Reason, Reply, NewState}
- %% Description: Whenever a gen_fsm receives an event sent using
- %% gen_fsm:sync_send_all_state_event/2,3, this function is called to handle
- %% the event.
- %%--------------------------------------------------------------------
- handle_sync_event(_Event, _From, StateName, State) ->
- Reply = ok,
- {reply, Reply, StateName, State}.
- %%--------------------------------------------------------------------
- %% Function:
- %% handle_info(Info,StateName,State)-> {next_state, NextStateName, NextState}|
- %% {next_state, NextStateName, NextState,
- %% Timeout} |
- %% {stop, Reason, NewState}
- %% Description: This function is called by a gen_fsm when it receives any
- %% other message than a synchronous or asynchronous event
- %% (or a system message).
- %%--------------------------------------------------------------------
- handle_info(_Info, StateName, State) ->
- {next_state, StateName, State}.
- %%--------------------------------------------------------------------
- %% Function: terminate(Reason, StateName, State) -> void()
- %% Description:This function is called by a gen_fsm when it is about
- %% to terminate. It should be the opposite of Module:init/1 and do any
- %% necessary cleaning up. When it returns, the gen_fsm terminates with
- %% Reason. The return value is ignored.
- %%--------------------------------------------------------------------
- terminate(_Reason, _StateName, _State) ->
- ok.
- %%--------------------------------------------------------------------
- %% Function:
- %% code_change(OldVsn, StateName, State, Extra) -> {ok, StateName, NewState}
- %% Description: Convert process state when code is changed
- %%--------------------------------------------------------------------
- code_change(_OldVsn, StateName, State, _Extra) ->
- {ok, StateName, State}.
- %%--------------------------------------------------------------------
- %%% Internal functions
- %%--------------------------------------------------------------------
- run_ops(#par{ops=Ops}, Run, Receiver) ->
- {_, Fsms} =
- lists:foldl(
- fun(Op, {Offset, Fsms}) ->
- Out = ebb_prim:out_arity(Op),
- {ok, Target} =
- case Offset of
- 0 -> {ok, Receiver};
- _ -> ebb_offset_fsm:start_link(Out, Offset, Receiver)
- end,
- case Run(Op, Target) of
- {ok, Fsm} -> {Offset+Out, [Fsm | Fsms]};
- ignore -> {Offset+Out, [ignore | Fsms]}
- end
- end,
- {0, []}, Ops),
- lists:reverse(Fsms).
- build_in_map(#par{ops=Ops}, Fsms) ->
- {_, Map} = lists:foldl(
- fun({Op, Fsm}, {Offset, Map}) ->
- In = ebb_prim:in_arity(Op),
- L = [ {N+Offset, {N, Fsm}} || N <- lists:seq(1, In) ],
- {Offset+In, L ++ Map}
- end,
- {0, []}, lists:zip(Ops, Fsms)),
- ?DICT:from_list(Map).
- is_done(#state{par=#par{in=In}, input=Inputs}) ->
- (?DICT:size(Inputs) == In).
|