inviso_rt_meta.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,195 行 · 第 1/4 页
ERL
1,195 行
%% It must return an internal notation of the time of file open and a%% useful descriptor the write_output function can use.%% Returns {ok,TiDescriptor} or {error,Reason}.open_traceinfo_file({file,FileName}) -> % A plain raw binary file. case file:open(FileName,[write,raw,binary]) of {ok,FD} -> {ok,{file,FD}}; {error,Reason} -> {error,{open,[FileName,Reason]}} end;open_traceinfo_file({relay,ToNode}) -> % Use distributed Erlang. {ok,{relay,ToNode}};open_traceinfo_file(IncorrectTI) -> {error,{badarg,IncorrectTI}}.%% -----------------------------------------------------------------------------close_traceinfo_file({file,FD}) -> file:close(FD);close_traceinfo_file(_) -> ok.%% -----------------------------------------------------------------------------%% Help function handling initializing meta tracing of a function.%% Returns {NewLD,NewPublLD}.h_init_tpm(Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc,TI,LD,PublLD) -> case do_initfunc(InitFunc,Mod,Func,Arity,PublLD) of {NewPublLD,Output} -> write_output(TI,Output), NewLD=init_tpm_ld(Mod,Func,Arity,CallFunc,ReturnFunc,RemoveFunc,LD), {NewLD,NewPublLD}; false -> % The initfunc did not do anything. NewLD=init_tpm_ld(Mod,Func,Arity,CallFunc,ReturnFunc,RemoveFunc,LD), {NewLD,PublLD} end.%% -----------------------------------------------------------------------------%% Help function handling initializing meta tracing of a function and also%% set the meta trace pattern as specified.%% Returns {NewLD,NewPublLD,N}.h_tpm(Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc,TI,LD,PublLD) -> {NewLD,NewPublLD}= h_init_tpm(Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc,TI,LD,PublLD), case set_meta_tracing(Mod,Func,Arity,MS) of true -> % Ok, set one pattern. {NewLD,NewPublLD,1}; false -> {NewLD,NewPublLD,0} end.%% -----------------------------------------------------------------------------%% Help function handling setting meta trace patter for a function which has%% already been intialized. Note that we must remove all potentially stored%% match-specs, if this function has been given match-specs before with%% tpm_ms.%% Returns a {NewLD,N}.h_tpm(Mod,Func,Arity,MS,LD) -> case set_meta_tracing(Mod,Func,Arity,MS) of true -> {remove_ms_ld(Mod,Func,Arity,LD),1}; false -> {LD,0} end.%% -----------------------------------------------------------------------------%% Help function that adds a match-spec to Mod:Func/Arity. It is not defined%% in which order the match-specs will be given to the BIF.%% Note that if an MS with the same name as an exiting is inserted, the previous%% match-spec will be removed.%% Very important to realise is that the empty meta match spec [] imposes no%% restrictions what so ever on the generating of meta trace call messages.%% Uncontrolled sending of such messages may quickly drain power from the system.%% Since an empty match-spec will "disappear" when added to other match specs,%% the empty match is transformed to what it actually is: [{'_',[],[]}].%% Returns 0 or 1 indicating failure or success.h_tpm_ms(Mod,Func,Arity,MSname,MS) -> MSsNames=get_ms_ld(Mod,Func,Arity), % Fetch all previous match-specs. TransformedMS=h_tpm_ms_convert_null_ms(MS), MSsNames1=lists:keydelete(MSname,1,MSsNames), % If it already existed, it is gone! NewMSs=lists:flatten([TransformedMS,lists:map(fun({_Name,MSx})->MSx end,MSsNames1)]), case set_meta_tracing(Mod,Func,Arity,NewMSs) of true -> % We only save the MS if it was good. put_ms_ld(Mod,Func,Arity,MSname,TransformedMS,MSsNames1), 1; false -> 0 end.%% Help function converting the null match spec into, still a null match spec,%% on a proper match spec format. This because it will otherwise be difficult%% to see the difference between no active tpm_ms and all a set of null ms.h_tpm_ms_convert_null_ms([]) -> [{'_',[],[]}];h_tpm_ms_convert_null_ms(MS) -> MS.%% -----------------------------------------------------------------------------%% Help function returning a list of all names used for match-functions for%% the Mod:Func/Arity in question.h_list_tpm_ms(Mod,Func,Arity) -> MSsNames=get_ms_ld(Mod,Func,Arity), % A list of {MSname,MS}. lists:map(fun({MSname,_})->MSname end,MSsNames).%% -----------------------------------------------------------------------------%% Function that removes a named match-spec. Returns nothing significant.%% Note that if we end up with no match-specs, we must remove the meta trace%% patten all together. That is bringing the function back to just initiated.h_ctpm_ms(Mod,Func,Arity,MSname) -> case get_ms_ld(Mod,Func,Arity) of [] -> % The name does certainly not exist! true; % We don't have to do anything. MSsNames -> case lists:keysearch(MSname,1,MSsNames) of {value,{_,_MS}} -> % Ok, we must do something! NewMSsNames=lists:keydelete(MSname,1,MSsNames), case lists:flatten(lists:map(fun({_Name,MS})->MS end,NewMSsNames)) of [] -> % This means stop meta tracing. set_meta_tracing(Mod,Func,Arity,false); NewMSs -> set_meta_tracing(Mod,Func,Arity,NewMSs) end, set_ms_ld(Mod,Func,Arity,NewMSsNames); false -> % But this name does not exist. true % So we do not have to do anything. end end.%% -----------------------------------------------------------------------------%% Function that checks the arguments to the meta trace pattern. The reason we%% must do this is that we can only allow meta tracing on specific functions and%% not using wildpatterns. Otherwise the meta trace server will not understand%% which callfunc for instance to call when a meta-trace message is generated%% for a function.%% Returns 'true' or 'false'.check_tpm_args(Mod,Func,Arity) when is_atom(Mod),is_atom(Func),is_integer(Arity),Mod/='_',Func/='_' -> true;check_tpm_args(_,_,_) -> false.%% -----------------------------------------------------------------------------%% Help function which calls the actual BIF setting meta-trace-patterns.%% Returns 'true' or 'false'.set_meta_tracing(Mod,Func,Arity,MS) when is_atom(Mod) -> case erlang:module_loaded(Mod) of true -> set_meta_tracing_2(Mod,Func,Arity,MS); false -> % The module is not loaded. case code:ensure_loaded(Mod) of {module,_Mod} -> set_meta_tracing_2(Mod,Func,Arity,MS); {error,_Reason} -> % Could not load the module. false % No use try to trace. end end;set_meta_tracing(_,_,_,_) -> false.set_meta_tracing_2(Mod,Func,Arity,MS) -> case catch erlang:trace_pattern({Mod,Func,Arity},MS,[meta]) of 0 -> % Hmm, nothing happend :-) false; N when is_integer(N) -> % The normal case, some functions were hit. true; {'EXIT',_Reason} -> false end.%% -----------------------------------------------------------------------------%% Help function which removes all meta trace pattern for the functions mentioned%% in the list being first argument. It also executes the remove funcs for each%% and every no longer meta traced function. This done since some of the remove%% functions may do side-effects (like deleteing ETS tables).%% Returns nothing significant.stop_all_meta_tracing([{M,F,Arity}|Rest],PublLD,LD) -> catch erlang:trace_pattern({M,F,Arity},false,[meta]), NewPublLD=do_removefunc(get_remove_func_ld(M,F,Arity,LD),M,F,Arity,PublLD), stop_all_meta_tracing(Rest,NewPublLD,LD);stop_all_meta_tracing([],_,_) -> true.%% -----------------------------------------------------------------------------%% This function calls the function registered to be handler for a certain%% meta-traced function. Such a function or fun must take three arguments%% and return {ok,NewPrivLD,OutPutBinary} or 'false'. OutPutBinary may be%% something else, and is then ignored.handle_meta({M,F},Pid,Arg1,PrivLD) -> (catch M:F(Pid,Arg1,PrivLD));handle_meta(Fun,Pid,Arg1,PrivLD) when is_function(Fun) -> (catch Fun(Pid,Arg1,PrivLD));handle_meta(_,_,_,_) -> % Don't know how to do this. false.%% -----------------------------------------------------------------------------%% Help function writing output from a callback function to the ti-file.%% Output can be a binary or a list of binaries.write_output(TI,[OutPut|Rest]) -> write_output(TI,OutPut), write_output(TI,Rest);write_output({file,FD},Bin) when is_binary(Bin) -> % Plain direct-binary file Size=size(Bin), file:write(FD,list_to_binary([<<0,Size:32>>,Bin]));write_output({relay,ToNode},Bin) when is_atom(ToNode),is_binary(Bin) -> {inviso_rt_meta,ToNode} ! {relayed_meta,Bin};write_output(_,_) -> % Don't understand, just skip. true.%% -----------------------------------------------------------------------------%% =============================================================================%% Various help functions.%% =============================================================================%% Help function initializing the public loopdata structure. Note that if the%% supplied InitPublLDmfa is faulty we let the structure become the error.%% The error will most likely turn up in an error report somewhere, eventually.do_init_publ_ld({M,F,Args}) when is_atom(M),is_atom(F),is_list(Args) -> case catch apply(M,F,Args) of {'EXIT',_Reason} -> {error,init_publ_ld_func}; % Let the struct be this error! InitialPublLD -> InitialPublLD end;do_init_publ_ld(_) -> {error,init_publ_ld_func}.%% -----------------------------------------------------------------------------%% Help function which removes the public loopdata structure. The function does%% not necessarily have to exist. Returns nothing significant.do_remove_publ_ld({M,F},PublLD) when is_atom(M),is_atom(F) -> catch M:F(PublLD);do_remove_publ_ld(_,_) -> true.%% ----------------------------------------------------------------------------- %% Hlp function initializing a particular meta traced function into the public%% loopdata. Note that the function is not mandatory.%% Returns {NewPublLD,Output} or 'false'.do_initfunc({M,F},Mod,Func,Arity,PublLD) when is_atom(M),is_atom(F) -> case catch M:F(Mod,Func,Arity,PublLD) of {ok,NewPublLD,Output} -> {NewPublLD,Output}; _ -> % Everything else is an error. false % Act as no initialization function. end;do_initfunc(Fun,Mod,Func,Arity,PublLD) when is_function(Fun) -> case catch Fun(Mod,Func,Arity,PublLD) of {ok,NewPublLD,Output} -> {NewPublLD,Output}; _ -> % Everything else is an error. false % Act as no initialization function. end;do_initfunc(_,_,_,_,_) -> % Perhaps too generous, should be 'void' only. false.%% -----------------------------------------------------------------------------%% Help function removing a particular meta traced function from the public%% loopdata. Note that we do not make much noice should the call back function%% be faulty.do_removefunc({M,F},Mod,Func,Arity,PublLD) when is_atom(M),is_atom(F) -> case catch M:F(Mod,Func,Arity,PublLD) of {ok,NewPublLD} -> NewPublLD; _ -> % Everything else is an error. PublLD % Act as no initialization function. end;do_removefunc(Fun,Mod,Func,Arity,PublLD) when is_function(Fun) -> case catch Fun(Mod,Func,Arity,PublLD) of {ok,NewPublLD} -> NewPublLD; _ -> % Everything else is an error. PublLD % Act as no initialization function. end;do_removefunc(_,_,_,_,PublLD) -> PublLD.%% -----------------------------------------------------------------------------%% Function that, if the time has come, goes through the priv-ld structure and%% cleans away entryn left behind. The usual cause is that the function call%% caused an exception and there were therefore no matching return_from.%% Returns {NewPrivLD,now()}.throw_old_failed({M,F},PrivLD,PrevClean) -> case difference_in_now(PrevClean,now(),60) of % We clean once every minute. true -> case catch apply(M,F,[PrivLD]) of {'EXIT',_Reason} -> % Something went wrong, ignore it. {PrivLD,now()}; % Just keep the old priv-ld. NewPrivLD -> % The function must return a priv-ld. {NewPrivLD,now()} end; false -> % Not time yet! {PrivLD,PrevClean} end.%% -----------------------------------------------------------------------------%% Help function comparing two now timestamps. Returns true or false depending%% on if S2 is more than DiffS seconds after S1. Only works for differences%% less than 1 million seconds.difference_in_now({MegaS1,S1,_},{MegaS2,S2,_},DiffS) -> if
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?