Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

188 lines (155 sloc) 7.802 kB
%%% This code was developped by IDEALX (http://IDEALX.org/) and
%%% contributors (their names can be found in the CONTRIBUTORS file).
%%% Copyright (C) 2000-2001 IDEALX
%%%
%%% This program is free software; you can redistribute it and/or modify
%%% it under the terms of the GNU General Public License as published by
%%% the Free Software Foundation; either version 2 of the License, or
%%% (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
%%% GNU General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
%%%
%%% In addition, as a special exception, you have the permission to
%%% link the code of this program with any library released under
%%% the EPL license and distribute linked combinations including
%%% the two; the MPL (Mozilla Public License), which EPL (Erlang
%%% Public License) is based on, is included in this exception.
-module(ts_timer).
-vc('$Id$ ').
-author('jflecomte@IDEALX.com').
-modifiedby('nicolas@niclux.org').
-include("ts_macros.hrl").
-behaviour(gen_fsm).
%% Puropose:
%% gen_fsm with 3 states: receiver, ack, initialize
%% External events: connected
%% External exports
-export([start/1, connected/1, config/1, set_timeout/1]).
%% gen_fsm callbacks
-export([init/1, initialize/2, receiver/2, ack/2, handle_event/3,
handle_sync_event/4, handle_info/3, terminate/3, code_change/4]).
-record(state, {nclient = 0, % number of unacked clients
maxclients = 0, % total number of clients to ack
pidlist = [],
timeout=?config(global_ack_timeout)}).
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
start(NClients) ->
?LOG("starting fsm timer",?INFO),
gen_fsm:start_link({global, ?MODULE}, ?MODULE, [NClients], []).
config(NClients) ->
?LOGF("Configure fsm timer with ~p",[NClients],?INFO),
gen_fsm:send_event({global, ?MODULE}, {config, NClients}).
set_timeout(Timeout) ->
?LOGF("Configure fsm timer timeout to with ~p",[Timeout],?INFO),
gen_fsm:send_event({global, ?MODULE}, {set_timeout, Timeout}).
connected(Pid) ->
gen_fsm:send_event({global, ?MODULE}, {connected, Pid}).
%%%----------------------------------------------------------------------
%%% Callback functions from gen_fsm
%%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
%% Func: init/1
%% Returns: {ok, StateName, StateData} |
%% {ok, StateName, StateData, Timeout} |
%% ignore |
%% {stop, StopReason}
%%----------------------------------------------------------------------
init(_Args) ->
State= #state{},
?LOGF("starting timer with timeout ~p",[State#state.timeout],?INFO),
{ok, initialize, State}.
%%----------------------------------------------------------------------
%% Func: StateName/2
%% Returns: {next_state, NextStateName, NextStateData} |
%% {next_state, NextStateName, NextStateData, Timeout} |
%% {stop, Reason, NewStateData}
%%----------------------------------------------------------------------
initialize({config, Val}, State) ->
{next_state, receiver, State#state{nclient=Val, maxclients=Val}};
initialize({set_timeout, Val}, State) ->
{next_state, initialize, State#state{timeout=Val}}.
receiver({set_timeout, Val}, State) ->
{next_state, receiver, State#state{timeout=Val}};
%% now all the clients are connected, let's start to ack them
receiver({connected, Pid}, State=#state{pidlist=List, nclient=1}) ->
?LOG("All connected, global ack!",?NOTICE),
{next_state, ack, State#state{pidlist=[Pid|List],nclient=0}, 1};
%% receive a new connected mes
receiver({connected, Pid}, State=#state{pidlist=List, nclient=N}) ->
?LOGF("New connected ~p (nclient=~p)",[Pid, N],?DEB),
{next_state, receiver, State#state{pidlist=List ++ [Pid], nclient=N-1},
State#state.timeout};
%% timeout event, now we start to send ack, by sending a timeout event immediatly
receiver(timeout, StateData) ->
{next_state, ack, StateData,1}.
%% no more ack to send, stop
ack(timeout, #state{pidlist=[]}) ->
{stop, normal, #state{}};
%% ack all pids
ack(timeout, State=#state{pidlist=L, maxclients = Max}) ->
lists:foreach(fun(A)->ts_client:next({A}) end, L),
{next_state, receiver, State#state{pidlist=[], nclient = Max}}.
%%----------------------------------------------------------------------
%% Func: StateName/3
%% Returns: {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}
%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
%% Func: handle_event/3
%% Returns: {next_state, NextStateName, NextStateData} |
%% {next_state, NextStateName, NextStateData, Timeout} |
%% {stop, Reason, NewStateData}
%%----------------------------------------------------------------------
handle_event(_Event, StateName, StateData) ->
{next_state, StateName, StateData}.
%%----------------------------------------------------------------------
%% Func: handle_sync_event/4
%% Returns: {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}
%%----------------------------------------------------------------------
handle_sync_event(_Event, _From, StateName, StateData) ->
Reply = ok,
{reply, Reply, StateName, StateData}.
%%----------------------------------------------------------------------
%% Func: handle_info/3
%% Returns: {next_state, NextStateName, NextStateData} |
%% {next_state, NextStateName, NextStateData, Timeout} |
%% {stop, Reason, NewStateData}
%%----------------------------------------------------------------------
handle_info(_Info, StateName, StateData) ->
{next_state, StateName, StateData}.
%%----------------------------------------------------------------------
%% Func: terminate/3
%% Purpose: Shutdown the fsm
%% Returns: any
%%----------------------------------------------------------------------
terminate(_Reason, _StateName, _StateData) ->
?LOG("terminate timer",?INFO),
ok.
%%--------------------------------------------------------------------
%% Func: code_change/4
%% Purpose: Convert process state when code is changed
%% Returns: {ok, NewState, NewStateData}
%%--------------------------------------------------------------------
code_change(_OldVsn, StateName, StateData, _Extra) ->
{ok, StateName, StateData}.
%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
Jump to Line
Something went wrong with that request. Please try again.