erlang gen_fsm源码分析

         start函数调用gen:start,后者调用do_spawn,然后和gen_server相同,最后都要执行init_it函数,然后该函数执行init函数,并根据返回值执行不同的循环。

 

start(Mod, Args, Options) ->

    gen:start(?MODULE, nolink, Mod, Args, Options).

start(GenMod, LinkP, Name, Mod, Args, Options) ->

    casewhere(Name) of

    undefined ->

        do_spawn(GenMod, LinkP, Name, Mod, Args, Options);

 

do_spawn(GenMod, link, Mod, Args, Options) ->

    Time=timeout(Options),

   proc_lib:start_link(?MODULE, init_it,

 

init_it(Starter, Parent, Name0, Mod, Args, Options) ->

    Name=gen:name(Name0),

    Debug=gen:debug_options(Name, Options),

    HibernateAfterTimeout=gen:hibernate_after(Options),

    casecatchMod:init(Args) of

 

         loop循环:对于infinity版本,自身挂起并等待消息,接收到后执行decode_msg将接收到的消息分类,分为系统的,EXIT的,有无debug的其他消息四种。对于后面两种,调用handle_msg函数来处理。该函数也分为debug和非debug版本。

loop(Parent, Name, StateName, StateData, Mod, infinity, HibernateAfterTimeout, Debug) ->

    receive

        Msg ->

            decode_msg(Msg,Parent, Name, StateName, StateData, Mod, infinity, HibernateAfterTimeout, Debug, false)

 

decode_msg(Msg,Parent, Name, StateName, StateData, Mod, Time, HibernateAfterTimeout, Debug, Hib) ->

    caseMsgof

        {system, From, Req} ->

        sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,

                  [Name, StateName, StateData, Mod, Time, HibernateAfterTimeout], Hib);

    {'EXIT', Parent, Reason} ->

        terminate(Reason, Name, Msg, Mod, StateName, StateData, Debug);

    _MsgwhenDebug=:= [] ->

        handle_msg(Msg, Parent, Name, StateName, StateData, Mod, Time, HibernateAfterTimeout);

    _Msg ->

        Debug1=sys:handle_debug(Debug, funprint_event/3,

                      {Name, StateName}, {in, Msg}),

        handle_msg(Msg, Parent, Name, StateName, StateData,

               Mod, Time, HibernateAfterTimeout, Debug1)

    end.

 

         函数首先调用from函数将消息分类,分为’$gen_sync_event’,$gen_sync_all_state_event’,以及undefined版本请两个直接返回Msg本身,其他的返回undefined,这里是按照From参数的tag进行模式匹配。之后执行dispatch函数将Msg进行模式匹配来将消息分类,同时调用相应的回调函数来处理,根据它们的返回类型执行debug以及执行reply和不同的loop函数循环。

handle_msg(Msg, Parent, Name, StateName, StateData, Mod, _Time, HibernateAfterTimeout) ->%No debug here

    From=from(Msg),

    casecatchdispatch(Msg, Mod, StateName, StateData) of

    {next_state, NStateName, NStateData}->  

 

from({'$gen_sync_event', From, _Event}) ->From;

from({'$gen_sync_all_state_event', From, _Event}) ->From;

from(_) ->undefined.

 

dispatch({'$gen_event', Event}, Mod, StateName, StateData) ->

    Mod:StateName(Event, StateData);

dispatch({'$gen_all_state_event', Event}, Mod, StateName, StateData) ->

    Mod:handle_event(Event, StateName, StateData);

dispatch({'$gen_sync_event', From, Event}, Mod, StateName, StateData) ->

    Mod:StateName(Event, From, StateData);

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

    Mod, StateName, StateData) ->

    Mod:handle_sync_event(Event, From, StateName, StateData);

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

    Mod:StateName({timeout, Ref, Msg}, StateData);

dispatch({timeout, _Ref, {'$gen_event', Event}}, Mod, StateName, StateData) ->

    Mod:StateName(Event, StateData);

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

    Mod:handle_info(Info, StateName, StateData).

 

         导出函数:dispatch执行的函数都是回调模块中定义好的函数。

send_event函数:根据不同的名字进行模式匹配,直接发送{‘$gen_event’,Event}到gen_fsm进程。之后dispatch函数执行StateName(Event, StateData)函数。

 

sync_send_event函数:分为有Timeout和没有两个版本。调用gen:call函数,第二个参数是’$gen_sync_event’。 gen:call函数之后调用do_for_proc,其参数(gen_fsm名称或Pid,Fun)。其中Fun是一个do_call函数,作用是监督其参数Pid的函数  这里是监督gen_fsm进程(使用erlang:monitor),之后调用erlang:send发送消息到gen_fsm进程,然后挂起自己来接收gen_fsm的回复消息,之后先停止监督,(使用erlang:demonitor),然后将回复({ok, Reply}),之后回到sync_send_event,函数最终返回Reply(整个过程类似gen_server)。dispatch执行StateName(Event, From, StateData)函数。

sync_send_event(Name, Event) ->

    casecatchgen:call(Name, '$gen_sync_event', Event) of

 

send_all_state_event函数:根据不同的名字进行模式匹配,然后发送{‘$gen_all_state_event’, Event}到gen_fsm进程。dispatch函数执行handle_event(Event,StateName, StateData)函数。

 

sync_send_all_state_event函数:分为有Timeout和没有两个版本。类似sync_send_event,只是第二个参数变成了'$gen_sync_all_state_event'。dispatch执行handle_sync_event(Event,From, StateName, StateData)函数。

 

reply函数:直接发送到进程。

reply({To, Tag}, Reply) ->

    catchTo! {Tag, Reply}.

 

reply(Name, {To, Tag}, Reply, Debug, StateName) ->

    reply({To, Tag}, Reply),

    sys:handle_debug(Debug, funprint_event/3, Name,

             {out, Reply, To, StateName}).

 

start_timer函数:直接调用erlang:start_timer(Time, self(), {'$gen_timer', Msg}),在Time毫秒后发送消息到gen_fsm,之后dispatch接收到消息后执行StateName(timeout,Ref, Msg)函数。

start_timer(Time, Msg) ->% 启动一个计时器,在Time毫秒后将发送{timeout, TimerRef, Msg}

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

 

send_event_after函数:调用gen:start_timer(Time,self(), {'$gen_event', Event}),跟上面的区别是tag不同。dispatch执行StateName(Event, StateData)函数。

send_event_after(Time, Event) ->

    erlang:start_timer(Time, self(), {'$gen_event', Event}).

 

cancel_timer函数:调用erlang:cancel_timer(Ref)函数,取消一个计时器,后者是通过erlang:send_after或者erlang:start_timer返回的。

cancel_timer(Ref) ->

    caseerlang:cancel_timer(Ref) of

 

enter_loop函数:类似于gen_server,产生新的Name, Parent,Debug和HibernateAfterTimeout来执行新的循环。

 

gen_fsm行为类似于gen_server。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值