diff options
Diffstat (limited to 'lib/runtime_tools/src/inviso_rt_meta.erl')
-rw-r--r-- | lib/runtime_tools/src/inviso_rt_meta.erl | 1207 |
1 files changed, 0 insertions, 1207 deletions
diff --git a/lib/runtime_tools/src/inviso_rt_meta.erl b/lib/runtime_tools/src/inviso_rt_meta.erl deleted file mode 100644 index 6865dc2242..0000000000 --- a/lib/runtime_tools/src/inviso_rt_meta.erl +++ /dev/null @@ -1,1207 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2006-2009. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% Author: Lennart �hman, [email protected] -%% -%% This module implements the meta tracer process belonging to the -%% runtime component. Its main purpose is to write the ti-file (traceinformation). -%% The ti-file contains translations between process id:s and what ever "you" -%% want to read in the merged and formatted logfile. -%% This process interacts with the runtime component process. -%% -%% Currently it handles the following types of ti-files: -%% Plain raw, binary log. -%% Relay to other inviso_rt_meta process on another node. -%% -%% The TI file will be on binary format and each entry is: -%% <<LengthIndicator:32, {Pid,Alias,Op,NowStamp} >> -%% Pid=pid(), or if OP==unalias pid()|any_other_than_pid() -%% Op=alias|unalias -%% ----------------------------------------------------------------------------- --module(inviso_rt_meta). - -%% ----------------------------------------------------------------------------- -%% API exports. -%% ----------------------------------------------------------------------------- - --export([start/2,start/5]). --export([stop/1,suspend/1]). --export([init_tpm/5,init_tpm/8]). --export([tpm/5,tpm/6,tpm/9,tpm_tracer/5,tpm_tracer/6,tpm_tracer/9]). --export([tpm_ms/6,tpm_ms_tracer/6,ctpm_ms/5,ctpm/4]). --export([local_register/1,global_register/1]). --export([remove_local_register/1,remove_global_register/1]). - --export([write_ti/1]). - --export([get_tracer/0,tpm_ms/5,tpm_ms_tracer/5,list_tpm_ms/3,ctpm_ms/4]). - --export([metacast_call/5,metacast_return_from/6]). --export([get_state/1]). -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% Internal exports. -%% ----------------------------------------------------------------------------- - --export([init/6]). --export([init_std_publld/2,clean_std_publld/1]). -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% Constants. -%% ----------------------------------------------------------------------------- - --define(NAMED_MS_TAB,inviso_rt_meta_named_ms). - -%% ----------------------------------------------------------------------------- - - -%% ============================================================================= -%% Exported API (Meant to be used by a runtime component). -%% ============================================================================= - -%% start(TiData,Tracer)={ok,Pid} | {error,Reason} -%% start(TiData,Tracer,InitPublLDmfa,RemovePublLDmfa,CleanPublLDmf)= -%% {ok,Pid} | {error,Reason} -%% TiData={file,FileName}|{relay,Node} -%% Tracer=pid()|port() -%% FileName=string() -%% InitPublLDmfa={Mod,Func,ArgList} -%% RemovePublLDmf={Mod,Func} | void -%% RemovePublLDmf(PublLD)->nothing significant. -%% These functions are called to create and destroy the public loopdata -%% structure available to the meta-trace CallFunc and ReturnFunc. -%% CleanPublLDmf={Mod,Func} -%% This function will periodically be called to clean the public LD from -%% pending meta-trace messages waiting for a corresponding return_from -%% message. -%% -%% Starts a meta-tracer process, opening the ti-file specified in TiData. PublLD -%% is used to communicate data, typically between a call and return_from. -%% If no special initialization function is specified a standard one is used. -%% Note that the meta tracer function must know "who" is the regular tracer -%% (process or port). This because it must be possible to append {tracer,Tracer} -%% in meta match specs. -start(TiData,Tracer) -> - Pid=spawn_link(?MODULE, - init, - [self(), - TiData, - Tracer, - {?MODULE,init_std_publld,[2,[]]}, - void, - {?MODULE,clean_std_publld}]), - wait_for_reply(Pid). -start(TiData,Tracer,InitPublLDmfa,RemovePublLDmf,CleanPublLDmf) -> - Pid=spawn_link(?MODULE, - init, - [self(),TiData,Tracer,InitPublLDmfa,RemovePublLDmf,CleanPublLDmf]), - wait_for_reply(Pid). - -wait_for_reply(Pid) -> - receive - {Pid,ok} -> - {ok,Pid}; - {Pid,{error,Reason}} -> - {error,Reason} - after - 10000 -> % After very long time. - exit(Pid,kill), % It must be hanging. - {error,time_out} - end. -%% ----------------------------------------------------------------------------- - -%% stop(Pid)=ok -%% Pid=Adders to the meta tracer, pid(). -%% Shutsdown the metatracer. -stop(Pid) -> - Pid ! {stop,self()}, - ok. -%% ----------------------------------------------------------------------------- - -%% suspend(Pid)=ok -%% Pid=Adders to the meta tracer, pid(). -%% Suspends the meta tracer by removing all meta trace patterns. -suspend(Pid) -> - Pid ! {suspend,self()}, - ok. -%% ----------------------------------------------------------------------------- - -%% init_tpm(Pid,Mod,Func,Arity,CallFunc)= -%% init_tpm(Pid,Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc)=ok|{error,Reason}. -%% Pid=Address to meta tracer process, pid(). -%% Mod,Func=Pointing out the function which shall be meta traced, atom(). -%% Arity=As above, integer(). -%% InitFunc,RemoveFunc={Module,Function}|fun(), functions being called when -%% to initialize the public loopdata structure, and to reset it. -%% InitFunc(Mod,Func,Arity,PublLD)->{ok,NewPublLD,Output} -%% Supposed to initialize whatever needs to be done before -%% handling any incoming meta-trace message for the Mod:Func/Arity. -%% RemoveFunc(Mod,Func,Arity,PublLD)->{ok,NewPublLD} -%% Called when meta tracing of Mod:Func/Arity is stopped. It is supposed -%% to clear datastructures away from the PublLD. -%% Initializes the public loopdata for this function. Note that we can not use wildcards -%% here (even if it is perfectly legal in Erlang). It also sets the CallFunc and -%% ReturnFunc for the meta traced function. The function is hence ready to be -%% meta traced with either tpm/5 or tpm_ms/5. -%% This function is synchronous, waiting for a reply from the meta server. -init_tpm(Pid,Mod,Func,Arity,CallFunc) -> - init_tpm(Pid,Mod,Func,Arity,void,CallFunc,void,void). -init_tpm(Pid,Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> - send_wait(Pid, - {init_tpm,{Mod,Func,Arity},InitFunc,CallFunc,ReturnFunc,RemoveFunc}). -%% ----------------------------------------------------------------------------- - -%% tpm(Pid,Mod,Func,Arity,MatchSpec)={ok,N}|{error,Reason} -%% tpm(Pid,Mod,Func,Arity,MatchSpec,CallFunc)={ok,N}|{error,Reason} -%% tpm(Pid,Mod,Func,Arity,MatchSpec,InitFunc,CallFunc,ReturnFunc,RemoveFunc)= -%% Pid=Address to meta tracer process, pid(). -%% Mod,Func=Pointing out the function which shall be meta traced, atom(). -%% Arity=As above, integer(). -%% MatchSpec=List of match specification, possibly empty. Remember {return_trace} -%% if expecting return_from messages. -%% InitFunc,CallFunc,ReturnFunc,RemoveFunc={Module,Function}|fun(), -%% functions being called when these functions are called by the meta trace -%% server at certain events. -%% CallFunc(CallingPid,ActualArgList,PublLD)->{ok,NewPrivLD,Output} -%% ReturnFunc(CallingPid,ReturnValue,PublLD)->{ok,NewPrivLD,Output} -%% When a call respectively return_from trace message arrives for the meta -%% traced function, the corresponding function is called. -%% The ReturnFunc must handle the fact that a return_from message arrives -%% for a call which was never noticed. This because the message queue of the -%% meta tracer may have been emptied. -%% Reason=badarg | -%% Output=Characters to be written to the ti-file, bin() | 'void' -%% The tpm/5 function simply starts meta tracing for the function. It must -%% previously have been initialized. -%% tpm/6 & /9 initializes the function and starts meta tracing. -tpm(Pid,Mod,Func,Arity,MatchSpec) - when is_atom(Mod),is_atom(Func),is_integer(Arity),is_list(MatchSpec),Mod/='_',Func/='_'-> - send_wait(Pid,{tpm,{Mod,Func,Arity,MatchSpec}}); -tpm(_,_,_,_,_) -> - {error,badarg}. - -tpm(Pid,Mod,Func,Arity,MatchSpec,CallFunc) -> - tpm(Pid,Mod,Func,Arity,MatchSpec,void,CallFunc,void,void). - -tpm(Pid,Mod,Func,Arity,MatchSpec,InitFunc,CallFunc,ReturnFunc,RemoveFunc) - when is_atom(Mod),is_atom(Func),is_integer(Arity),is_list(MatchSpec),Mod/='_',Func/='_' -> - send_wait(Pid,{tpm,{Mod,Func,Arity,MatchSpec},InitFunc,CallFunc,ReturnFunc,RemoveFunc}); -tpm(_,_,_,_,_,_,_,_,_) -> - {error,badarg}. -%% ----------------------------------------------------------------------------- - -%% Same as tpm/X but the meta tracer will automatically append {tracer,Tracer} -%% to the enable list in a {trace,Disable,Enable} match spec action term. -tpm_tracer(Pid,Mod,Func,Arity,MatchSpec) - when is_atom(Mod),is_atom(Func),is_integer(Arity),is_list(MatchSpec),Mod/='_',Func/='_'-> - send_wait(Pid,{tpm_tracer,{Mod,Func,Arity,MatchSpec}}); -tpm_tracer(_,_,_,_,_) -> - {error,badarg}. - -tpm_tracer(Pid,Mod,Func,Arity,MatchSpec,CallFunc) -> - tpm_tracer(Pid,Mod,Func,Arity,MatchSpec,void,CallFunc,void,void). - -tpm_tracer(Pid,Mod,Func,Arity,MatchSpec,InitFunc,CallFunc,ReturnFunc,RemoveFunc) - when is_atom(Mod),is_atom(Func),is_integer(Arity),is_list(MatchSpec),Mod/='_',Func/='_' -> - send_wait(Pid,{tpm_tracer, - {Mod,Func,Arity,MatchSpec}, - InitFunc,CallFunc,ReturnFunc,RemoveFunc}); -tpm_tracer(_,_,_,_,_,_,_,_,_) -> - {error,badarg}. -%% ----------------------------------------------------------------------------- - -%% tpm_ms(Pid,Mod,Func,Arity,MSname,MS)={ok,N}|{error,Reason} -%% Pid=Address to meta tracer process, pid(). -%% Mod,Func=Pointing out the function to which we shall add a match-spec., atom(). -%% Arity=As above, integer(). -%% MSname=A name to be used if this MS shall be removed later. term(). -%% MatchSpec=List of match specification, Remember {return_trace} -%% if expecting return_from messages. -%% This function adds a list of match-specs to the already existing ones. It -%% uses an internal database to keep track of existing match-specs. If the -%% match-spec does not result in any meta traced functions (for whatever reason), -%% the MS is not saved in the database. The previously known match-specs are -%% not removed. -tpm_ms(Pid,Mod,Func,Arity,MSname,MS) -> - send_wait(Pid,{tpm_ms,{Mod,Func,Arity},MSname,MS}). -%% ----------------------------------------------------------------------------- - -%% Same as tpm_ms/6 but the meta tracer will automatically append {tracer,Tracer} -%% to the enable list in a {trace,Disable,Enable} match spec action term. -tpm_ms_tracer(Pid,Mod,Func,Arity,MSname,MS) -> - send_wait(Pid,{tpm_ms_tracer,{Mod,Func,Arity},MSname,MS}). -%% ----------------------------------------------------------------------------- - -%% ctpm_ms(Pid,Mod,Func,Arity)=ok -%% -%% Removes a names match-spec from the meta traced function. Note that is never -%% a fault to remove an MS. Not even from a function which is non existant. -ctpm_ms(Pid,Mod,Func,Arity,MSname) -> - send_wait(Pid,{ctpm_ms,{Mod,Func,Arity},MSname}). -%% ----------------------------------------------------------------------------- - -%% Quick versions for erlang:register/2 which also uses a default CallFunc -%% and a default ReturnFunc. -local_register(Pid) -> - Res1=tpm(Pid, - erlang,register,2,[{'_',[],[{exception_trace}]}], - fun metafunc_init/4,fun local_register_call/3, - fun local_register_return/3,void), - Res2=tpm(Pid, - erlang,unregister,1,[], - void,fun local_unregister_call/3,void,void), - {Res1,Res2}. -%% ----------------------------------------------------------------------------- - -%% Quick version for global:register_name/2, /3. -global_register(Pid) -> - Res1=tpm(Pid,global,handle_call,3,[{[{register,'_','_','_'},'_','_'],[],[]}], - void,fun global_register_call/3,void,void), - Res2=tpm(Pid,global,delete_global_name,2,[], - void,fun global_unregister_call/3,void,void), - {Res1,Res2}. -%% ----------------------------------------------------------------------------- - -%% ctpm(Pid,Mod,Func,Arity)=ok|{error,bad_mfa} -%% -%% Removes the meta trace pattern for the function, means stops generating output -%% for this function. The public LD may be cleared by the previously entered -%% RemoveFunc. -ctpm(Pid,Mod,Func,Arity) -> - send_wait(Pid,{ctpm,{Mod,Func,Arity}}). -%% ----------------------------------------------------------------------------- - -%% remove_local_register(Pid)={Res1,Res2} -%% Res1,Res2=ok|{error,Reason} -remove_local_register(Pid) -> - Res1=ctpm(Pid,erlang,register,2), - Res2=ctpm(Pid,erlang,unregister,1), - {Res1,Res2}. -%% ----------------------------------------------------------------------------- - -%% remove_global_register(Pid)={Res1,Res2} -%% Res1,Res2=ok|{error,Reason} -remove_global_register(Pid) -> - Res1=ctpm(Pid,global,handle_call,3), - Res2=ctpm(Pid,global,delete_global_name,2), - {Res1,Res2}. -%% ----------------------------------------------------------------------------- - -%% Exported help functions which may be used in programming CallFunc and/or -%% ReturnFunc. Useful if the call is done on one node but must trigger the -%% start of something at other nodes. -metacast_call(Nodes,OrigPid,M,F,Args) -> - multicast(Nodes,{trace_ts,OrigPid,call,{M,F,Args},void}), - ok. - -metacast_return_from(Nodes,OrigPid,M,F,Arity,Value) -> - multicast(Nodes,{trace_ts,OrigPid,return_from,{M,F,Arity},Value,void}), - ok. - -multicast([Node|Rest],Msg) -> - {?MODULE,Node} ! Msg, - multicast(Rest,Msg); -multicast([],_) -> - true. -%% ----------------------------------------------------------------------------- - -%% get_states(Pid)={ok,LD,PubLD}. -get_state(Pid) -> - send_wait(Pid,get_state). -%% ----------------------------------------------------------------------------- - - -send_wait(To,Msg) -> - Ref=make_ref(), - MRef=erlang:monitor(process,To), - To ! {Msg,Ref,self()}, - receive - {inviso_rt_meta_reply,Ref,Reply} -> - erlang:demonitor(MRef), - Reply; - {'DOWN',MRef,_,_To,_Reason} -> - {error,no_metatracer} - end. - -reply(To,Ref,Reply) -> - To ! {inviso_rt_meta_reply,Ref,Reply}. -%% ----------------------------------------------------------------------------- - -%% ============================================================================= -%% Special API. -%% ============================================================================= - -%% write_ti(OutPut)= -%% OutPut=binary() -%% Makes an extra entry into the trace information file (ti-file). This is useful -%% if a pid-alias association is learned in another way than through a meta traced -%% function call. Note that this API can only be used locally at the node in -%% question. -write_ti(OutPut) -> - catch ?MODULE ! {write_ti,OutPut}. -%% ----------------------------------------------------------------------------- - - -%% ============================================================================= -%% API intended to be used on CallFuncs and RemoveFuncs. -%% ============================================================================= - -%% The reason there must be a special API for CallFuncs and RemoveFuncs are is -%% that those functions are executed inside *this* process context. Hence they -%% can not make function calls requiering this process to receive messages. - -%% Returns the tracer used for regular tracing. The reason this is implemented -%% in this way is that this function is intended to be used in meta trace call- -%% back functions. And there we can not have message passing API:s to the meta -%% trace(!). -get_tracer() -> - get(tracer). -%% ----------------------------------------------------------------------------- - -%% Function equivalent to inviso_rt:tpm_ms/6. This function can *only* be used -%% inside a CallFunc or a RemoveFunc. -tpm_ms(Mod,Func,Arity,MSname,MS) -> - case check_mfarity_exists(Mod,Func,Arity) of - yes -> % Ok, and args must be ok then also. - {ok,h_tpm_ms(Mod,Func,Arity,MSname,MS)}; - no -> - {error,not_initiated} - end. -%% ----------------------------------------------------------------------------- - -tpm_ms_tracer(Mod,Func,Arity,MSname,MS) -> - case check_mfarity_exists(Mod,Func,Arity) of - yes -> % Ok, and args must be ok then also. - NewMS=add_tracer(MS,get_tracer()), - {ok,h_tpm_ms(Mod,Func,Arity,MSname,NewMS)}; - no -> - {error,not_initiated} - end. -%% ----------------------------------------------------------------------------- - -%% Function that returns all MSname in use for Mod:Func/Arity -list_tpm_ms(Mod,Func,Arity) -> - {ok,h_list_tpm_ms(Mod,Func,Arity)}. -%% ----------------------------------------------------------------------------- - -%% Function equivalent to inviso_rt:ctpm_ms/5. This function can *only* be used -%% inside a CallFunc or a RemoveFunc. -ctpm_ms(Mod,Func,Arity,MSname) -> - h_ctpm_ms(Mod,Func,Arity,MSname), - ok. -%% ----------------------------------------------------------------------------- - - -%% ============================================================================= -%% The server implemenation. -%% ============================================================================= - -init(Parent,TiData,Tracer,InitPublLDmfa,RemovePublLDmf,CleanPublLDmf) -> - process_flag(priority,high), % Since we may receive from many procs. - register(?MODULE,self()), % So we can act as relay receiver. - case open_traceinfo_file(TiData) of - {ok,TI} -> % The ti.-file. - TId=ets:new(?NAMED_MS_TAB,[named_table,set,protected]), - PublLD=do_init_publ_ld(InitPublLDmfa), - Parent ! {self(),ok}, - put(tracer,Tracer), % Uggly quick fix! - loop(Parent, - Tracer, - TI, - mk_new_ld(InitPublLDmfa,RemovePublLDmf,CleanPublLDmf,TId), - PublLD, - now()); - {error,Reason} -> - Parent ! {self(),{error,Reason}} - end. -%% ----------------------------------------------------------------------------- - -loop(Parent,Tracer,TI,LD,PrevPublLD,PrevCleanTime) -> - {PublLD,CleanTime}=throw_old_failed(get_cleanpublldmf_ld(LD),PrevPublLD,PrevCleanTime), - receive - {{init_tpm,{Mod,Func,Arity},InitFunc,CallFunc,ReturnFunc,RemoveFunc},Ref,Parent} -> - case check_mfarity_exists(Mod,Func,Arity) of - no -> % Good then we can add it! - case check_tpm_args(Mod,Func,Arity) of - true -> % Args are ok. - {NewLD,NewPublLD}= - h_init_tpm(Mod,Func,Arity, - InitFunc,CallFunc,ReturnFunc,RemoveFunc, - TI,LD,PublLD), - reply(Parent,Ref,ok), - loop(Parent,Tracer,TI,NewLD,NewPublLD,CleanTime); - false -> % Faulty arguments, - reply(Parent,Ref,{error,bad_mfa}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - yes -> % If it already exists, cant init again. - reply(Parent,Ref,{error,already_initiated}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {{tpm,{Mod,Func,Arity,MS},InitFunc,CallFunc,ReturnFunc,RemoveFunc},Ref,Parent} -> - case check_mfarity_exists(Mod,Func,Arity) of - no -> % Good then we can add it! - case check_tpm_args(Mod,Func,Arity) of - true -> % Args are ok. - {NewLD,NewPublLD,N}= - h_tpm(Mod,Func,Arity,MS, - InitFunc,CallFunc,ReturnFunc,RemoveFunc, - TI,LD,PublLD), - reply(Parent,Ref,{ok,N}), - loop(Parent,Tracer,TI,NewLD,NewPublLD,CleanTime); - false -> - reply(Parent,Ref,{error,bad_mfa}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - yes -> - reply(Parent,Ref,{error,already_initiated}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {{tpm,{Mod,Func,Arity,MS}},Ref,Parent} -> - case check_mfarity_exists(Mod,Func,Arity) of - yes -> % Ok, and args must be ok then also. - {NewLD,N}=h_tpm(Mod,Func,Arity,MS,LD), - reply(Parent,Ref,{ok,N}), - loop(Parent,Tracer,TI,NewLD,PublLD,CleanTime); - no -> % Must be initiated before. - reply(Parent,Ref,{error,not_initiated}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {{tpm_tracer,{Mod,Func,Arity,MS},InitFunc,CallFunc,ReturnFunc,RemoveFunc},Ref,Parent} -> - case check_mfarity_exists(Mod,Func,Arity) of - no -> % Good then we can add it! - case check_tpm_args(Mod,Func,Arity) of - true -> % Args are ok. - NewMS=add_tracer(MS,Tracer), - {NewLD,NewPublLD,N}= - h_tpm(Mod,Func,Arity,NewMS, - InitFunc,CallFunc,ReturnFunc,RemoveFunc, - TI,LD,PublLD), - reply(Parent,Ref,{ok,N}), - loop(Parent,Tracer,TI,NewLD,NewPublLD,CleanTime); - false -> - reply(Parent,Ref,{error,bad_mfa}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - yes -> - reply(Parent,Ref,{error,already_initiated}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {{tpm_tracer,{Mod,Func,Arity,MS}},Ref,Parent} -> - case check_mfarity_exists(Mod,Func,Arity) of - yes -> % Ok, and args must be ok then also. - NewMS=add_tracer(MS,Tracer), - {NewLD,N}=h_tpm(Mod,Func,Arity,NewMS,LD), - reply(Parent,Ref,{ok,N}), - loop(Parent,Tracer,TI,NewLD,PublLD,CleanTime); - no -> % Must be initiated before. - reply(Parent,Ref,{error,not_initiated}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {{tpm_ms,{Mod,Func,Arity},MSname,MS},Ref,Parent} -> - case check_mfarity_exists(Mod,Func,Arity) of - yes -> % Ok, and args must be ok then also. - reply(Parent,Ref,{ok,h_tpm_ms(Mod,Func,Arity,MSname,MS)}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime); - no -> - reply(Parent,Ref,{error,not_initiated}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {{tpm_ms_tracer,{Mod,Func,Arity},MSname,MS},Ref,Parent} -> - case check_mfarity_exists(Mod,Func,Arity) of - yes -> % Ok, and args must be ok then also. - NewMS=add_tracer(MS,Tracer), - reply(Parent,Ref,{ok,h_tpm_ms(Mod,Func,Arity,MSname,NewMS)}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime); - no -> - reply(Parent,Ref,{error,not_initiated}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {{ctpm_ms,{Mod,Func,Arity},MSname},Ref,Parent} -> - reply(Parent,Ref,ok), - h_ctpm_ms(Mod,Func,Arity,MSname), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime); - {{ctpm,{Mod,Func,Arity}},Ref,Parent} -> - case get_remove_func_ld(Mod,Func,Arity,LD) of - false -> % Incorrect Mod:Func/Arity! - reply(Parent,Ref,{error,bad_mfa}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime); % Do nothing! - MF -> % {M,F}, Func or 'void'. - catch erlang:trace_pattern({Mod,Func,Arity},false,[meta]), - NewPublLD=do_removefunc(MF,Mod,Func,Arity,PublLD), - NewLD=ctpm_ld(Mod,Func,Arity,LD), - reply(Parent,Ref,ok), - loop(Parent,Tracer,TI,NewLD,NewPublLD,CleanTime) - end; - {suspend,Parent} -> % Removes all meta trace patterns. - stop_all_meta_tracing(get_all_meta_funcs_ld(LD),PublLD,LD), - do_remove_publ_ld(get_removepublldmf_ld(LD),PublLD), - NewPublLD=do_init_publ_ld(get_initpublldmfa_ld(LD)), - loop(Parent,Tracer,TI,reset_ld(LD),NewPublLD,CleanTime); - {stop,Parent} -> % Make a controlled shutdown. - stop_all_meta_tracing(get_all_meta_funcs_ld(LD),PublLD,LD), - do_remove_publ_ld(get_removepublldmf_ld(LD),PublLD), - close_traceinfo_file(TI); % And then simply terminate. - {trace_ts,Pid,call,{M,F,Args},TS} -> - case handle_meta(get_call_func_ld(M,F,length(Args),LD),Pid,{call,Args,TS},PublLD) of - {ok,NewPublLD,Output} when is_binary(Output);is_list(Output) -> - write_output(TI,Output), - loop(Parent,Tracer,TI,LD,NewPublLD,CleanTime); - {ok,NewPublLD,_} -> % No output to the ti-file this time. - loop(Parent,Tracer,TI,LD,NewPublLD,CleanTime); - _ -> % Not handled correct, not much to do. - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {trace_ts,Pid,TypeTag,{M,F,Arity},Value,TS} - when TypeTag==return_from;TypeTag==exception_from -> - case handle_meta(get_return_func_ld(M,F,Arity,LD),Pid,{TypeTag,Value,TS},PublLD) of - {ok,NewPublLD,Output} when is_binary(Output);is_list(Output) -> - write_output(TI,Output), - loop(Parent,Tracer,TI,LD,NewPublLD,CleanTime); - {ok,NewPublLD,_} -> % No output to the ti-file this time. - loop(Parent,Tracer,TI,LD,NewPublLD,CleanTime); - _ -> % Not handled correct, not much to do. - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {relayed_meta,Bin} -> - write_output(TI,Bin), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime); - {write_ti,OutPut} -> - write_output(TI,OutPut), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime); - {get_state,Ref,From} -> % Debug function. - reply(From,Ref,{ok,LD,PublLD}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime); - _Other -> - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end. - - -%% ============================================================================= -%% First level help functions. -%% ============================================================================= - -%% Function which opens the trace-information file(s). It must understand -%% the tidata specification which is part of the tracerdata given to the -%% runtime component during init_tracing. -%% 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=byte_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 - MegaS1+1<MegaS2 -> % More than 1 Mega sec. difference. - true; - MegaS1==MegaS2,S1+DiffS<S2 -> - true; - MegaS1+1==MegaS2,S1+DiffS<S2+1000000 -> - true; - true -> - false - end. -%% ----------------------------------------------------------------------------- - -%% This help function adds a {tracer,Tracer} to the enable-list in a 'trace' -%% match spec action. The reason for this is that the author of the a meta -%% match spec meant to turn tracing on for the process executing the match spec -%% can not know the tracer. This since the match spec is most likely authored -%% at the control component's node, and not here. -%% Note the double tuple necessary to make it just precise a tuple! -%% Returns a new match spec. -add_tracer([MS1|Rest],Tracer) -> - [add_tracer_2(MS1,Tracer)|add_tracer(Rest,Tracer)]; -add_tracer([],_) -> - []; -add_tracer(NotList,_Tracer) -> % Can be 'false', but also an error. - NotList. - -add_tracer_2({Head,Cond,Body},Tracer) -> - {Head,Cond,add_tracer_3(Body,Tracer)}; -add_tracer_2(Faulty,_Tracer) -> - Faulty. - -add_tracer_3([{trace,Disable,Enable}|Rest],Tracer) when is_list(Enable) -> - [{trace,Disable,Enable++[{{tracer,Tracer}}]}|Rest]; -add_tracer_3([ActionTerm|Rest],Tracer) -> - [ActionTerm|add_tracer_3(Rest,Tracer)]; -add_tracer_3([],_Tracer) -> - []; -add_tracer_3(FaultyBody,_Tracer) -> - FaultyBody. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% Help functions handling internal loopdata. -%% ----------------------------------------------------------------------------- - --record(ld,{init_publ_ld_mfa, % {M,F,Args} - remove_publ_ld_mf, % {M,F} | void - clean_publ_ld_mf, % {Mod,Func} - ms_mfarities=notable, % ETS holding names match functions. - call_mfarities=[], % [{{M,F,Arity},2-TupleOrFun},...] - return_mfarities=[], % [{{M,F,Arity},2-TupleOrFun},...] - remove_mfarities=[] - }). - -mk_new_ld(InitPublLDmfa,RemovePublLDmf,CleanPublLDmf,TId) -> - #ld{ - init_publ_ld_mfa=InitPublLDmfa, - remove_publ_ld_mf=RemovePublLDmf, - clean_publ_ld_mf=CleanPublLDmf, - ms_mfarities=TId - }. -%% ----------------------------------------------------------------------------- - -%% Function which restores the internal loop data to somekind of initial state. -%% This is useful when tracing has been suspended. -reset_ld(#ld{init_publ_ld_mfa=InitPublLDmfa, - remove_publ_ld_mf=RemovePublLDmf, - clean_publ_ld_mf=CleanPublLDmf, - ms_mfarities=TId}) -> - ets:match_delete(TId,{'_','_'}), % Empty the table. - #ld{init_publ_ld_mfa=InitPublLDmfa, - remove_publ_ld_mf=RemovePublLDmf, - clean_publ_ld_mf=CleanPublLDmf, - ms_mfarities=TId}. -%% ----------------------------------------------------------------------------- - -get_initpublldmfa_ld(#ld{init_publ_ld_mfa=InitPublLDmfa}) -> - InitPublLDmfa. -%% ----------------------------------------------------------------------------- - -get_removepublldmf_ld(#ld{remove_publ_ld_mf=RemovePublLDmf}) -> - RemovePublLDmf. -%% ----------------------------------------------------------------------------- - -get_cleanpublldmf_ld(#ld{clean_publ_ld_mf=CleanPublLDmf}) -> - CleanPublLDmf. -%% ----------------------------------------------------------------------------- - -%% Help function adding data associated with a meta traced function to the -%% internal loopdata. Called when meta tracing is activated for M:F/Arity. -init_tpm_ld(M,F,Arity,CallFunc,ReturnFunc,RemoveFunc,LD) -> - ets:insert(LD#ld.ms_mfarities,{{M,F,Arity},[]}), - CallFuncs=LD#ld.call_mfarities, - ReturnFuncs=LD#ld.return_mfarities, - RemoveFuncs=LD#ld.remove_mfarities, - LD#ld{call_mfarities=[{{M,F,Arity},CallFunc}|CallFuncs], - return_mfarities=[{{M,F,Arity},ReturnFunc}|ReturnFuncs], - remove_mfarities=[{{M,F,Arity},RemoveFunc}|RemoveFuncs]}. -%% ----------------------------------------------------------------------------- - -%% Help function which answers the question if we have already initiated the -%% function. It is done by looking in the ETS-table with named match-functions. -%% If there is an entry in the set-type table for M:F/Arity, the function is -%% initiated. -%% Returns 'yes' or 'no'. -check_mfarity_exists(M,F,Arity) -> - case ets:lookup(?NAMED_MS_TAB,{M,F,Arity}) of - [] -> - no; - [_] -> - yes - end. -%% ----------------------------------------------------------------------------- - -%% Help function adding an entry with [{MSname,MSlist}|MSsNames] for M:F/Arity. -%% Note that any already existing entry is removed. -%% Returns nothing significant. -put_ms_ld(M,F,Arity,MSname,MS,MSsNames) -> - ets:insert(?NAMED_MS_TAB,{{M,F,Arity},[{MSname,MS}|MSsNames]}). -%% ----------------------------------------------------------------------------- - -%% Help function taking a list of {MSname,MSs} and storing them in the -%% internal loop data structure. The storage is actually implemented as an ETS -%% table. Any previous list of {MSname,MSs} associated with this {M,F,Arity} will -%% be lost. Returns nothing significant. -set_ms_ld(M,F,Arity,MSsNames) -> - ets:insert(?NAMED_MS_TAB,{{M,F,Arity},MSsNames}). -%% ----------------------------------------------------------------------------- - -%% Help function fetching a list of {MSname,MatchSpecs} for a M:F/Arity. The -%% match-functions are stored in an ETS table searchable on {M,F,Arity}. -get_ms_ld(M,F,Arity) -> - case ets:lookup(?NAMED_MS_TAB,{M,F,Arity}) of - [{_MFArity,MSsNames}] -> - MSsNames; - [] -> - [] - end. -%% ----------------------------------------------------------------------------- - -%% Help function removing all saved match-specs for a certain M:F/Arity. -%% Returns a new loopdata structure. -remove_ms_ld(M,F,Arity,LD) -> - ets:delete(LD#ld.ms_mfarities,{M,F,Arity}), - LD. -%% ----------------------------------------------------------------------------- - -%% Help function which removes all information about a meta traced function from -%% the internal loopdata. Returns a new loopdata structure. -ctpm_ld(M,F,Arity,LD) -> - ets:delete(LD#ld.ms_mfarities,{M,F,Arity}), - NewCallFuncs=lists:keydelete({M,F,Arity},1,LD#ld.call_mfarities), - NewReturnFuncs=lists:keydelete({M,F,Arity},1,LD#ld.return_mfarities), - NewRemoveFuncs=lists:keydelete({M,F,Arity},1,LD#ld.remove_mfarities), - LD#ld{call_mfarities=NewCallFuncs, - return_mfarities=NewReturnFuncs, - remove_mfarities=NewRemoveFuncs}. -%% ----------------------------------------------------------------------------- - -get_call_func_ld(M,F,Arity,#ld{call_mfarities=CallFuncs}) -> - case lists:keysearch({M,F,Arity},1,CallFuncs) of - {value,{_,MF}} -> - MF; - false -> - false - end. -%% ----------------------------------------------------------------------------- - -get_return_func_ld(M,F,Arity,#ld{return_mfarities=CallFuncs}) -> - case lists:keysearch({M,F,Arity},1,CallFuncs) of - {value,{_,MF}} -> - MF; - false -> - false - end. -%% ----------------------------------------------------------------------------- - -get_remove_func_ld(M,F,Arity,#ld{remove_mfarities=RemoveFuncs}) -> - case lists:keysearch({M,F,Arity},1,RemoveFuncs) of - {value,{_,MF}} -> - MF; - false -> - false - end. -%% ----------------------------------------------------------------------------- - -%% Function returning a list of all {Mod,Func,Arity} which are currently meta -%% traced. It does do by listifying the call_mfarities field in the internal -%% loopdata. -get_all_meta_funcs_ld(#ld{call_mfarities=CallFuncs}) -> - lists:map(fun({MFArity,_})->MFArity end,CallFuncs). -%% ----------------------------------------------------------------------------- - - -%% ============================================================================= -%% Functions for the standard PublLD structure. -%% -%% It is tuple {Part1,GlobalData} where Part1 is of length at least 2. -%% Where each field is a list of tuples. The last item in each tuple shall be -%% a now tuple, making it possible to clean it away should it be too old to be -%% relevant (there was no return_from message due to a failure). -%% Other fields can be used for other functions. -%% The GlobalData is not cleaned but instead meant to store data must be passed -%% to each CallFunc when a meta trace message arrives. -%% ============================================================================= - -%% Function returning our standard priv-loopdata structure. -init_std_publld(Size,GlobalData) -> - {list_to_tuple(lists:duplicate(Size,[])),GlobalData}. -%% ----------------------------------------------------------------------------- - -%% Function capable of cleaning out a standard publ-ld. The last element of each -%% tuple must be the now item. -%% Returns a new publ-ld structure. -clean_std_publld({Part1,GlobalData}) -> - {clean_std_publld_2(Part1,now(),tuple_size(Part1),[]),GlobalData}. - -clean_std_publld_2(_,_,0,Accum) -> - list_to_tuple(Accum); -clean_std_publld_2(PublLD,Now,Index,Accum) -> - NewTupleList=clean_std_publld_3(element(Index,PublLD),Now), - clean_std_publld_2(PublLD,Now,Index-1,[NewTupleList|Accum]). - -clean_std_publld_3([Tuple|Rest],Now) -> - PrevNow=element(tuple_size(Tuple),Tuple), % Last item shall be the now item. - case difference_in_now(PrevNow,Now,30) of - true -> % Remove it then! - clean_std_publld_3(Rest,Now); - false -> % Keep it! - [Tuple|clean_std_publld_3(Rest,Now)] - end; -clean_std_publld_3([],_) -> - []. -%% ----------------------------------------------------------------------------- - -%% ============================================================================= -%% Functions used as handling functions (as funs) for registered process names. -%% (Given that we use the standard priv-ld, otherwise you must do your own!). -%% ============================================================================= - -%% Call-back for initializing the meta traced functions there are quick functions -%% for. Returns a new public loop data structure. -metafunc_init(erlang,register,2,{Part1,GlobalData}) -> - {setelement(1,Part1,[]),GlobalData}. -%% ----------------------------------------------------------------------------- - -%% Call-function for erlang:register/2. -%% This function adds the call to register/2 to a standard priv-ld structure. -%% Note that we *must* search for previous entries from the same process. If such -%% still in structure it means a failed register/2 call. It must first be removed -%% so it can not be mixed up with this one. Since meta-trace message will arrive -%% in order, there was no return_from message for that call if we are here now. -local_register_call(CallingPid,{call,[Alias,Pid],TS},{Part1,GlobalData}) -> - TupleList=element(1,Part1), % The register/2 entry in a std. priv-ld. - NewTupleList=lists:keydelete(CallingPid,1,TupleList), % If present, remove previous call. - {ok, - {setelement(1,Part1,[{CallingPid,{Alias,Pid},TS}|NewTupleList]),GlobalData}, - void}. - -%% Return-function for the erlang:register/2 BIF. -%% This function formulates the output and removes the corresponding call entry -%% from the standard priv-ld structure. -local_register_return(CallingPid,{return_from,_Val,_TS},PublLD={Part1,GlobalData}) -> - TupleList=element(1,Part1), % The register/2 entry in a std. priv-ld. - case lists:keysearch(CallingPid,1,TupleList) of - {value,{_,{Alias,Pid},NowTS}} -> - NewTupleList=lists:keydelete(CallingPid,1,TupleList), - {ok, - {setelement(1,Part1,NewTupleList),GlobalData}, - term_to_binary({Pid,Alias,alias,NowTS})}; - false -> % Strange, then don't know what to do. - {ok,PublLD,void} % Do nothing seems safe. - end; -local_register_return(CallingPid,{exception_from,_Val,_TS},{Part1,GlobalData}) -> - TupleList=element(1,Part1), % The register/2 entry in a std. priv-ld. - NewTupleList=lists:keydelete(CallingPid,1,TupleList), - {ok,{setelement(1,Part1,NewTupleList),GlobalData},void}; % No association then. -local_register_return(_,_,PublLD) -> % Don't understand this. - {ok,PublLD,void}. - -%% When unregister/1 us called we simply want a unalias entry in the ti-file. -%% We can unfortunately not connect it with a certain pid. -local_unregister_call(_CallingPid,{_TypeTag,[Alias],TS},PublLD) -> - {ok,PublLD,term_to_binary({undefined,Alias,unalias,TS})}. -%% ----------------------------------------------------------------------------- - -%% Call-function for global:register_name/2,/3. -%% This function is actually the call function for the handle_call/3 in the -%% global server. Note that we must check that we only do this on the node -%% where Pid actually resides. -global_register_call(_CallingPid,{call,[{register,Alias,P,_},_,_],TS},PublLD) - when node(P)==node()-> - {ok,PublLD,term_to_binary({P,{global,Alias},alias,TS})}; -global_register_call(_CallingPid,_,PublLD) -> - {ok,PublLD,void}. - -%% Call-function for global:unregister_name. It acutally checks on the use of -%% global:delete_global_name/2 which is called when ever a global name is removed. -global_unregister_call(_CallingPid,{call,[Alias,P],TS},PublLD) when node(P)==node()-> - {ok,PublLD,term_to_binary({P,{global,Alias},unalias,TS})}; -global_unregister_call(_CallingPid,_,PublLD) -> - {ok,PublLD,void}. -%% ----------------------------------------------------------------------------- - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - |