| #!/usr/bin/env python |
| |
| # 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. |
| |
| """Windows platform implementation.""" |
| |
| import errno |
| import os |
| import sys |
| import platform |
| import warnings |
| |
| import _psutil_mswindows |
| from _psutil_mswindows import ERROR_ACCESS_DENIED |
| from psutil._error import AccessDenied, NoSuchProcess, TimeoutExpired |
| from psutil._common import * |
| from psutil._compat import PY3, xrange, long, wraps |
| |
| # Windows specific extended namespace |
| __extra__all__ = ["ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS", |
| "HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS", |
| "NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS"] |
| |
| |
| # --- module level constants (gets pushed up to psutil module) |
| |
| # Since these constants get determined at import time we do not want to |
| # crash immediately; instead we'll set them to None and most likely |
| # we'll crash later as they're used for determining process CPU stats |
| # and creation_time |
| try: |
| NUM_CPUS = _psutil_mswindows.get_num_cpus() |
| except Exception: |
| NUM_CPUS = None |
| warnings.warn("couldn't determine platform's NUM_CPUS", RuntimeWarning) |
| try: |
| BOOT_TIME = _psutil_mswindows.get_system_boot_time() |
| except Exception: |
| BOOT_TIME = None |
| warnings.warn("couldn't determine platform's BOOT_TIME", RuntimeWarning) |
| try: |
| TOTAL_PHYMEM = _psutil_mswindows.get_virtual_mem()[0] |
| except Exception: |
| TOTAL_PHYMEM = None |
| warnings.warn("couldn't determine platform's TOTAL_PHYMEM", RuntimeWarning) |
| |
| WAIT_TIMEOUT = 0x00000102 # 258 in decimal |
| ACCESS_DENIED_SET = frozenset([errno.EPERM, errno.EACCES, ERROR_ACCESS_DENIED]) |
| |
| # process priority constants: |
| # http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx |
| from _psutil_mswindows import (ABOVE_NORMAL_PRIORITY_CLASS, |
| BELOW_NORMAL_PRIORITY_CLASS, |
| HIGH_PRIORITY_CLASS, |
| IDLE_PRIORITY_CLASS, |
| NORMAL_PRIORITY_CLASS, |
| REALTIME_PRIORITY_CLASS, |
| INFINITE) |
| |
| @memoize |
| def _win32_QueryDosDevice(s): |
| return _psutil_mswindows.win32_QueryDosDevice(s) |
| |
| def _convert_raw_path(s): |
| # convert paths using native DOS format like: |
| # "\Device\HarddiskVolume1\Windows\systemew\file.txt" |
| # into: "C:\Windows\systemew\file.txt" |
| if PY3 and not isinstance(s, str): |
| s = s.decode('utf8') |
| rawdrive = '\\'.join(s.split('\\')[:3]) |
| driveletter = _win32_QueryDosDevice(rawdrive) |
| return os.path.join(driveletter, s[len(rawdrive):]) |
| |
| |
| # --- public functions |
| |
| get_system_boot_time = _psutil_mswindows.get_system_boot_time |
| |
| nt_virtmem_info = namedtuple('vmem', ' '.join([ |
| # all platforms |
| 'total', 'available', 'percent', 'used', 'free'])) |
| |
| def virtual_memory(): |
| """System virtual memory as a namedtuple.""" |
| mem = _psutil_mswindows.get_virtual_mem() |
| totphys, availphys, totpagef, availpagef, totvirt, freevirt = mem |
| # |
| total = totphys |
| avail = availphys |
| free = availphys |
| used = total - avail |
| percent = usage_percent((total - avail), total, _round=1) |
| return nt_virtmem_info(total, avail, percent, used, free) |
| |
| def swap_memory(): |
| """Swap system memory as a (total, used, free, sin, sout) tuple.""" |
| mem = _psutil_mswindows.get_virtual_mem() |
| total = mem[2] |
| free = mem[3] |
| used = total - free |
| percent = usage_percent(used, total, _round=1) |
| return nt_swapmeminfo(total, used, free, percent, 0, 0) |
| |
| def get_disk_usage(path): |
| """Return disk usage associated with path.""" |
| try: |
| total, free = _psutil_mswindows.get_disk_usage(path) |
| except WindowsError: |
| err = sys.exc_info()[1] |
| if not os.path.exists(path): |
| raise OSError(errno.ENOENT, "No such file or directory: '%s'" % path) |
| raise |
| used = total - free |
| percent = usage_percent(used, total, _round=1) |
| return nt_diskinfo(total, used, free, percent) |
| |
| def disk_partitions(all): |
| """Return disk partitions.""" |
| rawlist = _psutil_mswindows.get_disk_partitions(all) |
| return [nt_partition(*x) for x in rawlist] |
| |
| |
| _cputimes_ntuple = namedtuple('cputimes', 'user system idle') |
| |
| def get_system_cpu_times(): |
| """Return system CPU times as a named tuple.""" |
| user, system, idle = 0, 0, 0 |
| # computes system global times summing each processor value |
| for cpu_time in _psutil_mswindows.get_system_cpu_times(): |
| user += cpu_time[0] |
| system += cpu_time[1] |
| idle += cpu_time[2] |
| return _cputimes_ntuple(user, system, idle) |
| |
| def get_system_per_cpu_times(): |
| """Return system per-CPU times as a list of named tuples.""" |
| ret = [] |
| for cpu_t in _psutil_mswindows.get_system_cpu_times(): |
| user, system, idle = cpu_t |
| item = _cputimes_ntuple(user, system, idle) |
| ret.append(item) |
| return ret |
| |
| def get_system_users(): |
| """Return currently connected users as a list of namedtuples.""" |
| retlist = [] |
| rawlist = _psutil_mswindows.get_system_users() |
| for item in rawlist: |
| user, hostname, tstamp = item |
| nt = nt_user(user, None, hostname, tstamp) |
| retlist.append(nt) |
| return retlist |
| |
| get_pid_list = _psutil_mswindows.get_pid_list |
| pid_exists = _psutil_mswindows.pid_exists |
| network_io_counters = _psutil_mswindows.get_network_io_counters |
| disk_io_counters = _psutil_mswindows.get_disk_io_counters |
| |
| # --- decorator |
| |
| def wrap_exceptions(fun): |
| """Decorator which translates bare OSError and WindowsError |
| exceptions into NoSuchProcess and AccessDenied. |
| """ |
| @wraps(fun) |
| def wrapper(self, *args, **kwargs): |
| try: |
| return fun(self, *args, **kwargs) |
| except OSError: |
| err = sys.exc_info()[1] |
| if err.errno in ACCESS_DENIED_SET: |
| raise AccessDenied(self.pid, self._process_name) |
| if err.errno == errno.ESRCH: |
| raise NoSuchProcess(self.pid, self._process_name) |
| raise |
| return wrapper |
| |
| |
| class Process(object): |
| """Wrapper class around underlying C implementation.""" |
| |
| __slots__ = ["pid", "_process_name"] |
| |
| def __init__(self, pid): |
| self.pid = pid |
| self._process_name = None |
| |
| @wrap_exceptions |
| def get_process_name(self): |
| """Return process name as a string of limited len (15).""" |
| return _psutil_mswindows.get_process_name(self.pid) |
| |
| @wrap_exceptions |
| def get_process_exe(self): |
| # Note: os.path.exists(path) may return False even if the file |
| # is there, see: |
| # http://stackoverflow.com/questions/3112546/os-path-exists-lies |
| return _convert_raw_path(_psutil_mswindows.get_process_exe(self.pid)) |
| |
| @wrap_exceptions |
| def get_process_cmdline(self): |
| """Return process cmdline as a list of arguments.""" |
| return _psutil_mswindows.get_process_cmdline(self.pid) |
| |
| @wrap_exceptions |
| def get_process_ppid(self): |
| """Return process parent pid.""" |
| return _psutil_mswindows.get_process_ppid(self.pid) |
| |
| def _get_raw_meminfo(self): |
| try: |
| return _psutil_mswindows.get_process_memory_info(self.pid) |
| except OSError: |
| err = sys.exc_info()[1] |
| if err.errno in ACCESS_DENIED_SET: |
| return _psutil_mswindows.get_process_memory_info_2(self.pid) |
| raise |
| |
| @wrap_exceptions |
| def get_memory_info(self): |
| """Returns a tuple or RSS/VMS memory usage in bytes.""" |
| # on Windows RSS == WorkingSetSize and VSM == PagefileUsage |
| # fields of PROCESS_MEMORY_COUNTERS struct: |
| # http://msdn.microsoft.com/en-us/library/windows/desktop/ms684877(v=vs.85).aspx |
| t = self._get_raw_meminfo() |
| return nt_meminfo(t[2], t[7]) |
| |
| _nt_ext_mem = namedtuple('meminfo', |
| ' '.join(['num_page_faults', |
| 'peak_wset', |
| 'wset', |
| 'peak_paged_pool', |
| 'paged_pool', |
| 'peak_nonpaged_pool', |
| 'nonpaged_pool', |
| 'pagefile', |
| 'peak_pagefile', |
| 'private',])) |
| |
| @wrap_exceptions |
| def get_ext_memory_info(self): |
| return self._nt_ext_mem(*self._get_raw_meminfo()) |
| |
| nt_mmap_grouped = namedtuple('mmap', 'path rss') |
| nt_mmap_ext = namedtuple('mmap', 'addr perms path rss') |
| |
| def get_memory_maps(self): |
| try: |
| raw = _psutil_mswindows.get_process_memory_maps(self.pid) |
| except OSError: |
| # XXX - can't use wrap_exceptions decorator as we're |
| # returning a generator; probably needs refactoring. |
| err = sys.exc_info()[1] |
| if err.errno in (errno.EPERM, errno.EACCES, ERROR_ACCESS_DENIED): |
| raise AccessDenied(self.pid, self._process_name) |
| if err.errno == errno.ESRCH: |
| raise NoSuchProcess(self.pid, self._process_name) |
| raise |
| else: |
| for addr, perm, path, rss in raw: |
| path = _convert_raw_path(path) |
| addr = hex(addr) |
| yield (addr, perm, path, rss) |
| |
| @wrap_exceptions |
| def kill_process(self): |
| """Terminates the process with the given PID.""" |
| return _psutil_mswindows.kill_process(self.pid) |
| |
| @wrap_exceptions |
| def process_wait(self, timeout=None): |
| if timeout is None: |
| timeout = INFINITE |
| else: |
| # WaitForSingleObject() expects time in milliseconds |
| timeout = int(timeout * 1000) |
| ret = _psutil_mswindows.process_wait(self.pid, timeout) |
| if ret == WAIT_TIMEOUT: |
| raise TimeoutExpired(self.pid, self._process_name) |
| return ret |
| |
| @wrap_exceptions |
| def get_process_username(self): |
| """Return the name of the user that owns the process""" |
| if self.pid in (0, 4): |
| return 'NT AUTHORITY\\SYSTEM' |
| return _psutil_mswindows.get_process_username(self.pid) |
| |
| @wrap_exceptions |
| def get_process_create_time(self): |
| # special case for kernel process PIDs; return system boot time |
| if self.pid in (0, 4): |
| return BOOT_TIME |
| try: |
| return _psutil_mswindows.get_process_create_time(self.pid) |
| except OSError: |
| err = sys.exc_info()[1] |
| if err.errno in ACCESS_DENIED_SET: |
| return _psutil_mswindows.get_process_create_time_2(self.pid) |
| raise |
| |
| @wrap_exceptions |
| def get_process_num_threads(self): |
| return _psutil_mswindows.get_process_num_threads(self.pid) |
| |
| @wrap_exceptions |
| def get_process_threads(self): |
| rawlist = _psutil_mswindows.get_process_threads(self.pid) |
| retlist = [] |
| for thread_id, utime, stime in rawlist: |
| ntuple = nt_thread(thread_id, utime, stime) |
| retlist.append(ntuple) |
| return retlist |
| |
| @wrap_exceptions |
| def get_cpu_times(self): |
| try: |
| ret = _psutil_mswindows.get_process_cpu_times(self.pid) |
| except OSError: |
| err = sys.exc_info()[1] |
| if err.errno in ACCESS_DENIED_SET: |
| ret = _psutil_mswindows.get_process_cpu_times_2(self.pid) |
| else: |
| raise |
| return nt_cputimes(*ret) |
| |
| @wrap_exceptions |
| def suspend_process(self): |
| return _psutil_mswindows.suspend_process(self.pid) |
| |
| @wrap_exceptions |
| def resume_process(self): |
| return _psutil_mswindows.resume_process(self.pid) |
| |
| @wrap_exceptions |
| def get_process_cwd(self): |
| if self.pid in (0, 4): |
| raise AccessDenied(self.pid, self._process_name) |
| # return a normalized pathname since the native C function appends |
| # "\\" at the and of the path |
| path = _psutil_mswindows.get_process_cwd(self.pid) |
| return os.path.normpath(path) |
| |
| @wrap_exceptions |
| def get_open_files(self): |
| if self.pid in (0, 4): |
| return [] |
| retlist = [] |
| # Filenames come in in native format like: |
| # "\Device\HarddiskVolume1\Windows\systemew\file.txt" |
| # Convert the first part in the corresponding drive letter |
| # (e.g. "C:\") by using Windows's QueryDosDevice() |
| raw_file_names = _psutil_mswindows.get_process_open_files(self.pid) |
| for file in raw_file_names: |
| file = _convert_raw_path(file) |
| if isfile_strict(file) and file not in retlist: |
| ntuple = nt_openfile(file, -1) |
| retlist.append(ntuple) |
| return retlist |
| |
| @wrap_exceptions |
| def get_connections(self, kind='inet'): |
| if kind not in conn_tmap: |
| raise ValueError("invalid %r kind argument; choose between %s" |
| % (kind, ', '.join([repr(x) for x in conn_tmap]))) |
| families, types = conn_tmap[kind] |
| ret = _psutil_mswindows.get_process_connections(self.pid, families, types) |
| return [nt_connection(*conn) for conn in ret] |
| |
| @wrap_exceptions |
| def get_process_nice(self): |
| return _psutil_mswindows.get_process_priority(self.pid) |
| |
| @wrap_exceptions |
| def set_process_nice(self, value): |
| return _psutil_mswindows.set_process_priority(self.pid, value) |
| |
| # available on Windows >= Vista |
| if hasattr(_psutil_mswindows, "get_process_io_priority"): |
| @wrap_exceptions |
| def get_process_ionice(self): |
| return _psutil_mswindows.get_process_io_priority(self.pid) |
| |
| @wrap_exceptions |
| def set_process_ionice(self, value, _): |
| if _: |
| raise TypeError("set_process_ionice() on Windows takes only " \ |
| "1 argument (2 given)") |
| if value not in (2, 1, 0): |
| raise ValueError("value must be 2 (normal), 1 (low) or 0 " \ |
| "(very low); got %r" % value) |
| return _psutil_mswindows.set_process_io_priority(self.pid, value) |
| |
| @wrap_exceptions |
| def get_process_io_counters(self): |
| try: |
| ret = _psutil_mswindows.get_process_io_counters(self.pid) |
| except OSError: |
| err = sys.exc_info()[1] |
| if err.errno in ACCESS_DENIED_SET: |
| ret = _psutil_mswindows.get_process_io_counters_2(self.pid) |
| else: |
| raise |
| return nt_io(*ret) |
| |
| @wrap_exceptions |
| def get_process_status(self): |
| suspended = _psutil_mswindows.is_process_suspended(self.pid) |
| if suspended: |
| return STATUS_STOPPED |
| else: |
| return STATUS_RUNNING |
| |
| @wrap_exceptions |
| def get_process_cpu_affinity(self): |
| from_bitmask = lambda x: [i for i in xrange(64) if (1 << i) & x] |
| bitmask = _psutil_mswindows.get_process_cpu_affinity(self.pid) |
| return from_bitmask(bitmask) |
| |
| @wrap_exceptions |
| def set_process_cpu_affinity(self, value): |
| def to_bitmask(l): |
| if not l: |
| raise ValueError("invalid argument %r" % l) |
| out = 0 |
| for b in l: |
| out |= 2**b |
| return out |
| |
| # SetProcessAffinityMask() states that ERROR_INVALID_PARAMETER |
| # is returned for an invalid CPU but this seems not to be true, |
| # therefore we check CPUs validy beforehand. |
| allcpus = list(range(len(get_system_per_cpu_times()))) |
| for cpu in value: |
| if cpu not in allcpus: |
| raise ValueError("invalid CPU %r" % cpu) |
| |
| bitmask = to_bitmask(value) |
| _psutil_mswindows.set_process_cpu_affinity(self.pid, bitmask) |
| |
| @wrap_exceptions |
| def get_num_handles(self): |
| try: |
| return _psutil_mswindows.get_process_num_handles(self.pid) |
| except OSError: |
| err = sys.exc_info()[1] |
| if err.errno in ACCESS_DENIED_SET: |
| return _psutil_mswindows.get_process_num_handles_2(self.pid) |
| raise |
| |
| @wrap_exceptions |
| def get_num_ctx_switches(self): |
| return nt_ctxsw(*_psutil_mswindows.get_process_num_ctx_switches(self.pid)) |