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

Source Code for Module osh.process

  1  # osh 
  2  # Copyright (C) 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  import pickle 
 27   
28 -def processes(*dummy):
29 """Returns a list of process objects based on the current contents of C{/proc}. 30 Of course the list is stale as soon as it is formed. In particular, a C{Process} 31 object in the list may correspond to a process that has terminated by the time 32 you use the object. 33 """ 34 processes = [] 35 for file in os.listdir('/proc'): 36 if file.isdigit(): 37 processes.append(Process(int(file))) 38 return processes
39
40 -class Process(object):
41 """A C{Process} object represents a process with a particular PID. The process may or may not 42 be running when the C{Process} object is used. It is conceivable that the C{Process} object 43 does not represent the same process that was identified by the PID when the C{Process} object 44 was created. 45 """ 46 47 __pid = None 48 __parent = None 49 __commandline = None 50 __env = None 51 __status = None 52
53 - def __init__(self, pid):
54 """Creates a C{Process} object for a given C{pid}. For internal use only. 55 """ 56 self.__pid = pid
57
58 - def __repr__(self):
59 """Returns a string describing this C{Process}. 60 """ 61 return 'Process(%s)' % self.__pid
62
63 - def __cmp__(self, other):
64 """Ranks C{Process}es by PID. 65 """ 66 return self.__pid - other.___pid
67
68 - def __hash__(self):
69 return self.__pid
70
71 - def __reduce__(self):
72 # Get ready for pickling 73 self._ensure_status_file_read() 74 x = self.commandline 75 x = self.env
76
77 - def _parent(self):
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 """ 85 """ 86 subtree = [] 87 self._add_children_recursively(subtree, processes()) 88 return subtree
89
90 - def _state(self):
91 """ 92 """ 93 state = None 94 if self._ensure_status_file_read(): 95 state = self.__status.get('State', None) 96 if state is not None: 97 space = state.find(' ') 98 state = state[:space] 99 return state
100
101 - def _size(self):
102 size = None 103 if self._ensure_status_file_read(): 104 size = self.__status.get('VmSize', None) 105 if size is not None: 106 space = size.find(' ') 107 assert size[space + 1:].lower() == 'kb' 108 size = int(size[:space]) # chop off kB 109 size *= 1024 # multiply by kB 110 return size
111
112 - def _rss(self):
113 rss = None 114 if self._ensure_status_file_read(): 115 rss = self.__status.get('VmRSS', None) 116 if rss is not None: 117 space = rss.find(' ') 118 assert rss[space + 1:].lower() == 'kb' 119 rss = int(rss[:space]) # chop off kB 120 rss *= 1024 # multiply by kB 121 return rss
122
123 - def _commandline(self):
124 if not self.__commandline: 125 commandline_tokens = self._strings_file('cmdline') 126 if commandline_tokens: 127 self.__commandline = ' '.join(commandline_tokens) 128 if self.__commandline is None: 129 self.__commandline = '' 130 return self.__commandline
131
132 - def _env(self):
133 if not self.__env: 134 env_map = self._strings_file('environ') 135 if env_map: 136 self.__env = {} 137 for key_value_string in env_map: 138 eq = key_value_string.find('=') 139 key = key_value_string[:eq].strip() 140 value = key_value_string[eq + 1:].strip() 141 if key: 142 self.__env[key] = value 143 return self.__env
144 145 pid = property(lambda self: self.__pid, doc = 'The PID of this C{Process}.') 146 parent = property(_parent, doc = 'The parent of this C{Process}. Returns a C{Process} object.') 147 descendents = property(_descendents, doc = 'A list containing C{Process} objects corresponding to the descendents of this C{Process}, (children, grandchildren, etc.)') 148 state = property(_state, doc = 'The state of this C{Process}.') 149 size = property(_size, doc = 'The VM size of this C{Process}.') 150 rss = property(_rss, doc = 'The VM RSS of this C{Process}.') 151 commandline = property(_commandline, doc = 'The command-line used to create this C{Process}.') 152 env = property(_env, doc = 'A map describing the environment in effect during the creation of this C{Process}.') 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 exists = True 164 if self.__status is None: 165 self.__status = {} 166 try: 167 status_filename = '%s/status' % self._procdir() 168 status_file = open(status_filename, 'r') 169 status = status_file.read().split('\n') 170 status_file.close() 171 for key_value_string in status: 172 colon = key_value_string.find(':') 173 key = key_value_string[:colon].strip() 174 value = key_value_string[colon + 1:].strip() 175 self.__status[key] = value 176 except IOError: 177 exists = False 178 return exists
179
180 - def _add_children_recursively(self, subtree, processes):
181 children = [] 182 for process in processes: 183 if process.parent and process.parent.pid == self.pid: 184 children.append(process) 185 process._add_children_recursively(subtree, processes) 186 subtree.extend(children)
187
188 - def _strings_file(self, filename):
189 strings = [] 190 try: 191 filename = '%s/%s' % (self._procdir(), filename) 192 file = open(filename, 'r') 193 contents = file.read() 194 file.close() 195 strings = contents.split(chr(0)) 196 except IOError: 197 pass 198 return strings
199
200 - def _procdir(self):
201 return '/proc/%s' % self.pid
202