Erlang generic standard behaviours -- gen_server system msg
2015-02-07 22:37
369 查看
这是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 相关的内容,至于热更会放在之后的热更新系列中进行说明.
由上面的代码片段中,可以看出gen_server 的 MAIN loop 会接收{system, From, Req} 消息(L3), 并且调用sys:handle_system_msg/7 函数(L4)进行处理. 此外还会根据是否有Debug option参数(L8)而调用sys:handle_debug/4 函数进行处理(L11).
这个代码片段的注释中的信息已经说的很明白.
而log trace statistics 相关的辅助功能的实现,都是通过调用send_system_msg 函数,向gen_server 进程发送system 消息, 如:
L1 是trace 函数, L3 是statistics 函数.
也就是, handle_system_msg 函数调用了(L2)do_cmd 函数, 处理各种类型的system 消息
L1,L3,L16 的system 消息和热更相关.
L5,L7 的system 消息和gen_server 进程的state 相关.
L10 是获取gen_server 进程的所有状态信息, 包括但不仅限trace statistics state 信息.
L13 是trace log statistics 相关辅助函数的开关. 这些辅助函数功能对于gen_server 进程是可拔插的.
仅以trace 功能举例,true false 表示该函数功能的生效与否.而install_debug 的实现就是lists [|] 的操作, remove_debug 调用的是lists:keydelete/3 函数实现.
1, trace 会调用print_event 函数,将trace 信息打印在console
2, log_to_file 同样调用print_event 函数, 将trace 信息写入到指定文件
3, 而statistics 是将统计信息更新至gen_server 进程的status
在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 hibernate
- Erlang generic standard behaviours -- gen_server noblock call
- Erlang generic standard behaviours -- gen_server terminate
- Erlang generic standard behaviours -- gen
- Erlang generic standard behaviours -- gen_server module
- Erlang generic standard behaviours -- summary
- Erlang入门:gen_server代码模板
- Erlang gen_server和ets简单应用
- erlang 消息发送 gen_server:call cast info
- erlang gen_server行为模式
- Erlang学习:OTP - Application & supervisor & gen_server
- [Erlang 0036] "HOW TO"不创建崩溃报告主动销毁gen_server进程
- Erlang OTP编程初体验——gen_server和行为模式
- erlang OTP gen_server 图解分析
- erlang gen_server实例
- Erlang:RabbitMQ源码分析 2. gen_server和gen_server2 深入剖析
- erlang四大behaviour之一gen_server(转载)
- [Erlang 0023] 理解Erlang/OTP gen_server
- erlang gen_server
- erlang OTP gen_server 图解分析