diff options
Diffstat (limited to 'lib/inviso/src/inviso_tool_sh.erl')
-rw-r--r-- | lib/inviso/src/inviso_tool_sh.erl | 1749 |
1 files changed, 0 insertions, 1749 deletions
diff --git a/lib/inviso/src/inviso_tool_sh.erl b/lib/inviso/src/inviso_tool_sh.erl deleted file mode 100644 index b02f498c5b..0000000000 --- a/lib/inviso/src/inviso_tool_sh.erl +++ /dev/null @@ -1,1749 +0,0 @@ -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2011. 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% -%% -%% Description: -%% The runtime component of the trace tool Inviso. -%% -%% Authors: -%% Lennart �hman, [email protected] -%% ----------------------------------------------------------------------------- - --module(inviso_tool_sh). - -%% Inviso Session Handler. -%% This is the code for the session handler process. Its purpose is that we have -%% one session handler process for each trace session started through the -%% start_session inviso tool API. The session handler process is responsible for: -%% -%% -Knowing the state/status of all participating runtime components. -%% -Keeping storage of all tracerdata all our participants have used. This means -%% also to find out the tracerdata of runtime components connecting by them -%% selves. -%% -%% STORAGE STRATEGY -%% ---------------- -%% The local information storage can be changed by two things. Either by executing -%% commands issued through our APIs. Or by receiving trace_event from the control -%% component. When we execute commands, a corresponding event will also follow. -%% Meaning that in those situations we are informed twice. -%% A simple strategy could be to wait for the event even when doing the changes -%% to the runtime components our self (through commands). But that may result in -%% a small time frame where someone might do yet another command and failing -%% because the local information storage is not uptodate as it would have been -%% expected to be. Therefore we always update the local storage when making changes -%% to a runtime component our selves. There will eventually be a double update -%% through an incoming event. But the storage must coop with that, preventing -%% inconsitancies to happend. An example of a strategy is that the tracerdata table -%% is a bag, not allowing for double entries of the same kind. Therefore a double -%% update is harmless there. - -%% ------------------------------------------------------------------------------ -%% Module wide constants. -%% ------------------------------------------------------------------------------ --define(LOCAL_RUNTIME,local_runtime). % Used as node name when non-disitrbuted. --define(TRACING,tracing). % A state defined by the control component. --define(RUNNING,running). % A status according to control componet. - --define(COPY_LOG_FROM,copy_log_from). % Common fileystem option. -%% ------------------------------------------------------------------------------ - -%% ------------------------------------------------------------------------------ -%% API exports. -%% ------------------------------------------------------------------------------ --export([start_link/5,start_link/8]). --export([cancel_session/1,stop_session/3]). --export([reactivate/1,reactivate/2]). --export([ctpl/5,tpl/5,tpl/6,tpl/7, - tf/2,tf/3, - tpm_localnames/2,init_tpm/6,init_tpm/9,tpm/6,tpm/7,tpm/10, - tpm_ms/7,ctpm_ms/6,ctpm/5 - ]). -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ -%% Internal exports. -%% ------------------------------------------------------------------------------ --export([init/1,handle_call/3,handle_info/2,terminate/2]). - --export([get_loopdata/1]). -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ -%% Includes. -%% ------------------------------------------------------------------------------ --include_lib("kernel/include/file.hrl"). % Necessary for file module. -%% ------------------------------------------------------------------------------ - - -%% ============================================================================== -%% Exported API functions. -%% ============================================================================== - -%% start_link(From,NodeParams,CtrlNode,CtrlPid,SafetyCatches,NodesIn,NodesNotIn) = -%% {ok,Pid} | {error,Reason} -%% From= pid(), the initial client expecting the reply. -%% NodeParams=[{Node,TracerData},{Node,TracerData,Opts}...] -%% CtrlNode=atom() | 'void', the node where the trace control component is. -%% CtrlPid=pid(), the pid of the trace control component. -%% SafetyCatches= -%% Dir=string(), where to place fetched logs and the merged log. -%% Dbg=debug structure. -%% NodesIn=[Node,...], list of nodes already in another session. -%% NodesNotIn=[Node,...], list of nodes not in another session. -%% -%% Starts a session-handler. It keeps track of the the state and status of all -%% participating runtime components. Note that there is a non-distributed case too. -%% In the non-distributed case there is no things such as CtrlNode. -start_link(From,TracerData,CtrlPid,SafetyCatches,Dbg) -> - gen_server:start_link(?MODULE, - {self(),From,TracerData,CtrlPid,SafetyCatches,Dbg}, - []). - -start_link(From,NodeParams,CtrlNode,CtrlPid,SafetyCatches,Dbg,NodesIn,NodesNotIn) -> - gen_server:start_link(?MODULE, - {self(),From,NodeParams,CtrlNode,CtrlPid, - SafetyCatches,Dbg,NodesIn,NodesNotIn}, - []). -%% ------------------------------------------------------------------------------ - -%% Stops tracing where it is ongoing. Fetches all logfiles. -stop_session(SID,Dir,Prefix) -> - gen_server:call(SID,{stop_session,Dir,Prefix}). -%% ------------------------------------------------------------------------------ - -%% stop_session(SID) = ok -%% -%% Cancels the session brutaly. All runtime components are made to stop tracing, -%% all local log files are removed using the tracerdata we know for them. -cancel_session(SID) -> - gen_server:call(SID,cancel_session). -%% ------------------------------------------------------------------------------ - -%% reactivate(SID) = {ok, -%% reactivate(SID,Nodes) = {ok,NodeResults} | {error,Reason}. -%% SID=session id, pid(). -%% Nodes=[Node,...] -%% NodeResult=[{Node,Result},...] -%% Result={Good,Bad} -%% Good,Bad=integer(), the number of redone activities. -%% -%% Function which reactivates runtime components being suspended. This is done -%% replaying all trace flags (in the correct order) to the corresponding nodes. -%% Note that this may also mean turning flags off. Like first turning them on -%% then off a split second later. -reactivate(SID) -> - gen_server:call(SID,reactivate). %% NOT IMPLEMENTED YET. -reactivate(SID,Nodes) -> - gen_server:call(SID,{reactivate,Nodes}). -%% ------------------------------------------------------------------------------ - - -%% tpl(SessionID,Mod,Func,Arity,MS)= -%% tpl(SessionID,Mod,Func,Arity,MS,Opts)={ok,N}|{error,Reason}. -%% tpl(SessionID,Nodes,Mod,Func,Arity,MS)= -%% tpl(SessionID,Nodes,Mod,Func,Arity,MS,Opts)={ok,Result}|{error,Reason} -%% Mod='_' | ModuleName | ModRegExp | {DirRegExp,ModRegExp} -%% ModRegExp=DirRegExp= string() -%% Func='_' | FunctionName -%% Arity='_' | integer() -%% MS=[] | false | a match specification -%% Opts=[Opts,...] -%% Opt={arg,Arg}, disable_safety, {expand_regexp_at,NodeName}, only_loaded -%% Nodes=[NodeName,...] -tpl(SID,Mod,Func,Arity,MS) -> - gen_server:call(SID,{tp,tpl,Mod,Func,Arity,MS,[]}). -tpl(SID,Mod,Func,Arity,MS,Opts) when list(MS);MS==true;MS==false -> - gen_server:call(SID,{tp,tpl,Mod,Func,Arity,MS,Opts}); -tpl(SID,Nodes,Mod,Func,Arity,MS) when integer(Arity);Arity=='_' -> - gen_server:call(SID,{tp,tpl,Nodes,Mod,Func,Arity,MS,[]}). -tpl(SID,Nodes,Mod,Func,Arity,MS,Opts) -> - gen_server:call(SID,{tp,tpl,Nodes,Mod,Func,Arity,MS,Opts}). -%% ------------------------------------------------------------------------------ - -%% ctpl(SessionID,Nodes,Mod,Func,Arity)= -%% See tpl/X for arguments. -%% -%% Removes local trace-patterns from functions. -ctpl(SID,Nodes,Mod,Func,Arity) -> - gen_server:call(SID,{ctp,ctpl,Nodes,Mod,Func,Arity}). -%% ------------------------------------------------------------------------------ - - -tpm_localnames(SID,Nodes) -> - gen_server:call(SID,{tpm_localnames,Nodes}). - -%% tpm_globalnames(SID,Nodes) -> -%% gen_server:call(SID,{tpm_globalnames,Nodes}). - -init_tpm(SID,Nodes,Mod,Func,Arity,CallFunc) -> - gen_server:call(SID,{init_tpm,Nodes,Mod,Func,Arity,CallFunc}). -init_tpm(SID,Nodes,Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> - gen_server:call(SID, - {init_tpm,Nodes,Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc}). -tpm(SID,Nodes,Mod,Func,Arity,MS) -> - gen_server:call(SID,{tpm,Nodes,Mod,Func,Arity,MS}). -tpm(SID,Nodes,Mod,Func,Arity,MS,CallFunc) -> - gen_server:call(SID,{tpm,Nodes,Mod,Func,Arity,MS,CallFunc}). -tpm(SID,Nodes,Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> - gen_server:call(SID,{tpm,Nodes,Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc}). - -tpm_ms(SID,Nodes,Mod,Func,Arity,MSname,MS) -> - gen_server:call(SID,{tpm_ms,Nodes,Mod,Func,Arity,MSname,MS}). - -ctpm_ms(SID,Nodes,Mod,Func,Arity,MSname) -> - gen_server:call(SID,{tpm_ms,Nodes,Mod,Func,Arity,MSname}). - -ctpm(SID,Nodes,Mod,Func,Arity) -> - gen_server:call(SID,{ctpm,Nodes,Mod,Func,Arity}). -%% ------------------------------------------------------------------------------ - - -%% tf(SessionID,Nodes,TraceConfList)= -%% TraceConfList=[{PidSpec,Flags},...] -%% PidSpec=pid()|atom()|all|new|existing -%% Flags=[Flag,...] -tf(SID,TraceConfList) -> - gen_server:call(SID,{tf,TraceConfList}). -tf(SID,Nodes,TraceConfList) -> - gen_server:call(SID,{tf,Nodes,TraceConfList}). -%% ------------------------------------------------------------------------------ - - -get_loopdata(SID) -> - gen_server:call(SID,get_loopdata). -%% ------------------------------------------------------------------------------ - -%% ============================================================================== -%% Genserver call-backs. -%% ============================================================================== - -%% Initial function for the session handler process. The nodes participating in -%% the session must previously have been added to our control component by the tool. -%% The session handler first finds out the state/status of the specified runtime -%% components, then it tries to initiate tracing on those where it is applicable. -%% Note that a reply to the initial (tool)client is done from here instead from -%% the tool-server. -init({Parent,From,TracerData,CtrlPid,SafetyCatches,Dbg}) -> % The non-distributed case. - {ok,StateStatus}=init_rtcomponent_states([],void,CtrlPid,[?LOCAL_RUNTIME]), - case is_tool_internal_tracerdata(TracerData) of - false -> % We shall initiate local runtime. - case inviso:init_tracing(TracerData) of - ok -> - gen_server:reply(From,{ok,{self(),ok}}), - {ok,mk_ld(Parent, - void, - CtrlPid, - to_rtstates([{?LOCAL_RUNTIME,{tracing,?RUNNING},[]}]), - [{?LOCAL_RUNTIME,TracerData}], - [], - SafetyCatches, - Dbg)}; - {error,Reason} -> % It might have become suspended?! - gen_server:reply(From,{error,Reason}), - {ok,mk_ld(Parent, - void, - CtrlPid, - to_rtstates([{?LOCAL_RUNTIME,StateStatus,[]}]), - [{?LOCAL_RUNTIME,TracerData}], - [], - SafetyCatches, - Dbg)} - end; - true -> % We shall not pass this one on. - gen_server:reply(From,{ok,{self(),ok}}), % Then it is ok. - {ok,mk_ld(Parent, - void, - CtrlPid, - to_rtstates([{?LOCAL_RUNTIME,StateStatus,[]}]), - [], - [?LOCAL_RUNTIME], - SafetyCatches, - Dbg)} - end; -init({Parent,From,NodeParams,CtrlNode,CtrlPid,SafetyCatches,Dbg,NodesIn,NodesNotIn}) -> - case init_rtcomponent_states(NodeParams,CtrlNode,CtrlPid,NodesNotIn) of - {ok,States} -> % A list of {Node,{State,Status},Opts}. - {NodeParams2,Nodes2}=remove_nodeparams(NodesIn,NodeParams), - case inviso_tool_lib:inviso_cmd(CtrlNode,init_tracing,[NodeParams2]) of - {ok,Result} -> % Resulted in state changes! - RTStates=set_tracing_rtstates(to_rtstates(States),Result), - ReplyValue=init_fix_resultnodes(NodesIn,Nodes2,Result), - gen_server:reply(From,{ok,{self(),ReplyValue}}), - {ok,mk_ld(Parent,CtrlNode,CtrlPid,RTStates, - NodeParams2,Nodes2,SafetyCatches,Dbg)}; - {error,Reason} -> % Some general failure. - inviso_tool_lib:inviso_cmd(CtrlNode,unsubscribe,[]), - gen_server:reply(From,{error,{init_tracing,Reason}}), - {stop,{init_tracing,Reason}}; - What -> - io:format("GOT:~n~w~n",[What]), - exit(foo) - end; - {error,Reason} -> % Unable to get the state/status. - inviso_tool_lib:inviso_cmd(CtrlNode,unsubscribe,[]), - gen_server:reply(From,{error,Reason}), - {stop,{error,Reason}}; - What -> - io:format("GOT:~n~w~n",[What]), - exit(foo) - end. -%% ------------------------------------------------------------------------------ - -%% To stop a session means stop the tracing and remove all local files on the -%% runtime nodes. We do have a table with all tracer data and that is how we are -%% going to recreate what files to remove. -%% Since runtime components may actually change state when this procedure is -%% on-going, we do not care! It is the state in the session handling process at -%% the time of start of this procedure which is used. -handle_call(cancel_session,_From,LD) -> - CtrlNode=get_ctrlnode_ld(LD), - RTStates=get_rtstates_ld(LD), - Dbg=get_dbg_ld(LD), - TracingNodes=get_all_tracing_nodes_rtstates(RTStates), - case stop_all_tracing(CtrlNode,Dbg,TracingNodes) of - ok-> % Hopefully all nodes are stopped now. - AvailableNodes=get_all_available_nodes_rtstates(RTStates), - TRDstorage=get_trdstorage_ld(LD), - remove_all_local_logs(CtrlNode,TRDstorage,AvailableNodes,Dbg), - {stop,normal,ok,LD}; % LD actually not correct now! - {error,Reason} -> % Some serious error when stop_tracing. - {stop,normal,{error,Reason},LD} - end; -%% ------------------------------------------------------------------------------ - -%% *Stop all tracing on runtime components still tracing. -%% *Copy all local log files to the collection directory. -handle_call({stop_session,Dir,Prefix},_From,LD) -> - case check_directory_exists(Dir) of % Check that this directory exists here. - true -> - RTStates=get_rtstates_ld(LD), - CtrlNode=get_ctrlnode_ld(LD), - Dbg=get_dbg_ld(LD), - TracingNodes=get_all_tracing_nodes_rtstates(RTStates), - case stop_all_tracing(CtrlNode,Dbg,TracingNodes) of - ok -> % Hopefully no node is still tracing now. - TRDstorage=get_trdstorage_ld(LD), - AvailableNodes=get_all_available_nodes_rtstates(RTStates), - {FailedNodes,FetchedFiles}= - transfer_logfiles(RTStates,CtrlNode,Dir,Prefix, - TRDstorage,Dbg,AvailableNodes), - RemoveNodes= % We only delete local logs where fetch ok. - lists:filter(fun(N)-> - case lists:keysearch(N,1,FailedNodes) of - {value,_} -> - false; - false -> - true - end - end, - AvailableNodes), - remove_all_local_logs(CtrlNode,TRDstorage,RemoveNodes,Dbg), - {stop,normal,{ok,{FailedNodes,FetchedFiles}},LD}; - {error,Reason} -> % Some general failure, quit. - {stop,normal,{error,Reason},LD} - end; - false -> % You specified a non-existing directory! - {reply,{error,{faulty_dir,Dir}},LD} - end; -%% ------------------------------------------------------------------------------ - -handle_call({reactivate,Nodes},_From,LD) -> - RTStates=get_rtstates_ld(LD), - {OurNodes,OtherNodes}= - remove_nodes_not_ours(Nodes,get_all_session_nodes_rtstates(RTStates)), - CtrlNode=get_ctrlnode_ld(LD), - ACTstorage=get_actstorage_ld(LD), - case h_reactivate(CtrlNode,OurNodes,ACTstorage) of - {ok,Results} -> % A list of {Node,Result}. - if - OtherNodes==[] -> % Normal case, no non-session nodes. - {reply,{ok,Results},LD}; - true -> % Add error values for non-session nodes. - {reply, - {ok, - lists:map(fun(N)->{N,{error,not_in_session}} end,OtherNodes)++ - Results}, - LD} - end; - {error,Reason} -> % Then this error takes presidence. - {reply,{error,Reason},LD} - end; -%% ------------------------------------------------------------------------------ - -%% Call-back for set trace-pattern for both global and local functions. -handle_call({tp,PatternFunc,Mod,F,A,MS,Opts},_From,LD) -> - Reply=h_tp(all,PatternFunc,Mod,F,A,MS,Opts,LD), % For all active nodes in the session. - {reply,Reply,LD}; -handle_call({tp,PatternFunc,Nodes,Mod,F,A,MS,Opts},_From,LD) -> - RTStates=get_rtstates_ld(LD), - SNodes=get_all_session_nodes_rtstates(RTStates), % Notes belongoing to the session. - {Nodes2,FaultyNodes}=remove_nodes_not_ours(Nodes,SNodes), - Reply=h_tp(Nodes2,PatternFunc,Mod,F,A,MS,Opts,LD), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,FaultyNodes), - {reply,ErrorReply++Reply,LD}; -%% ------------------------------------------------------------------------------ - -%% Call-back handling the removal of both local and global trace-patterns. -%% NOT IMPLEMENTED YET. -handle_call({ctp,PatternFunc,Nodes,Mod,F,A},_From,LD) -> - Reply=h_ctp(Nodes,PatternFunc,Mod,F,A,LD), - {reply,Reply,LD}; -%% ------------------------------------------------------------------------------ - -handle_call({tpm_localnames,Nodes},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_tpm_localnames(get_ctrlnode_ld(LD),Nodes2,RTStates,ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; - -handle_call({init_tpm,Nodes,Mod,Func,Arity,CallFunc},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_all_tpm(get_ctrlnode_ld(LD), - Nodes2, - init_tpm, - [Mod,Func,Arity,CallFunc], - RTStates, - ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; - -handle_call({init_tpm,Nodes,Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_all_tpm(get_ctrlnode_ld(LD), - Nodes2, - init_tpm, - [Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc], - RTStates, - ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; - -handle_call({tpm,Nodes,Mod,Func,Arity,MS},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_all_tpm(get_ctrlnode_ld(LD),Nodes2,tpm,[Mod,Func,Arity,MS],RTStates,ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; - -handle_call({tpm,Nodes,Mod,Func,Arity,MS,CallFunc},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_all_tpm(get_ctrlnode_ld(LD), - Nodes2, - tpm, - [Mod,Func,Arity,MS,CallFunc], - RTStates, - ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; - -handle_call({tpm,Nodes,Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_all_tpm(get_ctrlnode_ld(LD), - Nodes2, - tpm, - [Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc], - RTStates, - ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; - -handle_call({tpm_ms,Nodes,Mod,Func,Arity,MSname,MS},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_all_tpm(get_ctrlnode_ld(LD), - Nodes2, - tpm_ms, - [Mod,Func,Arity,MSname,MS], - RTStates, - ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; - -handle_call({ctpm_ms,Nodes,Mod,Func,Arity,MSname},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_all_tpm(get_ctrlnode_ld(LD), - Nodes2, - ctpm_ms, - [Mod,Func,Arity,MSname], - RTStates, - ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; - -handle_call({ctpm,Nodes,Mod,Func,Arity},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_all_tpm(get_ctrlnode_ld(LD),Nodes2,ctpm,[Mod,Func,Arity],RTStates,ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; -%% ------------------------------------------------------------------------------ - -%% Call-back for setting process trace-flags. Handles both distributed and non- -%% distributed case. -handle_call({tf,TraceConfList},From,LD) -> - handle_call({tf,all,TraceConfList},From,LD); -handle_call({tf,Nodes,TraceConfList},_From,LD) -> - {Reply,NewACTstorage}=h_tf(get_ctrlnode_ld(LD), - Nodes, - TraceConfList, - get_actstorage_ld(LD), - get_rtstates_ld(LD)), - {reply,Reply,put_actstorage_ld(NewACTstorage,LD)}; -%% ------------------------------------------------------------------------------ - - - -handle_call(get_loopdata,_From,LD) -> - io:format("The loopdata:~n~p~n",[LD]), - {reply,ok,LD}. -%% ------------------------------------------------------------------------------ - - -%% Clause handling an incomming state-change event from the control component. -%% Note that it does not have to be one of our nodes since it is not possible -%% to subscribe to certain node-events. -%% We may very well get state-change events for state-changes we are the source -%% to our selves. Those state-changes are already incorporated into the RTStates. -%% There is however no harm in doing them again since we know that this event -%% message will reach us before a reply to a potentially following state-change -%% request will reach us. Hence we will do all state-changes in the correct order, -%% even if sometimes done twice. -handle_info({trace_event,CtrlPid,_Time,{state_change,Node,{State,Status}}},LD) -> - case get_ctrlpid_ld(LD) of - CtrlPid -> % It is from our control component. - case {State,Status} of - {?TRACING,?RUNNING} -> % This is the only case when new tracerdata! - NewTracerData=add_current_tracerdata_ld(get_ctrlnode_ld(LD), - Node, - get_rtstates_ld(LD), - get_trdstorage_ld(LD)), - NewRTStates=statechange_rtstates(Node,State,Status,get_rtstates_ld(LD)), - {noreply,put_trdstorage_ld(NewTracerData, - put_rtstates_ld(NewRTStates,LD))}; - _ -> % In all other cases, just fix rtstates. - NewRTStates=statechange_rtstates(Node,State,Status,get_rtstates_ld(LD)), - {noreply,put_rtstates_ld(NewRTStates,LD)} - end; - _ -> - {noreply,LD} - end; -%% If a new runtime component connects to our trace control component, and it is -%% in our list of runtime components belonging to this session, we may update its -%% state to now being present. Otherwise it does not belong to this session. -%% Note that we avoid updating an already connected runtime component. This -%% can happend if it connected by itself after we started the session handler, -%% but before we managed to initiate tracing. Doing so or not will not result in -%% any error in the long run, but during a short period of time we might be -%% prevented from doing things with the runtime though it actually is tracing. -handle_info({trace_event,CtrlPid,_Time,{connected,Node,{_Tag,{State,Status}}}},LD) -> - case get_ctrlpid_ld(LD) of - CtrlPid -> % It is from our control component. - case get_statestatus_rtstates(Node,get_rtstates_ld(LD)) of - {ok,unavailable} -> % This is the situation when we update! - NewRTStates=statechange_rtstates(Node,State,Status,get_rtstates_ld(LD)), - {noreply,put_rtstates_ld(NewRTStates,LD)}; - _ -> % In all other cases, let it be. - {noreply,LD} - end; - _ -> % Not from our control component. - {noreply,LD} - end; -%% If a runtime component disconnects we mark it as unavailable. We must also -%% remove all saved trace-flags in order for them to not be accidently reactivated -%% should the runtime component reconnect and then suspend. -handle_info({trace_event,CtrlPid,_Time,{disconnected,Node,_}},LD) -> - case get_ctrlpid_ld(LD) of - CtrlPid -> % It is from our control component. - NewRTStates=set_unavailable_rtstates(Node,get_rtstates_ld(LD)), - NewACTstorage=del_node_actstorage(Node,get_actstorage_ld(LD)), - {noreply,put_actstorage_ld(NewACTstorage,put_rtstates_ld(NewRTStates,LD))}; - _ -> - {noreply,LD} - end; -handle_info(_,LD) -> - {noreply,LD}. -%% ------------------------------------------------------------------------------ - -%% In terminate we cancel our subscription to event from the trace control component. -%% That should actually not be necessary, but lets do it the correct way! -terminate(_,LD) -> - case get_ctrlnode_ld(LD) of - void -> % Non-distributed. - inviso:unsubscribe(); - Node -> - inviso_tool_lib:inviso_cmd(Node,unsubscribe,[]) - end. -%% ------------------------------------------------------------------------------ - - - -%% ============================================================================== -%% First level help functions to call-backs. -%% ============================================================================== - -%% ------------------------------------------------------------------------------ -%% Help functions to init. -%% ------------------------------------------------------------------------------ - -%% Help function which find out the state/status of the runtime components. -%% Note that since we have just started subscribe to state changes we must -%% check our inqueue to see that we have no waiting messages for the nodes -%% we learned the state/status of. If there is a waiting message we don't -%% know whether that was a state change received before or after the state -%% check was done. We will then redo the state-check. -%% Returns {ok,States} or {error,Reason}. -%% Where States is [{Node,{State,Status},Opts},...]. -%% Note that {error,Reason} can not occur in the non-distributed case. -init_rtcomponent_states(NodeParams,void,CtrlPid,Nodes) -> % The non-distributed case. - ok=inviso:subscribe(), - init_rtcomponent_states_2(NodeParams,void,CtrlPid,Nodes,[]); -init_rtcomponent_states(NodeParams,CtrlNode,CtrlPid,Nodes) -> - ok=inviso_tool_lib:inviso_cmd(CtrlNode,subscribe,[]), - init_rtcomponent_states_2(NodeParams,CtrlNode,CtrlPid,Nodes,[]). - -init_rtcomponent_states_2(_,_,_,[],States) -> - {ok,States}; -init_rtcomponent_states_2(NodeParams,void,CtrlPid,_Nodes,States) -> - case inviso:get_status() of - {ok,StateStatus} -> % Got its state/status, now... - {ProblemNodes,NewStates}= - init_rtcomponent_states_3(NodeParams,CtrlPid,[{?LOCAL_RUNTIME,{ok,StateStatus}}], - [],States), - init_rtcomponent_states_2(NodeParams,void,CtrlPid,ProblemNodes,NewStates); - {error,_Reason} -> % The runtime is not available!? - {ok,[{?LOCAL_RUNTIME,unavailable,[]}]} % Create the return value immediately. - end; -init_rtcomponent_states_2(NodeParams,CtrlNode,CtrlPid,Nodes,States) -> - case inviso_tool_lib:inviso_cmd(CtrlNode,get_status,[Nodes]) of - {ok,NodeResult} -> - {ProblemNodes,NewStates}= - init_rtcomponent_states_3(NodeParams,CtrlPid,NodeResult,[],States), - init_rtcomponent_states_2(NodeParams,CtrlNode,CtrlPid,ProblemNodes,NewStates); - {error,Reason} -> % Severe problem, abort the session. - {error,{get_status,Reason}} - end. - -%% Traverses the list of returnvalues and checks that we do not have an event -%% waiting in the message queue. If we do have, it is a problem. That node will -%% be asked about its state again. -%% Note that it is here we construct the RTStatesList. -init_rtcomponent_states_3(NodeParams,CtrlPid,[{Node,{ok,{State,Status}}}|Rest],Problems,States) -> - receive - {trace_event,CtrlPid,_Time,{state_change,Node,_}} -> - init_rtcomponent_states_3(NodeParams,CtrlPid,Rest,[Node|Problems],States) - after - 0 -> % Not in msg queue, then we're safe! - RTState=case lists:keysearch(Node,1,NodeParams) of - {value,{_Node,_TracerData,Opts}} -> - {Node,{State,Status},Opts}; - _ -> % No option available, use []. - {Node,{State,Status},[]} - end, - init_rtcomponent_states_3(NodeParams,CtrlPid,Rest,Problems,[RTState|States]) - end; -init_rtcomponent_states_3(NodeParams,CtrlPid,[{Node,{error,_Reason}}|Rest],Problems,States) -> - RTState=case lists:keysearch(Node,1,NodeParams) of - {value,{_Node,_TracerData,Opts}} -> - {Node,unavailable,Opts}; - _ -> % No option available, use []. - {Node,unavailable,[]} - end, - init_rtcomponent_states_3(NodeParams,CtrlPid,Rest,Problems,[RTState|States]); -init_rtcomponent_states_3(_,_,[],Problems,States) -> - {Problems,States}. -%% ------------------------------------------------------------------------------ - -%% Help function removing nodes from NodeParams. The reason for this can either -%% be that we are using a tool internal tracerdata that shall not be forwarded to -%% the trace control component, or that the node is actually already part of -%% another session. -%% Returns {NewNodeParams,NodesWhichShallNotBeInitiated}. -remove_nodeparams(Nodes,NodesParams) -> - remove_nodeparams_2(Nodes,NodesParams,[],[]). - -remove_nodeparams_2(Nodes,[NodeParam|Rest],NPAcc,NAcc) when % NPAcc=NodeParamsAcc. - (is_tuple(NodeParam) and ((size(NodeParam)==2) or (size(NodeParam)==3))) -> - Node=element(1,NodeParam), - Params=element(2,NodeParam), % This is tracerdata! - case lists:member(Node,Nodes) of - true -> % Remove this one, in another session. - remove_nodeparams_2(Nodes,Rest,NPAcc,NAcc); - false -> % Ok so far... - case is_tool_internal_tracerdata(Params) of - false -> % Then keep it and use it later! - remove_nodeparams_2(Nodes,Rest,[{Node,Params}|NPAcc],NAcc); - true -> % Since it is, remove it from the list. - remove_nodeparams_2(Nodes,Rest,NPAcc,[Node|NAcc]) - end - end; -remove_nodeparams_2(Nodes,[_|Rest],NPAcc,NAcc) -> % Faulty NodeParam, skip it! - remove_nodeparams_2(Nodes,Rest,NPAcc,NAcc); -remove_nodeparams_2(_,[],NPAcc,NAcc) -> - {lists:reverse(NPAcc),NAcc}. -%% ------------------------------------------------------------------------------ - -%% Help function which adds both the nodes which were already part of another -%% session and the nodes that we actually did not issue any init_tracing for. -%% Returns a new Result list of [{Node,NodeResult},...]. -init_fix_resultnodes(NodesOtherSes,NodesNotInit,Result) -> - NewResult=init_fix_resultnodes_2(NodesOtherSes,{error,in_other_session},Result), - init_fix_resultnodes_2(NodesNotInit,ok,NewResult). - -init_fix_resultnodes_2([Node|Rest],NodeResult,Result) -> - [{Node,NodeResult}|init_fix_resultnodes_2(Rest,NodeResult,Result)]; -init_fix_resultnodes_2([],_,Result) -> - Result. % Append Result to the end of the list. -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ -%% Help functions to reactivate. -%% ------------------------------------------------------------------------------ - -h_reactivate(CtrlNode,Nodes,ACTstorage) -> % Distributed case. - case inviso_tool_lib:inviso_cmd(CtrlNode,cancel_suspension,[Nodes]) of - {ok,CSuspResults} -> - {GoodNodes,BadResults}= % Sort out nodes no longer suspended. - lists:foldl(fun({Node,ok},{GoodNs,BadNs})-> - {[Node|GoodNs],BadNs}; - ({Node,{error,Reason}},{GoodNs,BadNs})-> - {GoodNs,[{Node,{error,{cancel_suspension,Reason}}}|BadNs]} - end, - {[],[]}, - CSuspResults), - Results=h_reactivate_redo_activity(CtrlNode,GoodNodes,ACTstorage,[]), - {ok,BadResults++Results}; - {error,Reason} -> % General failure cancelling suspend. - {error,{cancel_suspension,Reason}} - end. -%% ------------------------------------------------------------------------------ - -%% Help function which traverses the list of nodes known to be ours and have -%% cancelled their suspend. If we fail redoing one of the activities associated -%% with a node, the node will be reported in the return value as failed. From -%% that point on its state must be considered unknown since we do not know how -%% many of the activities were successfully redone. -h_reactivate_redo_activity(CtrlNode,[Node|Rest],ACTstorage,Acc) -> - case get_activities_actstorage(Node,ACTstorage) of - {ok,Activities} -> % The node existed in activity storage. - {Good,Bad}=h_reactivate_redo_activity_2(CtrlNode,Node,Activities,0,0), - h_reactivate_redo_activity(CtrlNode,Rest,ACTstorage,[{Node,{Good,Bad}}|Acc]); - false -> % Node not present in activity storage. - h_reactivate_redo_activity(CtrlNode,Rest,ACTstorage,[{Node,{0,0}}|Acc]) - end; -h_reactivate_redo_activity(_CtrlNode,[],_,Acc) -> - lists:reverse(Acc). - -%% Help function actually redoing the activity. Note that there must be one -%% clause here for every type of activity. -%% Returns {NrGoodCmds,NrBadCmds}. -%% The number of good or bad commands refers to inviso commands done. If any -%% of the subparts of such a command returned an error, the command is concidered -%% no good. -h_reactivate_redo_activity_2(CtrlNode,Node,[{tf,{Op,TraceConfList}}|Rest],Good,Bad) -> - case inviso_tool_lib:inviso_cmd(CtrlNode,Op,[[Node],TraceConfList]) of - {ok,[{_Node,{ok,Answers}}]} -> - case h_reactivate_redo_activity_check_tf(Answers) of - ok -> - h_reactivate_redo_activity_2(CtrlNode,Node,Rest,Good+1,Bad); - error -> % At least oneReports the first encountered error. - h_reactivate_redo_activity_2(CtrlNode,Node,Rest,Good,Bad+1) - end; - {ok,[{_Node,{error,_Reason}}]} -> - h_reactivate_redo_activity_2(CtrlNode,Node,Rest,Good,Bad+1); - {error,_Reason} -> % General error when doing cmd. - h_reactivate_redo_activity_2(CtrlNode,Node,Rest,Good,Bad+1) - end; -h_reactivate_redo_activity_2(CtrlNode,Node,[{tpm,{Op,InvisoCmdParams}}|Rest],Good,Bad) -> - case inviso_tool_lib:inviso_cmd(CtrlNode,Op,[[Node]|InvisoCmdParams]) of - {ok,[{_Node,ok}]} -> - h_reactivate_redo_activity_2(CtrlNode,Node,Rest,Good+1,Bad); - {ok,[{_Node,{error,_Reason}}]} -> - h_reactivate_redo_activity_2(CtrlNode,Node,Rest,Good,Bad+1); - {error,_Reason} -> % General error when doing cmd. - h_reactivate_redo_activity_2(CtrlNode,Node,Rest,Good,Bad+1) - end; -h_reactivate_redo_activity_2(_CtrlNode,_Node,[],Good,Bad) -> - {Good,Bad}. - -%% Help function traversing a list of results from inviso:tf/2 or inviso:ctf/2 -%% to see if there were any errors. -h_reactivate_redo_activity_check_tf([N|Rest]) when integer(N) -> - h_reactivate_redo_activity_check_tf(Rest); -h_reactivate_redo_activity_check_tf([{error,_Reason}|_]) -> - error; -h_reactivate_redo_activity_check_tf([]) -> - ok. -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ -%% Help functions to tp (setting trace patterns, both local and global). -%% ------------------------------------------------------------------------------ - -%% Help function which handles both tpl and tp. Note that the non-distributed case -%% handled with Nodes='all'. -%% Returns what shall be the reply to the client. -h_tp(all,PatternFunc,Mod,F,A,MS,Opts,LD) -> % All available runtime nodes. - Nodes=get_all_available_nodes_rtstates(get_rtstates_ld(LD)), - h_tp(Nodes,PatternFunc,Mod,F,A,MS,Opts,LD); -h_tp(Nodes,PatternFunc,Mod,F,A,MS,Opts,LD) -> % Only certain nodes in the session. - CtrlNode=get_ctrlnode_ld(LD), - Dbg=get_dbg_ld(LD), - SafetyCatches=get_safetycatches_ld(LD), - case inviso_tool_lib:expand_module_names(Nodes,Mod,Opts) of % Take care of any reg-exps. - {multinode_expansion,NodeMods} -> - NodeTPs=inviso_tool_lib:make_patterns(SafetyCatches,Opts,Dbg,NodeMods,F,A,MS), - h_tp_node_by_node(CtrlNode,PatternFunc,Dbg,NodeTPs,[]); - {singlenode_expansion,Modules} -> - TPs=inviso_tool_lib:make_patterns(SafetyCatches,Opts,Dbg,Modules,F,A,MS), - h_tp_do_tps(CtrlNode,Nodes,TPs,PatternFunc,Dbg); - module -> - TPs=inviso_tool_lib:make_patterns(SafetyCatches,Opts,Dbg,[Mod],F,A,MS), - h_tp_do_tps(CtrlNode,Nodes,TPs,PatternFunc,Dbg); - wildcard -> % Means do for all modules, no safety. - h_tp_do_tps(CtrlNode,Nodes,[{Mod,F,A,MS}],PatternFunc,Dbg); - {error,Reason} -> - {error,Reason} - end. - -%% Note that this function can never be called in the non-distributed case. -h_tp_node_by_node(CtrlNode,PatternFunc,Dbg,[{Node,TPs}|Rest],Accum) -> - case h_tp_do_tps(CtrlNode,[Node],TPs,PatternFunc,Dbg) of - {ok,[{Node,Result}]} -> - h_tp_node_by_node(CtrlNode,PatternFunc,Dbg,Rest,[{Node,Result}|Accum]); - {error,Reason} -> % Failure, but don't stop. - h_tp_node_by_node(CtrlNode,PatternFunc,Dbg,Rest,[{Node,{error,Reason}}|Accum]) - end; -h_tp_node_by_node(_,_,_,[],Accum) -> - {ok,lists:reverse(Accum)}. - -%% Help function which does the actual call to the trace control component. -%% Note that Nodes can be a list of nodes (including a single one) or -%% ?LOCAL_RUNTIME if we are not distributed. The non-distributed case is otherwise -%% detected by the 'void' CtrlNode. -%% Returns {ok,[{Node,{ok,{NrOfFunctions,NrOfErrors}}},{Node,{error,Reason}},...]} or -%% {error,Reason}. In the non-distributed case {ok,{NrOfFunctions,NrOfErros}} or -%% {error,Reason}. -h_tp_do_tps(void,_Nodes,TPs,PatternFunc,Dbg) -> % Non distributed case! - inviso_tool_lib:debug(tp,Dbg,[TPs,PatternFunc]), - case inviso:PatternFunc(TPs) of - {ok,Result} -> % A list of [Nr1,Nr2,error,...]. - {ok, - lists:foldl(fun(N,{AccNr,AccErr}) when integer(N) -> - {AccNr+N,AccErr}; - (error,{AccNr,AccErr}) -> - {AccNr,AccErr+1} - end, - {0,0}, - Result)}; - {error,Reason} -> - {error,{PatternFunc,Reason}} - end; -h_tp_do_tps(CtrlNode,Nodes,TPs,PatternFunc,Dbg) -> - inviso_tool_lib:debug(tp,Dbg,[Nodes,TPs,PatternFunc]), - case inviso_tool_lib:inviso_cmd(CtrlNode,PatternFunc,[Nodes,TPs]) of - {ok,Result} -> % Result is [{Node,Result},...]. - {ok, - lists:map(fun({Node,{ok,Res}})-> - {Node,lists:foldl(fun(N,{ok,{AccNr,AccErr}}) when integer(N) -> - {ok,{AccNr+N,AccErr}}; - (error,{AccNr,AccErr}) -> - {ok,{AccNr,AccErr+1}} - end, - {ok,{0,0}}, - Res)}; - ({_Node,{error,Reason}})-> - {error,Reason} - end, - Result)}; - {error,Reason} -> - {error,{PatternFunc,Reason}} - end. -%% ------------------------------------------------------------------------------ - -%% ------------------------------------------------------------------------------ -%% Help functions for removing trace-patterns. -%% ------------------------------------------------------------------------------ - -%% NOT IMPLEMENTED YET. -h_ctp(Node,PatternFunc,Mod,F,A,LD) -> - tbd. -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ -%% Help functions for calling the trace information facility. -%% ------------------------------------------------------------------------------ - - -%% Function handling the meta trace pattern for capturing registration of local -%% process names. -h_tpm_localnames(CtrlNode,Nodes,RTStates,ACTstorage) -> - AvailableNodes=get_all_available_nodes_rtstates(RTStates), - {Nodes3,FaultyNodes}=remove_nodes_not_ours(Nodes,AvailableNodes), - case inviso_tool_lib:inviso_cmd(CtrlNode,tpm_localnames,[Nodes3]) of - {ok,Result} -> % That good we want to modify tpmstorage! - NewACTstorage=add_tpm_actstorage(Result,tpm_localnames,[],ACTstorage), - ErrorResult=lists:map(fun(N)->{N,{error,not_available}} end,FaultyNodes), - {{ok,ErrorResult++Result},NewACTstorage}; - {error,Reason} -> % If general failure, do not modify storage. - {{error,Reason},ACTstorage} - end. -%% ------------------------------------------------------------------------------ - -%% Functions calling meta trace functions for specified nodes. This function is -%% intended for use with all tmp function calls, init_tpm,tpm,tpm_ms,ctpm_ms and -%% ctpm. -%% Note that we must store called meta trace functions and their parameters in the -%% activity storage in order to be able to redo them in case of a reactivate. -h_all_tpm(CtrlNode,Nodes,TpmCmd,InvisoCmdParams,RTStates,ACTstorage) -> - AvailableNodes=get_all_available_nodes_rtstates(RTStates), - {Nodes3,FaultyNodes}=remove_nodes_not_ours(Nodes,AvailableNodes), - case inviso_tool_lib:inviso_cmd(CtrlNode,TpmCmd,[Nodes3|InvisoCmdParams]) of - {ok,Result} -> % That good we want to modify tpmstorage! - NewACTstorage=add_tpm_actstorage(Result,TpmCmd,InvisoCmdParams,ACTstorage), - ErrorResult=lists:map(fun(N)->{N,{error,not_available}} end,FaultyNodes), - {{ok,ErrorResult++Result},NewACTstorage}; - {error,Reason} -> % If general failure, do not modify storage. - {{error,Reason},ACTstorage} - end. -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ -%% Help functions for set trace flags. -%% ------------------------------------------------------------------------------ - -%% Help function which sets the tracepatterns in TraceConfList for all nodes -%% mentioned in Nodes. Note that non-distributed case is handled with Nodes='all'. -%% Returns {Reply,NewACTstorage} where Reply is whatever shall be returned to caller -%% and NewACTstorage is traceflag storage modified with the flags added to the -%% corresponding nodes. -h_tf(void,_Nodes,TraceConfList,ACTstorage,_RTStates) -> % The non-distributed case. - Reply=inviso:tf(TraceConfList), - NewACTstorage=add_tf_actstorage([{?LOCAL_RUNTIME,Reply}],tf,TraceConfList,ACTstorage), - {Reply,NewACTstorage}; -h_tf(CtrlNode,all,TraceConfList,ACTstorage,RTStates) -> - AllNodes=get_all_session_nodes_rtstates(RTStates), - h_tf(CtrlNode,AllNodes,TraceConfList,ACTstorage,RTStates); -h_tf(CtrlNode,Nodes,TraceConfList,ACTstorage,_RTStates) -> - case inviso_tool_lib:inviso_cmd(CtrlNode,tf,[Nodes,TraceConfList]) of - {ok,Result} -> % That good we want to modify actstorage! - NewACTstorage=add_tf_actstorage(Result,tf,TraceConfList,ACTstorage), - {{ok,Result},NewACTstorage}; - {error,Reason} -> % If general failure, do not modify actstorage. - {{error,Reason},ACTstorage} - end. -%% ------------------------------------------------------------------------------ - -%% ------------------------------------------------------------------------------ -%% Help functions to stop_session. -%% ------------------------------------------------------------------------------ - -%% This function fetches all local log-files using our stored tracerdata. Note -%% that there are two major ways of tranfering logfiles. Either via distributed -%% Erlang or by common filesystem (like NFS). The default is distributed Erlang. -%% But there may be info in the RTStates structure about a common file-system. -%% Returns {FailedNodes,FetchedFileNames} where FailedNodes is a list of -%% nodenames where problems occurred. Note that problems does not necessarily -%% mean that no files were copied. -%% FetchedFileNames contains one or two of the tuples {trace_log,Files} and/or -%% {ti_log,Files}, listing all files successfully fetched. Note that the -%% list of fetched files contains sublists of filenames. One for each node and -%% tracerdata. -%% In the non-distributed system we always use copy (since the files always -%% resides locally). -transfer_logfiles(RTStates,CtrlNode,Dir,Prefix,TRDstorage,Dbg,AvailableNodes) -> - if - CtrlNode==void -> % When non-distributed, always copy! - fetch_logfiles_copy(CtrlNode,Dir,Prefix,TRDstorage,Dbg,[?LOCAL_RUNTIME]); - true -> % The distributed case. - {FetchNodes,CopyNodes}=find_logfile_transfer_methods(AvailableNodes,RTStates), - {FailedFetchNodes,FetchedFiles}= - case fetch_logfiles_distributed(CtrlNode,Dir,Prefix,TRDstorage,Dbg,FetchNodes) of - {ok,Failed,Files} -> % So far no disasters. - {Failed,Files}; - {error,Reason} -> % Means all fetch-nodes failed! - inviso_tool_lib:debug(transfer_logfiles,Dbg,[FetchNodes,Reason]), - {lists:map(fun(N)->{N,error} end,FetchNodes),[]} - end, - {FailedCopyNodes,CopiedFiles}= - fetch_logfiles_copy(CtrlNode,Dir,Prefix,TRDstorage,Dbg,CopyNodes), - {FailedFetchNodes++FailedCopyNodes,FetchedFiles++CopiedFiles} - end. - -%% Help function which finds out which node we have a common file system with -%% and from which we must make distributed erlang tranfere. -%% Returns {DistributedNodes,CopyNodes} where CopyNode is [{Node,CopyFromDir},...]. -find_logfile_transfer_methods(Nodes,RTStates) -> - find_logfile_transfer_methods_2(Nodes,RTStates,[],[]). - -find_logfile_transfer_methods_2([Node|Rest],RTStates,FetchAcc,CopyAcc) -> - {ok,Opts}=get_opts_rtstates(Node,RTStates), % Node must be in RTStates! - case lists:keysearch(?COPY_LOG_FROM,1,Opts) of - {value,{_,FromDir}} when list(FromDir) -> % Node has common filesystem. - find_logfile_transfer_methods_2(Rest,RTStates,FetchAcc,[{Node,FromDir}|CopyAcc]); - {value,_} -> % Can't understand dir option. - find_logfile_transfer_methods_2(Rest,RTStates,[Node|FetchAcc],CopyAcc); - false -> % Then we want to use fetch instead. - find_logfile_transfer_methods_2(Rest,RTStates,[Node|FetchAcc],CopyAcc) - end; -find_logfile_transfer_methods_2([],_,FetchAcc,CopyAcc) -> - {FetchAcc,CopyAcc}. -%% ------------------------------------------------------------------------------ - -%% Help function which transferes all local logfiles according to the tracerdata -%% stored for the nodes in Nodes. -%% Returns {ok,FailedNodes,FileNodeSpecs} or {error,Reason}. -%% FailedNodes is a list of nodes where fetching logs did not succeed, partially -%% or not at all. -%% FileNames is a list of list of actually fetched files (the name as it is here, including -%% Dir). The sublists are files which belong together. -fetch_logfiles_distributed(CtrlNode,Dir,Prefix,TRDstorage,Dbg,Nodes) -> - LogSpecList=build_logspeclist(Nodes,TRDstorage), - case inviso_fetch_log(inviso_tool_lib:inviso_cmd(CtrlNode, - fetch_log, - [LogSpecList,Dir,Prefix])) of - {ok,Result} -> - Files=get_all_filenames_fetchlog_result(Result,Dbg), - FailedNodes=get_all_failednodes_fetchlog_result(Result), - {ok,FailedNodes,Files}; - {error,Reason} -> % Some general failure! - {error,{fetch_log,Reason}} - end. - -%% Help function which constructs a list {Node,TracerData} for all nodes in Nodes. -%% Note that there may be more than one tracerdata for a node, resulting in multiple -%% tuples for that node. -build_logspeclist(Nodes,TRDstorage) -> - build_logspeclist_2(Nodes,TRDstorage,[]). - -build_logspeclist_2([Node|Rest],TRDstorage,Acc) -> - TRDlist=find_tracerdata_for_node_trd(Node,TRDstorage), % A list of all tracerdata. - build_logspeclist_2(Rest, - TRDstorage, - [lists:map(fun(TRD)->{Node,TRD} end,TRDlist)|Acc]); -build_logspeclist_2([],_,Acc) -> - lists:flatten(Acc). - -%% Help function which translates inviso:fetch_log return values to what I -%% want! -inviso_fetch_log({error,Reason}) -> - {error,Reason}; -inviso_fetch_log({_Success,ResultList}) -> - {ok,ResultList}. - -%% Help function which collects all filenames mentioned in a noderesult structure. -%% The files may or may not be complete. -%% Returns a list of list of filenames. Each sublist contains files which belong -%% together, i.e because they are a wrap-set. -get_all_filenames_fetchlog_result(NodeResult,Dbg) -> - get_all_filenames_fetchlog_result_2(NodeResult,Dbg,[]). - -get_all_filenames_fetchlog_result_2([{Node,{Success,FileInfo}}|Rest],Dbg,Accum) - when Success=/=error, list(FileInfo) -> - SubAccum=get_all_filenames_fetchlog_result_3(FileInfo,[]), - get_all_filenames_fetchlog_result_2(Rest,Dbg,[{Node,SubAccum}|Accum]); -get_all_filenames_fetchlog_result_2([{Node,{error,FReason}}|Rest],Dbg,Accum) -> - inviso_tool_lib:debug(fetch_files,Dbg,[Node,FReason]), - get_all_filenames_fetchlog_result_2(Rest,Dbg,Accum); -get_all_filenames_fetchlog_result_2([],_Dbg,Accum) -> - Accum. - -get_all_filenames_fetchlog_result_3([{FType,Files}|Rest],SubAccum) -> - FilesOnly=lists:foldl(fun({ok,FName},Acc)->[FName|Acc];(_,Acc)->Acc end,[],Files), - get_all_filenames_fetchlog_result_3(Rest,[{FType,FilesOnly}|SubAccum]); -get_all_filenames_fetchlog_result_3([],SubAccum) -> - SubAccum. - -%% Help function which traverses a noderesult and builds a list as return -%% value containing the nodenames of all nodes not being complete. -%% Note that a node may occur multiple times since may have fetched logfiles -%% for several tracerdata from the same node. Makes sure the list contains -%% unique node names. -%% Returns a list nodes. -get_all_failednodes_fetchlog_result(NodeResult) -> - get_all_failednodes_fetchlog_result_2(NodeResult,[]). - -get_all_failednodes_fetchlog_result_2([{_Node,{complete,_}}|Rest],Acc) -> - get_all_failednodes_fetchlog_result_2(Rest,Acc); -get_all_failednodes_fetchlog_result_2([{Node,{_Severity,_}}|Rest],Acc) -> - case lists:member(Node,Acc) of - true -> % Already in the list. - get_all_failednodes_fetchlog_result_2(Rest,Acc); - false -> % Not in Acc, add it! - get_all_failednodes_fetchlog_result_2(Rest,[Node|Acc]) - end; -get_all_failednodes_fetchlog_result_2([],Acc) -> - Acc. -%% ------------------------------------------------------------------------------ - -%% Help function which copies files from one location to Dir and at the same time -%% adds the Prefix to the filename. NodeSpecs contains full path to the files. The -%% reason the node information is still part of NodeSpecs is that otherwise we can -%% not report faulty nodes. Note that one node may occur multiple times since there -%% may be more than one tracerdata for a node. -%% Returns {FailedNodes,Files} where FailedNodes is a list of nodes where problems -%% occurred. Files is a tuple list of [{Node,[{FType,FileNames},...]},...]. -fetch_logfiles_copy(CtrlNode,Dir,Prefix,TRDstorage,Dbg,NodeSpecs) -> - CopySpecList=build_copylist(CtrlNode,Dbg,NodeSpecs,TRDstorage), - fetch_logfiles_copy_2(Dir,Prefix,Dbg,CopySpecList,[],[]). - -fetch_logfiles_copy_2(Dir,Prefix,Dbg,[{Node,CopySpecs}|Rest],FailedNodes,Files) -> - case fetch_logfiles_copy_3(Dir,Prefix,Dbg,CopySpecs,[],0) of - {0,LocalFiles} -> % Copy went ok and zero errors. - fetch_logfiles_copy_2(Dir,Prefix,Dbg,Rest,FailedNodes,[{Node,LocalFiles}|Files]); - {_N,LocalFiles} -> % Copied files, but some went wrong. - case lists:member(Node,FailedNodes) of - true -> % Node already in FailedNodes. - fetch_logfiles_copy_2(Dir,Prefix,Dbg,Rest,FailedNodes, - [{Node,LocalFiles}|Files]); - false -> % Node not marked as failed, yet. - fetch_logfiles_copy_2(Dir,Prefix,Dbg,Rest,[Node|FailedNodes], - [{Node,LocalFiles}|Files]) - end - end; -fetch_logfiles_copy_2(_,_,_,[],FailedNodes,Files) -> - {FailedNodes,Files}. % The return value from fetch_logfiles_copy. - -fetch_logfiles_copy_3(Dir,Prefix,Dbg,[{FType,RemoteFiles}|Rest],Results,Errors) -> - {Err,LocalFiles}=fetch_logfiles_copy_3_1(Dir,Prefix,Dbg,RemoteFiles,[],0), - fetch_logfiles_copy_3(Dir,Prefix,Dbg,Rest,[{FType,LocalFiles}|Results],Errors+Err); -fetch_logfiles_copy_3(_,_,_,[],Results,Errors) -> - {Errors,Results}. - -%% For each file of one file-type (e.g. trace_log). -fetch_logfiles_copy_3_1(Dir,Prefix,Dbg,[File|Rest],LocalFiles,Errors) -> - DestName=Prefix++filename:basename(File), - Destination=filename:join(Dir,DestName), - case do_copy_file(File,Destination) of - ok -> - fetch_logfiles_copy_3_1(Dir,Prefix,Dbg,Rest,[DestName|LocalFiles],Errors); - {error,Reason} -> - inviso_tool_lib:debug(copy_files,Dbg,[File,Destination,Reason]), - fetch_logfiles_copy_3_1(Dir,Prefix,Dbg,Rest,LocalFiles,Errors+1) - end; -fetch_logfiles_copy_3_1(_,_,_,[],LocalFiles,Errors) -> - {Errors,LocalFiles}. - -%% Help function which builds a [{Node,[{Type,[ListOfRemoteFiles]}},...}] -%% where Type describes trace_log or ti_log and each entry in ListOfRemoteFiles -%% is a complete path to a file to be copied. -build_copylist(CtrlNode,Dbg,NodeSpecList,TRDstorage) -> - build_copylist_2(CtrlNode,Dbg,NodeSpecList,TRDstorage,[]). - -%% For each node specified in the NodeSpecList. -build_copylist_2(CtrlNode,Dbg,[{Node,SourceDir}|Rest],TRDstorage,Acc) -> - TRDlist=find_tracerdata_for_node_trd(Node,TRDstorage), - CopySpecList=build_copylist_3(CtrlNode,Dbg,SourceDir,Node,TRDlist), - build_copylist_2(CtrlNode,Dbg,Rest,TRDstorage,[CopySpecList|Acc]); -build_copylist_2(_,_,[],_,Acc) -> - lists:flatten(Acc). - -%% For each tracerdata found for the node. -build_copylist_3(void,Dbg,SourceDir,Node,[TRD|Rest]) -> % The non-distributed case. - case inviso:list_logs(TRD) of - {ok,FileSpec} when list(FileSpec) -> % [{trace_log,Dir,Files},...] - NewFileSpec=build_copylist_4(SourceDir,FileSpec,[]), - [{Node,NewFileSpec}|build_copylist_3(void,Dbg,SourceDir,Node,Rest)]; - {ok,no_log} -> % This tracedata not associated with any log. - build_copylist_3(void,Dbg,SourceDir,Node,Rest); - {error,Reason} -> - inviso_tool_lib:debug(list_logs,Dbg,[Node,TRD,Reason]), - build_copylist_3(void,Dbg,SourceDir,Node,Rest) - end; -build_copylist_3(CtrlNode,Dbg,SourceDir,Node,[TRD|Rest]) -> % The distributed case. - case inviso_tool_lib:inviso_cmd(CtrlNode,list_logs,[[{Node,TRD}]]) of - {ok,[{Node,{ok,FileSpec}}]} when list(FileSpec) -> - NewFileSpec=build_copylist_4(SourceDir,FileSpec,[]), - [{Node,NewFileSpec}|build_copylist_3(CtrlNode,Dbg,SourceDir,Node,Rest)]; - {ok,[{Node,{ok,no_log}}]} -> % It relays to another node, no files! - build_copylist_3(CtrlNode,Dbg,SourceDir,Node,Rest); - {ok,[{Node,{error,Reason}}]} -> - inviso_tool_lib:debug(list_logs,Dbg,[Node,TRD,Reason]), - build_copylist_3(CtrlNode,Dbg,SourceDir,Node,Rest); - {error,Reason} -> % Some general failure. - inviso_tool_lib:debug(list_logs,Dbg,[Node,TRD,Reason]), - build_copylist_3(CtrlNode,Dbg,SourceDir,Node,Rest) - end; -build_copylist_3(_,_,_,_,[]) -> - []. - -%% Help function which makes a [{Type,Files},...] list where each file in Files -%% is with full path as found from our file-system. -build_copylist_4(SourceDir,[{Type,_Dir,Files}|Rest],Accum) -> - NewFiles= - lists:foldl(fun(FName,LocalAcc)->[filename:join(SourceDir,FName)|LocalAcc] end, - [], - Files), - build_copylist_4(SourceDir,Rest,[{Type,NewFiles}|Accum]); -build_copylist_4(_,[],Accum) -> - Accum. - - -%% Help function which copies a file using os:cmd. -%% Returns 'ok' or {error,Reason}. -do_copy_file(Source,Destination) -> - case os:type() of - {win32,_} -> - os:cmd("copy "++Source++" "++Destination), % Perhaps a test on success? - ok; - {unix,_} -> - os:cmd("cp "++Source++" "++Destination), % Perhaps a test on success? - ok - end. -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ - -%% ============================================================================== -%% Various help functions. -%% ============================================================================== - -%% Help function going through the Nodes list and checking that only nodes -%% mentioned in OurNodes gets returned. It also makes the nodes in the return -%% value unique. -remove_nodes_not_ours(Nodes,OurNodes) -> - remove_nodes_not_ours_2(Nodes,OurNodes,[],[]). - -remove_nodes_not_ours_2([Node|Rest],OurNodes,OurAcc,OtherAcc) -> - case lists:member(Node,OurNodes) of - true -> % Ok it is one of our nodes. - case lists:member(Node,OurAcc) of - true -> % Already in the list, skip. - remove_nodes_not_ours_2(Rest,OurNodes,OurAcc,OtherAcc); - false -> - remove_nodes_not_ours_2(Rest,OurNodes,[Node|OurAcc],OtherAcc) - end; - false -> - case lists:member(Node,OtherAcc) of - true -> - remove_nodes_not_ours_2(Rest,OurNodes,OurAcc,OtherAcc); - false -> - remove_nodes_not_ours_2(Rest,OurNodes,OurAcc,[Node|OtherAcc]) - end - end; -remove_nodes_not_ours_2([],_,OurAcc,OtherAcc) -> - {lists:reverse(OurAcc),lists:reverse(OtherAcc)}. -%% ------------------------------------------------------------------------------ - -%% Help function which returns 'true' or 'false' depending on if TracerData is -%% meant to be used by the session handler (true) or if it supposed to be passed -%% on to the trace system. -is_tool_internal_tracerdata(_) -> % CURRENTLY NO INTERNAL TRACER DATA! - false. -%% ------------------------------------------------------------------------------ - -%% Help function which checks that all nodes in the first list of nodes exists -%% in the second list of nodes. Returns 'true' or 'false'. The latter if as much -%% as one incorrect node was found. -check_our_nodes([Node|Rest],AllNodes) -> - case lists:member(Node,AllNodes) of - true -> - check_our_nodes(Rest,AllNodes); - false -> % Then we can stop right here. - false - end; -check_our_nodes([],_) -> - true. -%% ------------------------------------------------------------------------------ - -%% Help function which checks that a directory actually exists. Returns 'true' or -%% 'false'. -check_directory_exists(Dir) -> - case file:read_file_info(Dir) of - {ok,#file_info{type=directory}} -> - true; - _ -> % In all other cases it is not valid. - false - end. -%% ------------------------------------------------------------------------------ - -%% This function stops the tracing on all nodes in Nodes. Preferably Nodes is a list -%% of only tracing runtime components. Not that there will actually be any difference -%% since the return value does not reflect how stopping the nodes went. -%% Returns 'ok' or {error,Reason}, the latter only in case of general failure. -stop_all_tracing(void,Dbg,[?LOCAL_RUNTIME]) -> % The non-distributed case, and is tracing. - case inviso:stop_tracing() of - {ok,_State} -> - ok; - {error,Reason} -> % We actually don't care. - inviso_tool_lib:debug(stop_tracing,Dbg,[?LOCAL_RUNTIME,Reason]), - ok - end; -stop_all_tracing(void,_,_) -> % There is no local runtime started. - ok; -stop_all_tracing(CtrlNode,Dbg,Nodes) -> - case inviso_tool_lib:inviso_cmd(CtrlNode,stop_tracing,[Nodes]) of - {ok,Result} -> % The result is only used for debug. - Failed=lists:foldl(fun({N,{error,Reason}},Acc)->[{N,{error,Reason}}|Acc]; - (_,Acc)->Acc - end, - [], - Result), - if - Failed==[] -> - ok; - true -> - inviso_tool_lib:debug(stop_tracing,Dbg,[Nodes,Failed]), - ok - end; - {error,Reason} -> - {error,{stop_tracing,Reason}} - end. -%% ------------------------------------------------------------------------------ - -%% Help function removing all local logs using the tracerdata to determine what -%% logs to remove from where. -%% There is no significant return value since it is not really clear what to do -%% if removal went wrong. The function can make debug-reports thought. -remove_all_local_logs(CtrlNode,TRDstorage,Nodes,Dbg) -> - LogSpecList=build_logspeclist_remove_logs(Nodes,TRDstorage), - case inviso_tool_lib:inviso_cmd(CtrlNode,delete_log,[LogSpecList]) of - {ok,Results} -> - case look_for_errors_resultlist(Results) of - [] -> % No errors found in the result! - true; - Errors -> - inviso_tool_lib:debug(remove_all_local_logs,Dbg,[Errors]), - true - end; - {error,Reason} -> % Some general error. - inviso_tool_lib:debug(remove_all_local_logs,Dbg,[{error,Reason}]), - true - end. - -%% Help function which puts together a list of {Node,Tracerdata} tuples. Note that -%% we must build one tuple for each tracerdata for one node. -build_logspeclist_remove_logs(Nodes,TRDstorage) -> - [{Node,TracerData}||Node<-Nodes,TracerData<-find_tracerdata_for_node_trd(Node,TRDstorage)]. -%% ------------------------------------------------------------------------------ - -%% Help function which traverses a resultlist from an inviso function. Such are -%% built up as [{Node,SubResults},...] where SubResult is a list of tuples for each -%% file-type (e.g trace_log) {FType,FileList} where a FileList is either {error,Reason} -%% or {ok,FileName}. -%% Returns a list of {Node,[{error,Reason},...]}. -look_for_errors_resultlist([{Node,{error,Reason}}|Rest]) -> - [{Node,{error,Reason}}|look_for_errors_resultlist(Rest)]; -look_for_errors_resultlist([{Node,{ok,NResults}}|Rest]) when list(NResults) -> - case look_for_errors_resultlist_2(NResults,[]) of - [] -> - look_for_errors_resultlist(Rest); - Errors -> % A list of lists. - [{Node,lists:flatten(Errors)}|look_for_errors_resultlist(Rest)] - end; -look_for_errors_resultlist([_|Rest]) -> - look_for_errors_resultlist(Rest); -look_for_errors_resultlist([]) -> - []. - -look_for_errors_resultlist_2([{_FType,NSubResult}|Rest],Accum) -> - case lists:filter(fun({error,_Reason})->true;(_)->false end,NSubResult) of - [] -> % No errors for this node. - look_for_errors_resultlist_2(Rest,Accum); - Errors -> % A list of at least one error. - look_for_errors_resultlist_2(Rest,[Errors|Accum]) - end; -look_for_errors_resultlist_2([],Accum) -> - Accum. -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ -%% Functions working on the loopdata structure. -%% Its main purpose is to store information about runtime components participating -%% in the session and their current status. -%% ------------------------------------------------------------------------------ - --record(ld,{parent, - ctrlnode, - ctrlpid, % To where to send inviso cmd. - rtstates, - tracerdata, - safetycatches, - dbg, - actstorage % Activity storage, for reactivate. - }). - -%% Function creating the initial datastructure. -%% The datastructure is [{Node,State},...]. -%% -%% The tracerdata table is a bag simply for the reason that if we try to insert -%% the same tracerdata for a node twice, we will end up with one tracerdata after -%% all. This is useful when we insert tracerdata ourselves, the tracerdata will -%% come as a state-change too. -mk_ld(Parent,CtrlNode,CtrlPid,RTStates,NodeParams,OtherNodes,SafetyCatches,Dbg) -> - TRDtableName=list_to_atom("inviso_tool_sh_trdstorage_"++pid_to_list(self())), - TRDtid=ets:new(TRDtableName,[bag]), - ACTtableName=list_to_atom("inviso_tool_sh_actstorage_"++pid_to_list(self())), - ACTtid=ets:new(ACTtableName,[bag]), - mk_ld_fill_tracerdata(CtrlNode,TRDtid,NodeParams,OtherNodes), % Fill the ETS table. - #ld{parent=Parent, % The tool main process. - ctrlnode=CtrlNode, % Node name where the control component is. - ctrlpid=CtrlPid, % The process id of the control component. - rtstates=RTStates, % All nodes and their state/status. - tracerdata=TRDtid, - safetycatches=SafetyCatches, - dbg=Dbg, - actstorage=ACTtid - }. - -%% Help function which inserts tracer data for the nodes. Note that we can get -%% tracer data either from the return value from init_tracing or by asking the -%% node for it. The latter is necessary for the nodes which were marked not to -%% be initiated by the session handler. This maybe because those nodes have -%% autostarted. -mk_ld_fill_tracerdata(CtrlNode,TId,NodeParams,OtherNodes) -> - mk_ld_fill_tracerdata_nodeparams(TId,NodeParams), - mk_ld_fill_tracerdata_othernodes(CtrlNode,TId,OtherNodes). - -mk_ld_fill_tracerdata_nodeparams(TId,[{Node,TracerData}|Rest]) -> - ets:insert(TId,{Node,TracerData}), - mk_ld_fill_tracerdata_nodeparams(TId,Rest); -mk_ld_fill_tracerdata_nodeparams(_,[]) -> - ok. - -mk_ld_fill_tracerdata_othernodes(_,_,[]) -> % Then not necessary to do anything. - ok; -mk_ld_fill_tracerdata_othernodes(void,TId,[Node]) -> % The non-distributed case. - case inviso:get_tracerdata() of - {error,_Reason} -> % Perhaps in state new or disconnected. - ok; % Do nothing. - {ok,TracerData} -> - ets:insert(TId,{Node,TracerData}) - end; -mk_ld_fill_tracerdata_othernodes(CtrlNode,TId,Nodes) -> - case inviso_tool_lib:invisomd(CtrlNode,get_tracerdata,[Nodes]) of - {ok,Results} -> - mk_ld_fill_tracerdata_othernodes_2(TId,Results); - {error,_Reason} -> % Strange, we will probably crash later. - ok - end. - -mk_ld_fill_tracerdata_othernodes_2(TId,[{_Node,{ok,no_tracerdata}}|Rest]) -> - mk_ld_fill_tracerdata_othernodes_2(TId,Rest); % It was not initiated then! -mk_ld_fill_tracerdata_othernodes_2(TId,[{Node,{ok,TracerData}}|Rest]) -> - ets:insert(TId,{Node,TracerData}), - mk_ld_fill_tracerdata_othernodes_2(TId,Rest); -mk_ld_fill_tracerdata_othernodes_2(_,[]) -> - ok. -%% ------------------------------------------------------------------------------ - -get_ctrlnode_ld(#ld{ctrlnode=CtrlNode}) -> - CtrlNode. -%% ------------------------------------------------------------------------------ - - -get_ctrlpid_ld(#ld{ctrlpid=CtrlPid}) -> - CtrlPid. -%% ------------------------------------------------------------------------------ - -get_rtstates_ld(#ld{rtstates=RTStates}) -> - RTStates. - -put_rtstates_ld(NewRTStates,LD) -> - LD#ld{rtstates=NewRTStates}. -%% ------------------------------------------------------------------------------ - -get_trdstorage_ld(#ld{tracerdata=TId}) -> - TId. - -put_trdstorage_ld(_NewTId,LD) -> - LD. -%% ------------------------------------------------------------------------------ - -%% Help function which adds the current tracerdata of node Node to the tracerdata -%% storage. We only want to add tracerdata we have not seen before. We therefore -%% avoid adding it if the node already is in state ?TRACING. -%% Returns a new tracerdata (what ever it is)! -add_current_tracerdata_ld(CtrlNode,Node,RTStates,TId) -> - case get_statestatus_rtstates(Node,RTStates) of - {ok,{?TRACING,_}} -> % Then we have already added the tracerdata. - TId; % Then do nothing. - {ok,_} -> % Since we were not tracing before. - case add_current_tracerdata_ld_fetchtracerdata(CtrlNode,Node) of - {ok,TracerData} -> - ets:insert(TId,{Node,TracerData}); - no_tracerdata -> % Strange, how could we become tracing - ok; - {error,_Reason} -> % The node perhaps disconnected!? - ok - end; - false -> % Very strange, not our node! - ok % Do nothing. - end. - -add_current_tracerdata_ld_fetchtracerdata(void,_Node) -> - case inviso:get_tracerdata() of - {ok,TracerData} -> - {ok,TracerData}; - {error,no_tracerdata} -> - no_tracerdata; - {error,Reason} -> - {error,Reason} - end; -add_current_tracerdata_ld_fetchtracerdata(CtrlNode,Node) -> - case inviso_tool_lib:inviso_cmd(CtrlNode,get_tracerdata,[[Node]]) of - {ok,[{Node,{ok,TracerData}}]} -> - {ok,TracerData}; - {ok,[{Node,{error,no_tracerdata}}]} -> - no_tracerdata; - {ok,[{Node,{error,Reason}}]} -> - {error,Reason}; - {error,Reason} -> - {error,Reason} - end. -%% ------------------------------------------------------------------------------ - - -get_safetycatches_ld(#ld{safetycatches=SCs}) -> - SCs. -%% ------------------------------------------------------------------------------ - -get_dbg_ld(#ld{dbg=Dbg}) -> - Dbg. -%% ------------------------------------------------------------------------------ - -get_actstorage_ld(#ld{actstorage=ACTstorage}) -> - ACTstorage. - -put_actstorage_ld(_NewACTstorage,LD) -> - LD. -%% ------------------------------------------------------------------------------ - - - -%% ------------------------------------------------------------------------------ -%% Functions working on the rtstates structure (which is a substructure of loopdata). -%% It is either: -%% [{Node,StateStatus,Opts},...] -%% Node is either the node name of the runtime component erlang node or -%% ?LOCAL_RUNTIME as returned from the trace control component. -%% StateStatus is {State,Status}, 'unavailable' or 'unknown'. -%% Status is the returnvalue from trace control component. -%% i.e: running | {suspended,Reason} -%% ------------------------------------------------------------------------------ - -%% Function contructing an rtstates structure from a list of [{Node,StateStatus,Opts},...]. -to_rtstates(ListOfStates) when list(ListOfStates) -> - ListOfStates. -%% ------------------------------------------------------------------------------ - -%% Function which takes a rtstates structure and returns a list of [{Node,StateStatus},...]. -from_rtstates(RTStates) -> - RTStates. -%% ------------------------------------------------------------------------------ - -%% Function which takes an rtstates structure and a result as returned from -%% init_tracing. The RTStates is modified for the nodes that changed state as a -%% result of successful init_tracing. -%% Returns a new RTStates. -set_tracing_rtstates([E={Node,_StateStatus,Opts}|Rest],Result) -> - case lists:keysearch(Node,1,Result) of - {value,{_,ok}} -> % Means state-change to tracing! - [{Node,{tracing,running},Opts}|set_tracing_rtstates(Rest,Result)]; - _ -> % Otherwise, leave it as is. - [E|set_tracing_rtstates(Rest,Result)] - end; -set_tracing_rtstates([],_Result) -> - []. -%% ------------------------------------------------------------------------------ - -%% Function updating the state/status for a certain runtime component. -%% Returns a new RTStates structure. Note that Node must not necessarily be one -%% of the nodes in the session. Meaning that Node shall not be added to RTStates -%% should it not already be in there. -statechange_rtstates(Node,State,Status,RTStates) when list(RTStates) -> - case lists:keysearch(Node,1,RTStates) of - {value,{_,_,Opts}} -> - lists:keyreplace(Node,1,RTStates,{Node,{State,Status},Opts}); - _ -> % Then Node does not exist. - RTStates % Just keep it as is, as keyreplace would have done. - end. -%% ------------------------------------------------------------------------------ - -%% Function updating the state/status for a certain runtime component. The -%% state/status is set to 'unavailable'. -%% Returns a new RTStates structure. -set_unavailable_rtstates(Node,RTStates) when list(RTStates) -> - case lists:keysearch(Node,1,RTStates) of - {value,{_,_,Opts}} -> - lists:keyreplace(Node,1,RTStates,{Node,unavailable,Opts}); - _ -> % Then Node does not exist. - RTStates % Just keep it as is, as keyreplace would have done. - end. -%% ------------------------------------------------------------------------------ - -%% Function finding the statestatus associated with Node in the RTStates structure. -%% Returns {ok,StateStatus} or 'false'. -get_statestatus_rtstates(Node,RTStates) -> - case lists:keysearch(Node,1,RTStates) of - {value,{_,StateStatus,_}} -> - {ok,StateStatus}; - false -> - false - end. -%% ------------------------------------------------------------------------------ - -%% Help function which returns a list of all nodes that are currently marked -%% as available to us in the runtime state structure. -get_all_available_nodes_rtstates(RTStates) -> - get_all_session_nodes_rtstates(lists:filter(fun({_N,unavailable,_})->false; - (_)->true - end, - RTStates)). -%% ------------------------------------------------------------------------------ - -%% Help function returning a list of all nodes belonging to this session. -get_all_session_nodes_rtstates(RTStates) -> - lists:map(fun({Node,_,_})->Node end,RTStates). -%% ------------------------------------------------------------------------------ - -%% Function which returns a list of nodes that are indicated as tracing in the -%% RTStates structure. -get_all_tracing_nodes_rtstates(RTStates) -> - lists:map(fun({N,_,_})->N end, - lists:filter(fun({_,{tracing,_},_})->true;(_)->false end,RTStates)). -%% ------------------------------------------------------------------------------ - -%% Returns the options associated with Node in the RTStates structure. -get_opts_rtstates(Node,RTStates) -> - case lists:keysearch(Node,1,RTStates) of - {value,{_,_,Opts}} -> - {ok,Opts}; - false -> - false - end. - -%% ------------------------------------------------------------------------------ -%% Functions working on the tracerdata structure, which is a part of the loopdata. -%% The tracerdata structure is an ETS-table of type bag storing: -%% {Node,TracerData}. -%% Note that there can of course be multiple entries for a node. -%% ------------------------------------------------------------------------------ - -%% Help function which takes a tracerdata loopdata structure and returns a list -%% of all stored tracerdata for a certain Node. -find_tracerdata_for_node_trd(Node,TRD) -> - case ets:lookup(TRD,Node) of - Result when list(Result) -> - lists:map(fun({_Node,TracerData})->TracerData end,Result); - _ -> % Should probably never happend. - [] - end. -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ -%% Functions working on the activity storage structure, which is part of the -%% loopdata. It stores entries about things that needs to be "redone" in case -%% of a reactivation of the node. The time order is also important. -%% Note that for every ActivityType there must be a "handler" in the reactivation -%% functionality. -%% -%% The structure is a bag of {Node,ActivityType,What}. -%% ActivityType/What=tf/{Op,TraceConfList}|tpm/{Op,[Mod,Func,Arity,MS,CallFunc]} -%% /{Op,[Mod,Func,Arity,MS,CallFunc,ReturnFunc]} -%% /{Op,[]} -%% TraceConfList=[{Proc,Flags},...] -%% How=true|false -%% ------------------------------------------------------------------------------ - -%% Function that adds meta-pattern activities to the activity storage. Note -%% that one of the parameters to the function is a return value from an -%% inviso call. In that way we do not enter activities that were unsuccessful. -%% Op can be either the setting or clearing of a meta pattern. -%% Returns a new ACTstorage. -add_tpm_actstorage([{Node,ok}|Rest],Op,InvisoCmdParams,ACTstorage) -> - true=ets:insert(ACTstorage,{Node,tpm,{Op,InvisoCmdParams}}), - add_tpm_actstorage(Rest,Op,InvisoCmdParams,ACTstorage); -add_tpm_actstorage([_|Rest],Op,InvisoCmdParams,ACTstorage) -> - add_tpm_actstorage(Rest,Op,InvisoCmdParams,ACTstorage); -add_tpm_actstorage([],_,_,ACTstorage) -> - ACTstorage. - -%% Function that adds process trace-flags to the activity storage. Note that one -%% of the parameters is the return value from an inviso function. Meaning that -%% if the flags failed in their entirety, no activity will be saved. If only -%% some of the flags failed, we will not go through the effort of trying to find -%% out exactly which. -%% Returns a new activity storage structure. -add_tf_actstorage([{_Node,{error,_Reason}}|Rest],Op,TraceConfList,ACTstorage) -> - add_tf_actstorage(Rest,Op,TraceConfList,ACTstorage); -add_tf_actstorage([{Node,_Result}|Rest],Op,TraceConfList,ACTstorage) -> - true=ets:insert(ACTstorage,{Node,tf,{Op,TraceConfList}}), - add_tf_actstorage(Rest,Op,TraceConfList,ACTstorage); -add_tf_actstorage([],_,_,ACTstorage) -> - ACTstorage. -%% ------------------------------------------------------------------------------ - -%% Finds all activities associated with Node. Returns a list of them in the -%% same order as they were inserted. -get_activities_actstorage(Node,ACTstorage) -> - case ets:lookup(ACTstorage,Node) of - [] -> - false; - Result when list(Result) -> - {ok,lists:map(fun({_N,Type,What})->{Type,What} end,Result)} - end. -%% ------------------------------------------------------------------------------ - -%% Function removing all activity entries associated with Node. This is useful -%% if the Node disconnects for instance. -del_node_actstorage(Node,ACTstorage) -> - ets:delete(ACTstorage,Node), - ACTstorage. -%% ------------------------------------------------------------------------------ - |