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 __command_line = 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 # Prevent pickling of Process 73 raise pickle.PicklingError("Can't pickle a Process: %s" % self)
74
75 - def _parent(self):
76 if self._ensure_status_file_read() and not self.__parent: 77 parent_pid = int(self.__status['PPid']) 78 self.__parent = Process(parent_pid) 79 return self.__parent
80
81 - def _descendents(self):
82 """ 83 """ 84 subtree = [] 85 self._add_children_recursively(subtree, processes()) 86 return subtree
87
88 - def _state(self):
89 """ 90 """ 91 state = None 92 if self._ensure_status_file_read(): 93 state = self.__status.get('State', None) 94 if state is not None: 95 space = state.find(' ') 96 state = state[:space] 97 return state
98
99 - def _size(self):
100 size = None 101 if self._ensure_status_file_read(): 102 size = self.__status.get('VmSize', None) 103 if size is not None: 104 space = size.find(' ') 105 assert size[space + 1:].lower() == 'kb' 106 size = int(size[:space]) # chop off kB 107 size *= 1024 # multiply by kB 108 return size
109
110 - def _rss(self):
111 rss = None 112 if self._ensure_status_file_read(): 113 rss = self.__status.get('VmRSS', None) 114 if rss is not None: 115 space = rss.find(' ') 116 assert rss[space + 1:].lower() == 'kb' 117 rss = int(rss[:space]) # chop off kB 118 rss *= 1024 # multiply by kB 119 return rss
120
121 - def _command_line(self):
122 if not self.__command_line: 123 command_line_tokens = self._strings_file('cmdline') 124 if command_line_tokens: 125 self.__command_line = ' '.join(command_line_tokens) 126 if self.__command_line is None: 127 self.__command_line = '' 128 return self.__command_line
129
130 - def _env(self):
131 if not self.__env: 132 env_map = self._strings_file('environ') 133 if env_map: 134 self.__env = {} 135 for key_value_string in env_map: 136 eq = key_value_string.find('=') 137 key = key_value_string[:eq].strip() 138 value = key_value_string[eq + 1:].strip() 139 if key: 140 self.__env[key] = value 141 return self.__env
142 143 pid = property(lambda self: self.__pid, doc = 'The PID of this C{Process}.') 144 parent = property(_parent, doc = 'The parent of this C{Process}. Returns a C{Process} object.') 145 descendents = property(_descendents, doc = 'A list containing C{Process} objects corresponding to the descendents of this C{Process}, (children, grandchildren, etc.)') 146 state = property(_state, doc = 'The state of this C{Process}.') 147 size = property(_size, doc = 'The VM size of this C{Process}.') 148 rss = property(_rss, doc = 'The VM RSS of this C{Process}.') 149 command_line = property(_command_line, doc = 'The command-line used to create this C{Process}.') 150 env = property(_env, doc = 'A map describing the environment in effect during the creation of this C{Process}.') 151
152 - def kill(self, signal = None):
153 """Send the indicated C{signal} to this process. 154 """ 155 if signal: 156 os.system('kill -%s %s' % (signal, self.pid)) 157 else: 158 os.system('kill %s' % (self.pid))
159
160 - def _ensure_status_file_read(self):
161 self.__status = {} 162 exists = True 163 try: 164 status_filename = '%s/status' % self._procdir() 165 status_file = open(status_filename, 'r') 166 status = status_file.read().split('\n') 167 status_file.close() 168 for key_value_string in status: 169 colon = key_value_string.find(':') 170 key = key_value_string[:colon].strip() 171 value = key_value_string[colon + 1:].strip() 172 self.__status[key] = value 173 except IOError: 174 exists = False 175 return exists
176
177 - def _add_children_recursively(self, subtree, processes):
178 children = [] 179 for process in processes: 180 if process.parent and process.parent.pid == self.pid: 181 children.append(process) 182 process._add_children_recursively(subtree, processes) 183 subtree.extend(children)
184
185 - def _strings_file(self, filename):
186 strings = [] 187 try: 188 filename = '%s/%s' % (self._procdir(), filename) 189 file = open(filename, 'r') 190 contents = file.read() 191 file.close() 192 strings = contents.split(chr(0)) 193 except IOError: 194 pass 195 return strings
196
197 - def _procdir(self):
198 return '/proc/%s' % self.pid
199