| Index: third_party/psutil/psutil/_pslinux.py
|
| diff --git a/third_party/psutil/psutil/_pslinux.py b/third_party/psutil/psutil/_pslinux.py
|
| old mode 100644
|
| new mode 100755
|
| index 26a8abf55a6be0583b88f7a5dba320633c2168ea..443b6ade9d2a9744778cc30e9ac55cc2d5da6658
|
| --- a/third_party/psutil/psutil/_pslinux.py
|
| +++ b/third_party/psutil/psutil/_pslinux.py
|
| @@ -1,15 +1,12 @@
|
| #!/usr/bin/env python
|
| #
|
| -# $Id: _pslinux.py 800 2010-11-12 21:51:25Z g.rodola $
|
| +# $Id: _pslinux.py 1142 2011-10-05 18:45:49Z g.rodola $
|
| #
|
| +# Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
|
|
| -__all__ = ["NUM_CPUS", "TOTAL_PHYMEM",
|
| - "PlatformProcess",
|
| - "avail_phymem", "used_phymem", "total_virtmem", "avail_virtmem",
|
| - "used_virtmem", "get_system_cpu_times", "pid_exists", "get_pid_list",
|
| - "phymem_buffers", "cached_phymem"
|
| - ]
|
| -
|
| +"""Linux platform implementation."""
|
|
|
| import os
|
| import errno
|
| @@ -17,50 +14,72 @@ import socket
|
| import struct
|
| import sys
|
| import base64
|
| +import re
|
|
|
| -try:
|
| - from collections import namedtuple
|
| -except ImportError:
|
| - from psutil.compat import namedtuple # python < 2.6
|
| -
|
| +import _psutil_posix
|
| +import _psutil_linux
|
| from psutil import _psposix
|
| -from psutil.error import AccessDenied, NoSuchProcess
|
| +from psutil.error import AccessDenied, NoSuchProcess, TimeoutExpired
|
| +from psutil._common import *
|
| +
|
| +__extra__all__ = [
|
| + "IOPRIO_CLASS_NONE", "IOPRIO_CLASS_RT", "IOPRIO_CLASS_BE",
|
| + "IOPRIO_CLASS_IDLE",
|
| + "phymem_buffers", "cached_phymem"]
|
|
|
|
|
| -def _get_uptime():
|
| +def _get_boot_time():
|
| """Return system boot time (epoch in seconds)"""
|
| f = open('/proc/stat', 'r')
|
| - for line in f:
|
| - if line.startswith('btime'):
|
| - f.close()
|
| - return float(line.strip().split()[1])
|
| + try:
|
| + for line in f:
|
| + if line.startswith('btime'):
|
| + return float(line.strip().split()[1])
|
| + raise RuntimeError("line not found")
|
| + finally:
|
| + f.close()
|
|
|
| def _get_num_cpus():
|
| """Return the number of CPUs on the system"""
|
| num = 0
|
| f = open('/proc/cpuinfo', 'r')
|
| - for line in f:
|
| - if line.startswith('processor'):
|
| + try:
|
| + lines = f.readlines()
|
| + finally:
|
| + f.close()
|
| + for line in lines:
|
| + if line.lower().startswith('processor'):
|
| num += 1
|
| - f.close()
|
| - return num
|
|
|
| -def _get_total_phymem():
|
| - """Return the total amount of physical memory, in bytes"""
|
| - f = open('/proc/meminfo', 'r')
|
| - for line in f:
|
| - if line.startswith('MemTotal:'):
|
| + # unknown format (e.g. amrel/sparc architectures), see:
|
| + # http://code.google.com/p/psutil/issues/detail?id=200
|
| + if num == 0:
|
| + f = open('/proc/stat', 'r')
|
| + try:
|
| + lines = f.readlines()
|
| + finally:
|
| f.close()
|
| - return int(line.split()[1]) * 1024
|
| + search = re.compile('cpu\d')
|
| + for line in lines:
|
| + line = line.split(' ')[0]
|
| + if search.match(line):
|
| + num += 1
|
| +
|
| + if num == 0:
|
| + raise RuntimeError("can't determine number of CPUs")
|
| + return num
|
|
|
|
|
| # Number of clock ticks per second
|
| _CLOCK_TICKS = os.sysconf(os.sysconf_names["SC_CLK_TCK"])
|
| -_UPTIME = _get_uptime()
|
| +_TERMINAL_MAP = _psposix._get_terminal_map()
|
| +BOOT_TIME = _get_boot_time()
|
| NUM_CPUS = _get_num_cpus()
|
| -TOTAL_PHYMEM = _get_total_phymem()
|
| -
|
| -del _get_uptime, _get_num_cpus, _get_total_phymem
|
| +# ioprio_* constants http://linux.die.net/man/2/ioprio_get
|
| +IOPRIO_CLASS_NONE = 0
|
| +IOPRIO_CLASS_RT = 1
|
| +IOPRIO_CLASS_BE = 2
|
| +IOPRIO_CLASS_IDLE = 3
|
|
|
| # http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
|
| _TCP_STATES_TABLE = {"01" : "ESTABLISHED",
|
| @@ -76,55 +95,20 @@ _TCP_STATES_TABLE = {"01" : "ESTABLISHED",
|
| "0B" : "CLOSING"
|
| }
|
|
|
| -def avail_phymem():
|
| - """Return the amount of physical memory available, in bytes."""
|
| - f = open('/proc/meminfo', 'r')
|
| - free = None
|
| - _flag = False
|
| - for line in f:
|
| - if line.startswith('MemFree:'):
|
| - free = int(line.split()[1]) * 1024
|
| - break
|
| - f.close()
|
| - return free
|
| -
|
| -def used_phymem():
|
| - """"Return the amount of physical memory used, in bytes."""
|
| - return (TOTAL_PHYMEM - avail_phymem())
|
| -
|
| -def total_virtmem():
|
| - """"Return the total amount of virtual memory, in bytes."""
|
| - f = open('/proc/meminfo', 'r')
|
| - for line in f:
|
| - if line.startswith('SwapTotal:'):
|
| - f.close()
|
| - return int(line.split()[1]) * 1024
|
| -
|
| -def avail_virtmem():
|
| - """Return the amount of virtual memory currently in use on the
|
| - system, in bytes.
|
| - """
|
| - f = open('/proc/meminfo', 'r')
|
| - for line in f:
|
| - if line.startswith('SwapFree:'):
|
| - f.close()
|
| - return int(line.split()[1]) * 1024
|
| -
|
| -def used_virtmem():
|
| - """Return the amount of used memory currently in use on the system,
|
| - in bytes.
|
| - """
|
| - return total_virtmem() - avail_virtmem()
|
| +# --- system memory functions
|
|
|
| def cached_phymem():
|
| """Return the amount of cached memory on the system, in bytes.
|
| This reflects the "cached" column of free command line utility.
|
| """
|
| f = open('/proc/meminfo', 'r')
|
| - for line in f:
|
| - if line.startswith('Cached:'):
|
| - f.close()
|
| - return int(line.split()[1]) * 1024
|
| + try:
|
| + for line in f:
|
| + if line.startswith('Cached:'):
|
| + return int(line.split()[1]) * 1024
|
| + raise RuntimeError("line not found")
|
| + finally:
|
| + f.close()
|
|
|
| def phymem_buffers():
|
| """Return the amount of physical memory buffers used by the
|
| @@ -132,36 +116,207 @@ def phymem_buffers():
|
| This reflects the "buffers" column of free command line utility.
|
| """
|
| f = open('/proc/meminfo', 'r')
|
| - for line in f:
|
| - if line.startswith('Buffers:'):
|
| - f.close()
|
| - return int(line.split()[1]) * 1024
|
| + try:
|
| + for line in f:
|
| + if line.startswith('Buffers:'):
|
| + return int(line.split()[1]) * 1024
|
| + raise RuntimeError("line not found")
|
| + finally:
|
| + f.close()
|
| +
|
| +def phymem_usage():
|
| + # total, used and free values are matched against free cmdline utility
|
| + # the percentage matches top/htop and gnome-system-monitor
|
| + f = open('/proc/meminfo', 'r')
|
| + try:
|
| + total = free = buffers = cached = None
|
| + for line in f:
|
| + if line.startswith('MemTotal:'):
|
| + total = int(line.split()[1]) * 1024
|
| + elif line.startswith('MemFree:'):
|
| + free = int(line.split()[1]) * 1024
|
| + elif line.startswith('Buffers:'):
|
| + buffers = int(line.split()[1]) * 1024
|
| + elif line.startswith('Cached:'):
|
| + cached = int(line.split()[1]) * 1024
|
| + break
|
| + used = total - free
|
| + percent = usage_percent(total - (free + buffers + cached), total,
|
| + _round=1)
|
| + return ntuple_sysmeminfo(total, used, free, percent)
|
| + finally:
|
| + f.close()
|
| +
|
| +
|
| +def virtmem_usage():
|
| + f = open('/proc/meminfo', 'r')
|
| + try:
|
| + total = free = None
|
| + for line in f:
|
| + if line.startswith('SwapTotal:'):
|
| + total = int(line.split()[1]) * 1024
|
| + elif line.startswith('SwapFree:'):
|
| + free = int(line.split()[1]) * 1024
|
| + if total is not None and free is not None:
|
| + break
|
| + assert total is not None and free is not None
|
| + used = total - free
|
| + percent = usage_percent(used, total, _round=1)
|
| + return ntuple_sysmeminfo(total, used, free, percent)
|
| + finally:
|
| + f.close()
|
| +
|
| +
|
| +# --- system CPU functions
|
|
|
| def get_system_cpu_times():
|
| - """Return a dict representing the following CPU times:
|
| + """Return a named tuple representing the following CPU times:
|
| user, nice, system, idle, iowait, irq, softirq.
|
| """
|
| f = open('/proc/stat', 'r')
|
| - values = f.readline().split()
|
| - f.close()
|
| + try:
|
| + values = f.readline().split()
|
| + finally:
|
| + f.close()
|
|
|
| values = values[1:8]
|
| values = tuple([float(x) / _CLOCK_TICKS for x in values])
|
| + return ntuple_sys_cputimes(*values[:7])
|
| +
|
| +def get_system_per_cpu_times():
|
| + """Return a list of namedtuple representing the CPU times
|
| + for every CPU available on the system.
|
| + """
|
| + cpus = []
|
| + f = open('/proc/stat', 'r')
|
| + # get rid of the first line who refers to system wide CPU stats
|
| + try:
|
| + f.readline()
|
| + for line in f.readlines():
|
| + if line.startswith('cpu'):
|
| + values = line.split()[1:8]
|
| + values = tuple([float(x) / _CLOCK_TICKS for x in values])
|
| + entry = ntuple_sys_cputimes(*values[:7])
|
| + cpus.append(entry)
|
| + return cpus
|
| + finally:
|
| + f.close()
|
|
|
| - return dict(user=values[0], nice=values[1], system=values[2], idle=values[3],
|
| - iowait=values[4], irq=values[5], softirq=values[6])
|
| +
|
| +# --- system disk functions
|
| +
|
| +def disk_partitions(all=False):
|
| + """Return mounted disk partitions as a list of nameduples"""
|
| + phydevs = []
|
| + f = open("/proc/filesystems", "r")
|
| + try:
|
| + for line in f:
|
| + if not line.startswith("nodev"):
|
| + phydevs.append(line.strip())
|
| + finally:
|
| + f.close()
|
| +
|
| + retlist = []
|
| + partitions = _psutil_linux.get_disk_partitions()
|
| + for partition in partitions:
|
| + device, mountpoint, fstype = partition
|
| + if device == 'none':
|
| + device = ''
|
| + if not all:
|
| + if device == '' or fstype not in phydevs:
|
| + continue
|
| + ntuple = ntuple_partition(device, mountpoint, fstype)
|
| + retlist.append(ntuple)
|
| + return retlist
|
| +
|
| +get_disk_usage = _psposix.get_disk_usage
|
| +
|
| +# --- process functions
|
|
|
| def get_pid_list():
|
| """Returns a list of PIDs currently running on the system."""
|
| pids = [int(x) for x in os.listdir('/proc') if x.isdigit()]
|
| - # special case for 0 (kernel process) PID
|
| - pids.insert(0, 0)
|
| return pids
|
|
|
| def pid_exists(pid):
|
| """Check For the existence of a unix pid."""
|
| return _psposix.pid_exists(pid)
|
|
|
| +def network_io_counters():
|
| + """Return network I/O statistics for every network interface
|
| + installed on the system as a dict of raw tuples.
|
| + """
|
| + f = open("/proc/net/dev", "r")
|
| + try:
|
| + lines = f.readlines()
|
| + finally:
|
| + f.close()
|
| +
|
| + retdict = {}
|
| + for line in lines[2:]:
|
| + fields = line.split()
|
| + name = fields[0][:-1]
|
| + bytes_recv = int(fields[1])
|
| + packets_recv = int(fields[2])
|
| + bytes_sent = int(fields[9])
|
| + packets_sent = int(fields[10])
|
| + retdict[name] = (bytes_sent, bytes_recv, packets_sent, packets_recv)
|
| + return retdict
|
| +
|
| +def disk_io_counters():
|
| + """Return disk I/O statistics for every disk installed on the
|
| + system as a dict of raw tuples.
|
| + """
|
| + # man iostat states that sectors are equivalent with blocks and
|
| + # have a size of 512 bytes since 2.4 kernels. This value is
|
| + # needed to calculate the amount of disk I/O in bytes.
|
| + SECTOR_SIZE = 512
|
| +
|
| + # determine partitions we want to look for
|
| + partitions = []
|
| + f = open("/proc/partitions", "r")
|
| + try:
|
| + lines = f.readlines()[2:]
|
| + finally:
|
| + f.close()
|
| + for line in lines:
|
| + _, _, _, name = line.split()
|
| + if name[-1].isdigit():
|
| + partitions.append(name)
|
| + #
|
| + retdict = {}
|
| + f = open("/proc/diskstats", "r")
|
| + try:
|
| + lines = f.readlines()
|
| + finally:
|
| + f.close()
|
| + for line in lines:
|
| + _, _, name, reads, _, rbytes, rtime, writes, _, wbytes, wtime = \
|
| + line.split()[:11]
|
| + if name in partitions:
|
| + rbytes = int(rbytes) * SECTOR_SIZE
|
| + wbytes = int(wbytes) * SECTOR_SIZE
|
| + reads = int(reads)
|
| + writes = int(writes)
|
| + # TODO: times are expressed in milliseconds while OSX/BSD has
|
| + # these expressed in nanoseconds; figure this out.
|
| + rtime = int(rtime)
|
| + wtime = int(wtime)
|
| + retdict[name] = (reads, writes, rbytes, wbytes, rtime, wtime)
|
| + return retdict
|
| +
|
| +
|
| +# taken from /fs/proc/array.c
|
| +_status_map = {"R" : STATUS_RUNNING,
|
| + "S" : STATUS_SLEEPING,
|
| + "D" : STATUS_DISK_SLEEP,
|
| + "T" : STATUS_STOPPED,
|
| + "t" : STATUS_TRACING_STOP,
|
| + "Z" : STATUS_ZOMBIE,
|
| + "X" : STATUS_DEAD,
|
| + "x" : STATUS_DEAD,
|
| + "K" : STATUS_WAKE_KILL,
|
| + "W" : STATUS_WAKING}
|
|
|
| # --- decorators
|
|
|
| @@ -173,7 +328,10 @@ def wrap_exceptions(callable):
|
| try:
|
| return callable(self, *args, **kwargs)
|
| except (OSError, IOError), err:
|
| - if err.errno == errno.ENOENT: # no such file or directory
|
| + # ENOENT (no such file or directory) gets raised on open().
|
| + # ESRCH (no such process) can get raised on read() if
|
| + # process is gone in meantime.
|
| + if err.errno in (errno.ENOENT, errno.ESRCH):
|
| raise NoSuchProcess(self.pid, self._process_name)
|
| if err.errno in (errno.EPERM, errno.EACCES):
|
| raise AccessDenied(self.pid, self._process_name)
|
| @@ -181,14 +339,9 @@ def wrap_exceptions(callable):
|
| return wrapper
|
|
|
|
|
| -class LinuxProcess(object):
|
| +class Process(object):
|
| """Linux process implementation."""
|
|
|
| - _meminfo_ntuple = namedtuple('meminfo', 'rss vms')
|
| - _cputimes_ntuple = namedtuple('cputimes', 'user system')
|
| - _openfile_ntuple = namedtuple('openfile', 'path fd')
|
| - _connection_ntuple = namedtuple('connection', 'fd family type local_address '
|
| - 'remote_address status')
|
| __slots__ = ["pid", "_process_name"]
|
|
|
| def __init__(self, pid):
|
| @@ -197,8 +350,6 @@ class LinuxProcess(object):
|
|
|
| @wrap_exceptions
|
| def get_process_name(self):
|
| - if self.pid == 0:
|
| - return 'sched' # special case for kernel process
|
| f = open("/proc/%s/stat" % self.pid)
|
| try:
|
| name = f.read().split(' ')[1].replace('(', '').replace(')', '')
|
| @@ -209,7 +360,7 @@ class LinuxProcess(object):
|
|
|
| def get_process_exe(self):
|
| if self.pid in (0, 2):
|
| - return "" # special case for kernel processes
|
| + raise AccessDenied(self.pid, self._process_name)
|
| try:
|
| exe = os.readlink("/proc/%s/exe" % self.pid)
|
| except (OSError, IOError), err:
|
| @@ -226,6 +377,10 @@ class LinuxProcess(object):
|
| raise AccessDenied(self.pid, self._process_name)
|
| raise
|
|
|
| + # readlink() might return paths containing null bytes causing
|
| + # problems when used with other fs-related functions (os.*,
|
| + # open(), ...)
|
| + exe = exe.replace('\x00', '')
|
| # It seems symlinks can point to a deleted/invalid location
|
| # (this usually happens with "pulseaudio" process).
|
| # However, if we had permissions to execute readlink() it's
|
| @@ -237,8 +392,6 @@ class LinuxProcess(object):
|
|
|
| @wrap_exceptions
|
| def get_process_cmdline(self):
|
| - if self.pid == 0:
|
| - return [] # special case for kernel process
|
| f = open("/proc/%s/cmdline" % self.pid)
|
| try:
|
| # return the args as a list
|
| @@ -247,28 +400,62 @@ class LinuxProcess(object):
|
| f.close()
|
|
|
| @wrap_exceptions
|
| + def get_process_terminal(self):
|
| + f = open("/proc/%s/stat" % self.pid)
|
| + try:
|
| + tty_nr = int(f.read().split(' ')[6])
|
| + finally:
|
| + f.close()
|
| + try:
|
| + return _TERMINAL_MAP[tty_nr]
|
| + except KeyError:
|
| + return None
|
| +
|
| + @wrap_exceptions
|
| + def get_process_io_counters(self):
|
| + f = open("/proc/%s/io" % self.pid)
|
| + try:
|
| + for line in f:
|
| + if line.startswith("rchar"):
|
| + read_count = int(line.split()[1])
|
| + elif line.startswith("wchar"):
|
| + write_count = int(line.split()[1])
|
| + elif line.startswith("read_bytes"):
|
| + read_bytes = int(line.split()[1])
|
| + elif line.startswith("write_bytes"):
|
| + write_bytes = int(line.split()[1])
|
| + return ntuple_io(read_count, write_count, read_bytes, write_bytes)
|
| + finally:
|
| + f.close()
|
| +
|
| + @wrap_exceptions
|
| def get_cpu_times(self):
|
| - # special case for 0 (kernel process) PID
|
| - if self.pid == 0:
|
| - return self._cputimes_ntuple(0.0, 0.0)
|
| f = open("/proc/%s/stat" % self.pid)
|
| - st = f.read().strip()
|
| - f.close()
|
| + try:
|
| + st = f.read().strip()
|
| + finally:
|
| + f.close()
|
| # ignore the first two values ("pid (exe)")
|
| st = st[st.find(')') + 2:]
|
| values = st.split(' ')
|
| utime = float(values[11]) / _CLOCK_TICKS
|
| stime = float(values[12]) / _CLOCK_TICKS
|
| - return self._cputimes_ntuple(utime, stime)
|
| + return ntuple_cputimes(utime, stime)
|
| +
|
| + @wrap_exceptions
|
| + def process_wait(self, timeout=None):
|
| + try:
|
| + return _psposix.wait_pid(self.pid, timeout)
|
| + except TimeoutExpired:
|
| + raise TimeoutExpired(self.pid, self._process_name)
|
|
|
| @wrap_exceptions
|
| def get_process_create_time(self):
|
| - # special case for 0 (kernel processes) PID; return system uptime
|
| - if self.pid == 0:
|
| - return _UPTIME
|
| f = open("/proc/%s/stat" % self.pid)
|
| - st = f.read().strip()
|
| - f.close()
|
| + try:
|
| + st = f.read().strip()
|
| + finally:
|
| + f.close()
|
| # ignore the first two values ("pid (exe)")
|
| st = st[st.find(')') + 2:]
|
| values = st.split(' ')
|
| @@ -276,43 +463,129 @@ class LinuxProcess(object):
|
| # unit is jiffies (clock ticks).
|
| # We first divide it for clock ticks and then add uptime returning
|
| # seconds since the epoch, in UTC.
|
| - starttime = (float(values[19]) / _CLOCK_TICKS) + _UPTIME
|
| + starttime = (float(values[19]) / _CLOCK_TICKS) + BOOT_TIME
|
| return starttime
|
|
|
| @wrap_exceptions
|
| def get_memory_info(self):
|
| - # special case for 0 (kernel processes) PID
|
| - if self.pid == 0:
|
| - return self._meminfo_ntuple(0, 0)
|
| f = open("/proc/%s/status" % self.pid)
|
| - virtual_size = 0
|
| - resident_size = 0
|
| - _flag = False
|
| - for line in f:
|
| - if (not _flag) and line.startswith("VmSize:"):
|
| - virtual_size = int(line.split()[1]) * 1024
|
| - _flag = True
|
| - elif line.startswith("VmRSS"):
|
| - resident_size = int(line.split()[1]) * 1024
|
| - break
|
| - f.close()
|
| - return self._meminfo_ntuple(resident_size, virtual_size)
|
| + try:
|
| + virtual_size = 0
|
| + resident_size = 0
|
| + _flag = False
|
| + for line in f:
|
| + if (not _flag) and line.startswith("VmSize:"):
|
| + virtual_size = int(line.split()[1]) * 1024
|
| + _flag = True
|
| + elif line.startswith("VmRSS"):
|
| + resident_size = int(line.split()[1]) * 1024
|
| + break
|
| + return ntuple_meminfo(resident_size, virtual_size)
|
| + finally:
|
| + f.close()
|
|
|
| @wrap_exceptions
|
| def get_process_cwd(self):
|
| - if self.pid == 0:
|
| - return ''
|
| - return os.readlink("/proc/%s/cwd" % self.pid)
|
| + # readlink() might return paths containing null bytes causing
|
| + # problems when used with other fs-related functions (os.*,
|
| + # open(), ...)
|
| + path = os.readlink("/proc/%s/cwd" % self.pid)
|
| + return path.replace('\x00', '')
|
|
|
| @wrap_exceptions
|
| def get_process_num_threads(self):
|
| - if self.pid == 0:
|
| - return 0
|
| f = open("/proc/%s/status" % self.pid)
|
| - for line in f:
|
| - if line.startswith("Threads:"):
|
| + try:
|
| + for line in f:
|
| + if line.startswith("Threads:"):
|
| + return int(line.split()[1])
|
| + raise RuntimeError("line not found")
|
| + finally:
|
| + f.close()
|
| +
|
| + @wrap_exceptions
|
| + def get_process_threads(self):
|
| + thread_ids = os.listdir("/proc/%s/task" % self.pid)
|
| + thread_ids.sort()
|
| + retlist = []
|
| + for thread_id in thread_ids:
|
| + try:
|
| + f = open("/proc/%s/task/%s/stat" % (self.pid, thread_id))
|
| + except (OSError, IOError), err:
|
| + if err.errno == errno.ENOENT:
|
| + # no such file or directory; it means thread
|
| + # disappeared on us
|
| + continue
|
| + raise
|
| + try:
|
| + st = f.read().strip()
|
| + finally:
|
| f.close()
|
| - return int(line.split()[1])
|
| + # ignore the first two values ("pid (exe)")
|
| + st = st[st.find(')') + 2:]
|
| + values = st.split(' ')
|
| + utime = float(values[11]) / _CLOCK_TICKS
|
| + stime = float(values[12]) / _CLOCK_TICKS
|
| + ntuple = ntuple_thread(int(thread_id), utime, stime)
|
| + retlist.append(ntuple)
|
| + return retlist
|
| +
|
| + @wrap_exceptions
|
| + def get_process_nice(self):
|
| + #f = open('/proc/%s/stat' % self.pid, 'r')
|
| + #try:
|
| + # data = f.read()
|
| + # return int(data.split()[18])
|
| + #finally:
|
| + # f.close()
|
| +
|
| + # Use C implementation
|
| + return _psutil_posix.getpriority(self.pid)
|
| +
|
| + @wrap_exceptions
|
| + def set_process_nice(self, value):
|
| + return _psutil_posix.setpriority(self.pid, value)
|
| +
|
| + # only starting from kernel 2.6.13
|
| + if hasattr(_psutil_linux, "ioprio_get"):
|
| +
|
| + @wrap_exceptions
|
| + def get_process_ionice(self):
|
| + ioclass, value = _psutil_linux.ioprio_get(self.pid)
|
| + return ntuple_ionice(ioclass, value)
|
| +
|
| + @wrap_exceptions
|
| + def set_process_ionice(self, ioclass, value):
|
| + if ioclass in (IOPRIO_CLASS_NONE, None):
|
| + if value:
|
| + raise ValueError("can't specify value with IOPRIO_CLASS_NONE")
|
| + ioclass = IOPRIO_CLASS_NONE
|
| + value = 0
|
| + if ioclass in (IOPRIO_CLASS_RT, IOPRIO_CLASS_BE):
|
| + if value is None:
|
| + value = 4
|
| + elif ioclass == IOPRIO_CLASS_IDLE:
|
| + if value:
|
| + raise ValueError("can't specify value with IOPRIO_CLASS_IDLE")
|
| + value = 0
|
| + else:
|
| + value = 0
|
| + if not 0 <= value <= 8:
|
| + raise ValueError("value argument range expected is between 0 and 8")
|
| + return _psutil_linux.ioprio_set(self.pid, ioclass, value)
|
| +
|
| + @wrap_exceptions
|
| + def get_process_status(self):
|
| + f = open("/proc/%s/status" % self.pid)
|
| + try:
|
| + for line in f:
|
| + if line.startswith("State:"):
|
| + letter = line.split()[1]
|
| + if letter in _status_map:
|
| + return _status_map[letter]
|
| + return constant(-1, '?')
|
| + finally:
|
| + f.close()
|
|
|
| @wrap_exceptions
|
| def get_open_files(self):
|
| @@ -329,20 +602,12 @@ class LinuxProcess(object):
|
| if file == "[]":
|
| continue
|
| if os.path.isfile(file) and not file in retlist:
|
| - ntuple = self._openfile_ntuple(file, int(fd))
|
| + ntuple = ntuple_openfile(file, int(fd))
|
| retlist.append(ntuple)
|
| return retlist
|
|
|
| -# --- lsof implementation
|
| -#
|
| -# def get_open_files(self):
|
| -# lsof = _psposix.LsofParser(self.pid, self._process_name)
|
| -# return lsof.get_process_open_files()
|
| -
|
| @wrap_exceptions
|
| def get_connections(self):
|
| - if self.pid == 0:
|
| - return []
|
| inodes = {}
|
| # os.listdir() is gonna raise a lot of access denied
|
| # exceptions in case of unprivileged user; that's fine:
|
| @@ -364,27 +629,37 @@ class LinuxProcess(object):
|
| def process(file, family, _type):
|
| retlist = []
|
| f = open(file)
|
| - f.readline() # skip the first line
|
| - for line in f:
|
| - _, laddr, raddr, status, _, _, _, _, _, inode = line.split()[:10]
|
| - if inode in inodes:
|
| - laddr = self._decode_address(laddr, family)
|
| - raddr = self._decode_address(raddr, family)
|
| - if _type == socket.SOCK_STREAM:
|
| - status = _TCP_STATES_TABLE[status]
|
| - else:
|
| - status = ""
|
| - fd = int(inodes[inode])
|
| - conn = self._connection_ntuple(fd, family, _type, laddr,
|
| - raddr, status)
|
| - retlist.append(conn)
|
| - f.close()
|
| - return retlist
|
| + try:
|
| + f.readline() # skip the first line
|
| + for line in f:
|
| + _, laddr, raddr, status, _, _, _, _, _, inode = \
|
| + line.split()[:10]
|
| + if inode in inodes:
|
| + laddr = self._decode_address(laddr, family)
|
| + raddr = self._decode_address(raddr, family)
|
| + if _type == socket.SOCK_STREAM:
|
| + status = _TCP_STATES_TABLE[status]
|
| + else:
|
| + status = ""
|
| + fd = int(inodes[inode])
|
| + conn = ntuple_connection(fd, family, _type, laddr,
|
| + raddr, status)
|
| + retlist.append(conn)
|
| + return retlist
|
| + finally:
|
| + f.close()
|
|
|
| tcp4 = process("/proc/net/tcp", socket.AF_INET, socket.SOCK_STREAM)
|
| - tcp6 = process("/proc/net/tcp6", socket.AF_INET6, socket.SOCK_STREAM)
|
| udp4 = process("/proc/net/udp", socket.AF_INET, socket.SOCK_DGRAM)
|
| - udp6 = process("/proc/net/udp6", socket.AF_INET6, socket.SOCK_DGRAM)
|
| + try:
|
| + tcp6 = process("/proc/net/tcp6", socket.AF_INET6, socket.SOCK_STREAM)
|
| + udp6 = process("/proc/net/udp6", socket.AF_INET6, socket.SOCK_DGRAM)
|
| + except IOError, err:
|
| + if err.errno == errno.ENOENT:
|
| + # IPv6 is not supported on this platform
|
| + tcp6 = udp6 = []
|
| + else:
|
| + raise
|
| return tcp4 + tcp6 + udp4 + udp6
|
|
|
| # --- lsof implementation
|
| @@ -395,40 +670,39 @@ class LinuxProcess(object):
|
|
|
| @wrap_exceptions
|
| def get_process_ppid(self):
|
| - if self.pid == 0:
|
| - return 0
|
| f = open("/proc/%s/status" % self.pid)
|
| - for line in f:
|
| - if line.startswith("PPid:"):
|
| - # PPid: nnnn
|
| - f.close()
|
| - return int(line.split()[1])
|
| + try:
|
| + for line in f:
|
| + if line.startswith("PPid:"):
|
| + # PPid: nnnn
|
| + return int(line.split()[1])
|
| + raise RuntimeError("line not found")
|
| + finally:
|
| + f.close()
|
|
|
| @wrap_exceptions
|
| - def get_process_uid(self):
|
| - if self.pid == 0:
|
| - return 0
|
| + def get_process_uids(self):
|
| f = open("/proc/%s/status" % self.pid)
|
| - for line in f:
|
| - if line.startswith('Uid:'):
|
| - # Uid line provides 4 values which stand for real,
|
| - # effective, saved set, and file system UIDs.
|
| - # We want to provide real UID only.
|
| - f.close()
|
| - return int(line.split()[1])
|
| + try:
|
| + for line in f:
|
| + if line.startswith('Uid:'):
|
| + _, real, effective, saved, fs = line.split()
|
| + return ntuple_uids(int(real), int(effective), int(saved))
|
| + raise RuntimeError("line not found")
|
| + finally:
|
| + f.close()
|
|
|
| @wrap_exceptions
|
| - def get_process_gid(self):
|
| - if self.pid == 0:
|
| - return 0
|
| + def get_process_gids(self):
|
| f = open("/proc/%s/status" % self.pid)
|
| - for line in f:
|
| - if line.startswith('Gid:'):
|
| - # Uid line provides 4 values which stand for real,
|
| - # effective, saved set, and file system GIDs.
|
| - # We want to provide real GID only.
|
| - f.close()
|
| - return int(line.split()[1])
|
| + try:
|
| + for line in f:
|
| + if line.startswith('Gid:'):
|
| + _, real, effective, saved, fs = line.split()
|
| + return ntuple_gids(int(real), int(effective), int(saved))
|
| + raise RuntimeError("line not found")
|
| + finally:
|
| + f.close()
|
|
|
| @staticmethod
|
| def _decode_address(addr, family):
|
| @@ -438,9 +712,9 @@ class LinuxProcess(object):
|
| "0500000A:0016" -> ("10.0.0.5", 22)
|
| "0000000000000000FFFF00000100007F:9E49" -> ("::ffff:127.0.0.1", 40521)
|
|
|
| - The IPv4 address portion is a little-endian four-byte hexadecimal
|
| - number; that is, the least significant byte is listed first,
|
| - so we need to reverse the order of the bytes to convert it
|
| + The IP address portion is a little or big endian four-byte
|
| + hexadecimal number; that is, the least significant byte is listed
|
| + first, so we need to reverse the order of the bytes to convert it
|
| to an IP address.
|
| The port is represented as a two-byte hexadecimal number.
|
|
|
| @@ -456,16 +730,22 @@ class LinuxProcess(object):
|
| if not port:
|
| return ()
|
| if family == socket.AF_INET:
|
| - ip = socket.inet_ntop(family, base64.b16decode(ip)[::-1])
|
| + # see: http://code.google.com/p/psutil/issues/detail?id=201
|
| + if sys.byteorder == 'little':
|
| + ip = socket.inet_ntop(family, base64.b16decode(ip)[::-1])
|
| + else:
|
| + ip = socket.inet_ntop(family, base64.b16decode(ip))
|
| else: # IPv6
|
| # old version - let's keep it, just in case...
|
| #ip = ip.decode('hex')
|
| #return socket.inet_ntop(socket.AF_INET6,
|
| # ''.join(ip[i:i+4][::-1] for i in xrange(0, 16, 4)))
|
| ip = base64.b16decode(ip)
|
| - ip = socket.inet_ntop(socket.AF_INET6,
|
| + # see: http://code.google.com/p/psutil/issues/detail?id=201
|
| + if sys.byteorder == 'little':
|
| + ip = socket.inet_ntop(socket.AF_INET6,
|
| struct.pack('>4I', *struct.unpack('<4I', ip)))
|
| + else:
|
| + ip = socket.inet_ntop(socket.AF_INET6,
|
| + struct.pack('<4I', *struct.unpack('<4I', ip)))
|
| return (ip, port)
|
| -
|
| -PlatformProcess = LinuxProcess
|
| -
|
|
|