diff options
author | Dan Gudmundsson <[email protected]> | 2013-11-07 15:42:36 +0100 |
---|---|---|
committer | Dan Gudmundsson <[email protected]> | 2013-11-07 15:42:36 +0100 |
commit | d45950d46037d169d5efd969ac2e3b7477481f9c (patch) | |
tree | 0e3916a1cf5f2a44eab36f491485505dd199f641 /lib/pman/src | |
parent | ebd380903569c2ae254849128542297629946feb (diff) | |
download | otp-d45950d46037d169d5efd969ac2e3b7477481f9c.tar.gz otp-d45950d46037d169d5efd969ac2e3b7477481f9c.tar.bz2 otp-d45950d46037d169d5efd969ac2e3b7477481f9c.zip |
Remove pman
Diffstat (limited to 'lib/pman/src')
-rw-r--r-- | lib/pman/src/Makefile | 112 | ||||
-rw-r--r-- | lib/pman/src/assert.hrl | 81 | ||||
-rw-r--r-- | lib/pman/src/pman.app.src | 40 | ||||
-rw-r--r-- | lib/pman/src/pman.appup.src | 19 | ||||
-rw-r--r-- | lib/pman/src/pman.erl | 132 | ||||
-rw-r--r-- | lib/pman/src/pman_buf.erl | 117 | ||||
-rw-r--r-- | lib/pman/src/pman_buf.hrl | 29 | ||||
-rw-r--r-- | lib/pman/src/pman_buf_buffer.erl | 102 | ||||
-rw-r--r-- | lib/pman/src/pman_buf_converter.erl | 190 | ||||
-rw-r--r-- | lib/pman/src/pman_buf_printer.erl | 91 | ||||
-rw-r--r-- | lib/pman/src/pman_buf_utils.erl | 106 | ||||
-rw-r--r-- | lib/pman/src/pman_main.erl | 789 | ||||
-rw-r--r-- | lib/pman/src/pman_module_info.erl | 133 | ||||
-rw-r--r-- | lib/pman/src/pman_options.erl | 395 | ||||
-rw-r--r-- | lib/pman/src/pman_options.hrl | 34 | ||||
-rw-r--r-- | lib/pman/src/pman_process.erl | 317 | ||||
-rw-r--r-- | lib/pman/src/pman_relay.erl | 127 | ||||
-rw-r--r-- | lib/pman/src/pman_relay_server.erl | 57 | ||||
-rw-r--r-- | lib/pman/src/pman_shell.erl | 827 | ||||
-rw-r--r-- | lib/pman/src/pman_tool.erl | 146 | ||||
-rw-r--r-- | lib/pman/src/pman_win.erl | 677 | ||||
-rw-r--r-- | lib/pman/src/pman_win.hrl | 39 |
22 files changed, 0 insertions, 4560 deletions
diff --git a/lib/pman/src/Makefile b/lib/pman/src/Makefile deleted file mode 100644 index eb0413bdbc..0000000000 --- a/lib/pman/src/Makefile +++ /dev/null @@ -1,112 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1996-2012. 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% -# -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -# ---------------------------------------------------- -# Application version -# ---------------------------------------------------- -include ../vsn.mk -VSN=$(PMAN_VSN) - -# ---------------------------------------------------- -# Release directory specification -# ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/lib/pman-$(VSN) - -# ---------------------------------------------------- -# Common Macros -# ---------------------------------------------------- - -MODULES= \ - pman \ - pman_main \ - pman_shell \ - pman_relay \ - pman_relay_server \ - pman_module_info \ - pman_win \ - pman_buf \ - pman_buf_utils \ - pman_buf_buffer \ - pman_buf_converter \ - pman_buf_printer \ - pman_options \ - pman_process \ - pman_tool - -HRL_FILES= \ - assert.hrl \ - pman_buf.hrl \ - pman_options.hrl \ - pman_win.hrl - -ERL_FILES= $(MODULES:%=%.erl) - -TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET) - -APP_FILE = pman.app -APP_SRC = $(APP_FILE).src -APP_TARGET = $(EBIN)/$(APP_FILE) - -APPUP_FILE = pman.appup -APPUP_SRC = $(APPUP_FILE).src -APPUP_TARGET = $(EBIN)/$(APPUP_FILE) - -# ---------------------------------------------------- -# FLAGS -# ---------------------------------------------------- -ERL_COMPILE_FLAGS += +warn_obsolete_guard - -# ---------------------------------------------------- -# Targets -# ---------------------------------------------------- - -debug opt: $(TARGET_FILES) - -clean: - rm -f $(TARGET_FILES) - rm -f errs core *~ - -$(APP_TARGET): $(APP_SRC) ../vsn.mk - $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@ - -$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk - $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@ - -docs: - -# ---------------------------------------------------- -# Special Targets -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -release_spec: opt - $(INSTALL_DIR) "$(RELSYSDIR)/src" - $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(TOOLBOX_FILES) "$(RELSYSDIR)/src" - $(INSTALL_DIR) "$(RELSYSDIR)/ebin" - $(INSTALL_DATA) $(TARGET_FILES) $(TARGET_TOOLBOX_FILES) "$(RELSYSDIR)/ebin" - -release_docs_spec: - diff --git a/lib/pman/src/assert.hrl b/lib/pman/src/assert.hrl deleted file mode 100644 index ea3b68cd7c..0000000000 --- a/lib/pman/src/assert.hrl +++ /dev/null @@ -1,81 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-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% -%% -%%% Purpose : Assert macro - - -%% ?ASSERT/2 - will simply return true if the first argument evaluates to true -%% otherwise it will exit and output (via the error logger) the -%% second string -%% -%% Arguments: -%% Flag Expression that should evalueate to true or false -%% String String to return as a part of the exit reason as well -%% be to be sent to the error logger. -%% -%% Returns: -%% true If the Flag expression evaluates to true -%% -%% Exits: -%% {'EXIT', {assertion_failed, String}} -%% If the Flag expression evaluates to something other than -%% true. -%% -%% Usage notes: -%% Please note that the Flag argument must be a valid expression that -%% evaluates to true. -%% -%% Also, avoid any side effects in the Flag, as everything performed -%% within the scope of the ?ASSERT macro will not be present when -%% the code is not compiled with the debug_on flag. -%% -%% Side effects include the binding of a variable, sending of a -%% message, etc. -%% - --ifdef(debug_on). --define(ASSERT(Flag, String), - case Flag of - true -> - true; - _ -> - S2 = - lists:flatten( - io_lib:format( - "=ASSERT====~nPid:~p, Module:~p, Line:~p~nTermination because assertion failed:~n~p", - [self(),?MODULE, ?LINE,String])), - error_logger:error_report(S2), - exit({assertion_failed, String}) - end - ). - --define(ALWAYS_ASSERT(String), - S2 = lists:flatten( - io_lib:format( - "=ASSERT====~nPid:~p, Module:~p, Line:~p~nTermination because of unconditional assert:~n~p", - [self(),?MODULE, ?LINE, String])), - error_logger:error_report(S2), - exit({always_assert, String}) - ). --else. --define(ASSERT(_Flag,_String), true). --define(ALWAYS_ASSERT(_String), true). --endif. - - - diff --git a/lib/pman/src/pman.app.src b/lib/pman/src/pman.app.src deleted file mode 100644 index cc32a17296..0000000000 --- a/lib/pman/src/pman.app.src +++ /dev/null @@ -1,40 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-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% -%% -{application, pman, - [{description, "pman The Process Manager"}, - {vsn, "%VSN%"}, - {modules, [ - pman, - pman_buf, - pman_buf_buffer, - pman_buf_converter, - pman_buf_printer, - pman_buf_utils, - pman_main, - pman_module_info, - pman_options, - pman_process, - pman_relay, - pman_relay_server, - pman_shell, - pman_tool, - pman_win - ]}, - {registered, []}, - {applications, [kernel, stdlib]}]}. diff --git a/lib/pman/src/pman.appup.src b/lib/pman/src/pman.appup.src deleted file mode 100644 index 7a435e9b22..0000000000 --- a/lib/pman/src/pman.appup.src +++ /dev/null @@ -1,19 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2001-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% -%% -{"%VSN%",[],[]}. diff --git a/lib/pman/src/pman.erl b/lib/pman/src/pman.erl deleted file mode 100644 index c8ea34b6b7..0000000000 --- a/lib/pman/src/pman.erl +++ /dev/null @@ -1,132 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1996-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% -%% -%%---------------------------------------------------------------------- -%%% Purpose : Exported API to the Pman graphical tool -%%---------------------------------------------------------------------- - --module(pman). - - -%% --------------------------------------------------------------- -%% The user interface exports -%% --------------------------------------------------------------- --export([start/0, - start_notimeout/0, - start/1, - start_notimeout/1, - proc/1, - proc/3]). - -%% --------------------------------------------------------------- - -%% Timeout for the startup function. -%% If no {initialization_complete, Pid} message has been received -%% from the spawned init-function within ?STARTUP_TIMEOUT ms -%% the start-function will call exit(Reason). --define(STARTUP_TIMEOUT, 20000). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% start/0 - -start() -> - start([], ?STARTUP_TIMEOUT). %Start w/o excluded modules - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% start_notimeout/0 - -start_notimeout() -> - start([],infinity). %Start w/o excluded modules - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% start/1 - -start(LIModuleExcluded) -> - start(LIModuleExcluded, ?STARTUP_TIMEOUT). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% start_notimeout/1 - -start_notimeout(LIModuleExcluded) -> - start(LIModuleExcluded, infinity). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% start/2 - Spawns the main Pman process, that will supervise -%% all processes except those running code from the modules -%% specified in LIModuleExcluded -%% - -start(LIModuleExcluded, Timeout) -> - - OSModuleExcluded = ordsets:from_list(LIModuleExcluded), - - PidInit = spawn(pman_main, init, [self(), OSModuleExcluded]), - - %% Wait for a initialization completion message from - %% the spawned process before returning its Pid. - %% - - receive - {initialization_complete, PidInit} -> - PidInit - - %% (Conditional) Failure to start within the time limit will - %% result in termination - - after - Timeout -> - exit(PidInit, kill), - exit({startup_timeout, ?MODULE}) - end. - - - -%% --------------------------------------------------------------- -%% If we want to trace just one process, we can call proc, giving it -%% either the Pid, or the registered name, (Global or local). -%% -%% (???) -%% Note that this function must not be used internally to create a -%% trace window, since it is assumed that it is started from any -%% process (esp. the shell) it will not have any supervisor process -%% that shall be notified about it's exit/death. -%% -%% Returns: Trace loop Pid|udefined - -%% --------------------------------------------------------------- - - -proc(undefined) -> - exit(undefined); - -proc({shell,P}) when is_pid(P) -> - pman_shell:start({{shell,P},self()}); - -proc(P) when is_atom(P) -> - proc(whereis(P)); - -proc({global, N}) -> - proc(global:whereis_name(N)); - -proc(P) when is_pid(P) -> - pman_shell:start({P,self()}). - -proc(X,Y,Z) -> - proc(c:pid(X,Y,Z)). - diff --git a/lib/pman/src/pman_buf.erl b/lib/pman/src/pman_buf.erl deleted file mode 100644 index d56ce184fa..0000000000 --- a/lib/pman/src/pman_buf.erl +++ /dev/null @@ -1,117 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-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% -%% -%%%---------------------------------------------------------------------- -%%% Purpose : This module is the exported interface to the buffering mechanism -%%% used in PMAN to prevent the trace output to congest -%%% the system. -%%% -%%% This module depends on the modules (direct or indirectly): -%%% pman_buf.hrl -%%% pman_buf_utils.erl -%%% pman_buf_buffer.erl -%%% pman_buf_converter.erl -%%% pman_buf_printer.erl -%%% -%%%---------------------------------------------------------------------- - --module(pman_buf). - -%%-compile(export_all). --export([start/2,clear/3]). - - --include("pman_buf.hrl"). - - -%% The buffering mechanism consists of three processes that -%% work in a chain to prevent the process monitor from congesting -%% output mechanism. -%% -%% Messages are buffered in the CONVERTER process before they are sent to -%% to the BUFFER process where they are formatted before they are finally -%% sent to either a file or the PRINTER process. The printer process -%% outputs the messages in the graphical user interface. -%% -%% -%% -%% --> CONVERTER --> BUFFER --> PRINTER --> gui -%% | -%% | -%% | -%% V -%% -%% file -%% - - - - - -%% ---------------------------------------------------------------- -%% The amount of data produced by a trace message may be large, and -%% cause the run time system to run out of memory. To avoid this, -%% the task of storing, cutting buffers, formating data and printing -%% it is performed by three processes: The buffer, the converter and -%% the printer. -%% -%% The converter accepts the raw data, a list -%% of {trace,Msg} tuples. Having max priority, it assures that the -%% amount of raw data stored never excedes ?BUFF_SIZE messages. -%% (With the exception of the last batch received, which assures that -%% the last trace message printed is never a buffer cut message.) -%% Whenever there is space available in the buffer process, (The -%% Buffer process stores max. ?BUFF_SIZE converted messages), -%% the buffer asks for more unconverted messages, and ?PRINT_LEN messages -%% are sent. They are converted by the buffer, and added to the list -%% of messages to be sent. - -%% The printer process requests formatted messages from the buffer, -%% and in chuncs of ?MAX_OUTPUT sends them to the buffer. If traces -%% are to be dumped on file, due to the max priority, such is handled -%% in the converter, and buffers are not cut. -%% - - -%% --------------------------------------------------------------- -%% Initializes the buffering mechanism, which consist of three -%% processes, each involved with a phase of the formattation and -%% output of data to the process windows. - -start(Editor, FileName) -> - Buffer_Pid = spawn_link(pman_buf_buffer,init,[Editor]), - Converter_Pid = - spawn_link(pman_buf_converter,init,[Buffer_Pid, FileName]), - Buffer_Pid!{converter_pid, Converter_Pid}, - #buffer{converter=Converter_Pid,buffer=Buffer_Pid}. - - - -%% --------------------------------------------------------------- -%% Kills the converter and the clears the buffer with formated data -%% starting a new converter. - -clear(Buff,String, FileName) -> - exit(Buff#buffer.converter,win_killed), - Converter_Pid=spawn_link(pman_buf_converter,init,[Buff#buffer.buffer, - FileName]), - Buff#buffer.buffer!{clear,String,Converter_Pid }, - Buff#buffer{converter = Converter_Pid}. - - - diff --git a/lib/pman/src/pman_buf.hrl b/lib/pman/src/pman_buf.hrl deleted file mode 100644 index 3f25dcc5f0..0000000000 --- a/lib/pman/src/pman_buf.hrl +++ /dev/null @@ -1,29 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-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% -%% - -%%-compile(export_all). -%%-export([Function/Arity, ...]). - --define(BUFF_SIZE,1000). --define(EDITOR_MAX,10000). --define(PRINT_LEN,50). --define(MAX_OUTPUT,5000). - - --record(buffer,{buffer,converter}). diff --git a/lib/pman/src/pman_buf_buffer.erl b/lib/pman/src/pman_buf_buffer.erl deleted file mode 100644 index ad92eb1f3e..0000000000 --- a/lib/pman/src/pman_buf_buffer.erl +++ /dev/null @@ -1,102 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-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% -%% -%%%---------------------------------------------------------------------- -%%% Purpose : The purpouse of the buffer process is to take -%%% care of the data that is received by the converter -%%% process and pass it on to the printer process in chunks -%%% that can be handled. -%%% -%%% This module is a part of the buffering system, and -%%% should not be used except through the API defined -%%% in the pman_buf module. -%%% -%%%---------------------------------------------------------------------- - --module(pman_buf_buffer). - -%%-compile(export_all). --export([init/1]). - --include("pman_buf.hrl"). - - - -%% -%% Initialization function for the buffer process. -%% To be started with spawn from the calling process. -%% - -init(Editor) -> - Printer_pid = spawn_link(pman_buf_printer,init,[Editor,self()]), - receive - {converter_pid,Pid} -> - Pid!{buffer,accept}, - buffer_loop([],0,0,Printer_pid,Pid) - end. - - - -%% -%% Receive loop for the buffer process. -%% - -buffer_loop(Buffer,Size,Acc,Printer,Converter) -> - receive - {save_buffer,Name} -> - Printer!{save_buffer,Name}, - buffer_loop(Buffer,Size,Acc,Printer,Converter); - {raw,Raw,Length} -> %%output to editor - New_Size = Size + Length, - if New_Size < ?BUFF_SIZE -> - Converter!{buffer,accept}; - true -> ok - end, - Print = lists:map(fun(X) -> pman_buf_utils:textformat(X) end, Raw), - New_Buff = lists:append(Buffer,Print), - buffer_loop(New_Buff,New_Size,Acc,Printer,Converter); - {clear,Text,N_Converter} -> - Converter!{buffer,accept}, - Printer!clear, - buffer_loop([Text],1,1,Printer,N_Converter); - {printer,send} when Buffer /= [] -> - if - Acc > ?EDITOR_MAX -> - Printer!clear, - Printer !{buffer,"Cleared Buffer due to Size\n\n"}, - buffer_loop(Buffer,Size,1,Printer,Converter); - true -> - {Length,Rest,Print} = pman_buf_utils:split(Buffer, - ?PRINT_LEN, - 0, - []), - Printer ! {buffer,Print}, - New_Size = Size - Length, - if New_Size < ?BUFF_SIZE -> - Converter!{buffer,accept}; - true -> ok - end, - buffer_loop(Rest,New_Size,Acc+Length,Printer,Converter) - end; - {converter,file} -> - Converter!{buffer,Buffer}, - self()!{raw,[to_file],1}, - buffer_loop([],0,Acc,Printer,Converter) - end. - - diff --git a/lib/pman/src/pman_buf_converter.erl b/lib/pman/src/pman_buf_converter.erl deleted file mode 100644 index c8b3fe37aa..0000000000 --- a/lib/pman/src/pman_buf_converter.erl +++ /dev/null @@ -1,190 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2012. 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% -%% -%%---------------------------------------------------------------------- -%% Purpose : The purpouse of the converter process is to take -%% care of the raw data that is received by the tracing -%% process (a pman_shell process) and pass it on to -%% the buffer process in chunks that can be handled. -%% -%% This module is a part of the buffering system, and -%% should not be used except through the API defined -%% in the pman_buf module. -%% -%%---------------------------------------------------------------------- - --module(pman_buf_converter). --compile([{nowarn_deprecated_function,{gs,start,0}}]). - -%%-compile(export_all). --export([init/2]). - --include("pman_buf.hrl"). - - -%% --------------------------------------------------------------- -%% Starts the process which received the raw data from the debugger, -%% cuts and forwards it to the buffer in smaller chunks. High priority -%% to avoid large message queues waiting to be processed. - -init(Buffer_Pid, FileName) -> - process_flag(priority, max), - converter_loop(Buffer_Pid,[],0,true,[], FileName). - -converter_loop(Buffer_Pid,Raw,Size,State,Last, FileName) -> - receive - {file,Shell} -> - case init_file(lists:append(Raw,Last), - FileName, - Shell, - Buffer_Pid) of - true -> converter_loop(Buffer_Pid, - [to_buffer], - 1, - State, - [], - FileName); - false -> converter_loop(Buffer_Pid, - Raw, - Size, - State, - Last, - FileName) - end; - {raw,Trace} -> - {New_Raw,New_Size,New_State,New_Last} = - converter_data(Trace, Buffer_Pid, Raw, Size, State, Last), - converter_loop(Buffer_Pid, - New_Raw, - New_Size, - New_State, - New_Last, - FileName); - {buffer,accept} when Raw /= [] -> - {Length,Rest,Print} = pman_buf_utils:split(Raw,?PRINT_LEN,0,[]), - Buffer_Pid!{raw,Print,Length}, - converter_loop(Buffer_Pid,Rest,Size-Length,false,Last,FileName); - {buffer,accept} when Last /= [] -> - {New_Raw,New_Size,New_State,New_Last} = - converter_data(Last,Buffer_Pid,Raw,Size,true,[]), - converter_loop(Buffer_Pid, - New_Raw, - New_Size, - New_State, - New_Last, - FileName); - {buffer,accept} -> - converter_loop(Buffer_Pid,Raw,Size,true,Last, FileName); - {clear,Str} -> - Buffer_Pid!{clear,Str}, - converter_loop(Buffer_Pid,[],0,State,Last,FileName) - end. - -converter_data(Trace,Buffer_Pid,Raw,Size,State,Last) -> - if - ?BUFF_SIZE - Size > 0 -> - {Len,Rest,New_Trace} = pman_buf_utils:split(Trace, - ?BUFF_SIZE-Size, - 0,[]), - {New_Raw,New_Last} = - case Rest of - [] -> - {lists:append(Raw,New_Trace),Last}; - [_|_] -> - case Last of - [] -> - {lists:append(Raw,New_Trace),Rest}; - _ ->{lists:concat([Raw,New_Trace,[cut_buffer]]), - Rest} - end - end, - case State of true -> - {Length,Cut_Raw,Print} = pman_buf_utils:split(New_Raw, - ?PRINT_LEN, - 0,[]), - Buffer_Pid!{raw,Print,Length}, - {Cut_Raw,Size-Length,false,New_Last}; - _ -> - {New_Raw,Size+Len,false,New_Last} - end; - true -> - {Raw,Size,State,Trace} - end. - - -%% --------------------------------------------------------------- -%% Initializes the environment for saving the trace to file. The -%% actual saving is taken care of by the buffer process. - -init_file(Raw,FileName, Name,Buffer_Pid) -> - case open_file(FileName, Name) of - {false,T} -> - pman_win:msg_win(T), - false; - {File,T} -> - Buffer_Pid!{converter,file}, - pman_win:dialog_window(gs:start(),T), - save_loop_init(File,Raw) - end. - -open_file(FileName, _Shell) -> -%% L = "pman_trace." ++ Shell, - case file:open(FileName, [read,write]) of - {error, _} -> - Str = "ERROR: Could not create_file\n" ++ FileName, - {false,Str}; - {ok,File} -> - file:position(File, {eof, 0}), - Str1 = " Appending trace log to file\n" ++ FileName, - {File,Str1} - end. - - -save_loop_init(Fd,Raw) -> - {Date, Time} = calendar:local_time(), - {Year, Month, Day} = Date, - {Hour, Minute, Second} = Time, - io:format(Fd,"%%% ~n",[]), - io:format(Fd,"%%% Trace output~n",[]), - io:format(Fd,"%%% Started at ~4p-~2p-~2p ~2p:~2p:~2p~n", - [Year, Month, Day, - Hour, Minute, Second - ]), - io:format(Fd,"%%% ~n~n",[]), - - Print = lists:map(fun(X) -> pman_buf_utils:textformat(X) end, Raw), - receive - {buffer,Text} when is_list(Text) -> - io:format(Fd,Text,[]), - io:format(Fd,Print,[]), - save_loop(Fd) - end. - -save_loop(Fd) -> - receive - {raw,Raw} -> - Print = lists:map(fun(X) -> pman_buf_utils:textformat(X) end, Raw), - io:format(Fd,Print,[]), - save_loop(Fd); - buffer -> true - end. - - - - - diff --git a/lib/pman/src/pman_buf_printer.erl b/lib/pman/src/pman_buf_printer.erl deleted file mode 100644 index 3284c57559..0000000000 --- a/lib/pman/src/pman_buf_printer.erl +++ /dev/null @@ -1,91 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2012. 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% -%% - --module(pman_buf_printer). --compile([{nowarn_deprecated_function,{gs,config,2}}, - {nowarn_deprecated_function,{gs,start,0}}]). - -%%-compile(export_all). --export([init/2]). - - --include("pman_buf.hrl"). - -%% --------------------------------------------------------------- -%% Starts the part of the buffer which regulates the flow of data to -%% be printed in the pid editors - - -init(Editor,Buffer_pid) -> - Buffer_pid!{printer,send}, - printer_loop(Editor,Buffer_pid). - -printer_loop(Editor,Buffer_pid)-> - receive - {save_buffer,Name} -> - gs:config(Editor,{save,Name}), - TT = "Buffer saved in file\n" ++ Name, - pman_win:dialog_window(gs:start(),TT), - printer_loop(Editor,Buffer_pid); - {buffer,Trace} -> - case lists:flatlength(Trace) of - Len when Len > ?MAX_OUTPUT -> - printer_long(lists:flatten(Trace),Editor), - Buffer_pid!{printer,send}, - printer_loop(Editor,Buffer_pid); - _ -> - Buffer_pid!{printer,send}, - print_trace(Editor,Trace), - printer_loop(Editor,Buffer_pid) - end; - clear -> - pman_win:configeditor(Editor, [{enable, true}]), - pman_win:configeditor(Editor,clear), - pman_win:configeditor(Editor, [{enable, false}]), - printer_loop(Editor,Buffer_pid); - _Other -> - printer_loop(Editor,Buffer_pid) - end. - -printer_long([],_) -> ok; -printer_long(Trace,Editor) -> - receive - clear -> - pman_win:configeditor(Editor, [{enable, true}]), - pman_win:configeditor(Editor,clear), - pman_win:configeditor(Editor, [{enable, false}]) - after 0 -> - {_Length,Rest,Print} = pman_buf_utils:split(Trace, - ?MAX_OUTPUT, - 0, - []), - print_trace(Editor,Print), - printer_long(Rest,Editor) - end. - - - -%% --------------------------------------------------------------- -%% Function which print trace messages on the window -%% --------------------------------------------------------------- - -print_trace(Editor,Elements) -> - pman_win:configeditor(Editor, [{enable, true}]), - pman_win:configeditor(Editor, [{insert, {'end',Elements}}]), - pman_win:configeditor(Editor, [{enable, false}]). diff --git a/lib/pman/src/pman_buf_utils.erl b/lib/pman/src/pman_buf_utils.erl deleted file mode 100644 index af3982665e..0000000000 --- a/lib/pman/src/pman_buf_utils.erl +++ /dev/null @@ -1,106 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-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% -%% - --module(pman_buf_utils). - -%%-compile(export_all). --export([textformat/1, split/4]). - - -%% --------------------------------------------------------------- -%% Funtion which format the trace message -%% --------------------------------------------------------------- - -textformat(died) -> - "\n\nProcess died\n"; -textformat({died, Pid}) -> - io_lib:format("~w Process died.~n",[Pid]); -textformat({shell_died, Old, New}) -> - io_lib:format("~w Shell Process died. Restarted as ~w~n~n",[Old,New]); - - -textformat(to_buffer) -> - "\nAppending trace log to Buffer\n\n"; -textformat(to_file) -> - "\nAppending trace log to File\n\n"; -textformat(cut_buffer) -> - "\nCUT BUFFER\n\n"; -textformat({trace, From, 'receive', Msg}) -> - io_lib:format("~w: rec ~s~n", [From, - tuple_space(Msg)]); -textformat({trace, From, send, Msg, To}) -> - io_lib:format("~w: ! To: ~w Msg: ~s~n", [From, - To, - tuple_space(Msg)]); -textformat({trace, From, call, Func}) -> - io_lib:format("~w: call ~s~n",[From, ffunc(Func)]); -textformat({trace, From, spawn, Data}) -> - io_lib:format("~w: spawn ~p~n", [From, Data]); -textformat({trace, From, link, Data}) -> - io_lib:format("~w: link ~p~n", [From, Data]); -textformat({trace, From, unlink, Data}) -> - io_lib:format("~w: U-lnk ~p~n", [From, Data]); - -textformat({trace, From, Op, Data}) -> - io_lib:format("~w: ~w ~p~n", [From, Op, Data]); - -textformat({print, Format, Args}) -> - io_lib:format(Format, Args); -textformat(Other) -> - io_lib:format("~p~n",[Other]). - - - - - -ffunc({M,F, Argl}) -> - io_lib:format("~w:~w(~s)", [M, F, fargs(Argl)]); -ffunc(X) -> tuple_space(X). -fargs([]) -> []; -fargs([A]) -> tuple_space(A); %% last arg -fargs([A|Args]) -> [tuple_space(A),", "|fargs(Args)]. - - -tuple_space(X) when is_tuple(X) -> print(size(X), X, "}"); -tuple_space(X) -> io_lib:format("~p",[X]). - -print(0 , _X, Buff) -> ["{"|Buff]; -print(1 , X, Buff) -> - Str = tuple_space(element(1, X)), - ["{",Str|Buff]; -print(Num, X, Buff) -> - Str = tuple_space(element(Num, X)), - print(Num-1, X, [", ",Str|Buff]). - - - -%% ---------------------------------------------------------------- -%% splits the list at element Size, returns Size, and the 2 lists -%% If the list is not long enough, it returns {size(List),[],List} - - -split([],_,Length,Buff) -> - {Length,[],lists:reverse(Buff)}; -split(Rest,0,Length,Buff) -> - {Length,Rest,lists:reverse(Buff)}; -split([L|List],Size,Length,Buff) -> - split(List,Size-1,Length+1,[L|Buff]). - - - diff --git a/lib/pman/src/pman_main.erl b/lib/pman/src/pman_main.erl deleted file mode 100644 index 2f51284293..0000000000 --- a/lib/pman/src/pman_main.erl +++ /dev/null @@ -1,789 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2012. 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% -%% --module(pman_main). --compile([{nowarn_deprecated_function,{gs,config,2}}, - {nowarn_deprecated_function,{gs,read,2}}]). - -%% Main process and window - --export([init/2]). - --record(state, {win, % GS top window - frame, % GS top frame - grid, % GS process info grid - - size, % int() No. of displayed procs - w, % int() Window width - h, % int() Window height - - hide_system=false, % bool() Auto-hide system procs - hide_new=false, % bool() Auto-hide new processes - - hide_modules, % ordset() Excluded modules - - hide_all=[], % [{node(), bool()}] Hide all - hide_pids=[], % [{node(), Ordset}] Processes - % explicitly to hide, per node - show_pids=[], % [{node(), Ordset}] Processes - % explicitly to show, per node - - shown_pids=[], % [{node(), Ordset}] Processes - % actually shown, per node - - node, % node() Current node - nodes=[], % [node()] All known nodes - - focus=1, % int() Grid line with focus - focus_pid=undefined, % pid() | undefined Proc in focus - - noshell, % bool() Noshell mode on - - options}). % term() Trace options settings - - --include("pman_win.hrl"). - --define(REFRESH_TIME,5000). - --define(REQUIRES_FOCUS, % List of menus that should - ['Trace Process', % be disabled if no process - 'Kill', % is in focus - 'Hide Selected Process', - 'Module']). - -%%--Process init and loop----------------------------------------------- - -init(PidCaller, OSModuleExcluded) -> - process_flag(trap_exit, true), - - %% Monitor all nodes in a distributed system - case is_alive() of - - %% We have a distributed system - true -> net_kernel:monitor_nodes(true); - - %% No distribution - false -> ignore - end, - Nodes = [node()|nodes()], - - %% Create the main window - %% For some extremely strange reason, the frame must be resized - %% or the grid won't be visible... - GridSize = length(processes()) + 61, - {Window, Grid, Frame, Visible, W, H} = - pman_win:pman_window(GridSize, OSModuleExcluded, Nodes), - gse:resize(Frame, ?WIN_WIDTH, ?WIN_HEIGHT-?MENU_HEIGHT), - - Noshell = case pman_shell:find_shell() of - noshell -> true; - _ -> false - end, - - State1 = #state{win=Window, frame=Frame, grid=Grid, - size=Visible, - w=W, h=H, - hide_modules=OSModuleExcluded, - node=node(), - noshell=Noshell}, - - State2 = lists:foldl(fun(Node, State) -> add_node(Node, State) end, - State1, - Nodes), - - State3 = refresh(State2), - - %% Notify caller that the process appears - %% to have been started. - PidCaller ! {initialization_complete, self()}, - - %% Initiate a 'catch all' trace pattern so call tracing works - erlang:trace_pattern({'_', '_', '_'}, true, [local]), - - %% Read default options file - Options = restore_options(State3), - - loop(State3#state{options=Options}). - -add_node(Node, State) -> - pman_win:add_menu(node, [Node], "Show"), - State#state{hide_all=nl_update(Node, false, State#state.hide_all), - hide_pids=nl_update(Node, [], State#state.hide_pids), - show_pids=nl_update(Node, [], State#state.show_pids), - shown_pids=nl_update(Node, [], State#state.shown_pids), - nodes=[Node|State#state.nodes]}. - -%% Restore saved options from default file -restore_options(State)-> - File = options_file(), - case pman_options:read_from_file(File) of - {ok, Options} -> - Options; - {error, ReasonStr, DefOptions} -> - Parent = State#state.win, - Msg = io_lib:format( - "Problems reading default option file~n~s:~n~s", - [File, ReasonStr]), - tool_utils:notify(Parent, Msg), - DefOptions - end. - -options_file() -> - {ok, [[Home]]} = init:get_argument(home), - filename:join([Home, ".erlang_tools", "pman.opts"]). - -loop(State) -> - receive - {nodeup, Node} -> - case nl_exists(Node, State#state.hide_all) of - true -> - pman_win:add_menu(node, [Node], "Show"), - loop(State#state{nodes=[Node|State#state.nodes]}); - false -> - loop(add_node(Node, State)) - end; - - {nodedown, Node} -> - pman_win:remove_menu([Node]), - - Msg = io_lib:format("Node~n~p~ndown.", [Node]), - spawn_link(tool_utils, notify, [State#state.win, Msg]), - - %% We remove Node from the list of nodes but not from - %% the other lists of State, in case Node reappears later - Nodes = lists:delete(Node, State#state.nodes), - State2 = State#state{nodes=Nodes}, - - %% If it was the shown node that went down, - %% change overview to this node - if - Node==State#state.node -> - State3 = execute_cmd({node,node()}, State2, [], []), - loop(State3); - true -> - loop(State2) - end; - - %% Ignore EXIT signals from help processes - {'EXIT', _Pid, _Reason} -> - loop(State); - - %% GS events - {gs, _Obj, _Event, _Data, _Args} = Cmd -> - case gs_cmd(Cmd, State) of - stop -> - exit(topquit); - State2 -> - loop(State2) - end - - after ?REFRESH_TIME -> - State2 = refresh(State), - loop(State2) - end. - -%% gs_cmd(Event, State) -> stop | State' -gs_cmd(Event, State) -> - case Event of - - %% --- Window manager commands --- - - %% Window is moved or resized - {gs, _, configure, _Data, Args} -> - configure(Args, State); - - %% Window closed, stop Pman - {gs, _, destroy, _, _} -> - stop; - - %% --- Dynamic commands --- - - %% Click in any object where the GS Data field is a 2-tuple - {gs, _, click, Data, Args} when is_tuple(Data), size(Data)==2 -> - execute_cmd(Data, State, [], Args); - - %% Single click in the grid sets focus to selected process - {gs, _, click, {pidfunc,_,_}, [_,Row|_]} when is_integer(Row) -> - focus(Row, State); - - %% Double click in the grid starts tracing of selected process - {gs, _, doubleclick, {pidfunc,_,_}, [_Col,Row| _]} when is_integer(Row) -> - execute_cmd('Trace Process', State, [], []); - - %% Click in named GS objects - {gs, Cmd, click, Data, Args} when is_atom(Cmd); - is_atom(element(1, Cmd)) -> - execute_cmd(Cmd, State, Data, Args); - - %% --- Keyboard accelerator commands --- - - %% Move focus up and down - {gs, _, keypress, [], ['Up',_,0,0]} -> - execute_cmd(focus_previous, State, [], []); - {gs, _, keypress, [], ['Down',_,0,0]} -> - execute_cmd(focus_next, State, [], []); - - %% Other keyboard shortcuts - {gs, _, keypress, [], ['Return',_,0,0]} -> - execute_cmd('Trace Process', State, [], []); - {gs, _, keypress, [], [Key,_,0,1]} -> - execute_cmd(shortcut(Key), State, [], []); - - %% Ignore all other GS events - _Other -> - State - end. - -%% Keyboard shortcuts - -%% File menu -shortcut(o) -> 'Default Options'; -shortcut(e) -> 'Exit'; -shortcut(z) -> 'Exit'; - -%% View menu -shortcut(i) -> 'Hide All'; -shortcut(u) -> 'Hide Modules'; -shortcut(d) -> 'Hide Selected Process'; -shortcut(m) -> 'Module'; -shortcut(r) -> 'Refresh'; - -%% Trace menu -shortcut(k) -> 'Kill'; -shortcut(t) -> 'Trace Process'; -shortcut(s) -> 'Trace Shell'; - -%% Help menu -shortcut(h) -> 'Help'; - -%% Keyboard command only -shortcut(l) -> 'All Links'; - -%% Process grid traversal -shortcut(p) -> focus_previous; -shortcut(n) -> focus_next; -shortcut(_) -> dummy. - -%% configure([W,H,X,Y|_], State) -> State' -%% Window has been moved or resized -configure([W,H|_], State) -> - if - W==State#state.w, H==State#state.h -> - ignore; - - true -> - gse:resize(State#state.frame, W, H-?MENU_HEIGHT), - - Grid = State#state.grid, - case abs(W - gs:read(Grid,width) - 6) of - 0 -> - ok; %% Avoid refreshing width if possible - _Anything -> - Cols = pman_win:calc_columnwidths(W-6), - gs:config(Grid, Cols) - end, - pman_win:configwin(Grid, W, H) - end, - State. - -%% focus(Row, State) -> State' -%% Row = int() Grid row -%% User has selected a row in the grid. -%% Row==1 means header row. -focus(Row, State) -> - - Pid = case get_pid_in_focus(Row, State#state.grid) of - {true, {pidfunc,Pid0,_}} -> - pman_win:change_colour(State#state.grid, - State#state.focus, Row), - enable_pid_actions(), - Pid0; - false -> - disable_pid_actions(), - undefined - end, - - State#state{focus=Row, focus_pid=Pid}. - -%% get_pid_in_focus(Row, Grid) -> {true, Data} | false -%% Data = {pidfunc, Pid, Func} -%% Func = {Mod,Name,Arity} | term() -%% Return the data associated with the process in focus if there is one, -get_pid_in_focus(1, _Grid) -> - false; -get_pid_in_focus(Row, Grid) -> - case gs:read(Grid, {obj_at_row,Row}) of - undefined -> false; - GridLine -> - Data = gs:read(GridLine, data), - {true, Data} - end. - -%% execute_cmd(Cmd, State, Data, Args) -> stop | State' - -%% Checkbutton "Hide System Processes" -execute_cmd('Hide System', State, _Data, Args) -> - [_Text, _Group, Bool|_Rest] = Args, - State2 = State#state{hide_system=Bool}, - refresh(State2); - -%% Checkbutton "Auto-Hide New" -execute_cmd('Auto Hide New', State, _Data, Args ) -> - [_Text, _Group, Bool|_Rest] = Args, - refresh(State#state{hide_new=Bool}); - -%% File->Options... -execute_cmd('Default Options', State, _Data, _Args) -> - OldOptions = State#state.options, - NewOptions = pman_options:dialog(State#state.win, - "Default Trace Options", - OldOptions), - case NewOptions of - {error, _Reason} -> - State; - Options -> - State#state{options=Options} - end; - -%% File->Save Options -%% Save the set default options to the user's option file -execute_cmd('Save Options', State, _Data, _Args)-> - Options = State#state.options, - File = options_file(), - Parent = State#state.win, - - case pman_options:save_to_file(Options, File) of - ok -> - tool_utils:notify(Parent, "Options saved to\n" ++ File); - {error, ReasonStr} -> - Msg = io_lib:format("Could not save options to~n~s:~n~s", - [File, ReasonStr]), - tool_utils:notify(Parent, Msg) - end, - State; - -%% File->Exit -%% Exit the application -execute_cmd('Exit', _State, _Data, _Args) -> - stop; - -%% View->Hide All Processes -execute_cmd('Hide All', State, _Data, _Args) -> - Node = State#state.node, - HideAll = nl_update(Node, true, State#state.hide_all), - ShowPids = nl_del_all(State#state.node, State#state.show_pids), - State2 = State#state{hide_all=HideAll, show_pids=ShowPids}, - refresh(State2, true); - -%% View->Hide modules... -%% Opens a dialog where the user can select from a list of -%% the loaded modules. -%% The selected module is added to the list of hidden modules. -execute_cmd('Hide Modules', State, _Data, _Args) -> - - %% Get all loaded modules that are not already hidden - AllModules = lists:map(fun({Module, _File}) -> Module end, - code:all_loaded()), - ModulesSet = ordsets:subtract(ordsets:from_list(AllModules), - State#state.hide_modules), - - %% Let the user select which of the loaded modules to exclude from - %% the process overview - Title = "Module selection", - case pman_tool:select(State#state.win, Title, ModulesSet) of - Modules when is_list(Modules) -> - HideModules = ordsets:union(State#state.hide_modules, - ordsets:from_list(Modules)), - refresh(State#state{hide_modules=HideModules}); - cancelled -> State - end; - -%% View->Hide Selected Process -%% The process in focus should explicitly be hidden -execute_cmd('Hide Selected Process', State, _Data, _Args) -> - case State#state.focus_pid of - undefined -> State; - Pid -> - Node = State#state.node, - HidePids = nl_add(Node, Pid, State#state.hide_pids), - ShowPids = nl_del(Node, Pid, State#state.show_pids), - refresh(State#state{hide_pids=HidePids, show_pids=ShowPids}) - end; - -%% View->Module Info... -%% Open window with module information. -execute_cmd('Module', State, _Data, _Args) -> - case get_pid_in_focus(State#state.focus, State#state.grid) of - {true, {pidfunc, _Pid, {Module,_Name,_Arity}}} -> - pman_module_info:start(Module); - _ -> % false | {true, {pidfunc, Pid, Other}} - ignore - end, - State; - -%% View->Refresh -%% Refresh the main window. -%% (Called automatically every ?REFRESH_TIME millisecond) -execute_cmd('Refresh', State, _Data, _Args) -> - refresh(State); - -%% View->Show All Processes -%% Makes all processes visible except system processes and new -%% processes, if those buttons are checked. -%% Note: Also un-hides all hidden modules! -execute_cmd('Show All', State, _Data, _Args) -> - Node = State#state.node, - HideAll = nl_update(Node, false, State#state.hide_all), - HidePids = nl_del_all(State#state.node, State#state.hide_pids), - ShowPids = nl_del_all(State#state.node, State#state.show_pids), - State2 = State#state{hide_modules=ordsets:new(), hide_all=HideAll, - hide_pids=HidePids, show_pids=ShowPids}, - refresh(State2, true); - -%% View->Show Processes... -%% Open a list of all hidden processes, if the user selects one this -%% process should explicitly be shown -execute_cmd('Show Selected', State, _Data, _Args) -> - Node = State#state.node, - - All = pman_process:r_processes(Node), - Hidden = case nl_lookup(Node, State#state.hide_all) of - true -> - All; - false -> - Shown = nl_lookup(Node, State#state.shown_pids), - ordsets:subtract(All, Shown) - end, - - %% Selection window - Title = "Select Processes to Show", - Tuples = - lists:map(fun(Pid) -> - {M,F,A} = pman_process:function_info(Pid), - Str = case pman_process:get_name(Pid) of - " " -> - io_lib:format("~p:~p/~p", - [M, F, A]); - Name -> - io_lib:format("[~p] ~p:~p/~p", - [Name, M, F, A]) - end, - {Pid, Str} - end, - Hidden), - case pman_tool:select(State#state.win, Title, Tuples) of - Pids when is_list(Pids) -> - HidePids = nl_del(Node, Pids, State#state.hide_pids), - ShowPids = nl_add(Node, Pids, State#state.show_pids), - refresh(State#state{hide_pids=HidePids,show_pids=ShowPids}); - cancelled -> State - end; - -%% Trace->Kill -execute_cmd('Kill', State, _Data, _Args) -> - case State#state.focus_pid of - Pid when is_pid(Pid) -> - exit(Pid, kill); - undefined -> - ignore - end, - State; - -%% Trace->Selected Process -execute_cmd('Trace Process', State, _Data, _Args) -> - case State#state.focus_pid of - Pid when is_pid(Pid) -> - pman_shell:start({Pid,self()}, State#state.options); - undefined -> - ignore - end, - State; - -%% Trace->Shell Process -execute_cmd('Trace Shell', State, _Data, _Args) -> - case pman_shell:find_shell() of - noshell -> - State; - Shell -> - pman_shell:start({{shell,Shell},self()}, - State#state.options), - State#state{noshell=false} - end; - -%% Nodes->Show <Node> -%% Change shown node -execute_cmd({node,Node}, State, _Data, _Args) -> - gse:config(State#state.win, - [{title,lists:concat(["Pman: Overview on ", Node])}]), - gse:disable(Node), - catch gse:enable(State#state.node), % Menu may not exist any more - refresh(State#state{node=Node}, true); - -%% Help->Help -execute_cmd('Help', State, _Data, _Args) -> - Win = State#state.win, - HelpFile = - filename:join([code:lib_dir(pman),"doc","html","index.html"]), - tool_utils:open_help(Win, HelpFile), - State; - -%% Keyboard shortcut Ctrl-l -execute_cmd('All Links', State, _Data, _Args) -> - case State#state.focus_pid of - Pid when is_pid(Pid) -> - case process_info(Pid, links) of - {links, Pids} -> - pman_shell:start_list(Pids, self(), - State#state.options); - undefined -> - ignore - end; - undefined -> ignore - end, - State; - -%% Keyboard shortcuts for process grid traversal -execute_cmd(focus_previous, State, _Data, _Args) -> - focus(previous_row(State), State); -execute_cmd(focus_next, State, _Data, _Args) -> - focus(next_row(State), State); - -%% Keyboard combinations that are not shortcuts -execute_cmd(dummy, State, _Data, _Args) -> - State. - -%% Convenience functions for disabling/enabling menu items that require -%% that a process is selected. -disable_pid_actions() -> - lists:foreach(fun(X) -> gse:disable(X) end, ?REQUIRES_FOCUS). - -enable_pid_actions() -> - lists:foreach(fun(X) -> gse:enable(X) end, ?REQUIRES_FOCUS). - -%% refresh(State) -> State' -%% refresh(State, ForceP) -> State' -%% Refreshes the main window. -refresh(State) -> - refresh(State, false). -refresh(#state{node=Node} = State, ForceP) -> - - %% Update shown processes - - %% First, get an ordset of all processes running at the current node - All = pman_process:r_processes(Node), - - Shown = nl_lookup(Node, State#state.shown_pids), - ExpShown = nl_lookup(Node, State#state.show_pids), - - {Show, State2} = - case nl_lookup(Node, State#state.hide_all) of - - %% If the user has selected "Hide All Processes", only - %% explicitly selected processes which still exist should - %% be shown - true -> - {ordsets:intersection(ExpShown, All), State}; - - false -> - %% Compute which processes should be hidden according - %% to the flags/menu items selected - Hidden = hidden_pids(All, State), - - NotHidden = ordsets:subtract(All, Hidden), - - Show0 = case State#state.hide_new of - %% If the user has selected "Auto-Hide New", - %% then only those processes in NotHidden - %% which are already shown, should be shown, - %% together with explicitly selected - %% processes which still exist - true -> - ordsets:union( - ordsets:intersection(NotHidden,Shown), - ordsets:intersection(ExpShown, All)); - - %% Otherwise, show all processes in - %% NotHidden, together with explicitly - %% selected processes which still exist - false -> - ordsets:union( - NotHidden, - ordsets:intersection(ExpShown, All)) - end, - - ShownPids = nl_update(Node, Show0, - State#state.shown_pids), - {Show0, State#state{shown_pids=ShownPids}} - end, - - NoOfHidden = length(All) - length(Show), - - if - Show==Shown, not ForceP -> - pman_win:update(NoOfHidden), - State; - - true -> - ShowInfo = display_info(Show), - pman_win:update(State#state.grid, ShowInfo, NoOfHidden), - - %% Set the focus appropriately - State3 = case State2#state.focus_pid of - undefined -> - disable_pid_actions(), - State2; - Pid -> - Row = get_row(Pid, Show), - focus(Row, State2) - end, - - trace_shell_possible(State3), - - Size = length(Show), - case Size of - 1 -> gse:disable('Hide All'); - _ -> gse:enable('Hide All') - end, - - State3#state{size=Size} - end. - -%% hidden_pids(All, State) -> Hidden -hidden_pids(All, State) -> - - %% Processes hidden because they are system processes - HideSys = case State#state.hide_system of - true -> - lists:filter( - fun(Pid) -> - pman_process:is_system_process(Pid) - end, - All); - false -> - [] - end, - - %% Process hidden because they are executing code in a hidden module - Mods = State#state.hide_modules, - HideMod = - lists:filter(fun(Pid) -> - pman_process:is_hidden_by_module(Pid, Mods) - end, - All), - - %% Explicitly hidden processes - HideExp = nl_lookup(State#state.node, State#state.hide_pids), - - %% All hidden processes - ordsets:union([HideSys, HideMod, HideExp]). - -display_info(Pids) -> - lists:map(fun(Pid) -> - Func = pman_process:function_info(Pid), - Name = pman_process:get_name(Pid), - Msgs = pman_process:msg(Pid), - Reds = pman_process:reds(Pid), - Size = pman_process:psize(Pid), - {Pid, Func, Name, Msgs, Reds, Size} - end, - Pids). - -get_row(Pid, List) -> - get_row(Pid, List, length(List)+1). - -get_row(Pid, [Pid | _], Row) -> - Row; -get_row(Pid, [_ | T], Row) -> - get_row(Pid, T, Row-1); -get_row(_Pid, [], _Row) -> - 1. - -next_row(#state{size=Size, focus=Row}) -> - check_row(Row+1, Size). - -previous_row(#state{size=Size, focus=Row}) -> - check_row(Row-1, Size). - -check_row(1, Size) -> - Size+1; -check_row(Row, Size) when Row==Size+2 -> - 2; -check_row(Row, _Size) -> - Row. - -%% Check if node is running in noshell mode and if so disable the -%% 'Trace Shell' menu option. -trace_shell_possible(#state{noshell=true}) -> - gse:disable('Trace Shell'); -trace_shell_possible(_) -> - ok. - -%% -- Functions for manipulating {Node, Data} lists -- - -%% nl_add(Node, Elem|Elems, NList) -> NList' -nl_add(Node, Elems, [{Node, Ordset} | T]) when is_list(Elems) -> - [{Node, ordsets:union(Elems, Ordset)} | T]; -nl_add(Node, Elem, [{Node, Ordset} | T]) -> - [{Node, ordsets:add_element(Elem, Ordset)} | T]; -nl_add(Node, Elem, [H | T]) -> - [H | nl_add(Node, Elem, T)]; -nl_add(Node, Elems, []) when is_list(Elems) -> - [{Node, Elems}]; -nl_add(Node, Elem, []) -> - [{Node, ordsets:add_element(Elem, ordsets:new())}]. - -%% nl_del(Node, Elem|Elems, NList) -> NList' -nl_del(Node, Elems, [{Node, Ordset} | T]) when is_list(Elems) -> - [{Node, ordsets:subtract(Ordset, Elems)} | T]; -nl_del(Node, Elem, [{Node, Ordset} | T]) -> - [{Node, ordsets:del_element(Elem, Ordset)} | T]; -nl_del(Node, Elem, [H | T]) -> - [H | nl_del(Node, Elem, T)]; -nl_del(_Node, _Elem, []) -> - []. - -%% nl_del_all(Node, NList) -> NList' -nl_del_all(Node, [{Node, _Ordset} | T]) -> - [{Node, ordsets:new()} | T]; -nl_del_all(Node, [H | T]) -> - [H | nl_del_all(Node, T)]; -nl_del_all(_Node, []) -> - []. - -%% nl_update(Node, Val, NList) -> NList' -nl_update(Node, Val, [{Node, _OldVal} | T]) -> - [{Node, Val} | T]; -nl_update(Node, Val, [H | T]) -> - [H | nl_update(Node, Val, T)]; -nl_update(Node, Val, []) -> - [{Node, Val}]. - -%% nl_lookup(Node, NList) -> Val -nl_lookup(Node, NList) -> - {value, {_Node,Val}} = lists:keysearch(Node, 1, NList), - Val. - -%% nl_exists(Node, NList) -> bool() -nl_exists(Node, NList) -> - case lists:keysearch(Node, 1, NList) of - {value, _Val} -> - true; - false -> - false - end. diff --git a/lib/pman/src/pman_module_info.erl b/lib/pman/src/pman_module_info.erl deleted file mode 100644 index 944fd4a462..0000000000 --- a/lib/pman/src/pman_module_info.erl +++ /dev/null @@ -1,133 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2012. 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% -%% --module(pman_module_info). --compile([{nowarn_deprecated_function,{gs,config,2}}, - {nowarn_deprecated_function,{gs,start,1}}]). - -%% Window with module information (View->Module Info...) - -%% External exports --export([start/1]). - -%% Record for keeping the loop state for the -%% module info process. --record(state, {topwin, % GS identifier for top window - editor, % GS identifier for editor - module, % Name of the viewed module - parent}). % Pid of the parent - -start(Module) -> - Self = self(), - spawn_link(fun() -> init(Module, Self) end). - -init(Module, Parent) -> - process_flag(trap_exit, true), - - GS = gs:start([{kernel,true}]), - Font = pman_win:font(GS), - - WinTitle = lists:flatten(io_lib:format("Pman - Module Info: ~p", - [Module])), - WinOptions = [{title,WinTitle}, {width,550}, {height, 400}, - {configure,true}, {keypress,true}, {destroy,true}], - TopWindow = gse:window(GS, WinOptions), - - %% File menu - MenuBar = gse:menubar(TopWindow, []), - MBFile = gse:menubutton(MenuBar, [{label,{text," File "}}, - {font,Font}, {underline, 1}]), - MenuFile = gse:menu(MBFile, []), - - gse:named_menuitem('Save buffer', MenuFile, - [{label,{text,"Save buffer..."}}, - {font,Font}, {underline,0}]), - gse:named_menuitem('Close', MenuFile, - [{label,{text,"Close"}}, - {font,Font}, {underline,0}]), - - %% Output part of window - Editor = gse:editor(TopWindow, - [{font,Font}, - {x,3}, {y,40}, {width,546}, {height,348}]), - gse:config(Editor, [{keypress,true}, - {insert,{'end',pman_win:module_data(Module)}}]), - gse:config(Editor, [{enable,false}, - {vscroll,right}, {hscroll,bottom}, - {wrap,none}]), - gse:map(TopWindow), - - State = #state{topwin=TopWindow, editor=Editor, module=Module, - parent=Parent}, - loop(State). - -loop(State) -> - - receive - %% Die if the parent dies - {'EXIT', Pid, _Reason} when Pid==State#state.parent -> - gse:destroy(State#state.topwin); - - %% Ignore other exit signals (from file dialog window) - {'EXIT', _Pid, _Reason} -> - loop(State); - - %% Window closed - {gs, _TopWindow, destroy, [], []} -> - ok; - - %% Window resized or moved - {gs, _TopWindow, configure ,_Data, [W,H,_X,_Y|_]} -> - gs:config(State#state.editor, [{width,W-3}, {height,H-40}]), - loop(State); - - %% Close - destroy window and exit process - {gs, 'Close', click, _Data, _Args} -> - gse:destroy(State#state.topwin), - ok; - - %% Save Buffer - make filename and save buffer to file - {gs, 'Save buffer', click, _Data, _Args} -> - save_buffer(State), - loop(State); - - %% Keyboard accelerator commands - {gs, _, keypress, [], [c,_,0,1]} -> % 'Close' - gse:destroy(State#state.topwin), - ok; - {gs, _, keypress, [], [s,_,0,1]} -> % 'Save buffer' - save_buffer(State), - loop(State); - {gs, _, keypress, _Data, _Args} -> - loop(State) - end. - -save_buffer(State) -> - DefaultFile = atom_to_list(State#state.module) ++ ".module_info", - Result = tool_utils:file_dialog([{type,save}, {file,DefaultFile}]), - case Result of - %% User selected a file, now save the result - {ok, File, _Dir} -> - gs:config(State#state.editor, {save,File}), - Msg = "Module information saved in file\n" ++ File, - tool_utils:notify(State#state.topwin, Msg); - - %% File dialog was cancelled in some way. - {error, _Reason} -> - ignore - end. diff --git a/lib/pman/src/pman_options.erl b/lib/pman/src/pman_options.erl deleted file mode 100644 index 0765458fdc..0000000000 --- a/lib/pman/src/pman_options.erl +++ /dev/null @@ -1,395 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-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% -%% --module(pman_options). - -%% Window with trace options settings (File->Options...) - --export([dialog/3, - read_from_file/1, save_to_file/2]). - --include("pman_options.hrl"). - --define(WIN_WIDTH, 350). --define(WIN_HEIGHT, 350). - --define(TOP_WINDOW, xx_pman_option_window_xx). --define(TOP_FRAME, xx_pman_top_frame_xx). - --record(state, {resize_frame, % GS identifier for the main frame - parent}). % Pid of parent - -%%--dialog/3------------------------------------------------------------ -%% Create a window, or return a value indicating that is is already -%% created. - -dialog(ParentWin, Title, Options) -> - Self = self(), - Pid = spawn(fun() -> dialog(Self, ParentWin, Title, Options) end), - receive - {Pid, Value} -> - Value % Options2 | {error,destroyed} | {error,cancelled} - end. - -dialog(Parent, ParentWin, Title, Options) -> - - %% Check if the dialog has already been created, in that - %% case, we can reuse it. Otherwise a new dialog is created. - case gse:name_occupied(?TOP_WINDOW) of - false -> make_window(ParentWin, Title); - true -> ok - end, - - %% Window has now been created or may be re-used - update_window_from_options(Options), - - gse:resize(?TOP_FRAME, ?WIN_WIDTH, ?WIN_HEIGHT), - gse:map(?TOP_WINDOW), - - loop(#state{resize_frame=?TOP_FRAME, parent=Parent}). - -loop(State) -> - receive - {gs, _Id, destroy, _Data, _Arg} -> - State#state.parent ! {self(), {error,destroyed}}; - - {gs, ?TOP_WINDOW, configure, _Data, [W, H |_]} -> - gse:config(State#state.resize_frame, - [{width,W},{height,H}]), % repack - loop(State); - - {gs, ok_button, click, _Data, _Arg} -> - Options = get_options_from_window(), - gse:unmap(?TOP_WINDOW), - State#state.parent ! {self(), Options}; - - {gs, cancel_button, click, _Data, _Arg} -> - gse:unmap(?TOP_WINDOW), - State#state.parent ! {self(), {error,cancelled}}; - - {gs, trace_spawn, click, _Data, [_Text,_,Value]} -> - group_radio(Value, trace_spawn_all, [trace_spawn_all, - trace_spawn_first]), - loop(State); - - {gs, trace_link, click, _Data, [_Text,_,Value]} -> - group_radio(Value, trace_link_all, [trace_link_all, - trace_link_first]), - loop(State); - - {gs, trace_in_window, click, _Data, _Arg} -> - lists:foreach(fun(X) -> gse:disable(X) end, - [trace_file, trace_file_browse]), - loop(State); - - {gs, trace_to_file, click, _Data, [_Text,_,_Value]} -> - lists:foreach(fun(X) -> gse:enable(X) end, - [trace_file, trace_file_browse]), - loop(State); - - {gs, trace_file_browse, click, _Data, _Arg} -> - Result = tool_utils:file_dialog([{type,save}, - {file, "Untitled.log"}]), - case Result of - {error, _Reason} -> - loop(State); - {ok, Name,_State} -> - gse:config(trace_file, [{text, Name}]), - loop(State) - end - end. - --define(LBLOPTS, [{justify,left}, {align,w}]). --define(BTNOPTS, [{justify,left}, {align,w}]). - -make_window(ParentWin, Title) -> - - Font = pman_win:font(), - - gse:named_window(?TOP_WINDOW, ParentWin, [{title,Title}, - {configure,true}, - {width, ?WIN_WIDTH}, - {height, ?WIN_HEIGHT}]), - - gse:named_frame(?TOP_FRAME, ?TOP_WINDOW, - [{bw,3}, - {packer_x,[{stretch,1,175}, {stretch,1,175}]}, - {packer_y,[{stretch,3},{stretch,2},{stretch,1}]}]), - - F11 = gse:frame(?TOP_FRAME, [{bw,3}, - {pack_xy,{1,1}}, - {packer_x,[{stretch,1}, - {stretch,20}, - {stretch,2}]}, - {packer_y,[{stretch,2}, - {stretch,1}, - {stretch,1}, - {stretch,1}, - {stretch,1}, - {stretch,1}, - {stretch,1}, - {stretch,1}]}]), - - gse:label(F11,[{pack_xy,{2,1}}, - {label,{text,"Trace output options:"}}, - {font,Font} | ?LBLOPTS]), - - gse:named_checkbutton(trace_send, F11, - [{pack_xy,{2,2}}, - {label,{text,"Trace send"}}, - {font,Font} | ?BTNOPTS]), - gse:named_checkbutton(trace_receive, F11, - [{pack_xy,{2,3}}, - {label,{text, "Trace receive"}}, - {font,Font} | ?BTNOPTS]), - gse:named_checkbutton(trace_functions,F11, - [{pack_xy,{2,4}}, - {label,{text, "Trace functions"}}, - {font,Font} | ?BTNOPTS]), - gse:named_checkbutton(trace_events,F11, - [{pack_xy,{2,5}}, - {label,{text, "Trace events"}}, - {font,Font} | ?BTNOPTS]), - - F21 = gse:frame(?TOP_FRAME, [{bw,3}, - {pack_xy,{2,1}}, - {packer_x,[{stretch,1}, - {stretch,2}, - {stretch,2}, - {stretch,20}, - {stretch,1}]}, - {packer_y,[{stretch,2}, - {stretch,1}, - {stretch,1}, - {stretch,1}, - {stretch,1}, - {stretch,1}, - {stretch,1}, - {stretch,1}, - {stretch,1}]}]), - - gse:label(F21, [{pack_xy,{{2,4},1}}, - {label,{text,"Inheritance options:"}}, - {font,Font} | ?LBLOPTS]), - - gse:named_checkbutton(trace_spawn, F21, - [{pack_xy,{{2,4},2}}, - {data,trace_send}, - {label,{text,"Inherit on spawn"}}, - {font,Font} | ?BTNOPTS]), - gse:named_radiobutton(trace_spawn_all, F21, - [{pack_xy,{{3,4},3}}, - {group,spawn}, - {data,trace_receive}, - {label,{text, "All spawns"}}, - {font,Font} | ?BTNOPTS]), - gse:named_radiobutton(trace_spawn_first, F21, - [{pack_xy,{{3,4},4}}, - {group,spawn}, - {data,trace_receive}, - {label,{text,"First spawn only"}}, - {font,Font} | ?BTNOPTS]), - gse:named_checkbutton(trace_link, F21, - [{pack_xy,{{2,4},6}}, - {data,trace_send}, - {label,{text,"Inherit on link"}}, - {font,Font} | ?BTNOPTS]), - gse:named_radiobutton(trace_link_all, F21, - [{pack_xy,{{3,4},7}}, - {group,link}, - {data,trace_receive}, - {label,{text,"All links"}}, - {font,Font} | ?BTNOPTS]), - - gse:named_radiobutton(trace_link_first, F21, - [{pack_xy,{{3,4},8}}, - {group,link}, - {data,trace_receive}, - {label,{text,"First link only"}}, - {font,Font} | ?BTNOPTS]), - - F12 = gse:frame(?TOP_FRAME, [{bw,3}, - {pack_xy,{{1,2},2}}, - {packer_x,[{stretch,1}, - {stretch,5}, % Label - {stretch,1}, - {stretch,10}, % Field - {stretch,1}, - {stretch,5}, % Button - {stretch,1}]}, - {packer_y,[{stretch,2}, - {stretch,1}, - {stretch,1}, - {stretch,1}]}]), - - gse:label(F12, [{pack_xy,{{2,6},1}}, - {label,{text,"Trace output options:"}}, - {font,Font} | ?LBLOPTS]), - gse:named_radiobutton(trace_in_window, F12, - [{pack_xy,{{2,6},2}}, - {group, trace_dest}, - {label,{text,"In window"}}, - {font,Font} | ?BTNOPTS]), - gse:named_radiobutton(trace_to_file, F12, - [{pack_xy,{2,3}}, - {group, trace_dest}, - {label,{text,"To file"}}, - {font,Font} | ?BTNOPTS]), - gse:named_entry(trace_file, F12, [{pack_xy,{4,3}}, {font,Font}]), - gse:named_button(trace_file_browse, F12, - [{pack_xy,{6,3}}, - {label,{text," Browse..."}}, - {font,Font} | ?BTNOPTS]), - - F13 = gse:frame(?TOP_FRAME, [{bw,3}, - {pack_xy,{{1,2},3}}, - {packer_x,[{stretch, 1}, - {fixed, 60}, - {stretch, 1}, - {fixed, 60}, - {stretch, 1}]}, - {packer_y,[{stretch,1}, - {fixed, 30}, - {stretch,1}]}]), - - gse:named_button(ok_button, F13, [{pack_xy,{2,2}}, - {label,{text,"OK"}}, - {font,Font}]), - gse:named_button(cancel_button, F13, [{pack_xy,{4,2}}, - {label,{text,"Cancel"}}, - {font,Font}]). - -update_window_from_options(Options) -> - - %% Trace output - gse:config(trace_send, [{select,Options#trace_options.send}]), - gse:config(trace_receive, - [{select,Options#trace_options.treceive}]), - gse:config(trace_functions, - [{select,Options#trace_options.functions}]), - gse:config(trace_events, [{select,Options#trace_options.events}]), - - %% Trace inheritance - case (Options#trace_options.inherit_on_all_spawn or - Options#trace_options.inherit_on_1st_spawn) of - true -> - gse:select(trace_spawn), - gse:config(trace_spawn_all, - [{select,Options#trace_options.inherit_on_all_spawn}]), - gse:config(trace_spawn_first, - [{select,Options#trace_options.inherit_on_1st_spawn}]); - false -> - lists:foreach(fun(X) -> gse:disable(X) end, - [trace_spawn_all,trace_spawn_first]) - end, - - case (Options#trace_options.inherit_on_all_link or - Options#trace_options.inherit_on_1st_link) of - true -> gse:select(trace_link), - gse:config(trace_link_all, - [{select,Options#trace_options.inherit_on_all_link}]), - gse:config(trace_link_first, - [{select, Options#trace_options.inherit_on_1st_link}]); - false -> - lists:foreach(fun(X) -> gse:disable(X) end, - [trace_link_all,trace_link_first]) - end, - - %% Trace ouput destinations - gse:config(trace_in_window, - [{select,(not Options#trace_options.to_file)}]), - - gse:config(trace_to_file, [{select,Options#trace_options.to_file}]), - gse:config(trace_file, [{text,Options#trace_options.file}]), - case Options#trace_options.to_file of - true -> - ok; - false -> - lists:foreach(fun(X) -> gse:disable(X) end, - [trace_file, trace_file_browse]) - end. - -get_options_from_window() -> - #trace_options{send = gse:read(trace_send,select), - treceive = gse:read(trace_receive,select), - functions = gse:read(trace_functions,select), - events = gse:read(trace_events,select), - inherit_on_1st_spawn = gse:read(trace_spawn_first,select), - inherit_on_all_spawn = gse:read(trace_spawn_all,select), - inherit_on_1st_link = gse:read(trace_link_first,select), - inherit_on_all_link = gse:read(trace_link_all,select), - to_file = gse:read(trace_to_file,select), - file = gse:read(trace_file,text)}. - -group_radio(Value, Default, GroupList) -> - case Value of - true -> - gse:select(Default), - lists:foreach(fun(X) -> gse:enable(X) end, GroupList); - false -> - lists:foreach(fun(X) -> gse:deselect(X) end, GroupList), - lists:foreach(fun(X) -> gse:disable(X) end, GroupList) - end. - -%%--read_from_file/(File)----------------------------------------------- -%% Returns the options saved in File. -%% If no options can be found, then the default options are -%% returned. - -read_from_file(File) -> - case file:consult(File) of - {ok, [Term]} -> - if - is_record(Term, trace_options) -> - {ok, Term}; - true -> - {error, "unexpected contents", #trace_options{}} - end; - {ok, _Terms} -> - {error, "unexpected contents", #trace_options{}}; - {error, Tuple} when is_tuple(Tuple) -> % {Line,Mod,Term} - {error, "erroneous contents", #trace_options{}}; - {error, _Posix} -> - %% The most probable reason is that the file does not - %% exist, this is not an error so we simply return - %% the default trace options instead - {ok, #trace_options{}} - end. - -%%--save_to_file(Options, File)----------------------------------------- - -save_to_file(Options, File) -> - case file:open(File, [write]) of - {ok, Fd} -> - {{Year,Month,Day},{H,M,S}} = calendar:local_time(), - io:format(Fd, "%%%~n", []), - io:format(Fd, "%%% File: ~s~n", [File]), - io:format(Fd, "%%% Date: ~w-~2..0w-~2..0w, ~2..0w:~2..0w:~2..0w~n", - [Year,Month,Day,H,M,S]), - io:format(Fd, "%%%~n", []), - io:format(Fd, "%%% This file was created by Pman. ~n", []), - io:format(Fd, "%%%~n", []), - io:format(Fd, "%%% DO NOT EDIT! ~n", []), - io:format(Fd, "%%%~n", []), - io:format(Fd, "%%%~n", []), - io:format(Fd, "~p.~n", [Options]), - file:close(Fd), - ok; - {error, Posix} -> - {error, file:format_error(Posix)} - end. diff --git a/lib/pman/src/pman_options.hrl b/lib/pman/src/pman_options.hrl deleted file mode 100644 index 047b9866c3..0000000000 --- a/lib/pman/src/pman_options.hrl +++ /dev/null @@ -1,34 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-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% -%% - -%% -%% An options-record contains the return data from the option dialog. -%% - --record(trace_options, {send=true, - treceive=true, - functions=true, - events=true, - to_file=false, - file="", - inherit_on_1st_spawn=false, - inherit_on_all_spawn=true, - inherit_on_1st_link=false, - inherit_on_all_link=true}). - diff --git a/lib/pman/src/pman_process.erl b/lib/pman/src/pman_process.erl deleted file mode 100644 index 276407a0f1..0000000000 --- a/lib/pman/src/pman_process.erl +++ /dev/null @@ -1,317 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-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% -%% -%%---------------------------------------------------------------------- -%% Purpose : A front-end to the erlang:process_info() functions, that -%% can handle processes on different nodes in a transparent -%% way. -%% Also some convenience functions for process info, as well -%% as some application specific functions for process -%% classification. -%%---------------------------------------------------------------------- - --module(pman_process). - --export([pinfo/1, pinfo/2, - r_processes/1, - function_info/1, - get_name/1, msg/1, reds/1, psize/1, - is_running/1, - is_pid_or_shell/1, - get_pid/1, - is_system_process/1, - is_hidden_by_module/2 - ]). - -%% List of registered name that will make a prodcess a "SYSTEM"-process --define(SYSTEM_REG_NAMES, - [ - %% kernel - application_controller, - erl_reply, - auth, - boot_server, - code_server, - disk_log_server, - disk_log_sup, - erl_prim_loader, - error_logger, - file_server_2, - fixtable_server, - global_group, - global_name_server, - heart, - inet_gethost_native, - inet_gethost_native_sup, - init, - kernel_config, - kernel_safe_sup, - kernel_sup, - net_kernel, - net_sup, - rex, - user, - os_server, - ddll_server, - erl_epmd, - inet_db, - pg2, - - %% stdlib - timer_server, - rsh_starter, - take_over_monitor, - pool_master, - dets, - - %% sasl - sasl_safe_sup, sasl_sup, alarm_handler, overload, - release_handler, - - %% gs - gs_frontend - ]). - -%% List of module:function/arity calls that will make the caller a -%% "SYSTEM"-process. -%% --define(SYSTEM_INIT_CALLS, - [{application_master,init,4}, - {application_master,start_it,4}, - {inet_tcp_dist,accept_loop,2}, - {net_kernel,ticker,2}, - {supervisor_bridge,user_sup,1}, - {user_drv,server,2}, - {group,server,3}, - {kernel_config,init,1}, - {inet_tcp_dist,do_accept,6}, - {inet_tcp_dist,do_setup,6}, - {pman_main,init,2}, - {pman_buf_printer,init,2}, - {pman_buf_converter,init,2}, - {pman_buf_buffer,init,1}, - {gstk,init,1}, - {gstk_port_handler,init,2}, - {gstk,worker_init,1} - ]). - -%% List of module:function/arity calls that will make the executing -%% process a "SYSTEM"-process. --define(SYSTEM_RUNNING_CALLS, - [{file_io_server,server_loop,1}, - {global,loop_the_locker,1}, - {global,collect_deletions,2}, - {global,loop_the_registrar,0}, - {gs_frontend,request,2}, - {shell,get_command1,5}, - {shell,eval_loop,3}, - {io,wait_io_mon_reply,2}, - {pman_module_info,loop,1}, - {pman_options,dialog,3}, - {pman_options,loop,1}, - {pman_relay_server,loop,1}, - {pman_shell,monitor_loop,1}, - {pman_shell,safe_loop,2} - ]). - -%% pinfo(Pid) -> [{Item, Info}] | undefined -%% pinfo(Pid, Item) -> Info | undefined -%% A version of process_info/1 that handles pid on remote nodes as well. -pinfo({_, Pid}) -> % Handle internal process format - pinfo(Pid); -pinfo(Pid) when node(Pid)==node() -> - process_info(Pid); -pinfo(Pid) -> - case rpc:call(node(Pid), erlang, process_info, [Pid]) of - {badrpc, _} -> undefined; - Res -> Res - end. - -pinfo({_, Pid}, Item) -> % Handle internal process format - pinfo(Pid, Item); -pinfo(Pid, Item) when node(Pid)==node() -> - case process_info(Pid, Item) of - {Item, Info} -> Info; - "" -> ""; % Item == registered_name - undefined -> undefined - end; -pinfo(Pid, Item) -> - case rpc:call(node(Pid), erlang, process_info, [Pid, Item]) of - {badrpc, _} -> undefined; - {Item, Info} -> Info; - "" -> ""; % Item == registered_name - undefined -> undefined - end. - -%% function_info(Pid) -> {M, F, A} -%% Returns the initial function for the specified process. -function_info(Pid) -> - case pinfo(Pid, current_function) of - {Module, Function, Arity} -> - {Module, Function, Arity}; - undefined -> - {unknown, unknown, 0} - end. - -%% r_processes(Node) -> Pids -%% Return a list of all processes at Node. -%% -%% If there is a problem with getting information from a remote -%% node, an empty list is returned. -r_processes(Node) -> - ordsets:from_list(r_processes1(Node)). - -r_processes1(Node) -> - if - Node==node() -> - processes(); - true -> - case rpc:block_call(Node, erlang, processes, []) of - {badrpc, _} -> - []; - Pids -> Pids - end - end. - -%% is_running(Object) -> {true, {shell,Pid}} | {true, Pid} | false -%% Object = {shell, Pid} | {link, Pid, ?} | Pid -is_running({shell,Pid}) -> - case is_running(Pid) of - {true,Pid} -> - {true,{shell,Pid}}; - false -> - false - end; -is_running({link,Pid,_}) -> - is_running(Pid); -is_running(Pid) -> - case is_pid_or_shell(Pid) of - true -> - case pinfo(Pid) of - undefined -> false; - _PInfo -> {true, Pid} - end; - false -> - false - end. - -%% is_pid_or_shell(Object) -> bool() -%% Checks if the argument is an pid or a tuple {shell, Pid}. -is_pid_or_shell({shell,Pid}) when is_pid(Pid) -> - true; -is_pid_or_shell(Pid) when is_pid(Pid) -> - true; -is_pid_or_shell(_) -> - false. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% get_pid/1 - returns the Pid of the object provided that -%% it is a proper process specifier. -%% -%% Arguments: -%% Object A process specifier -%% -%% Returns: -%% The Pid. - -get_pid({shell,Pid}) -> - Pid; -get_pid(Pid) when is_pid(Pid) -> - Pid. - -%% is_system_process(Pid) -> bool() -%% Returns true if Pid is a "system process". -%% This is a prototype version, use file configuration later. -is_system_process(Pid) -> - catch is_system_process2(Pid). - -is_system_process2(Pid) -> - - %% Test if the registered name is a system registered name - case pinfo(Pid, registered_name) of - undefined -> ignore; - "" -> ignore; - Name -> - case lists:member(Name, ?SYSTEM_REG_NAMES) of - true -> throw(true); - false -> ignore - end - end, - - %% Test if the start specification is a "system start function" - MFAi = case pinfo(Pid, initial_call) of - {proc_lib, init_p, 5} -> - proc_lib:translate_initial_call(Pid); % {M,F,A} | Fun - Res -> Res % {M,F,A} | undefined - end, - case lists:member(MFAi, ?SYSTEM_INIT_CALLS) of - true -> throw(true); - false -> ignore - end, - - %% Test if the running specification is a "system running function" - case pinfo(Pid, current_function) of - undefined -> false; - MFAc -> - lists:member(MFAc, ?SYSTEM_RUNNING_CALLS) - end. - -%% is_hidden_by_module(Pid, Modules) -> bool() -%% Checks if Pid is to be hidden because it executes code from one -%% of Modules -is_hidden_by_module(Pid, Modules) -> - case pinfo(Pid, current_function) of - {Module, _Function, _Arity} -> - lists:member(Module, Modules); - undefined -> false - end. - -%% get_name(Pid) -> Name | " " -%% Returns the registered name of a process, if any, or " " otherwise. -get_name(Pid) -> - case pinfo(Pid, registered_name) of - undefined -> " "; - "" -> " "; - Name -> Name - end. - -%% msg(Pid) -> int() -msg(Pid) -> - case pinfo(Pid, messages) of - undefined -> 0; - Msgs -> length(Msgs) - end. - -%% reds(Pid) -> int() -reds(Pid) -> - case pinfo(Pid, reductions) of - undefined -> 0; - Reds -> Reds - end. - -%% psize(Pid) -> int() -%% Returns the total process size (stack + heap). -psize(Pid) -> - Stack = pinfo(Pid, stack_size), - Heap = pinfo(Pid, heap_size), - case {Heap, Stack} of - {undefined, undefined} -> 0; - {undefined, Sz} -> Sz; - {Sz, undefined} -> Sz; - {Sz0, Sz1} -> Sz0 + Sz1 - end. diff --git a/lib/pman/src/pman_relay.erl b/lib/pman/src/pman_relay.erl deleted file mode 100644 index 289765492f..0000000000 --- a/lib/pman/src/pman_relay.erl +++ /dev/null @@ -1,127 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-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% -%% -%%---------------------------------------------------------------------- -%% Purpose : Interface function to relay calls (esp. trace calls) -%% to processes on other nodes. Some of the calls -%% are conditionally relayed. -%%---------------------------------------------------------------------- - --module(pman_relay). - -%%-compile(export_all). --export([start/1, - ok_to_trace/1, - trac/3]). - - --include("assert.hrl"). - -%% -------------------------------------------------------------- -%% DISTRIBUTION -%% -------------------------------------------------------------- -%% (???) Process dictionary alert!!! -%% -%% Since we are not allowed to do erlang:trace/3 on remote -%% processe we create a help process at the remote node to -%% do the job for us -%% --------------------------------------------------------------- - -start(P) when is_pid(P), node(P)/=node() -> - - %% Remote supervision, relaying necessary - - put(relay, spawn_link(node(P), pman_relay_server, init, [self()])); - - -start(_) -> - - %% Local supervision, no relaying - - ignore. - - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% ok_to_trace/1 - Tests wheter we can actually start tracing -%% a process. -%% -%% Arguments: -%% Pid Pid of the process to trace (on local or remote node) -%% -%% Returns -%% true If it is OK to trace the process -%% false If the process is already traced, or some other -%% condition prevents it from being traced. - -ok_to_trace(Pid) when node(Pid) == node()-> - - %% Local trace, no relaying - - case catch erlang:trace(Pid, false, [send]) of - 1 -> - true; - _Otherwise -> - false - end; -ok_to_trace(Pid) -> - - %% Remote trace, relaying necessary - - PidRelay = get(relay), - PidRelay ! {ok_to_trace, self(), Pid}, - receive - {ok_to_trace, PidRelay} -> - true; - {not_ok_to_trace, PidRelay} -> - false; - _Otherwise -> - ?ALWAYS_ASSERT("Unexpected message from relay process") - after - 5000 -> - false - end. - - - - - - -%% --------------------------------------------------------------- -%% Possibly send a request to do tracing to a remote node. -%% --------------------------------------------------------------- - -trac(Pid, How, Flag) when node(Pid) == node() -> - - %% Local trace, no relaying necessary - - - case catch erlang:trace(Pid, How, Flag) of - 1 -> ok; - _ -> pman_win:format("** Illegal trace request ** \n", []) - end; - -trac(Pid, How, Flag) -> - - - - %% Remote trace, relaying necessary - - get(relay) ! {self(), erlang, trace, [Pid, How, Flag]}. - diff --git a/lib/pman/src/pman_relay_server.erl b/lib/pman/src/pman_relay_server.erl deleted file mode 100644 index 2fcbb663bc..0000000000 --- a/lib/pman/src/pman_relay_server.erl +++ /dev/null @@ -1,57 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-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% -%% -%%%---------------------------------------------------------------------- -%%% Purpose : Relay server code. -%%%---------------------------------------------------------------------- - --module(pman_relay_server). - -%%-compile(export_all). --export([init/1]). - - - -init(P) -> - process_flag(trap_exit, true), - - loop(P). - -loop(P) -> - receive - {ok_to_trace, PidSender, PidToTrace} -> - case catch erlang:trace(PidToTrace, false, [send]) of - 1 -> - PidSender ! {ok_to_trace, self()}, - loop(P); - _Otherwise -> - PidSender ! {not_ok_to_trace, self()} - end; - - {P, M,F,A} -> - case catch apply(M, F, A) of - 1 -> ok; - _Other -> P ! {print, "** Illegal trace request **\n", []} - end, - loop(P); - {'EXIT', P, _Reason} -> - exit(normal); - Other -> %% Here is the normal case for trace i/o - P ! Other, - loop(P) - end. diff --git a/lib/pman/src/pman_shell.erl b/lib/pman/src/pman_shell.erl deleted file mode 100644 index 2d2b8ce000..0000000000 --- a/lib/pman/src/pman_shell.erl +++ /dev/null @@ -1,827 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1996-2012. 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% -%% -%% -%% --------------------------------------------------------------- -%% Purpose: Create a trace window with process -%% information or a help window with information -%% about pman. -%% -%% --------------------------------------------------------------- - --module(pman_shell). --compile([{nowarn_deprecated_function,{gs,config,2}}, - {nowarn_deprecated_function,{gs,destroy,1}}, - {nowarn_deprecated_function,{gs,start,0}}, - {nowarn_deprecated_function,{gs,start,1}}]). - -%% --------------------------------------------------------------- -%% The user interface exports -%% --------------------------------------------------------------- - --export([start_list/3, - start/2, - start/1, - find_shell/0]). - -%% --------------------------------------------------------------- -%% Includes -%% --------------------------------------------------------------- --include("assert.hrl"). --include("pman_options.hrl"). --include("pman_buf.hrl"). - - -%% --------------------------------------------------------------- -%% Internal record declarations -%% --------------------------------------------------------------- --record(pman_shell,{win, - editor, - pid, - buffer, - father, - shell_flag, % boolean, true for shell - trace_options, % Keeps trace options - db}). % DB for trace windows - - -%% -%% Constants -%% - --define (PMAN_DB, pman_db). % The pman db for trace windows - - - -%% --------------------------------------------------------------- -%% start/1, start/2 -%% -%% Starts a new trace shell process. -%% -%% start(Pid, DefaultOptions) -%% Pid The Pid of the process to trace -%% DefaultOptions The default trace options passed along from -%% the calling process. -%% -%% -%% start(Pid) -%% Pid The Pid of the process to trace -%% -%% start(Pid) starts without using any default options except for those -%% hardwired into the application. (See pman_options.hrl). -%% -%% -%% Return: Both functions return a process id -%% --------------------------------------------------------------- - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% start_list/3 - Starts a trace window for each of the processes -%% in the list - -start_list(LIPid, Father, Options) -> - StartFun = fun(Pid) -> - start({Pid,Father}, Options) - end, - lists:foreach(StartFun, LIPid). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% start/1 - Starts a trace window for the specified Pid. -%% - -start(Pid) -> - start(Pid, #trace_options{}). - -%% -%% start/2 -%% - -start(Pid,DefaultOptions) when is_pid(Pid) -> - start({Pid,self()}, DefaultOptions); - -start(Var,DefaultOptions) -> - Db = db_start(), - spawn_link(fun() -> internal(Var, DefaultOptions, Db) end). - -%% --------------------------------------------------------------- -%% Initialize the enviroment for tracing/viewing Object -%% -%% Object can either be {shell,Shell} or a Pid. -%% The main loop is then called, which handles trace and event -%% requests. The window dies whenever Supervisor dies, while -%% message windows die whenever their parent dies. -%% --------------------------------------------------------------- - -internal({Object,Supervisor}, DefaultOptions, Db) -> - - %% (???) This call will cause minor problems when the window has been - %% invoked with proc/1 from for instance the shell. The shell - %% does not handle the exit-signals, so it will exit - %% when the window is exited. - - - %% First check that no other process is tracing the process we want - %% to trace. There is no well defined way of doing this, so the - %% code below is used instead. (???) - - pman_relay:start(Object), %(???) Uses proc. dict. - - Pid = pman_process:get_pid(Object), - - case pman_relay:ok_to_trace(Pid) of - - %% Tracing cannot be performed on the specified process - - false -> - T = lists:flatten(io_lib:format("ERROR: Process ~p is already being~ntraced by some other process.~nOr there may be a problem communicating with it.",[Pid])), - tool_utils:notify(gs:start(),T), - exit(quit); - - %% Tracing can be performed, go ahead! - - true -> - - case db_insert_key (Db, Pid) of - true -> - - link(Supervisor), - process_flag(trap_exit, true), - - case catch pman_win:window(Object) of - {'EXIT', badrpc} -> - T = "ERROR: Could not access node", - pman_win:dialog_window(gs:start(),T); - {'EXIT', dead} -> - T = "ERROR: The process is dead", - pman_win:dialog_window(gs:start(),T); - {'EXIT',_W} -> - T = "ERROR: Untracable process \n(unexpected EXIT reason)", - pman_win:dialog_window(gs:start(),T); - {Win, Ed} -> - init_monitor_loop(Win, - Ed, - Object, - Supervisor, - DefaultOptions, - Db) - end; - - false -> - T = lists:flatten(io_lib:format("ERROR: Process ~p is already being~ntraced by some other process.",[Pid])), - tool_utils:notify(gs:start(),T), - exit(quit); - - Error -> - Error - end - - end. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% init_monitor_loop/5 - -init_monitor_loop(Win,Ed,Object,Supervisor, DefaultOptions, Db) -> - - process_flag(priority, max), - - %% Most default options come from the main window. Now we must set - %% the default file name to something that is shows what process - %% is being traced. - - %% Find out an appropriate file name to write the trace output - %% to if the output should go to a file. - - FileName = case pman_process:is_pid_or_shell(Object) of - true -> - default_file_name(pman_process:get_pid(Object)); - false -> - "NoName" - end, - - Buff = pman_buf:start(Ed, FileName), - - case pman_process:is_running(Object) of - - %% We are tracing a shell process. - {true,{shell,Pid}} -> - safe_link(Pid), - NewDefaultOptions = - DefaultOptions#trace_options{file=FileName}, - perform_option_changes(Pid, NewDefaultOptions, Buff), - monitor_loop(#pman_shell{win=Win, editor=Ed, pid=Pid, buffer=Buff, - father = Supervisor, - shell_flag = true, - trace_options = NewDefaultOptions, - db = Db}); - - %% We are tracing an ordinary process. - {true,Pid} -> - safe_link(Pid), - NewDefaultOptions = - DefaultOptions#trace_options{file=FileName}, - perform_option_changes(Pid, NewDefaultOptions, Buff), - monitor_loop(#pman_shell{win=Win, editor=Ed, pid=Pid, buffer=Buff, - father = Supervisor, - shell_flag = false, - trace_options = NewDefaultOptions, - db = Db}); - - %% The process being traced is dead. - false -> - monitor_loop(#pman_shell{win=Win, editor=Ed, pid=nopid, - buffer=Buff, - father = Supervisor, - shell_flag = false, - trace_options= DefaultOptions, - db = Db}) - end. - -%% ---------------------------------------------------------------- -%% What is the Pid of the shell on our node? -%% ---------------------------------------------------------------- - -find_shell() -> - case shell:whereis_evaluator() of - undefined -> % noshell - noshell; - Pid -> - Pid - end. - -%% --------------------------------------------------------------- -%% Functions called in case of an exit message -%% --------------------------------------------------------------- - -clean_up(Win, Buff,Pid) -> - - %% (???) Unlinks the traced process, but since we are using a safe link - %% it is probably unnecessary. - - safe_unlink(Pid), - - %% Kill helper processes - - exit(Buff#buffer.converter, topquit), - exit(Buff#buffer.buffer, topquit), - - gs:destroy(Win). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% exit_cmd/3 - Takes care of the necessary details when -%% a linked process terminates. - - -exit_cmd(Pid,_Reason, State) -> - case State#pman_shell.shell_flag of - - %% This clause handles the case when a shell process dies. - %% Since it is restarted and the intention is to continue tracing - %% the restarted shell process, we need to handle it separately by - %% finding the new shell process. - true -> - - NewShell = find_shell(), - safe_link(NewShell), - pman_relay:start(NewShell), - - %% Update the window title with the new PID - Title = pman_win:title({shell, NewShell}), - Win = State#pman_shell.win, - gse:config(Win,[{title,Title}]), - - pman_relay:trac(NewShell, true, flags()), - - B = State#pman_shell.buffer, - B#buffer.converter!{raw,[{shell_died, Pid, NewShell}]}, - - - - State#pman_shell{pid=NewShell}; - - %% This clause handles the case when a traced process that is - %% not a shell process dies. - false -> - - B = State#pman_shell.buffer, - B#buffer.converter!{raw,[{died, Pid}]}, - - lists:foreach(fun(X) -> gse:disable(X) end, - ['Options', - 'Kill', - 'LinksMenu']), - State#pman_shell{pid=undefined} - end. - -flags() -> - [send, 'receive', call, procs, - set_on_spawn, set_on_first_spawn, set_on_link, set_on_first_link]. - -options_to_flaglists(Options) -> - AssocList = - [{Options#trace_options.send, send}, - {Options#trace_options.treceive, 'receive'}, - {Options#trace_options.inherit_on_1st_spawn, set_on_first_spawn}, - {Options#trace_options.inherit_on_all_spawn, set_on_spawn}, - {Options#trace_options.inherit_on_1st_link, set_on_first_link}, - {Options#trace_options.inherit_on_all_link, set_on_link}, - {Options#trace_options.events, procs}, - {Options#trace_options.functions,call}], - - TrueFun = fun ({Option,Flag}) -> - case Option of - true -> Flag; - _Otherwise -> false - end - end, - TrueFlags = mapfilter(TrueFun, AssocList), - - FalseFun = fun ({Option,Flag}) -> - case Option of - false -> Flag; - _Otherwise -> false - end - end, - FalseFlags = mapfilter(FalseFun, AssocList), - {TrueFlags,FalseFlags}. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% mapfilter/2 - Combines the functionality of lists:map and -%% lists:filter. mapfilter applies the function argument to -%% each element in the list. All returned values that are -%% not false will occur in the resulting list. -%% -%% Arguments: -%% Fun A fun that takes one argument -%% List A list. Each element will become an argument to Fun. -%% -%% Returns: -%% A list of all results from the map operation that are not false. -%% - -mapfilter(Fun,[E|Es]) -> - case apply(Fun,[E]) of - false -> - mapfilter(Fun,Es); - Value -> [Value | mapfilter(Fun,Es)] - end; -mapfilter(_Fun, []) -> []. - - - -perform_option_changes(Pid,Options,Buffer) -> - - %% Notify the trace output functionality - %% if the destination is supposed to go to a file... - - case Options#trace_options.to_file of - true -> - FName = Options#trace_options.file, - Buffer#buffer.converter!{file,FName}; - false -> - done - end, - - %%...then set the trace flags of the traced process - - {OnFlags, OffFlags} = options_to_flaglists(Options), - case catch begin - - %% (???) Note that the following calls cannot actually fail - %% This may be a problem. And the catch appears unnecessary - %% However, it may become necessary to let the - %% pman_relay:trac/3 function retrun appropriate values. - pman_relay:trac(Pid,true, OnFlags), - pman_relay:trac(Pid,false, OffFlags) - end of - true -> - ok; - _ -> pman_win:format("** Illegal trace request ** \n", []) - end. - - - - - - -%% --------------------------------------------------------------- -%% Take care of the command executed by the user. - -execute_cmd(Cmd,Shell_data) -> - Window = Shell_data#pman_shell.win, - Editor = Shell_data#pman_shell.editor, - Shell = Shell_data#pman_shell.pid, - Buffer = Shell_data#pman_shell.buffer, - TraceOptions = Shell_data#pman_shell.trace_options, - - case Cmd of - 'Close' -> - db_delete_key (Shell_data#pman_shell.db, Shell_data#pman_shell.pid), - clean_up(Window, Buffer, Shell), - exit(quit); - 'Destroy' -> - db_delete_key (Shell_data#pman_shell.db, Shell_data#pman_shell.pid), - exit(Buffer#buffer.buffer,topquit), - safe_unlink(Shell), - exit(Buffer#buffer.converter,topquit), - exit(Buffer#buffer.buffer,topquit), - exit(quit); - - 'Clear' when is_pid(Shell) -> - New_buffer = pman_buf:clear(Buffer,pman_win:display(Shell), - TraceOptions#trace_options.file), - Shell_data#pman_shell{buffer = New_buffer}; - 'Save buffer' -> - DefaultFile = "Pman_buffer." ++ default_file_name(Shell), - Result = tool_utils:file_dialog([{type,save}, - {file,DefaultFile}]), - case Result of - {ok, UserFile, _State} -> - Buffer#buffer.buffer!{save_buffer,UserFile}; - {error,_Reason} -> - true - end, - Shell_data; - 'Help' -> - HelpFile = filename:join([code:lib_dir(pman), "doc", "html", "index.html"]), - tool_utils:open_help(gs:start([{kernel, true}]), HelpFile), - Shell_data; - 'Kill' when is_pid(Shell) -> - exit(Buffer#buffer.converter,killed), - exit(Buffer#buffer.buffer,killed), - lists:foreach(fun(X) -> gse:disable(X) end, - ['TraceMenu', - 'Clear']), - catch exit(Shell, kill), - Shell_data#pman_shell{pid = undefined}; - 'All Links' when is_pid(Shell) -> - LIPid = pman_process:pinfo(Shell, links), - ?ALWAYS_ASSERT("Just a brutal test"), - start_list(LIPid, - Shell_data#pman_shell.father, - Shell_data#pman_shell.trace_options), - Shell_data; - 'Module' when is_pid(Shell) -> - {ModuleName,_,_} = pman_process:function_info(Shell), - pman_module_info:start(ModuleName), - Shell_data; - 'Options' when is_pid(Shell) -> - case pman_options:dialog(Window, - "Trace Options for Process", - TraceOptions) of - {error, _Reason} -> - Shell_data; - Options -> - perform_option_changes(Shell, Options, Buffer), - Shell_data#pman_shell{trace_options=Options} - end; - - {trac,Choice,Bool} when is_pid(Shell) -> - pman_relay:trac(Shell, Bool, [Choice]), - Shell_data; - - - {configure,{X,Y}} -> - configure (Editor, X, Y), - Shell_data; - - Pid when is_pid(Pid) -> - pman_shell:start({Pid, Shell_data#pman_shell.father}, - Shell_data#pman_shell.trace_options), - Shell_data; - _Other -> - ?ALWAYS_ASSERT("Received unexpected event"), - Shell_data - end. - - -default_file_name(Shell) when is_pid(Shell) -> - [A,B,C] = string:tokens(pid_to_list(Shell),[$.,$<,$>]), - "pman_trace." ++ A ++ "_" ++ B ++ "_" ++ C; -default_file_name(_OTHER) -> - "shell". - - - - - -%% Key accellerators - -key(e) -> 'Clear'; -key(s) -> 'Save buffer'; -key(c) -> 'Close'; -key(a) -> 'All'; -key(r) -> 'Reset'; -key(m) -> 'Module'; -key(l) -> 'All Links'; -key(k) -> 'Kill'; -key(h) -> 'Help'; -key(z) -> 'Close'; -key(O) -> O. - - - -%% --------------------------------------------------------------- -%% The main loop takes care of data coming in from the traces, as -%% well as exit signals from proceses we are monitoring. Events -%% caused by the user or window manager are also handled here. -%% --------------------------------------------------------------- - - -monitor_loop(Shell_data) -> - receive - - %% WM destroy - {gs,_Window,destroy,[],[]} -> %%Avoid links menus - execute_cmd('Destroy', Shell_data); - - - %% Handle EXIT signal from parent process - {'EXIT', _Pid, topquit} -> - clean_up(Shell_data#pman_shell.win, - Shell_data#pman_shell.buffer, - Shell_data#pman_shell.pid), - exit(topquit); - - %% (???) Ignore "stray" EXIT signal from converter - {'EXIT', _Pid, win_killed} -> - monitor_loop(Shell_data); - - - %% Handle EXIT signal from safely linked Pid - %% This is received when a traced process dies. - {'SAFE_EXIT', Pid, Reason} -> - New_Shell_data = exit_cmd(Pid, Reason,Shell_data ), - monitor_loop(New_Shell_data); - - - %% Handle EXIT signal from processes where we expect - %% some EXIT signals, such as the file_dialog opened, and possibly - %% others. - - {'EXIT', _Pid, _Reason} -> - monitor_loop(Shell_data); - - %% Handle incoming trace messages - Message when is_tuple(Message) , element(1,Message) == trace-> - {L, Suspended} = collect_tracs([Message]), - Buffer = Shell_data#pman_shell.buffer, - Buffer#buffer.converter!{raw,L}, - lists:foreach(fun(P) -> erlang:resume_process(P) end, Suspended), - monitor_loop(Shell_data); - - - %% All other messages on the form {...,...,...} - Message when is_tuple(Message) -> - do_link_stuff(Shell_data), - - New_Shell_data = process_gs_event(Message,Shell_data), - monitor_loop(New_Shell_data); - - %% Catch all for unexpected messages - _Anything -> - ?ALWAYS_ASSERT("Received unexpected event"), - monitor_loop(Shell_data) - - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% process_event/1 - Error handling wrapper for gs_cmd - -process_gs_event(Message, Shell_data) -> - case catch gs_cmd(Message,Shell_data) of - - %% - %% Error exits from gs_cmd - - {'EXIT', badrpc} -> - Text = "\nERROR: Could not access node", - pman_win:msg_win(Text), - Shell_data; - {'EXIT', dead} -> - Text = "\nERROR: The process is dead", - pman_win:msg_win(Text), - Shell_data; - - %% A controlled application initiated termination - {'EXIT', quit} -> - db_delete_key (Shell_data#pman_shell.db, Shell_data#pman_shell.pid), - exit(quit); - - - {'EXIT',Reason} -> - db_delete_key (Shell_data#pman_shell.db, Shell_data#pman_shell.pid), - io:format("Debug info, Reason: ~p~n",[Reason]), - ?ALWAYS_ASSERT("Unexpected EXIT reason"), - exit({unexpected_EXIT_reason,Reason}); - - %% - %% "Proper" exits from gs_cmd - - New_Shell_data -> - New_Shell_data - end. - - - -gs_cmd(Cmd, Shell_data) -> - case Cmd of - - %%User Command - {gs, Command, click, _Data, _Args} -> - execute_cmd(Command,Shell_data); - - %%Key accellerator - {gs,_Window,keypress,_D,[Key,_,0,1]} -> - execute_cmd(key(Key),Shell_data); - - %%Window Resize - {gs,_Window,configure,_,[X,Y|_]} -> - execute_cmd({configure,{X,Y}},Shell_data); - - - {gs, _Object, _Event, _Data, _Args} -> - ?ALWAYS_ASSERT("Unhandled gs event"), - Shell_data - - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% (???) do_link_stuff/1 - I have no clue. -%% - -do_link_stuff(Shell_data) -> - - %% This appears to be code to execute for adding - %% dynamic links menus. - - case Shell_data#pman_shell.pid of - undefined -> - ok; - Pid -> - case pman_process:pinfo(Pid, links) of - Links when is_list(Links) -> - pman_win:links_menus(Links); - undefined -> - ok - end - end. - - -%% (???) Process dictionary used to safe Pid-Pid pairs. -%% -%% safe_link/1 - Spawns a process, that links to the Pid, and sends -%% a message to the caller when the linked process dies. -%% -%% Since we (think we) need to link to the traced process, we want -%% to do it in a way that has the smallest possible risk. The process -%% that links to the Pid is small and simple, which is safer than if -%% the calling process would link directly to the Pid. - -safe_link(Pid) when is_pid(Pid) -> - Self = self(), - PidSafe = spawn_link(fun() -> safe_init(Self, Pid) end), - put(Pid, PidSafe). - - -%% safe_unlink/1 - Removes a safe link -%% - -safe_unlink(Pid) when is_pid(Pid) -> - PidSafe = get(Pid), - PidSafe ! {unlink, self(), Pid}, - erase(Pid); - -safe_unlink(_Anything)-> - true. - -%% safe_init/2 - Initialize a simple receive loop that controls safe linking -%% to application processes. -%% -safe_init(Caller, Pid) -> - - process_flag(trap_exit, true), - link(Pid), - - safe_loop(Caller, Pid). - - -%% safe_loop/2 - Simply waits for an exit signal from the linked Pid, -%% all other messages are disregarded. -%% - - -safe_loop(Caller, Pid) -> - receive - %% Linked process dies - {'EXIT' , Pid, Reason} -> - Caller ! {'SAFE_EXIT', Pid, Reason}; - - %% Caller dies - {'EXIT', Caller, _Reason} -> - unlink(Pid); - - - %% Unlink request - {unlink, Caller, Pid} -> - unlink(Pid); - - %% Ignore everything else - _Anything -> - safe_loop(Caller, Pid) - end. - - - -configure (Editor, W, H) -> - gs:config (Editor, [{width, W - 3}, - {height, H - 40}]). - - - - -%%% The DB is used to avoid multiple trace windows -%%% of the same process. - -%%% db_start /0 -%%% - -db_start() -> - case ets:info(?PMAN_DB) of - undefined -> ets:new(?PMAN_DB, [public, named_table]); - _ -> ?PMAN_DB - end. - - - -%%% db_insert_key /2 -%%% - -db_insert_key (Db, Pid) -> - case ets:lookup (Db, Pid) of - [] -> - case catch ets:insert (Db, {Pid}) of - true -> - true; - - _Error -> - error_insert_db - end; - - _already_exists -> - false - end. - - - -%%% db_delete_key /2 -%%% - -db_delete_key (Db, Pid) -> - ets:delete (Db, Pid). - - -%% Function to collect all trace messages in the receive queue. -%% Returns: {Messages,SuspendedProcesses} - -collect_tracs(Ack) -> collect_tracs(Ack, ordsets:new()). - -collect_tracs(Ack, Procs) -> - receive - Trac when is_tuple(Trac), element(1, Trac) == trace -> - P = suspend(Trac, Procs), - collect_tracs([Trac | Ack], P) - after 0 -> - {lists:reverse(Ack), ordsets:to_list(Procs)} - end. - -suspend({trace,From,call,_Func}, Suspended) when node(From) == node() -> - case ordsets:is_element(From, Suspended) of - true -> Suspended; - false -> - case (catch erlang:suspend_process(From)) of - true -> - ordsets:add_element(From, Suspended); - _ -> - Suspended - end - end; -suspend(_Other, Suspended) -> Suspended. diff --git a/lib/pman/src/pman_tool.erl b/lib/pman/src/pman_tool.erl deleted file mode 100644 index 36382745af..0000000000 --- a/lib/pman/src/pman_tool.erl +++ /dev/null @@ -1,146 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2012. 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% -%% --module(pman_tool). --compile([{nowarn_deprecated_function,{gs,read,2}}]). - -%% Listbox selection window - --export([select/3]). - --record(state, {topwin, - frame, - listbox}). - -%% Constants --define(WIN_WIDTH, 350). --define(WIN_HEIGHT, 350). - -select(Win, Title, Choices) -> - Self = self(), - Pid = spawn_link(fun() -> init(Self, Win, Title, Choices) end), - receive - {Pid, Result} -> - Result - end. - -init(Pid, Win, Title, Choices) -> - - %% Create window - State = create_window(Win, Title, Choices), - - gse:map(State#state.topwin), - - %% enter event loop - loop(Pid, Choices, State). - -loop(Pid, Choices, State) -> - receive - {gs, _, destroy, _Data, _Args} -> - Pid ! {self(), cancelled}; - {gs, _, configure, _Data, [W, H|_]} -> - gse:resize(State#state.frame, W, H), - loop(Pid, Choices, State); - {gs, _, click, ok, _Args} -> - case gs:read(State#state.listbox, selection) of - [] -> - Pid ! {self(), cancelled}; - Indices -> - Selection = selection(Indices, Choices), - Pid ! {self(), Selection} - end; - {gs, _, click, cancel, _Args} -> - Pid ! {self(), cancelled}; - {gs, Obj, doubleclick, _Data, _Args} -> - self() ! {gs, Obj, click, ok, []}, - loop(Pid, Choices, State); - _GSEvent -> - loop(Pid, Choices, State) - end. - -selection(Indices, Choices) -> - selection(0, Indices, Choices). - -selection(I, [I|Is], [{Val,_Str}|Vals]) -> - [Val | selection(I+1, Is, Vals)]; -selection(I, [I|Is], [Val|Vals]) -> - [Val | selection(I+1, Is, Vals)]; -selection(_I, [], _Vals) -> - []; -selection(I, Is, [_Val|Vals]) -> - selection(I+1, Is, Vals). - -create_window(Win, Title, Choices) -> - Font = pman_win:font(Win), - - %% Top window and a frame that covers it entirely, to allow - %% usage of the packer for geometry management. - Topwin = gse:window(Win, [{width, ?WIN_WIDTH}, - {height,?WIN_HEIGHT}, - {configure, true}, - {title, Title}]), - Frame = gse:frame(Topwin, [{packer_x,[{stretch,1}, - {stretch,1}]}, - {packer_y,[{stretch,1}, - {stretch,5}, - {stretch,1}]}]), - - %% Caption above the list of items - CaptionTxt = "Select one or more of the following:", - gse:label(Frame, [{pack_x,{1,2}}, - {pack_y,{1,1}}, - {label,{text,CaptionTxt}}, {font,Font}]), - - %% List of selectable items - Listbox = gse:listbox(Frame, [{pack_x,{1,2}}, - {pack_y,{2,2}}, - {selectmode,multiple}, - {doubleclick, true}, - {font,Font}, - {items, str_choices(Choices)}]), - - %% OK and Cancel buttons in a separate frame. - F13 = gse:frame(Frame, [{bw,1}, - {pack_xy,{{1,2},3}}, - {packer_x,[{stretch,1}, - {fixed, 60}, - {stretch,1}, - {fixed, 60}, - {stretch,1}]}, - {packer_y,[{stretch,1}, - {fixed, 30}, - {stretch,1}]}]), - - gse:button(F13, [{pack_xy,{2,2}}, - {label,{text,"OK"}}, {font,Font}, - {data,ok}]), - gse:button(F13, [{pack_xy,{4,2}}, - {label,{text,"Cancel"}}, {font,Font}, - {data,cancel}]), - - gse:resize(Frame, ?WIN_WIDTH, ?WIN_HEIGHT), - #state{topwin=Topwin, frame=Frame, listbox=Listbox}. - -str_choices(Choices) -> - lists:map( - fun({Val, Str}) -> - lists:flatten(io_lib:format("~p: ~s", [Val, Str])); - (Term) -> - lists:flatten(io_lib:format("~p", [Term])) - end, - Choices). diff --git a/lib/pman/src/pman_win.erl b/lib/pman/src/pman_win.erl deleted file mode 100644 index aec7dc4412..0000000000 --- a/lib/pman/src/pman_win.erl +++ /dev/null @@ -1,677 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1996-2013. 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% -%% -%% ------------------------------------------------------------ -%% Purpose: window management and the gs interface -%% ------------------------------------------------------------ - --module(pman_win). --compile([{nowarn_deprecated_function,{gs,button,2}}, - {nowarn_deprecated_function,{gs,canvas,2}}, - {nowarn_deprecated_function,{gs,config,2}}, - {nowarn_deprecated_function,{gs,create,3}}, - {nowarn_deprecated_function,{gs,create,4}}, - {nowarn_deprecated_function,{gs,destroy,1}}, - {nowarn_deprecated_function,{gs,read,2}}, - {nowarn_deprecated_function,{gs,start,1}}, - {nowarn_deprecated_function,{gs,text,2}}, - {nowarn_deprecated_function,{gs,window,2}}]). - -%% --------------------------------------------------------------- -%% The user interface exports -%% --------------------------------------------------------------- - --export([pman_window/3, window/1, module_data/1, display/1, format/2, - dialog_window/2, configeditor/2, configwin/3, - update/1, update/3, - msg_win/1, title/1, - remove_menu/1, add_menu/3, - change_colour/3, links_menus/1, calc_columnwidths/1]). --export([font/0, font/1]). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Constants -%% --include("pman_win.hrl"). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% pman_window/3 - Create a GS window and components for the -%% Pman overview window, the main window. -%% -%% Arguments: -%% Size number of processes -%% HiddenModules list of modules -%% Nodes list of supervised nodes -%% -%% Return: -%% {Win, Grid, Frame, Procnum, W, H} where -%% Win The GS top window -%% Grid The GS grid -%% Procnum Number of displayed processes -%% - -pman_window(Size, _HiddenModules, Nodes) -> - GS = gs:start([{kernel,true}]), - Font = font(GS), - Win_Options = [{title, lists:concat(["Pman: Overview on ",node()])}, - {width, ?WIN_WIDTH}, {height, ?WIN_HEIGHT}, - {destroy, true}, - {keypress,true}], - Win = gs:create(window, GS, Win_Options), - - %% Menu bar - MenuBar = gs:create(menubar, Win, []), - MBFile = gs:create(menubutton, MenuBar, [{label,{text," File "}}, - {font,Font}, - {underline,1}]), - MBView = gs:create(menubutton, MenuBar, [{label,{text, " View "}}, - {font,Font}, - {underline,1}]), - MBTrace = gs:create(menubutton, MenuBar, [{label,{text, " Trace "}}, - {font,Font}, - {underline,1}]), - MBHelp = gs:create(menubutton, MenuBar, [{label, {text, " Help "}}, - {font,Font}, - {side,right}, - {underline,1}]), - - %% Addition of a menu for distribution - add_node_menu(MenuBar, Nodes, Font), - - %% All menu buttons - MenuFile = gs:create(menu, MBFile, []), - MenuView = gs:create(menu, MBView, []), - MenuTrace = gs:create(menu, MBTrace, []), - MenuHelp = gs:create(menu, MBHelp, []), - - %% File menu - gse:named_menuitem('Default Options', MenuFile, - [{label,{text,"Options..."}}, {font,Font}, - {underline,0}]), - gse:named_menuitem('Save Options',MenuFile, - [{label,{text,"Save Options"}}, {font,Font}]), - gse:named_menuitem('Exit', MenuFile, - [{label,{text,"Exit"}}, {font,Font}, - {underline,0}]), - - %% View menu - gse:named_menuitem('Hide All',MenuView, - [{label, {text, "Hide All Processes"}}, - {font,Font}, - {underline,1}]), - - gse:named_menuitem('Hide Modules', MenuView, - [{label, {text, "Hide Modules..."}}, - {font,Font}, - {underline,8}]), - - gse:named_menuitem('Hide Selected Process', MenuView, - [{label, {text, "Hide Selected Process"}}, - {font,Font}, - {underline,2}]), - - gse:named_menuitem('Module',MenuView, - [{label, {text, "Module Info..."}}, {font,Font}, - {underline,7}]), - - gse:named_menuitem('Refresh', MenuView, - [{label, {text, "Refresh"}}, {font,Font}, - {underline,0}]), - - gse:named_menuitem('Show All',MenuView, - [{label, {text, "Show All Processes"}}, - {font,Font}]), - - gse:named_menuitem('Show Selected',MenuView, - [{label, {text, "Show Processes..."}}, - {font,Font}]), - - %% Trace menu - gs:create(menuitem, 'Kill', MenuTrace, [{label,{text, "Kill"}}, - {font,Font}, - {underline,0}]), - - gs:create(menuitem, 'Trace Process', MenuTrace, - [{label, {text, "Trace Selected Process"}}, {font,Font}, - {underline,0}]), - - gs:create(menuitem,'Trace Shell', MenuTrace, - [{label, {text,"Shell Process"}}, {font,Font}, - {underline,0}]), - - %% Help menu - gs:create(menuitem,'Help', MenuHelp, [{label, {text, "Help" }}, - {font,Font}, - {underline,0}]), - - %% Window contents - - %% Geometry managing frame - Frame = gse:frame(Win, [{y,?MENU_HEIGHT}, - {packer_x,[{stretch, 1}]}, - {packer_y,[{stretch,10}, - {fixed,?CHECKBAR_HEIGHT}]}]), - - - - %% Grid - Grid_Options = [ - {pack_x,1}, {pack_y,1}, - {fg,black}, - {vscroll,right},{hscroll,bottom}, - calc_columnwidths(739), - {rows, {1,Size}}], - Grid = gse:grid(Frame,Grid_Options), - - - %% Checkbutton bar at the bottom of the window - - CheckBar = gse:frame(Frame, [{pack_x,1}, - {pack_y,2}, - {packer_x,[{stretch, 2, 100,300}, - {stretch, 2, 100,300}, - {stretch,1}, - {stretch, 2,100,300}]}, - {packer_y,[{stretch,1}]}]), - gse:named_checkbutton('Hide System',CheckBar, - [{pack_xy,{1,1}}, - {justify, left}, - {align,w}, - {width, 200}, - {font, Font}, - {label, {text, "Hide System Processes" }}]), - - gse:named_checkbutton('Auto Hide New',CheckBar, - [{pack_xy,{2,1}}, - {width, 200}, - {justify, left}, - {align,w}, - {font, Font}, - {label, {text, "Auto-Hide New" }}]), - - gse:named_label('Number Hidden',CheckBar, - [{pack_xy,{4,1}}, - {justify, left}, - {align,w}, - {width, 200}, - {font, Font}, - {label, {text, ?CPIDHIDDENTEXT }}]), - - %% Finalize it! - gse:map(Win), - gse:config(Win,[raise]), - gse:config(Win,[{configure,true}]), - - - {Win, Grid, Frame, length(processes())+1, ?WIN_WIDTH, ?WIN_HEIGHT}. - - -%% Calculate columnwidths in respect to the size of the window. - -calc_columnwidths(Width) -> - if - Width =< 739 -> - {columnwidths,[75,215,146,90,105,105]}; - true -> - S = (Width - 75)/(215+146+90+105+105), - {columnwidths,[75,round(215*S),round(146*S),round(90*S), - round(105*S),round(105*S)]} - end. - -%% --------------------------------------------------------------- -%% Create a trace window -%% -%% Process, a process id or an atom -%% -%% Return: A window and a editor -%% --------------------------------------------------------------- - - -window(Process) -> - GS = gs:start([{kernel,true}]), - Font = font(GS), - Win_Options = [{title,title(Process)}, {width,550}, {keypress,true}, - {configure,true}, - {destroy,true},{height, 400}], - Win = gs:create(window,GS,Win_Options), - - MenuBar = gs:create(menubar, Win, []), - - %% File menu - MBFile = gs:create(menubutton,MenuBar,[{label,{text," File "}}, - {font,Font}, - {underline, 1}]), - MenuFile = gs:create(menu, MBFile, []), - make_menus(pman_process:is_running(Process), MenuBar, MenuFile, - Font), - - gse:named_menuitem('Save buffer',MenuFile, - [{label,{text, "Save buffer..."}}, - {font,Font}, - {underline,0}]), - gse:named_menuitem('Close',MenuFile, - [{label, {text, "Close"}}, - {font,Font}, - {underline,0}]), - - - Editor = gs:create(editor,Win,[{x,3}, {y,40}, - {width,546}, {height,348}, - {font,Font}]), - gs:config(Editor, [{keypress, true},{insert, {'end', display(Process)}}]), - gs:config(Editor, [{enable, false},{vscroll, right}, {hscroll, bottom}, - {wrap,none}]), - gs:config(Win, [{map, true}]), - {Win, Editor}. - -%% --------------------------------------------------------------------- -%% Menu Help Fuctions -%% --------------------------------------------------------------------- - - -links_menus(Links) -> - gs:destroy('Links'), - gs:create(menu,'Links','LinksMenu',[]), - Flag = case links_menus(Links,[]) of - [] -> false; - Pids -> - add_menu('Links', Pids, "Trace"), - true - end, - gse:config('LinksMenu',[{enable,Flag}]). - -links_menus([],Pids) -> Pids; -links_menus([Pid|Links],Pids) when is_pid(Pid) -> - links_menus(Links,[Pid|Pids]); -links_menus([_Port|Links],Pids) -> - links_menus(Links,Pids). - - -%% Create the node menu. - -add_node_menu(MenuBar, Nodes, Font) -> - MBNode = gs:create(menubutton, MenuBar, [{label,{text, " Nodes "}}, - {font,Font}, - {underline, 1}]), - gs:create(menu, node, MBNode, []), - add_menu(node, Nodes, "Show", Font), - gse:disable(node()). - - -%% --------------------------------------------------------------------- -%% Add Menus in the list under Menu menuitem. - -add_menu(Menu, Names, Tag) -> - add_menu(Menu, Names, Tag, font()). - -add_menu(_Menu, [], _Tag, _Font) -> ok; -add_menu(Menu, [Name|Names], Tag, Font) -> - Title = io_lib:format("~s ~p",[Tag, Name]), - gs:create(menuitem,Name,Menu,[{label,{text,Title}}, - {font,Font}, - {data,{Menu,Name}}]), - add_menu(Menu, Names, Tag, Font). - -%% --------------------------------------------------------------------- -%% Remove a specific menu item, or a whole menu, or a list of both. -%% - -remove_menu(List) when is_list(List)-> - lists:foreach(fun(X) -> gs:destroy(X) end, List); - -remove_menu(Object) -> - gse:destroy(Object). - - -%% --------------------------------------------------------------------- -%% If the trace window opened is supposed to trace a real pid, let us -%% add the trace menu, and other items specific to tracing. If not, -%% the only menus available are the ones in the default defined in -%% window(Pid). - -make_menus(false, _, _, _) -> ok; -make_menus({true,Pid}, MenuBar, MenuFile, Font) -> - MBView = gs:create(menubutton,'ViewMenu',MenuBar, - [{underline,1}, - {label,{text," View "}}, {font,Font}, - {side,left}]), - MenuView = gs:create(menu, MBView, []), - - MBTrace = gs:create(menubutton,'TraceMenu',MenuBar, - [{underline,1}, - {label,{text," Trace "}}, {font,Font}, - {side,left}]), - MenuTrace = gs:create(menu, MBTrace, []), - - - MBHelp = gs:create(menubutton,'HelpMenu',MenuBar, - [{underline,1}, - {label,{text," Help "}}, {font,Font}, - {side,right}]), - MenuHelp = gs:create(menu, MBHelp, []), - - %% File menu - gse:named_menuitem('Options', MenuFile, - [{label, {text, "Options..."}}, {font,Font}, - {underline,0}]), - - %% Trace menu - gse:named_menuitem('All Links', MenuTrace, - [{label, {text, "All Linked Processes"}}, - {font,Font}, - {underline,0}]), - gse:named_menuitem('LinksMenu', MenuTrace, - [{underline,0}, - {label, {text, "Linked Process..."}}, - {font,Font}, - {itemtype, cascade}, - {enable,false}]), - gs:create(menu,'Links','LinksMenu',[]), - case pman_process:pinfo(Pid, links) of - Links when is_list(Links) -> - links_menus(Links); - undefined -> - lists:foreach(fun(X) -> gse:disable(X) end,['LinksMenu']) - end, - gse:named_menuitem('Kill', MenuTrace, - [{label, {text, "Kill"}}, {font,Font}, - {underline,0}]), - - %% View menu - gse:named_menuitem('Clear', MenuView, - [{label, {text, "Clear buffer"}}, {font,Font}, - {underline,0}]), - - gse:named_menuitem('Module', MenuView, - [{label, {text, "Module Info"}}, {font,Font}, - {underline,0}]), - - %% Help menu - gse:named_menuitem('Help', MenuHelp, - [{label, {text, "Help"}}, {font,Font}, - {underline,0}]). - -%% --------------------------------------------------------------------- -%% Configurate the actual editor -%% -%% Editor, actual editor -%% Options, actual options for the editor -%% -%% Return: A configurated editor with the actual options -%% --------------------------------------------------------------------- - -configeditor(Editor, Options) -> - gs:config(Editor, Options). - -%% --------------------------------------------------------------------- -%% Configure the actual window after it has been resized. -%% --------------------------------------------------------------------- - -configwin(Object, W, H) -> - Dx = abs(W - gs:read(Object,width) - 4), - Dy = abs(H - gs:read(Object,height) - 42), - if - Dx + Dy =/= 0 -> - gs:config(Object,[{width,W - 4}]); - true -> ok - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% update/1, 3 -update(NoOfHidden) -> - Str = lists:flatten(io_lib:format(?CPIDHIDDENTEXT++"~w", - [NoOfHidden])), - gse:config('Number Hidden', [{label, {text,Str}}]). - -update(Grid, ShowInfoR, NoOfHidden) -> - - %% We reverse the list because we want the processes to appear with - %% the newest (=highest) pid first in the list. - ShowInfo = lists:reverse(ShowInfoR), - - %% Set the length of the grid - CGridline = length(ShowInfo) + 1, - gs:config(Grid, [{rows, {1,CGridline}}]), - - %% Add the header line - add_gridline(Grid, - 1, - {'Pid','Current Function','Name','Msgs','Reds','Size'}, - []), - - update(NoOfHidden), - - %% Recurse through the ordset of pids - update_r(Grid, ShowInfo, 2). - -update_r(Grid, [], Row) -> - delete_gridlines(Grid, Row); -update_r(Grid, [{Pid,Func,Name,Msgs,Reds,Psize}|ShowInfo], Row) -> - {M, F, A} = Func, - FuncText = lists:flatten(io_lib:format("~w:~w/~w", [M, F, A])), - add_gridline(Grid, - Row, - {Pid, FuncText, Name, Msgs, Reds, Psize}, - [{data,{pidfunc,Pid,Func}}]), - update_r(Grid, ShowInfo, Row+1). - -add_gridline(Grid, Row, Tuple, LIOptSpec) -> - {Pid, FuncText, Name, Msgs, Reds, Psize} = Tuple, - LIOpt = [{click,true}, - {doubleclick,true}, - {fg, colour(Row)}, - {text,{1,Pid}}, - {text,{2,FuncText}}, - {text,{3,Name}}, - {text,{4,Msgs}}, - {text,{5,Reds}}, - {text,{6,Psize}} |LIOptSpec], - case gs:read(Grid, {obj_at_row, Row}) of - undefined -> - gse:gridline(Grid,[{row, Row}|LIOpt]); - GridLine -> - gs:config(GridLine,LIOpt) - end. - -delete_gridlines(Grid, Row) -> - case gs:read(Grid, {obj_at_row, Row}) of - undefined -> - ok; - GridLine -> - gs:destroy(GridLine), - delete_gridlines(Grid, Row+1) - end. - -colour(1) -> - ?HEADER_COLOUR; -colour(_Row) -> - ?UNSELECTED_COLOUR. - -%% Interchange colours between two rows -change_colour(Grid, Row, Row) -> - Gitem = gs:read(Grid, {obj_at_row,Row}), - gs:config(Gitem, {fg,?SELECTED_COLOUR}); -change_colour(Grid, From, To) -> - Gitem_to = gs:read(Grid, {obj_at_row,To}), - Gitem_fr = gs:read(Grid, {obj_at_row,From}), - gs:config(Gitem_to, {fg,?SELECTED_COLOUR}), - gs:config(Gitem_fr, {fg,colour(From)}). - -%% -------------------------------------------------------------- -%% Create a title for the window -%% Return: the title -%% -------------------------------------------------------------- - -title({module, Mod}) -> - lists:flatten([io_lib:format("Pman: Module info ~p", [Mod])]); - -title({shell, Sh} ) -> - lists:flatten([io_lib:format("Pman: Shell process ~p on ~p", - [Sh,node(Sh)])]); - -title(Sh) -> - lists:flatten([io_lib:format("Pman: Process ~p on ~p", - [Sh, node(Sh)]),name(Sh)]). -name(Pid) -> - case pman_process:pinfo(Pid, registered_name) of - undefined -> ""; - Name -> - lists:flatten([io_lib:format("[~p]", [Name])]) - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% module_data/1 - %% Returns the module information for a -%% module, on a format suitable to insert into a GS editor. -%% -%% Arguments: -%% ModuleName The module -%% -%% Returns: -%% A string with module information. -%% - -module_data(ModuleName) -> - vformat("", catch apply(ModuleName, module_info, [])). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% display/1 - -%% - -display({_,Pid,_}) -> display(Pid); -display({_,Pid}) -> display(Pid); -display(Pid) when is_pid(Pid) -> - case pman_process:pinfo(Pid) of - undefined -> - format('Process is dead~n',[]); - Other -> - proc_format(Other) - end. - -%% -------------------------------------------------------------- -%% Format functions for the shell and help window. -%% -------------------------------------------------------------- - -vformat(Pad, {M,F,A}) when is_atom(F) -> - Pad2 = lists:append(Pad,mkpad(io_lib:format("~w:~w",[M,F]))), - lists:flatten([format("~p:~p", [M,F]),argformat(Pad2, A)]); - -vformat(Pad, [H|T]) -> - kvformat(Pad, [H|T],"["); - -vformat(_Pad, X) -> format("~p~n", [X]). - -format(Format) -> format(Format, []). - -format(Format, Args) -> - io_lib:format(Format, Args). - - -kvformat(S, [Item],Buff) -> - lists:reverse([format("\n~s~p]\n",[S,Item])|Buff]); - -kvformat(S,[H|T],Buff) -> - kvformat(S,T,[format("\n~s~p, ",[S,H])|Buff]); - -kvformat(_,[],Buff) -> - lists:reverse(["]\n"|Buff]). - -argformat(_Pad,A) when is_integer(A) -> - format("/~p\n", [A]); -argformat(_,A) -> - lists:flatten([format("/~p\n", [length(A)]), - format("args: \n"), - argformat2(" ", A)]). - -argformat2(Pad, Arglist) -> - Chars = lists:flatten(io_lib:format("~p",[Arglist])), - if - length(Chars) < (70 - length(Pad)) -> - format("~s~s\n", [Pad, Chars]); - true -> - argformat3(Pad, Arglist) - end. - -argformat3(_,[]) -> format("\n"); -argformat3(Pad, [H|T]) -> - Chars = truncate(65,io_lib:format("~s~p",[Pad, H])), - format("~s,\n", [Chars]), - argformat3(Pad, T). - -pformat(false) -> []; -pformat({value,{_, 0}}) -> []; -pformat({value,{_, []}}) -> []; -pformat({value, {Key, Vals}}) -> - Pad = mkpad(io_lib:format("~p ",[Key])), - format(lists:flatten(["~p: " ,vformat(Pad, Vals), "~n"]), [Key]). - -truncate(0, _Chars) -> "....."; -truncate(I, [H|T]) -> [H|truncate(I-1, T)]; -truncate(_I, []) -> []. - -mkpad([_|T]) -> [32|mkpad(T)]; -mkpad([]) -> []. - -proc_format(Pi) -> %% process_info struct - X1 = pformat(lists:keysearch(initial_call, 1, Pi)), - X2 = pformat(lists:keysearch(current_function, 1,Pi)), - X3 = pformat(lists:keysearch(messages, 1,Pi)), - X4 = pformat(lists:keysearch(dictionary,1, Pi)), - X5 = pformat(lists:keysearch(heap_size, 1,Pi)), - X6 = pformat(lists:keysearch(stack_size, 1,Pi)), - X7 = pformat(lists:keysearch(reductions, 1,Pi)), - X8 = pformat(lists:keysearch(links, 1,Pi)), - X9 = pformat(lists:keysearch(trap_exit, 1,Pi)), - lists:flatten([X1, X2, X3, X4, X5,X6,X7,X8,X9]). - - -%% Using the tool_utils function for presenting messages. -dialog_window(GSParent, Text) -> - spawn_link(tool_utils, notify, [GSParent, Text]). - -%% Create a window with a dismiss button. -msg_win(Text) -> - spawn_link(fun() -> display_msg_win(Text) end). - -display_msg_win(Text) -> - GS = gs:start([{kernel,true}]), - Font = font(GS), - Win = gs:window(GS, [{width,200}, {height,75}, {destroy,true}, - {title,"Pman Message"}]), - Can = gs:canvas(Win, [{width,200}, {height, 75},{x,0},{y,0}]), - gs:text(Can, [{text,Text}, {coords,[{10,0}]}, {justify,center}]), - Btn = gs:button(Win, [{label,{text,"Dismiss"}}, {font,Font}, - {width,100}, {x,50}, {y,40}]), - gs:config(Win, {map,true}), - receive - {gs, Btn, click, _, _} -> - ok - end. - -%% Choose default font -font() -> - font(gs:start([{kernel,true}])). - -font(GS) -> - case gs:read(GS, {choose_font, {screen,[],12}}) of - Font when element(1, Font)==screen -> - Font; - _ -> - gs:read(GS, {choose_font, {courier,[],12}}) - end. diff --git a/lib/pman/src/pman_win.hrl b/lib/pman/src/pman_win.hrl deleted file mode 100644 index 8a2778d5b7..0000000000 --- a/lib/pman/src/pman_win.hrl +++ /dev/null @@ -1,39 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-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% -%% - --define(WIN_HEIGHT, 390). --define(WIN_WIDTH, 745). - --define(MENU_HEIGHT, 40). --define(CHECKBAR_HEIGHT, 40). - --define(CPIDHIDDENTEXT, "# Hidden: "). - --define(HEADER_COLOUR, blue). --define(UNSELECTED_COLOUR, black). --define(SELECTED_COLOUR, white). - - - - - - - - - |