%% %% %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.