appmon_a.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,117 行 · 第 1/3 页

ERL
1,117
字号
%% ``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 via the world wide web 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.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %%     $Id$%%-module(appmon_a).%%----------------------------------------------------------------------%%%% Monitors an application, i.e its supervision tree.%%%%----------------------------------------------------------------------%%%%%%		INTRODUCTION%%		------------%%%%		This file contains a description of the files involved%%		and the communication between the appmon_a display%%		manager and the appmon_a2 information gatherer. Further%%		information on the placement algorithm can be found in%%		the place.erl file.%%%%%%		FILES%%		-----%%%%		The supervision tree graphical software consists of%%		the following files:%%%% appmon_a	Gen server driving the process display window.%%		Responsible for assigning gs identifiers to all %%		processes and process link%% appmon_a2	The process information gathering routines. %%		Works by following the process links from application %%		master once every second%% dg		The process database is implemented as a shared %%		digraph (see manual pages for digraph) and this is %%		the routines handling this digraph. Since the digraph %%		is shared appmon_a2 will put some info into it that the %%		appmon_a later will modify. The structures used are %%		described in dg.hrl%% place	Places a tree, decides the x and y coordinates (not %%		necessarily corresponding to window coordinates) of %%		processes (or vertices to be specific). Note that %%		special routines are used to transform the possibly %%		cyclic digraph into a strict tree before trying to %%		place it.%%%%%%%%		IMPLEMENTATION DETAIL%%		---------------------%%%%		The appmon_a module will follow links between processes,%%		starting with the application master. A unique%%		reference is used to prevent infinite recursion. Note%%		that this process and link gathering is done in the%%		live digraph so that already known processes are%%		updated with the reference and new ones are added to%%		the digraph. After all processes and links have been%%		added or updated a search is made for those processes%%		and links that have an old reference. These are those%%		processes and links that are not present in the%%		application any more. Those are extracted from the%%		digraph and then deleted and the extracts are then%%		used (by appmon_a) to delete the appropriate gs%%		objects. The responsibilities of appmon_a is thus 1) add%%		all new processes and links to the digraph and 2) make%%		a list of all those objects from the digraph that have%%		been deleted.%%%%		When appmon_a2 has gathered all necessary information it%%		notifies the appmon_a display manager. Note that this is%%		implemented as a call (as opposed to a cast) to%%		prevent appmon_a2 from changing the digraph while appmon_a%%		uses it. appmon_a places all processes using the place%%		module. place will place the processes in the x y%%		planes, hopefully in a nice way, re-forming the%%		digraph during the process into a strict tree using%%		some simple heuristics, some links that makes the%%		graph cyclic will be considered secondary and later%%		coloured red. Note that the process links are not%%		placed since their coordinates are those of the%%		processes that they are links between. The place%%		module is only concerned at a fairly high level of%%		abstraction. Currently its x coordinates are used as%%		real coordinates while the y coordinates must be%%		scaled to correct values, thus the x plane is%%		continous and the y plane is disctrete.%%%%		Having placed processes the new ones are drawn on the%%		display along with all new process links, then all%%		processes and process links are moved to their%%		possibly new positions. The place module is not%%		sensitive to changes in position and therefore has no%%		concept of which nodes will have to be moved. hence%%		all nodes are moved (but most of them probably to the%%		same position as before)%%%%%%%%%%-----------------------------------------------------------------------export([start/2, start/3, stop/0]).-record(astate, {app, name, client, digraph}).-import(lists, [foreach/2]).%% gen server stuff-behaviour(gen_server).-export([init/1, handle_cast/2, handle_info/2, terminate/2]).-export([handle_call/3, code_change/3]).-define(APPSPACE, 10).				% The space between apps-define(NODEAREA_H, 90).			% The height of a node-define(BUTTAREA_H, 80).			% The button area height-define(APPBUTT_H, 20).				% Height of appl button-define(EDITORW, 260).-define(MAXWIDTH, 800).-define(MINWIDTH, 382).-define(MAXHEIGHT, 450).-define(MINHEIGHT, 325).-define(SUPVIEWTXT, "Sup. view").-define(PROCVIEWTXT, "Proc. view").-define(CLOSETXT, "Close").-define(REFRESHTXT, "Refresh").-define(SAVEOPTSTXT, "Save options").-define(HELPTXT, "Help").-define(CHARWIDTH, 7).				%Should use GS primitives-define( darkkhaki, {189, 183, 107}).-define( palegoldenrod, {238, 232, 170}).-define( peachpuff4, {139, 119, 101}).-define( red, red).-define( darkgrey, {169, 169, 169}).-define( lightgrey, {211, 211, 211}).-define( royalblue, {65, 105, 225}).-define( aquamarine4, {69, 139, 116}).-define( palegreen4, {84, 139,  84}).-define( darkseagreen, {105, 139, 105}).-define( f_line_col, {150, 150, 255}).-include("appmon_dg.hrl").%%------------------------------------------------------------%%------------------------------------------------------------start(NodeName, AppName) ->    gen_server:start_link(?MODULE, {NodeName, AppName, AppName}, []).start(NodeName, AppName, AppId) ->    gen_server:start_link(?MODULE, {NodeName, AppName, AppId}, []).stop() ->    ok.%%------------------------------------------------------------%% Public interface%%------------------------------------------------------------%% Administration%% AppName is the name of the application, usually an atom like sasl%% or kernel, AppId is the application pid or the application name,%% either goes.init({NodeName, AppName, AppId}) ->    process_flag(trap_exit, true),    {ok, Client} = appmon_info:start_link(NodeName, self(), []),    init_ref(),    init_foreign_places(),    DG = digraph:new([cyclic, private]),    State = #astate{app=AppId, name=AppName, client=Client, digraph=DG},    refresh(State),    setup_base_win(NodeName, AppName),    {ok, State}.terminate(_Reason, _State) ->    ok.code_change(_OldVsn, State, _Extra) ->    {ok, State}.handle_call(norequest, _From, State) ->    {reply, null, State}.%%------------------------------------------------------------%% handle castshandle_cast({ping, _Node, _From}, State) ->    {noreply, State};handle_cast(_Other, State) ->    {noreply, State}.%%------------------------------------------------------------%% handle infohandle_info({gs, _, click, _, [?CLOSETXT|_]}, State) ->    {stop, normal, State};handle_info({gs, _, destroy, _, _}, State) ->    {stop, normal, State};handle_info({gs, _, click, _, [?REFRESHTXT|_]}, State) ->    refresh(State),    {noreply, State};handle_info({gs, _, click, _, [?HELPTXT|_]}, State) ->    HelpFile = filename:join([code:lib_dir(appmon),			      "doc", "html", "part_frame.html"]),    tool_utils:open_help(win(), HelpFile),    {noreply, State};handle_info({gs, Id, click, {mode, Mode}, _}, State) ->    %%io:format("handle_info: Setting mode: ~p~n", [Mode]),    set_mode(Id, Mode),    {noreply, State};handle_info({gs, _, click, _, [?SUPVIEWTXT|_]}, State) ->    refresh(State, [{info_type, sup}]),    {noreply, State};handle_info({gs, _, click, _, [?PROCVIEWTXT|_]}, State) ->    refresh(State, [{info_type, link}]),    {noreply, State};handle_info({gs, Id, buttonpress, _,[1, X, Y|_]}, State) ->    %%io:format("Id clicked: ~p~n", [gs:read(Id, {find, {X, Y}})]),    catch find_pid(State, Id, X, Y),    set_default_mode(),    {noreply, State};handle_info({gs, Win, configure, _Data, [W, H|_]}, State) ->    case win() of Win -> user_driven_resize(W, H);	_-> ok    end,    {noreply, State};handle_info({delivery, _S, pinfo, _N, Res}, State) ->    appmon_txt:print(Res),    {noreply, State};handle_info({delivery, S, app, N, Res}, State) ->    {delivery, _Serv, app, _Name, {Root, Vs, Ls, SecLs}} = 	flush({delivery, S, app, N, Res}),    update2(Vs, Root, Ls, SecLs, State),    {noreply, State};handle_info({kill}, State) ->    {stop, normal, State};handle_info({state}, State) ->    {noreply, State};handle_info({'EXIT', _Pid, _Reason}, State) ->    {noreply, State};handle_info(_Other, State) ->    {noreply, State}.%% Refresh sets new options for the request and forces an update of%% the screen ant status.refresh(State) ->    refresh(State, []).refresh(State, Opts) ->    appmon_info:app(State#astate.client,		    State#astate.name, true, Opts).%% find_pid finds the pid of the clicked object. The scenario is that%% the user clicks on an item in his window, that ObjId is searched%% for among all nodes (vertices) and if found action is taken%% depending on the current mode (see handle_info)find_pid(State, Id, X, Y) ->    %% Try to manage both versions of GS, remove first case later.    ObjList = case gs:read(Id, {find, {X, Y}}) of		  {error, _} ->		      gs:read(Id, {hit, {X, Y}}); % Try new format		  Num when is_integer(Num) -> [Num];		  _Other -> []	      end,    DG = State#astate.digraph,    All = appmon_dg:get(all, DG),    find_pid2(ObjList, All, DG, State).find_pid2([Id | Ids], All, DG, State) ->    case search_for_pid(All, DG, Id) of	{ok, _KeyStr, Pid} ->	    handle_proc_press(mode(), Pid, State);	_ -> find_pid2(Ids, All, DG, State)    end;find_pid2([], _All, _DG, _State) -> ok.search_for_pid([V|Vs], DG, ObjId) ->    VD = appmon_dg:get(data, DG, V),    if  ObjId==VD#vdata.txt_obj ->	    {ok, V, VD#vdata.type};	true -> search_for_pid(Vs, DG, ObjId)    end;search_for_pid([], _DG, _ObjId) -> false.%%%% called when a process has been clicked on.%%handle_proc_press(info, Pid, State) ->     appmon_info:pinfo(State#astate.client, Pid, true, 		      [{timeout, at_most_once}]);handle_proc_press(send, Pid, _State) ->     {P, RawStr} = two_entries(winroot(), 250, 70,			      "Send", "To: ", "Msg: ", 			      pid_to_list(Pid), "", bg()),    Str = case lists:last(RawStr) of	       46 -> RawStr;	       _ -> RawStr++"."	   end,    case erl_scan:string(Str) of	{ok, Tokens, _} ->	    case erl_parse:parse_term(Tokens) of		{ok, Term} ->		    case catch list_to_pid(P) of			To when is_pid(To) -> To ! Term;			_ -> error		    end;		_Error -> error	    end;	_Error -> error    end;handle_proc_press(trace, Pid, _State) ->     case trace_state(Pid) of	true ->	    io:format("Removing trace on ~p~n", [Pid]),	    sys:trace(Pid, false),	    set_trace_state(Pid, false);	_Other ->	    io:format("Putting trace on ~p~n", [Pid]),	    sys:trace(Pid, true, 1000),	    set_trace_state(Pid, true)    end;handle_proc_press(kill, Pid, _State) ->     exit(Pid, kill).trace_state(Pid) -> get({trace_state, Pid}).set_trace_state(Pid, State) -> put({trace_state, Pid}, State).set_default_mode() ->    {Id, Mode} = get(default_mode),    case mode() of	Mode -> true;	_Other -> set_mode(Id, Mode)    end.set_default_mode(Id, Mode) ->

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?