这是Erlang generic standard behaviors gen_server 分析的系列的最后一篇,主要分析gen_server module 辅助性的功能函数.

在gen_server 的MAIN loop 流程中,除了处理Parent 的'EXIT' 消息, user module 常规消息之外, 还处理了一类 system 消息. 这一类system 消息的来源是一个sys 的module,在Erlang OTP体系中,sys module 主要有两大类的作用,一个是热更,另一个是trace log statistics 相关的辅助功能.

这次主要分析trace log statistics 相关的内容,至于热更会放在之后的热更新系列中进行说明.

 decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, Hib) ->
case Msg of
  {system, From, Req} ->
   sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
   [Name, State, Mod, Time], Hib);
  {'EXIT', Parent, Reason} ->
   terminate(Reason, Name, Msg, Mod, State, Debug);
  _Msg when Debug =:= [] ->
  handle_msg(Msg, Parent, Name, State, Mod);
  _Msg ->
   Debug1 = sys:handle_debug(Debug, fun print_event/3,
   Name, {in, Msg}),
   handle_msg(Msg, Parent, Name, State, Mod, Debug1)
end.

由上面的代码片段中,可以看出gen_server 的 MAIN loop 会接收{system, From, Req} 消息(L3), 并且调用sys:handle_system_msg/7 函数(L4)进行处理. 此外还会根据是否有Debug option参数(L8)而调用sys:handle_debug/4 函数进行处理(L11).

system 消息来源

gen_server MAIL loop 中处理的{system, From, Req} 消息是来自sys module, 代码片段见下:

 %%-----------------------------------------------------------------
%% All system messages sent are on the form {system, From, Msg}
%% The receiving side should send Msg to handle_system_msg/5.
%%-----------------------------------------------------------------
send_system_msg(Name, Request) ->
case catch gen:call(Name, system, Request) of
{ok,Res} -> Res;
{'EXIT', Reason} -> exit({Reason, mfa(Name, Request)})
end. send_system_msg(Name, Request, Timeout) ->
case catch gen:call(Name, system, Request, Timeout) of
{ok,Res} -> Res;
{'EXIT', Reason} -> exit({Reason, mfa(Name, Request, Timeout)})
end.

这个代码片段的注释中的信息已经说的很明白.

而log trace statistics 相关的辅助功能的实现,都是通过调用send_system_msg 函数,向gen_server 进程发送system 消息, 如:

 trace(Name, Flag) ->
send_system_msg(Name, {debug, {trace, Flag}}).
statistics(Name, Flag) ->
send_system_msg(Name, {debug, {statistics, Flag}}).

L1 是trace 函数, L3 是statistics 函数.

system 消息处理

当gen_server MAIN loop 接收到system 消息时, 调用sys:handle_system_msg/7 函数进行处理, sys:handle_system_msg/7 函数的实现:

 handle_system_msg(SysState, Msg, From, Parent, Mod, Debug, Misc, Hib) ->
case do_cmd(SysState, Msg, Parent, Mod, Debug, Misc) of
{suspended, Reply, NDebug, NMisc} ->
_ = gen:reply(From, Reply),
suspend_loop(suspended, Parent, Mod, NDebug, NMisc, Hib);
{running, Reply, NDebug, NMisc} ->
_ = gen:reply(From, Reply),
Mod:system_continue(Parent, NDebug, NMisc)
end.

也就是, handle_system_msg 函数调用了(L2)do_cmd 函数, 处理各种类型的system 消息

 do_cmd(_, suspend, _Parent, _Mod, Debug, Misc) ->
{suspended, ok, Debug, Misc};
do_cmd(_, resume, _Parent, _Mod, Debug, Misc) ->
{running, ok, Debug, Misc};
do_cmd(SysState, get_state, _Parent, Mod, Debug, Misc) ->
{SysState, do_get_state(Mod, Misc), Debug, Misc};
do_cmd(SysState, {replace_state, StateFun}, _Parent, Mod, Debug, Misc) ->
{Res, NMisc} = do_replace_state(StateFun, Mod, Misc),
{SysState, Res, Debug, NMisc};
do_cmd(SysState, get_status, Parent, Mod, Debug, Misc) ->
Res = get_status(SysState, Parent, Mod, Debug, Misc),
{SysState, Res, Debug, Misc};
do_cmd(SysState, {debug, What}, _Parent, _Mod, Debug, Misc) ->
{Res, NDebug} = debug_cmd(What, Debug),
{SysState, Res, NDebug, Misc};
do_cmd(suspended, {change_code, Module, Vsn, Extra}, _Parent,
Mod, Debug, Misc) ->
{Res, NMisc} = do_change_code(Mod, Module, Vsn, Extra, Misc),
{suspended, Res, Debug, NMisc};
do_cmd(SysState, Other, _Parent, _Mod, Debug, Misc) ->
{SysState, {error, {unknown_system_msg, Other}}, Debug, Misc}.

L1,L3,L16 的system 消息和热更相关.

L5,L7 的system 消息和gen_server 进程的state 相关.

L10 是获取gen_server 进程的所有状态信息, 包括但不仅限trace statistics state 信息.

L13 是trace log statistics 相关辅助函数的开关. 这些辅助函数功能对于gen_server 进程是可拔插的.

 debug_cmd({trace, true}, Debug) ->
{ok, install_debug(trace, true, Debug)};
debug_cmd({trace, false}, Debug) ->
{ok, remove_debug(trace, Debug)};

仅以trace 功能举例,true false 表示该函数功能的生效与否.而install_debug 的实现就是lists [|] 的操作, remove_debug 调用的是lists:keydelete/3 函数实现.

触发debug

在gen_server 的MAIN loop 中,等Debug option 参数时, 在decode_msg, handle_msg, handle_common_reply, reply 函数处理时,即会调用sys:handle_debug 函数, 继而触发debug.

 %%-----------------------------------------------------------------
%% Func: handle_debug/4
%% Purpose: Called by a process that wishes to debug an event.
%% Func is a formatting function, called as Func(Device, Event).
%% Returns: [debug_opts()]
%%-----------------------------------------------------------------
-spec handle_debug(Debug, FormFunc, Extra, Event) -> [dbg_opt()] when
Debug :: [dbg_opt()],
FormFunc :: format_fun(),
Extra :: term(),
Event :: system_event().
handle_debug([{trace, true} | T], FormFunc, State, Event) ->
print_event({Event, State, FormFunc}),
[{trace, true} | handle_debug(T, FormFunc, State, Event)];
handle_debug([{log, {N, LogData}} | T], FormFunc, State, Event) ->
NLogData = [{Event, State, FormFunc} | trim(N, LogData)],
[{log, {N, NLogData}} | handle_debug(T, FormFunc, State, Event)];
handle_debug([{log_to_file, Fd} | T], FormFunc, State, Event) ->
print_event(Fd, {Event, State, FormFunc}),
[{log_to_file, Fd} | handle_debug(T, FormFunc, State, Event)];
handle_debug([{statistics, StatData} | T], FormFunc, State, Event) ->
NStatData = stat(Event, StatData),
[{statistics, NStatData} | handle_debug(T, FormFunc, State, Event)];
handle_debug([{Func, FuncState} | T], FormFunc, State, Event) ->
case catch Func(FuncState, Event, State) of
done -> handle_debug(T, FormFunc, State, Event);
{'EXIT', _} -> handle_debug(T, FormFunc, State, Event);
NFuncState ->
[{Func, NFuncState} | handle_debug(T, FormFunc, State, Event)]
end;
handle_debug([], _FormFunc, _State, _Event) ->
[].

1, trace 会调用print_event 函数,将trace 信息打印在console

2, log_to_file 同样调用print_event 函数, 将trace 信息写入到指定文件

3, 而statistics 是将统计信息更新至gen_server 进程的status

总结

在Erlang 的设计与源码实现中, 这种功能完备利于debug且可拔插的周边tools, 总能让人兴奋.

Erlang generic standard behaviours -- gen_server system msg的更多相关文章

  1. Erlang generic standard behaviours -- gen_server module

    在分析完gen module (http://www.cnblogs.com/--00/p/4271386.html)之后,就可以开始进入gen_server 的主体module 了.gen_serv ...

  2. Erlang generic standard behaviours -- gen_server terminate

    gen_server 主体 module 已经分析完了(http://www.cnblogs.com/--00/p/4271982.html),接着,分析下gen_server 中的terminate ...

  3. Erlang generic standard behaviours -- gen_server hibernate

    hibernate 主要用于在内存空闲时,通过整理进程的stack,回收进程的heap 来达到回收内存节省资源的效果. hibernate 可用于OTP 进程以及普通进程, hibernate 的官方 ...

  4. Erlang generic standard behaviours -- gen_server noblock call

    在Erlang 系统中,经常需要gen_server 进程来处理共享性的数据,也就是总希望一个gen_server 进程来为多个普通进程提供某种通用性的服务,这也是gen_server 设计的初衷.但 ...

  5. Erlang generic standard behaviours -- gen

    在分析 gen_server (或者是gen_fsm )之前,首先应该弄明白,gen 这个module . -module(gen). -compile({inline,[get_node/1]}). ...

  6. Erlang generic standard behaviours -- summary

    gen_server 相关的片段分析得也差不多了, 这篇作为一个简要的总结.这一系列相关的分析暂且告一段落(之后如有必要,还会回来的 ^^ ),下一个系列主要是以pool 相关, 包括但不仅限于开源项 ...

  7. erlang四大behaviour之一gen_server

      来源:http://www.cnblogs.com/puputu/articles/1701017.html erlang程序设计里面有个设计原则就是把你的进程构造成树,把共用代码提出来,特定功能 ...

  8. erlang四大behaviour之一gen_server(转载)

    erlang程序设计里面有个设计原则就是把你的进程构造成树,把共用代码提出来,特定功能用自己的module实现,这也就是behaviour了,应用behaviour可以减少与本身事务无关的代码量,设计 ...

  9. System.Collections.Generic.List<T> 与 System.Collections.ArrayList

    [推荐] System.Collections.Generic.List<T> [原因] 泛型集合类List<T>在操作值类型的集合时可以不进行 装箱/拆箱 处理. 使得性能较 ...

随机推荐

  1. nginx服务器的内核调优

    TCP公有类 net.core.somaxconn = 262144 net.core.netdev_max_backlog = 262144 net.ipv4.ip_local_port_range ...

  2. nginx学习之压缩解压篇(七)

    1.简介 压缩响应可以减少传输数据的大小,节省带宽.但过多的压缩会造成很大的处理开销.在发送给客户端之前,nginx会对响应做压缩,但是如果后端服务器已经 压缩过了,nginx就不再压缩. 2.开启压 ...

  3. php建立一个空类: stdClass

    $pick = new stdClass; $pick->type = 'full'; ;

  4. TCP协议要点和难点全解

    转载自http://www.cnblogs.com/leetieniu2014/p/5771324.html TCP协议要点和难点全解 说明: 1).本文以TCP的发展历程解析容易引起混淆,误会的方方 ...

  5. Symfony 使用KnpTimeBundle

    使用time_diff时出现:diff.ago.hour; 解决:1:引入"knplabs/knp-time-bundle": "^1.7",https://g ...

  6. 自编码器(autoencoder)

    今天我们会来聊聊用神经网络如何进行非监督形式的学习. 也就是 autoencoder, 自编码. 压缩与解压 有一个神经网络, 它在做的事情是 接收一张图片, 然后 给它打码, 最后 再从打码后的图片 ...

  7. activiti--5 -----------------Activiti 工作流 流程各个步骤所涉及到的表

    ACT_RE_*: 'RE'表示repository. 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等). ACT_RU_*: 'RU'表示runtime. 这些运行时的表,包含流程实例 ...

  8. 培训笔记——Linux基本命令

    在介绍命令之前,更重要的要先介绍一下快速输入命令的方法. 如果你能记住一些常用命令,毫无疑问,通过命令的操作方式比通过鼠标的操作方式要快. 但是有一些命令或是命令用到的参数如文件名特别复杂特别长,这时 ...

  9. Win7打开新的文件夹总会以新窗口的形式打开

    首先可以在 组织-->文件夹和搜索选项   中设置“在同一窗口中打开每个文件夹” 如果设置后不起作用还可以 管理员方式执行以下两条命令 在开始菜单-运行中输入regsvr32 "%Sy ...

  10. vue backup

    为了解决跨域问题 目前在项目,目录下创建了vue.config.js文件,目前是指向别外的一个端口,之前是记得在express后端进行端口指定的,先备注一下,后期跟进 npm ls | grep ax ...