Package osh :: Module process
[frames] | no frames]

Source Code for Module osh.process

  1  # osh 
  2  # Copyright (C) 2005 Jack Orenstein <jao@geophile.com> 
  3  # 
  4  # This program is free software; you can redistribute it and/or modify 
  5  # it under the terms of the GNU General Public License as published by 
  6  # the Free Software Foundation; either version 2 of the License, or 
  7  # (at your option) any later version. 
  8  # 
  9  # This program is distributed in the hope that it will be useful, 
 10  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 11  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 12  # GNU General Public License for more details. 
 13  # 
 14  # You should have received a copy of the GNU General Public License 
 15  # along with this program; if not, write to the Free Software 
 16  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 17   
 18  """Provides information on currently running processes, by examining files in the C{/proc} filesystem. 
 19  (So it doesn't work on OS X, for example.) The C{processes} function returns a list of C{Process} 
 20  objects. Each C{Process} object reveals information derived from C{/proc}, identifies 
 21  parent and child processes, and can be used to send signals to the process. 
 22  """ 
 23   
 24  import os 
 25  import os.path 
 26   
27 -def processes(*dummy):
28 """Returns a list of process objects based on the current contents of C{/proc}. 29 Of course the list is stale as soon as it is formed. In particular, a C{Process} 30 object in the list may correspond to a process that has terminated by the time 31 you use the object. 32 """ 33 processes = [] 34 for file in os.listdir('/proc'): 35 if file.isdigit(): 36 processes.append(Process(int(file))) 37 return processes
38
39 -class Process(object):
40 """A C{Process} object represents a process with a particular PID. The process may or may not 41 be running when the C{Process} object is used. It is conceivable that the C{Process} object 42 does not represent the same process that was identified by the PID when the C{Process} object 43 was created. 44 """ 45 46 _pid = None 47 _parent = None 48 _command_line = None 49 _env = None 50 _status = None 51
52 - def __init__(self, pid):
53 """Creates a C{Process} object for a given C{pid}. For internal use only. 54 """ 55 self._pid = pid
56
57 - def __str__(self):
58 """Returns a string describing this C{Process}. 59 """ 60 return 'Process(%s)' % self._pid
61
62 - def __cmp__(self, other):
63 """Ranks C{Process}es by PID. 64 """ 65 return self._pid - other.__pid
66
67 - def __hash__(self):
68 return self._pid
69
70 - def pid(self):
71 """The PID of this C{Process}. 72 """ 73 return self._pid
74
75 - def parent(self):
76 """The parent of this C{Process}. Returns a C{Process} object. 77 """ 78 if self._ensure_status_file_read() and not self._parent: 79 parent_pid = int(self._status['PPid']) 80 self._parent = Process(parent_pid) 81 return self._parent
82
83 - def descendents(self):
84 """A list containing C{Process} objects corresponding to the descendents 85 of this C{Process}, (children, grandchildren, etc.) 86 """ 87 subtree = [] 88 self._add_children_recursively(subtree, processes()) 89 return subtree
90
91 - def state(self):
92 """The state of this C{Process}. 93 """ 94 state = None 95 if self._ensure_status_file_read(): 96 state = self._status.get('State', None) 97 if state is not None: 98 space = state.find(' ') 99 state = state[:space] 100 return state
101
102 - def size(self):
103 """The VM size of this C{Process}. 104 """ 105 size = None 106 if self._ensure_status_file_read(): 107 size = self._status.get('VmSize', None) 108 if size is not None: 109 space = size.find(' ') 110 assert size[space + 1:].lower() == 'kb' 111 size = int(size[:space]) # chop off kB 112 size *= 1024 # multiply by kB 113 return size
114
115 - def rss(self):
116 """The VM RSS of this C{Process}. 117 """ 118 rss = None 119 if self._ensure_status_file_read(): 120 rss = self._status.get('VmRSS', None) 121 if rss is not None: 122 space = rss.find(' ') 123 assert rss[space + 1:].lower() == 'kb' 124 rss = int(rss[:space]) # chop off kB 125 rss *= 1024 # multiply by kB 126 return rss
127
128 - def command_line(self):
129 """The command-line used to create this C{Process}. 130 """ 131 if not self._command_line: 132 command_line_tokens = self._strings_file('cmdline') 133 if command_line_tokens: 134 self._command_line = ' '.join(command_line_tokens) 135 if self._command_line is None: 136 self._command_line = '' 137 return self._command_line
138
139 - def env(self):
140 """A map describing the environment in effect during the creation of this C{Process}. 141 """ 142 if not self._env: 143 env_map = self._strings_file('environ') 144 if env_map: 145 self._env = {} 146 for key_value_string in env_map: 147 eq = key_value_string.find('=') 148 key = key_value_string[:eq].strip() 149 value = key_value_string[eq + 1:].strip() 150 if key: 151 self._env[key] = value 152 return self._env
153
154 - def kill(self, signal = None):
155 """Send the indicated C{signal} to this process. 156 """ 157 if signal: 158 os.system('kill -%s %s' % (signal, self._pid)) 159 else: 160 os.system('kill %s' % (self._pid))
161
162 - def _ensure_status_file_read(self):
163 self._status = {} 164 exists = True 165 try: 166 status_filename = '%s/status' % self._procdir() 167 status_file = open(status_filename, 'r') 168 status = status_file.read().split('\n') 169 status_file.close() 170 for key_value_string in status: 171 colon = key_value_string.find(':') 172 key = key_value_string[:colon].strip() 173 value = key_value_string[colon + 1:].strip() 174 self._status[key] = value 175 except IOError: 176 exists = False 177 return exists
178
179 - def _add_children_recursively(self, subtree, processes):
180 children = [] 181 for process in processes: 182 if process.parent() and process.parent()._pid == self._pid: 183 children.append(process) 184 process._add_children_recursively(subtree, processes) 185 subtree.extend(children)
186
187 - def _strings_file(self, filename):
188 strings = [] 189 try: 190 filename = '%s/%s' % (self._procdir(), filename) 191 file = open(filename, 'r') 192 contents = file.read() 193 file.close() 194 strings = contents.split(chr(0)) 195 except IOError: 196 pass 197 return strings
198
199 - def _procdir(self):
200 return '/proc/%s' % self._pid
201