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