1# -*- coding: utf-8 -*-
2
3# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""psutil is a cross-platform library for retrieving information on
8running processes and system utilization (CPU, memory, disks, network,
9sensors) in Python. Supported platforms:
10
11 - Linux
12 - Windows
13 - macOS
14 - FreeBSD
15 - OpenBSD
16 - NetBSD
17 - Sun Solaris
18 - AIX
19
20Works with Python versions from 2.6 to 3.4+.
21"""
22
23from __future__ import division
24import collections
25import contextlib
26import datetime
27import functools
28import os
29import signal
30import subprocess
31import sys
32import threading
33import time
34try:
35    import pwd
36except ImportError:
37    pwd = None
38
39from . import _common
40from ._common import AccessDenied
41from ._common import Error
42from ._common import memoize_when_activated
43from ._common import NoSuchProcess
44from ._common import TimeoutExpired
45from ._common import wrap_numbers as _wrap_numbers
46from ._common import ZombieProcess
47from ._compat import long
48from ._compat import PermissionError
49from ._compat import ProcessLookupError
50from ._compat import PY3 as _PY3
51
52from ._common import CONN_CLOSE
53from ._common import CONN_CLOSE_WAIT
54from ._common import CONN_CLOSING
55from ._common import CONN_ESTABLISHED
56from ._common import CONN_FIN_WAIT1
57from ._common import CONN_FIN_WAIT2
58from ._common import CONN_LAST_ACK
59from ._common import CONN_LISTEN
60from ._common import CONN_NONE
61from ._common import CONN_SYN_RECV
62from ._common import CONN_SYN_SENT
63from ._common import CONN_TIME_WAIT
64from ._common import NIC_DUPLEX_FULL
65from ._common import NIC_DUPLEX_HALF
66from ._common import NIC_DUPLEX_UNKNOWN
67from ._common import POWER_TIME_UNKNOWN
68from ._common import POWER_TIME_UNLIMITED
69from ._common import STATUS_DEAD
70from ._common import STATUS_DISK_SLEEP
71from ._common import STATUS_IDLE
72from ._common import STATUS_LOCKED
73from ._common import STATUS_PARKED
74from ._common import STATUS_RUNNING
75from ._common import STATUS_SLEEPING
76from ._common import STATUS_STOPPED
77from ._common import STATUS_TRACING_STOP
78from ._common import STATUS_WAITING
79from ._common import STATUS_WAKING
80from ._common import STATUS_ZOMBIE
81
82from ._common import AIX
83from ._common import BSD
84from ._common import FREEBSD  # NOQA
85from ._common import LINUX
86from ._common import MACOS
87from ._common import NETBSD  # NOQA
88from ._common import OPENBSD  # NOQA
89from ._common import DRAGONFLY # NOQA
90from ._common import OSX  # deprecated alias
91from ._common import POSIX  # NOQA
92from ._common import SUNOS
93from ._common import WINDOWS
94
95if LINUX:
96    # This is public API and it will be retrieved from _pslinux.py
97    # via sys.modules.
98    PROCFS_PATH = "/proc"
99
100    from . import _pslinux as _psplatform
101
102    from ._pslinux import IOPRIO_CLASS_BE  # NOQA
103    from ._pslinux import IOPRIO_CLASS_IDLE  # NOQA
104    from ._pslinux import IOPRIO_CLASS_NONE  # NOQA
105    from ._pslinux import IOPRIO_CLASS_RT  # NOQA
106
107elif WINDOWS:
108    from . import _pswindows as _psplatform
109    from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS  # NOQA
110    from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS  # NOQA
111    from ._psutil_windows import HIGH_PRIORITY_CLASS  # NOQA
112    from ._psutil_windows import IDLE_PRIORITY_CLASS  # NOQA
113    from ._psutil_windows import NORMAL_PRIORITY_CLASS  # NOQA
114    from ._psutil_windows import REALTIME_PRIORITY_CLASS  # NOQA
115    from ._pswindows import CONN_DELETE_TCB  # NOQA
116    from ._pswindows import IOPRIO_VERYLOW  # NOQA
117    from ._pswindows import IOPRIO_LOW  # NOQA
118    from ._pswindows import IOPRIO_NORMAL  # NOQA
119    from ._pswindows import IOPRIO_HIGH  # NOQA
120
121elif MACOS:
122    from . import _psosx as _psplatform
123
124elif BSD:
125    from . import _psbsd as _psplatform
126
127elif SUNOS:
128    from . import _pssunos as _psplatform
129    from ._pssunos import CONN_BOUND  # NOQA
130    from ._pssunos import CONN_IDLE  # NOQA
131
132    # This is public writable API which is read from _pslinux.py and
133    # _pssunos.py via sys.modules.
134    PROCFS_PATH = "/proc"
135
136elif AIX:
137    from . import _psaix as _psplatform
138
139    # This is public API and it will be retrieved from _pslinux.py
140    # via sys.modules.
141    PROCFS_PATH = "/proc"
142
143else:  # pragma: no cover
144    raise NotImplementedError('platform %s is not supported' % sys.platform)
145
146
147__all__ = [
148    # exceptions
149    "Error", "NoSuchProcess", "ZombieProcess", "AccessDenied",
150    "TimeoutExpired",
151
152    # constants
153    "version_info", "__version__",
154
155    "STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP",
156    "STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD",
157    "STATUS_WAKING", "STATUS_LOCKED", "STATUS_WAITING", "STATUS_LOCKED",
158    "STATUS_PARKED",
159
160    "CONN_ESTABLISHED", "CONN_SYN_SENT", "CONN_SYN_RECV", "CONN_FIN_WAIT1",
161    "CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT",
162    "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", "CONN_NONE",
163    # "CONN_IDLE", "CONN_BOUND",
164
165    "AF_LINK",
166
167    "NIC_DUPLEX_FULL", "NIC_DUPLEX_HALF", "NIC_DUPLEX_UNKNOWN",
168
169    "POWER_TIME_UNKNOWN", "POWER_TIME_UNLIMITED",
170
171    "BSD", "FREEBSD", "LINUX", "NETBSD", "OPENBSD", "MACOS", "OSX", "POSIX",
172    "SUNOS", "WINDOWS", "AIX", "DRAGONFLY",
173
174    # "RLIM_INFINITY", "RLIMIT_AS", "RLIMIT_CORE", "RLIMIT_CPU", "RLIMIT_DATA",
175    # "RLIMIT_FSIZE", "RLIMIT_LOCKS", "RLIMIT_MEMLOCK", "RLIMIT_NOFILE",
176    # "RLIMIT_NPROC", "RLIMIT_RSS", "RLIMIT_STACK", "RLIMIT_MSGQUEUE",
177    # "RLIMIT_NICE", "RLIMIT_RTPRIO", "RLIMIT_RTTIME", "RLIMIT_SIGPENDING",
178
179    # classes
180    "Process", "Popen",
181
182    # functions
183    "pid_exists", "pids", "process_iter", "wait_procs",             # proc
184    "virtual_memory", "swap_memory",                                # memory
185    "cpu_times", "cpu_percent", "cpu_times_percent", "cpu_count",   # cpu
186    "cpu_stats",  # "cpu_freq", "getloadavg"
187    "net_io_counters", "net_connections", "net_if_addrs",           # network
188    "net_if_stats",
189    "disk_io_counters", "disk_partitions", "disk_usage",            # disk
190    # "sensors_temperatures", "sensors_battery", "sensors_fans"     # sensors
191    "users", "boot_time",                                           # others
192]
193
194
195__all__.extend(_psplatform.__extra__all__)
196
197# Linux, FreeBSD
198if hasattr(_psplatform.Process, "rlimit"):
199    # Populate global namespace with RLIM* constants.
200    from . import _psutil_posix
201
202    _globals = globals()
203    _name = None
204    for _name in dir(_psutil_posix):
205        if _name.startswith('RLIM') and _name.isupper():
206            _globals[_name] = getattr(_psutil_posix, _name)
207            __all__.append(_name)
208    del _globals, _name
209
210AF_LINK = _psplatform.AF_LINK
211
212__author__ = "Giampaolo Rodola'"
213__version__ = "5.8.0"
214version_info = tuple([int(num) for num in __version__.split('.')])
215
216_timer = getattr(time, 'monotonic', time.time)
217_TOTAL_PHYMEM = None
218_LOWEST_PID = None
219_SENTINEL = object()
220
221# Sanity check in case the user messed up with psutil installation
222# or did something weird with sys.path. In this case we might end
223# up importing a python module using a C extension module which
224# was compiled for a different version of psutil.
225# We want to prevent that by failing sooner rather than later.
226# See: https://github.com/giampaolo/psutil/issues/564
227if (int(__version__.replace('.', '')) !=
228        getattr(_psplatform.cext, 'version', None)):
229    msg = "version conflict: %r C extension module was built for another " \
230          "version of psutil" % getattr(_psplatform.cext, "__file__")
231    if hasattr(_psplatform.cext, 'version'):
232        msg += " (%s instead of %s)" % (
233            '.'.join([x for x in str(_psplatform.cext.version)]), __version__)
234    else:
235        msg += " (different than %s)" % __version__
236    msg += "; you may try to 'pip uninstall psutil', manually remove %s" % (
237        getattr(_psplatform.cext, "__file__",
238                "the existing psutil install directory"))
239    msg += " or clean the virtual env somehow, then reinstall"
240    raise ImportError(msg)
241
242
243# =====================================================================
244# --- Utils
245# =====================================================================
246
247
248if hasattr(_psplatform, 'ppid_map'):
249    # Faster version (Windows and Linux).
250    _ppid_map = _psplatform.ppid_map
251else:  # pragma: no cover
252    def _ppid_map():
253        """Return a {pid: ppid, ...} dict for all running processes in
254        one shot. Used to speed up Process.children().
255        """
256        ret = {}
257        for pid in pids():
258            try:
259                ret[pid] = _psplatform.Process(pid).ppid()
260            except (NoSuchProcess, ZombieProcess):
261                pass
262        return ret
263
264
265def _assert_pid_not_reused(fun):
266    """Decorator which raises NoSuchProcess in case a process is no
267    longer running or its PID has been reused.
268    """
269    @functools.wraps(fun)
270    def wrapper(self, *args, **kwargs):
271        if not self.is_running():
272            raise NoSuchProcess(self.pid, self._name)
273        return fun(self, *args, **kwargs)
274    return wrapper
275
276
277def _pprint_secs(secs):
278    """Format seconds in a human readable form."""
279    now = time.time()
280    secs_ago = int(now - secs)
281    if secs_ago < 60 * 60 * 24:
282        fmt = "%H:%M:%S"
283    else:
284        fmt = "%Y-%m-%d %H:%M:%S"
285    return datetime.datetime.fromtimestamp(secs).strftime(fmt)
286
287
288# =====================================================================
289# --- Process class
290# =====================================================================
291
292
293class Process(object):
294    """Represents an OS process with the given PID.
295    If PID is omitted current process PID (os.getpid()) is used.
296    Raise NoSuchProcess if PID does not exist.
297
298    Note that most of the methods of this class do not make sure
299    the PID of the process being queried has been reused over time.
300    That means you might end up retrieving an information referring
301    to another process in case the original one this instance
302    refers to is gone in the meantime.
303
304    The only exceptions for which process identity is pre-emptively
305    checked and guaranteed are:
306
307     - parent()
308     - children()
309     - nice() (set)
310     - ionice() (set)
311     - rlimit() (set)
312     - cpu_affinity (set)
313     - suspend()
314     - resume()
315     - send_signal()
316     - terminate()
317     - kill()
318
319    To prevent this problem for all other methods you can:
320     - use is_running() before querying the process
321     - if you're continuously iterating over a set of Process
322       instances use process_iter() which pre-emptively checks
323     process identity for every yielded instance
324    """
325
326    def __init__(self, pid=None):
327        self._init(pid)
328
329    def _init(self, pid, _ignore_nsp=False):
330        if pid is None:
331            pid = os.getpid()
332        else:
333            if not _PY3 and not isinstance(pid, (int, long)):
334                raise TypeError('pid must be an integer (got %r)' % pid)
335            if pid < 0:
336                raise ValueError('pid must be a positive integer (got %s)'
337                                 % pid)
338        self._pid = pid
339        self._name = None
340        self._exe = None
341        self._create_time = None
342        self._gone = False
343        self._hash = None
344        self._lock = threading.RLock()
345        # used for caching on Windows only (on POSIX ppid may change)
346        self._ppid = None
347        # platform-specific modules define an _psplatform.Process
348        # implementation class
349        self._proc = _psplatform.Process(pid)
350        self._last_sys_cpu_times = None
351        self._last_proc_cpu_times = None
352        self._exitcode = _SENTINEL
353        # cache creation time for later use in is_running() method
354        try:
355            self.create_time()
356        except AccessDenied:
357            # We should never get here as AFAIK we're able to get
358            # process creation time on all platforms even as a
359            # limited user.
360            pass
361        except ZombieProcess:
362            # Zombies can still be queried by this class (although
363            # not always) and pids() return them so just go on.
364            pass
365        except NoSuchProcess:
366            if not _ignore_nsp:
367                msg = 'no process found with pid %s' % pid
368                raise NoSuchProcess(pid, None, msg)
369            else:
370                self._gone = True
371        # This pair is supposed to indentify a Process instance
372        # univocally over time (the PID alone is not enough as
373        # it might refer to a process whose PID has been reused).
374        # This will be used later in __eq__() and is_running().
375        self._ident = (self.pid, self._create_time)
376
377    def __str__(self):
378        try:
379            info = collections.OrderedDict()
380        except AttributeError:  # pragma: no cover
381            info = {}  # Python 2.6
382        info["pid"] = self.pid
383        if self._name:
384            info['name'] = self._name
385        with self.oneshot():
386            try:
387                info["name"] = self.name()
388                info["status"] = self.status()
389            except ZombieProcess:
390                info["status"] = "zombie"
391            except NoSuchProcess:
392                info["status"] = "terminated"
393            except AccessDenied:
394                pass
395            if self._exitcode not in (_SENTINEL, None):
396                info["exitcode"] = self._exitcode
397            if self._create_time:
398                info['started'] = _pprint_secs(self._create_time)
399            return "%s.%s(%s)" % (
400                self.__class__.__module__,
401                self.__class__.__name__,
402                ", ".join(["%s=%r" % (k, v) for k, v in info.items()]))
403
404    __repr__ = __str__
405
406    def __eq__(self, other):
407        # Test for equality with another Process object based
408        # on PID and creation time.
409        if not isinstance(other, Process):
410            return NotImplemented
411        return self._ident == other._ident
412
413    def __ne__(self, other):
414        return not self == other
415
416    def __hash__(self):
417        if self._hash is None:
418            self._hash = hash(self._ident)
419        return self._hash
420
421    @property
422    def pid(self):
423        """The process PID."""
424        return self._pid
425
426    # --- utility methods
427
428    @contextlib.contextmanager
429    def oneshot(self):
430        """Utility context manager which considerably speeds up the
431        retrieval of multiple process information at the same time.
432
433        Internally different process info (e.g. name, ppid, uids,
434        gids, ...) may be fetched by using the same routine, but
435        only one information is returned and the others are discarded.
436        When using this context manager the internal routine is
437        executed once (in the example below on name()) and the
438        other info are cached.
439
440        The cache is cleared when exiting the context manager block.
441        The advice is to use this every time you retrieve more than
442        one information about the process. If you're lucky, you'll
443        get a hell of a speedup.
444
445        >>> import psutil
446        >>> p = psutil.Process()
447        >>> with p.oneshot():
448        ...     p.name()  # collect multiple info
449        ...     p.cpu_times()  # return cached value
450        ...     p.cpu_percent()  # return cached value
451        ...     p.create_time()  # return cached value
452        ...
453        >>>
454        """
455        with self._lock:
456            if hasattr(self, "_cache"):
457                # NOOP: this covers the use case where the user enters the
458                # context twice:
459                #
460                # >>> with p.oneshot():
461                # ...    with p.oneshot():
462                # ...
463                #
464                # Also, since as_dict() internally uses oneshot()
465                # I expect that the code below will be a pretty common
466                # "mistake" that the user will make, so let's guard
467                # against that:
468                #
469                # >>> with p.oneshot():
470                # ...    p.as_dict()
471                # ...
472                yield
473            else:
474                try:
475                    # cached in case cpu_percent() is used
476                    self.cpu_times.cache_activate(self)
477                    # cached in case memory_percent() is used
478                    self.memory_info.cache_activate(self)
479                    # cached in case parent() is used
480                    self.ppid.cache_activate(self)
481                    # cached in case username() is used
482                    if POSIX:
483                        self.uids.cache_activate(self)
484                    # specific implementation cache
485                    self._proc.oneshot_enter()
486                    yield
487                finally:
488                    self.cpu_times.cache_deactivate(self)
489                    self.memory_info.cache_deactivate(self)
490                    self.ppid.cache_deactivate(self)
491                    if POSIX:
492                        self.uids.cache_deactivate(self)
493                    self._proc.oneshot_exit()
494
495    def as_dict(self, attrs=None, ad_value=None):
496        """Utility method returning process information as a
497        hashable dictionary.
498        If *attrs* is specified it must be a list of strings
499        reflecting available Process class' attribute names
500        (e.g. ['cpu_times', 'name']) else all public (read
501        only) attributes are assumed.
502        *ad_value* is the value which gets assigned in case
503        AccessDenied or ZombieProcess exception is raised when
504        retrieving that particular process information.
505        """
506        valid_names = _as_dict_attrnames
507        if attrs is not None:
508            if not isinstance(attrs, (list, tuple, set, frozenset)):
509                raise TypeError("invalid attrs type %s" % type(attrs))
510            attrs = set(attrs)
511            invalid_names = attrs - valid_names
512            if invalid_names:
513                raise ValueError("invalid attr name%s %s" % (
514                    "s" if len(invalid_names) > 1 else "",
515                    ", ".join(map(repr, invalid_names))))
516
517        retdict = dict()
518        ls = attrs or valid_names
519        with self.oneshot():
520            for name in ls:
521                try:
522                    if name == 'pid':
523                        ret = self.pid
524                    else:
525                        meth = getattr(self, name)
526                        ret = meth()
527                except (AccessDenied, ZombieProcess):
528                    ret = ad_value
529                except NotImplementedError:
530                    # in case of not implemented functionality (may happen
531                    # on old or exotic systems) we want to crash only if
532                    # the user explicitly asked for that particular attr
533                    if attrs:
534                        raise
535                    continue
536                retdict[name] = ret
537        return retdict
538
539    def parent(self):
540        """Return the parent process as a Process object pre-emptively
541        checking whether PID has been reused.
542        If no parent is known return None.
543        """
544        lowest_pid = _LOWEST_PID if _LOWEST_PID is not None else pids()[0]
545        if self.pid == lowest_pid:
546            return None
547        ppid = self.ppid()
548        if ppid is not None:
549            ctime = self.create_time()
550            try:
551                parent = Process(ppid)
552                if parent.create_time() <= ctime:
553                    return parent
554                # ...else ppid has been reused by another process
555            except NoSuchProcess:
556                pass
557
558    def parents(self):
559        """Return the parents of this process as a list of Process
560        instances. If no parents are known return an empty list.
561        """
562        parents = []
563        proc = self.parent()
564        while proc is not None:
565            parents.append(proc)
566            proc = proc.parent()
567        return parents
568
569    def is_running(self):
570        """Return whether this process is running.
571        It also checks if PID has been reused by another process in
572        which case return False.
573        """
574        if self._gone:
575            return False
576        try:
577            # Checking if PID is alive is not enough as the PID might
578            # have been reused by another process: we also want to
579            # verify process identity.
580            # Process identity / uniqueness over time is guaranteed by
581            # (PID + creation time) and that is verified in __eq__.
582            return self == Process(self.pid)
583        except ZombieProcess:
584            # We should never get here as it's already handled in
585            # Process.__init__; here just for extra safety.
586            return True
587        except NoSuchProcess:
588            self._gone = True
589            return False
590
591    # --- actual API
592
593    @memoize_when_activated
594    def ppid(self):
595        """The process parent PID.
596        On Windows the return value is cached after first call.
597        """
598        # On POSIX we don't want to cache the ppid as it may unexpectedly
599        # change to 1 (init) in case this process turns into a zombie:
600        # https://github.com/giampaolo/psutil/issues/321
601        # http://stackoverflow.com/questions/356722/
602
603        # XXX should we check creation time here rather than in
604        # Process.parent()?
605        if POSIX:
606            return self._proc.ppid()
607        else:  # pragma: no cover
608            self._ppid = self._ppid or self._proc.ppid()
609            return self._ppid
610
611    def name(self):
612        """The process name. The return value is cached after first call."""
613        # Process name is only cached on Windows as on POSIX it may
614        # change, see:
615        # https://github.com/giampaolo/psutil/issues/692
616        if WINDOWS and self._name is not None:
617            return self._name
618        name = self._proc.name()
619        if POSIX and len(name) >= 15:
620            # On UNIX the name gets truncated to the first 15 characters.
621            # If it matches the first part of the cmdline we return that
622            # one instead because it's usually more explicative.
623            # Examples are "gnome-keyring-d" vs. "gnome-keyring-daemon".
624            try:
625                cmdline = self.cmdline()
626            except AccessDenied:
627                pass
628            else:
629                if cmdline:
630                    extended_name = os.path.basename(cmdline[0])
631                    if extended_name.startswith(name):
632                        name = extended_name
633        self._name = name
634        self._proc._name = name
635        return name
636
637    def exe(self):
638        """The process executable as an absolute path.
639        May also be an empty string.
640        The return value is cached after first call.
641        """
642        def guess_it(fallback):
643            # try to guess exe from cmdline[0] in absence of a native
644            # exe representation
645            cmdline = self.cmdline()
646            if cmdline and hasattr(os, 'access') and hasattr(os, 'X_OK'):
647                exe = cmdline[0]  # the possible exe
648                # Attempt to guess only in case of an absolute path.
649                # It is not safe otherwise as the process might have
650                # changed cwd.
651                if (os.path.isabs(exe) and
652                        os.path.isfile(exe) and
653                        os.access(exe, os.X_OK)):
654                    return exe
655            if isinstance(fallback, AccessDenied):
656                raise fallback
657            return fallback
658
659        if self._exe is None:
660            try:
661                exe = self._proc.exe()
662            except AccessDenied as err:
663                return guess_it(fallback=err)
664            else:
665                if not exe:
666                    # underlying implementation can legitimately return an
667                    # empty string; if that's the case we don't want to
668                    # raise AD while guessing from the cmdline
669                    try:
670                        exe = guess_it(fallback=exe)
671                    except AccessDenied:
672                        pass
673                self._exe = exe
674        return self._exe
675
676    def cmdline(self):
677        """The command line this process has been called with."""
678        return self._proc.cmdline()
679
680    def status(self):
681        """The process current status as a STATUS_* constant."""
682        try:
683            return self._proc.status()
684        except ZombieProcess:
685            return STATUS_ZOMBIE
686
687    def username(self):
688        """The name of the user that owns the process.
689        On UNIX this is calculated by using *real* process uid.
690        """
691        if POSIX:
692            if pwd is None:
693                # might happen if python was installed from sources
694                raise ImportError(
695                    "requires pwd module shipped with standard python")
696            real_uid = self.uids().real
697            try:
698                return pwd.getpwuid(real_uid).pw_name
699            except KeyError:
700                # the uid can't be resolved by the system
701                return str(real_uid)
702        else:
703            return self._proc.username()
704
705    def create_time(self):
706        """The process creation time as a floating point number
707        expressed in seconds since the epoch.
708        The return value is cached after first call.
709        """
710        if self._create_time is None:
711            self._create_time = self._proc.create_time()
712        return self._create_time
713
714    def cwd(self):
715        """Process current working directory as an absolute path."""
716        return self._proc.cwd()
717
718    def nice(self, value=None):
719        """Get or set process niceness (priority)."""
720        if value is None:
721            return self._proc.nice_get()
722        else:
723            if not self.is_running():
724                raise NoSuchProcess(self.pid, self._name)
725            self._proc.nice_set(value)
726
727    if POSIX:
728
729        @memoize_when_activated
730        def uids(self):
731            """Return process UIDs as a (real, effective, saved)
732            namedtuple.
733            """
734            return self._proc.uids()
735
736        def gids(self):
737            """Return process GIDs as a (real, effective, saved)
738            namedtuple.
739            """
740            return self._proc.gids()
741
742        def terminal(self):
743            """The terminal associated with this process, if any,
744            else None.
745            """
746            return self._proc.terminal()
747
748        def num_fds(self):
749            """Return the number of file descriptors opened by this
750            process (POSIX only).
751            """
752            return self._proc.num_fds()
753
754    # Linux, BSD, AIX and Windows only
755    if hasattr(_psplatform.Process, "io_counters"):
756
757        def io_counters(self):
758            """Return process I/O statistics as a
759            (read_count, write_count, read_bytes, write_bytes)
760            namedtuple.
761            Those are the number of read/write calls performed and the
762            amount of bytes read and written by the process.
763            """
764            return self._proc.io_counters()
765
766    # Linux and Windows
767    if hasattr(_psplatform.Process, "ionice_get"):
768
769        def ionice(self, ioclass=None, value=None):
770            """Get or set process I/O niceness (priority).
771
772            On Linux *ioclass* is one of the IOPRIO_CLASS_* constants.
773            *value* is a number which goes from 0 to 7. The higher the
774            value, the lower the I/O priority of the process.
775
776            On Windows only *ioclass* is used and it can be set to 2
777            (normal), 1 (low) or 0 (very low).
778
779            Available on Linux and Windows > Vista only.
780            """
781            if ioclass is None:
782                if value is not None:
783                    raise ValueError("'ioclass' argument must be specified")
784                return self._proc.ionice_get()
785            else:
786                return self._proc.ionice_set(ioclass, value)
787
788    # Linux / FreeBSD only
789    if hasattr(_psplatform.Process, "rlimit"):
790
791        def rlimit(self, resource, limits=None):
792            """Get or set process resource limits as a (soft, hard)
793            tuple.
794
795            *resource* is one of the RLIMIT_* constants.
796            *limits* is supposed to be a (soft, hard) tuple.
797
798            See "man prlimit" for further info.
799            Available on Linux and FreeBSD only.
800            """
801            return self._proc.rlimit(resource, limits)
802
803    # Windows, Linux and FreeBSD only
804    if hasattr(_psplatform.Process, "cpu_affinity_get"):
805
806        def cpu_affinity(self, cpus=None):
807            """Get or set process CPU affinity.
808            If specified, *cpus* must be a list of CPUs for which you
809            want to set the affinity (e.g. [0, 1]).
810            If an empty list is passed, all egible CPUs are assumed
811            (and set).
812            (Windows, Linux and BSD only).
813            """
814            if cpus is None:
815                return sorted(set(self._proc.cpu_affinity_get()))
816            else:
817                if not cpus:
818                    if hasattr(self._proc, "_get_eligible_cpus"):
819                        cpus = self._proc._get_eligible_cpus()
820                    else:
821                        cpus = tuple(range(len(cpu_times(percpu=True))))
822                self._proc.cpu_affinity_set(list(set(cpus)))
823
824    # Linux, FreeBSD, SunOS
825    if hasattr(_psplatform.Process, "cpu_num"):
826
827        def cpu_num(self):
828            """Return what CPU this process is currently running on.
829            The returned number should be <= psutil.cpu_count()
830            and <= len(psutil.cpu_percent(percpu=True)).
831            It may be used in conjunction with
832            psutil.cpu_percent(percpu=True) to observe the system
833            workload distributed across CPUs.
834            """
835            return self._proc.cpu_num()
836
837    # All platforms has it, but maybe not in the future.
838    if hasattr(_psplatform.Process, "environ"):
839
840        def environ(self):
841            """The environment variables of the process as a dict.  Note: this
842            might not reflect changes made after the process started.  """
843            return self._proc.environ()
844
845    if WINDOWS:
846
847        def num_handles(self):
848            """Return the number of handles opened by this process
849            (Windows only).
850            """
851            return self._proc.num_handles()
852
853    def num_ctx_switches(self):
854        """Return the number of voluntary and involuntary context
855        switches performed by this process.
856        """
857        return self._proc.num_ctx_switches()
858
859    def num_threads(self):
860        """Return the number of threads used by this process."""
861        return self._proc.num_threads()
862
863    if hasattr(_psplatform.Process, "threads"):
864
865        def threads(self):
866            """Return threads opened by process as a list of
867            (id, user_time, system_time) namedtuples representing
868            thread id and thread CPU times (user/system).
869            On OpenBSD this method requires root access.
870            """
871            return self._proc.threads()
872
873    @_assert_pid_not_reused
874    def children(self, recursive=False):
875        """Return the children of this process as a list of Process
876        instances, pre-emptively checking whether PID has been reused.
877        If *recursive* is True return all the parent descendants.
878
879        Example (A == this process):
880
881         A ─┐
882883            ├─ B (child) ─┐
884            │             └─ X (grandchild) ─┐
885            │                                └─ Y (great grandchild)
886            ├─ C (child)
887            └─ D (child)
888
889        >>> import psutil
890        >>> p = psutil.Process()
891        >>> p.children()
892        B, C, D
893        >>> p.children(recursive=True)
894        B, X, Y, C, D
895
896        Note that in the example above if process X disappears
897        process Y won't be listed as the reference to process A
898        is lost.
899        """
900        ppid_map = _ppid_map()
901        ret = []
902        if not recursive:
903            for pid, ppid in ppid_map.items():
904                if ppid == self.pid:
905                    try:
906                        child = Process(pid)
907                        # if child happens to be older than its parent
908                        # (self) it means child's PID has been reused
909                        if self.create_time() <= child.create_time():
910                            ret.append(child)
911                    except (NoSuchProcess, ZombieProcess):
912                        pass
913        else:
914            # Construct a {pid: [child pids]} dict
915            reverse_ppid_map = collections.defaultdict(list)
916            for pid, ppid in ppid_map.items():
917                reverse_ppid_map[ppid].append(pid)
918            # Recursively traverse that dict, starting from self.pid,
919            # such that we only call Process() on actual children
920            seen = set()
921            stack = [self.pid]
922            while stack:
923                pid = stack.pop()
924                if pid in seen:
925                    # Since pids can be reused while the ppid_map is
926                    # constructed, there may be rare instances where
927                    # there's a cycle in the recorded process "tree".
928                    continue
929                seen.add(pid)
930                for child_pid in reverse_ppid_map[pid]:
931                    try:
932                        child = Process(child_pid)
933                        # if child happens to be older than its parent
934                        # (self) it means child's PID has been reused
935                        intime = self.create_time() <= child.create_time()
936                        if intime:
937                            ret.append(child)
938                            stack.append(child_pid)
939                    except (NoSuchProcess, ZombieProcess):
940                        pass
941        return ret
942
943    def cpu_percent(self, interval=None):
944        """Return a float representing the current process CPU
945        utilization as a percentage.
946
947        When *interval* is 0.0 or None (default) compares process times
948        to system CPU times elapsed since last call, returning
949        immediately (non-blocking). That means that the first time
950        this is called it will return a meaningful 0.0 value.
951
952        When *interval* is > 0.0 compares process times to system CPU
953        times elapsed before and after the interval (blocking).
954
955        In this case is recommended for accuracy that this function
956        be called with at least 0.1 seconds between calls.
957
958        A value > 100.0 can be returned in case of processes running
959        multiple threads on different CPU cores.
960
961        The returned value is explicitly NOT split evenly between
962        all available logical CPUs. This means that a busy loop process
963        running on a system with 2 logical CPUs will be reported as
964        having 100% CPU utilization instead of 50%.
965
966        Examples:
967
968          >>> import psutil
969          >>> p = psutil.Process(os.getpid())
970          >>> # blocking
971          >>> p.cpu_percent(interval=1)
972          2.0
973          >>> # non-blocking (percentage since last call)
974          >>> p.cpu_percent(interval=None)
975          2.9
976          >>>
977        """
978        blocking = interval is not None and interval > 0.0
979        if interval is not None and interval < 0:
980            raise ValueError("interval is not positive (got %r)" % interval)
981        num_cpus = cpu_count() or 1
982
983        def timer():
984            return _timer() * num_cpus
985
986        if blocking:
987            st1 = timer()
988            pt1 = self._proc.cpu_times()
989            time.sleep(interval)
990            st2 = timer()
991            pt2 = self._proc.cpu_times()
992        else:
993            st1 = self._last_sys_cpu_times
994            pt1 = self._last_proc_cpu_times
995            st2 = timer()
996            pt2 = self._proc.cpu_times()
997            if st1 is None or pt1 is None:
998                self._last_sys_cpu_times = st2
999                self._last_proc_cpu_times = pt2
1000                return 0.0
1001
1002        delta_proc = (pt2.user - pt1.user) + (pt2.system - pt1.system)
1003        delta_time = st2 - st1
1004        # reset values for next call in case of interval == None
1005        self._last_sys_cpu_times = st2
1006        self._last_proc_cpu_times = pt2
1007
1008        try:
1009            # This is the utilization split evenly between all CPUs.
1010            # E.g. a busy loop process on a 2-CPU-cores system at this
1011            # point is reported as 50% instead of 100%.
1012            overall_cpus_percent = ((delta_proc / delta_time) * 100)
1013        except ZeroDivisionError:
1014            # interval was too low
1015            return 0.0
1016        else:
1017            # Note 1:
1018            # in order to emulate "top" we multiply the value for the num
1019            # of CPU cores. This way the busy process will be reported as
1020            # having 100% (or more) usage.
1021            #
1022            # Note 2:
1023            # taskmgr.exe on Windows differs in that it will show 50%
1024            # instead.
1025            #
1026            # Note 3:
1027            # a percentage > 100 is legitimate as it can result from a
1028            # process with multiple threads running on different CPU
1029            # cores (top does the same), see:
1030            # http://stackoverflow.com/questions/1032357
1031            # https://github.com/giampaolo/psutil/issues/474
1032            single_cpu_percent = overall_cpus_percent * num_cpus
1033            return round(single_cpu_percent, 1)
1034
1035    @memoize_when_activated
1036    def cpu_times(self):
1037        """Return a (user, system, children_user, children_system)
1038        namedtuple representing the accumulated process time, in
1039        seconds.
1040        This is similar to os.times() but per-process.
1041        On macOS and Windows children_user and children_system are
1042        always set to 0.
1043        """
1044        return self._proc.cpu_times()
1045
1046    @memoize_when_activated
1047    def memory_info(self):
1048        """Return a namedtuple with variable fields depending on the
1049        platform, representing memory information about the process.
1050
1051        The "portable" fields available on all plaforms are `rss` and `vms`.
1052
1053        All numbers are expressed in bytes.
1054        """
1055        return self._proc.memory_info()
1056
1057    @_common.deprecated_method(replacement="memory_info")
1058    def memory_info_ex(self):
1059        return self.memory_info()
1060
1061    def memory_full_info(self):
1062        """This method returns the same information as memory_info(),
1063        plus, on some platform (Linux, macOS, Windows), also provides
1064        additional metrics (USS, PSS and swap).
1065        The additional metrics provide a better representation of actual
1066        process memory usage.
1067
1068        Namely USS is the memory which is unique to a process and which
1069        would be freed if the process was terminated right now.
1070
1071        It does so by passing through the whole process address.
1072        As such it usually requires higher user privileges than
1073        memory_info() and is considerably slower.
1074        """
1075        return self._proc.memory_full_info()
1076
1077    def memory_percent(self, memtype="rss"):
1078        """Compare process memory to total physical system memory and
1079        calculate process memory utilization as a percentage.
1080        *memtype* argument is a string that dictates what type of
1081        process memory you want to compare against (defaults to "rss").
1082        The list of available strings can be obtained like this:
1083
1084        >>> psutil.Process().memory_info()._fields
1085        ('rss', 'vms', 'shared', 'text', 'lib', 'data', 'dirty', 'uss', 'pss')
1086        """
1087        valid_types = list(_psplatform.pfullmem._fields)
1088        if memtype not in valid_types:
1089            raise ValueError("invalid memtype %r; valid types are %r" % (
1090                memtype, tuple(valid_types)))
1091        fun = self.memory_info if memtype in _psplatform.pmem._fields else \
1092            self.memory_full_info
1093        metrics = fun()
1094        value = getattr(metrics, memtype)
1095
1096        # use cached value if available
1097        total_phymem = _TOTAL_PHYMEM or virtual_memory().total
1098        if not total_phymem > 0:
1099            # we should never get here
1100            raise ValueError(
1101                "can't calculate process memory percent because "
1102                "total physical system memory is not positive (%r)"
1103                % total_phymem)
1104        return (value / float(total_phymem)) * 100
1105
1106    if hasattr(_psplatform.Process, "memory_maps"):
1107        def memory_maps(self, grouped=True):
1108            """Return process' mapped memory regions as a list of namedtuples
1109            whose fields are variable depending on the platform.
1110
1111            If *grouped* is True the mapped regions with the same 'path'
1112            are grouped together and the different memory fields are summed.
1113
1114            If *grouped* is False every mapped region is shown as a single
1115            entity and the namedtuple will also include the mapped region's
1116            address space ('addr') and permission set ('perms').
1117            """
1118            it = self._proc.memory_maps()
1119            if grouped:
1120                d = {}
1121                for tupl in it:
1122                    path = tupl[2]
1123                    nums = tupl[3:]
1124                    try:
1125                        d[path] = map(lambda x, y: x + y, d[path], nums)
1126                    except KeyError:
1127                        d[path] = nums
1128                nt = _psplatform.pmmap_grouped
1129                return [nt(path, *d[path]) for path in d]  # NOQA
1130            else:
1131                nt = _psplatform.pmmap_ext
1132                return [nt(*x) for x in it]
1133
1134    def open_files(self):
1135        """Return files opened by process as a list of
1136        (path, fd) namedtuples including the absolute file name
1137        and file descriptor number.
1138        """
1139        return self._proc.open_files()
1140
1141    def connections(self, kind='inet'):
1142        """Return socket connections opened by process as a list of
1143        (fd, family, type, laddr, raddr, status) namedtuples.
1144        The *kind* parameter filters for connections that match the
1145        following criteria:
1146
1147        +------------+----------------------------------------------------+
1148        | Kind Value | Connections using                                  |
1149        +------------+----------------------------------------------------+
1150        | inet       | IPv4 and IPv6                                      |
1151        | inet4      | IPv4                                               |
1152        | inet6      | IPv6                                               |
1153        | tcp        | TCP                                                |
1154        | tcp4       | TCP over IPv4                                      |
1155        | tcp6       | TCP over IPv6                                      |
1156        | udp        | UDP                                                |
1157        | udp4       | UDP over IPv4                                      |
1158        | udp6       | UDP over IPv6                                      |
1159        | unix       | UNIX socket (both UDP and TCP protocols)           |
1160        | all        | the sum of all the possible families and protocols |
1161        +------------+----------------------------------------------------+
1162        """
1163        return self._proc.connections(kind)
1164
1165    # --- signals
1166
1167    if POSIX:
1168        def _send_signal(self, sig):
1169            assert not self.pid < 0, self.pid
1170            if self.pid == 0:
1171                # see "man 2 kill"
1172                raise ValueError(
1173                    "preventing sending signal to process with PID 0 as it "
1174                    "would affect every process in the process group of the "
1175                    "calling process (os.getpid()) instead of PID 0")
1176            try:
1177                os.kill(self.pid, sig)
1178            except ProcessLookupError:
1179                if OPENBSD and pid_exists(self.pid):
1180                    # We do this because os.kill() lies in case of
1181                    # zombie processes.
1182                    raise ZombieProcess(self.pid, self._name, self._ppid)
1183                else:
1184                    self._gone = True
1185                    raise NoSuchProcess(self.pid, self._name)
1186            except PermissionError:
1187                raise AccessDenied(self.pid, self._name)
1188
1189    @_assert_pid_not_reused
1190    def send_signal(self, sig):
1191        """Send a signal *sig* to process pre-emptively checking
1192        whether PID has been reused (see signal module constants) .
1193        On Windows only SIGTERM is valid and is treated as an alias
1194        for kill().
1195        """
1196        if POSIX:
1197            self._send_signal(sig)
1198        else:  # pragma: no cover
1199            self._proc.send_signal(sig)
1200
1201    @_assert_pid_not_reused
1202    def suspend(self):
1203        """Suspend process execution with SIGSTOP pre-emptively checking
1204        whether PID has been reused.
1205        On Windows this has the effect ot suspending all process threads.
1206        """
1207        if POSIX:
1208            self._send_signal(signal.SIGSTOP)
1209        else:  # pragma: no cover
1210            self._proc.suspend()
1211
1212    @_assert_pid_not_reused
1213    def resume(self):
1214        """Resume process execution with SIGCONT pre-emptively checking
1215        whether PID has been reused.
1216        On Windows this has the effect of resuming all process threads.
1217        """
1218        if POSIX:
1219            self._send_signal(signal.SIGCONT)
1220        else:  # pragma: no cover
1221            self._proc.resume()
1222
1223    @_assert_pid_not_reused
1224    def terminate(self):
1225        """Terminate the process with SIGTERM pre-emptively checking
1226        whether PID has been reused.
1227        On Windows this is an alias for kill().
1228        """
1229        if POSIX:
1230            self._send_signal(signal.SIGTERM)
1231        else:  # pragma: no cover
1232            self._proc.kill()
1233
1234    @_assert_pid_not_reused
1235    def kill(self):
1236        """Kill the current process with SIGKILL pre-emptively checking
1237        whether PID has been reused.
1238        """
1239        if POSIX:
1240            self._send_signal(signal.SIGKILL)
1241        else:  # pragma: no cover
1242            self._proc.kill()
1243
1244    def wait(self, timeout=None):
1245        """Wait for process to terminate and, if process is a children
1246        of os.getpid(), also return its exit code, else None.
1247        On Windows there's no such limitation (exit code is always
1248        returned).
1249
1250        If the process is already terminated immediately return None
1251        instead of raising NoSuchProcess.
1252
1253        If *timeout* (in seconds) is specified and process is still
1254        alive raise TimeoutExpired.
1255
1256        To wait for multiple Process(es) use psutil.wait_procs().
1257        """
1258        if timeout is not None and not timeout >= 0:
1259            raise ValueError("timeout must be a positive integer")
1260        if self._exitcode is not _SENTINEL:
1261            return self._exitcode
1262        self._exitcode = self._proc.wait(timeout)
1263        return self._exitcode
1264
1265
1266# The valid attr names which can be processed by Process.as_dict().
1267_as_dict_attrnames = set(
1268    [x for x in dir(Process) if not x.startswith('_') and x not in
1269     ['send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait',
1270      'is_running', 'as_dict', 'parent', 'parents', 'children', 'rlimit',
1271      'memory_info_ex', 'oneshot']])
1272
1273
1274# =====================================================================
1275# --- Popen class
1276# =====================================================================
1277
1278
1279class Popen(Process):
1280    """Same as subprocess.Popen, but in addition it provides all
1281    psutil.Process methods in a single class.
1282    For the following methods which are common to both classes, psutil
1283    implementation takes precedence:
1284
1285    * send_signal()
1286    * terminate()
1287    * kill()
1288
1289    This is done in order to avoid killing another process in case its
1290    PID has been reused, fixing BPO-6973.
1291
1292      >>> import psutil
1293      >>> from subprocess import PIPE
1294      >>> p = psutil.Popen(["python", "-c", "print 'hi'"], stdout=PIPE)
1295      >>> p.name()
1296      'python'
1297      >>> p.uids()
1298      user(real=1000, effective=1000, saved=1000)
1299      >>> p.username()
1300      'giampaolo'
1301      >>> p.communicate()
1302      ('hi\n', None)
1303      >>> p.terminate()
1304      >>> p.wait(timeout=2)
1305      0
1306      >>>
1307    """
1308
1309    def __init__(self, *args, **kwargs):
1310        # Explicitly avoid to raise NoSuchProcess in case the process
1311        # spawned by subprocess.Popen terminates too quickly, see:
1312        # https://github.com/giampaolo/psutil/issues/193
1313        self.__subproc = subprocess.Popen(*args, **kwargs)
1314        self._init(self.__subproc.pid, _ignore_nsp=True)
1315
1316    def __dir__(self):
1317        return sorted(set(dir(Popen) + dir(subprocess.Popen)))
1318
1319    def __enter__(self):
1320        if hasattr(self.__subproc, '__enter__'):
1321            self.__subproc.__enter__()
1322        return self
1323
1324    def __exit__(self, *args, **kwargs):
1325        if hasattr(self.__subproc, '__exit__'):
1326            return self.__subproc.__exit__(*args, **kwargs)
1327        else:
1328            if self.stdout:
1329                self.stdout.close()
1330            if self.stderr:
1331                self.stderr.close()
1332            try:
1333                # Flushing a BufferedWriter may raise an error.
1334                if self.stdin:
1335                    self.stdin.close()
1336            finally:
1337                # Wait for the process to terminate, to avoid zombies.
1338                self.wait()
1339
1340    def __getattribute__(self, name):
1341        try:
1342            return object.__getattribute__(self, name)
1343        except AttributeError:
1344            try:
1345                return object.__getattribute__(self.__subproc, name)
1346            except AttributeError:
1347                raise AttributeError("%s instance has no attribute '%s'"
1348                                     % (self.__class__.__name__, name))
1349
1350    def wait(self, timeout=None):
1351        if self.__subproc.returncode is not None:
1352            return self.__subproc.returncode
1353        ret = super(Popen, self).wait(timeout)
1354        self.__subproc.returncode = ret
1355        return ret
1356
1357
1358# =====================================================================
1359# --- system processes related functions
1360# =====================================================================
1361
1362
1363def pids():
1364    """Return a list of current running PIDs."""
1365    global _LOWEST_PID
1366    ret = sorted(_psplatform.pids())
1367    _LOWEST_PID = ret[0]
1368    return ret
1369
1370
1371def pid_exists(pid):
1372    """Return True if given PID exists in the current process list.
1373    This is faster than doing "pid in psutil.pids()" and
1374    should be preferred.
1375    """
1376    if pid < 0:
1377        return False
1378    elif pid == 0 and POSIX:
1379        # On POSIX we use os.kill() to determine PID existence.
1380        # According to "man 2 kill" PID 0 has a special meaning
1381        # though: it refers to <<every process in the process
1382        # group of the calling process>> and that is not we want
1383        # to do here.
1384        return pid in pids()
1385    else:
1386        return _psplatform.pid_exists(pid)
1387
1388
1389_pmap = {}
1390_lock = threading.Lock()
1391
1392
1393def process_iter(attrs=None, ad_value=None):
1394    """Return a generator yielding a Process instance for all
1395    running processes.
1396
1397    Every new Process instance is only created once and then cached
1398    into an internal table which is updated every time this is used.
1399
1400    Cached Process instances are checked for identity so that you're
1401    safe in case a PID has been reused by another process, in which
1402    case the cached instance is updated.
1403
1404    The sorting order in which processes are yielded is based on
1405    their PIDs.
1406
1407    *attrs* and *ad_value* have the same meaning as in
1408    Process.as_dict(). If *attrs* is specified as_dict() is called
1409    and the resulting dict is stored as a 'info' attribute attached
1410    to returned Process instance.
1411    If *attrs* is an empty list it will retrieve all process info
1412    (slow).
1413    """
1414    def add(pid):
1415        proc = Process(pid)
1416        if attrs is not None:
1417            proc.info = proc.as_dict(attrs=attrs, ad_value=ad_value)
1418        with _lock:
1419            _pmap[proc.pid] = proc
1420        return proc
1421
1422    def remove(pid):
1423        with _lock:
1424            _pmap.pop(pid, None)
1425
1426    a = set(pids())
1427    b = set(_pmap.keys())
1428    new_pids = a - b
1429    gone_pids = b - a
1430    for pid in gone_pids:
1431        remove(pid)
1432
1433    with _lock:
1434        ls = sorted(list(_pmap.items()) +
1435                    list(dict.fromkeys(new_pids).items()))
1436
1437    for pid, proc in ls:
1438        try:
1439            if proc is None:  # new process
1440                yield add(pid)
1441            else:
1442                # use is_running() to check whether PID has been reused by
1443                # another process in which case yield a new Process instance
1444                if proc.is_running():
1445                    if attrs is not None:
1446                        proc.info = proc.as_dict(
1447                            attrs=attrs, ad_value=ad_value)
1448                    yield proc
1449                else:
1450                    yield add(pid)
1451        except NoSuchProcess:
1452            remove(pid)
1453        except AccessDenied:
1454            # Process creation time can't be determined hence there's
1455            # no way to tell whether the pid of the cached process
1456            # has been reused. Just return the cached version.
1457            if proc is None and pid in _pmap:
1458                try:
1459                    yield _pmap[pid]
1460                except KeyError:
1461                    # If we get here it is likely that 2 threads were
1462                    # using process_iter().
1463                    pass
1464            else:
1465                raise
1466
1467
1468def wait_procs(procs, timeout=None, callback=None):
1469    """Convenience function which waits for a list of processes to
1470    terminate.
1471
1472    Return a (gone, alive) tuple indicating which processes
1473    are gone and which ones are still alive.
1474
1475    The gone ones will have a new *returncode* attribute indicating
1476    process exit status (may be None).
1477
1478    *callback* is a function which gets called every time a process
1479    terminates (a Process instance is passed as callback argument).
1480
1481    Function will return as soon as all processes terminate or when
1482    *timeout* occurs.
1483    Differently from Process.wait() it will not raise TimeoutExpired if
1484    *timeout* occurs.
1485
1486    Typical use case is:
1487
1488     - send SIGTERM to a list of processes
1489     - give them some time to terminate
1490     - send SIGKILL to those ones which are still alive
1491
1492    Example:
1493
1494    >>> def on_terminate(proc):
1495    ...     print("process {} terminated".format(proc))
1496    ...
1497    >>> for p in procs:
1498    ...    p.terminate()
1499    ...
1500    >>> gone, alive = wait_procs(procs, timeout=3, callback=on_terminate)
1501    >>> for p in alive:
1502    ...     p.kill()
1503    """
1504    def check_gone(proc, timeout):
1505        try:
1506            returncode = proc.wait(timeout=timeout)
1507        except TimeoutExpired:
1508            pass
1509        else:
1510            if returncode is not None or not proc.is_running():
1511                # Set new Process instance attribute.
1512                proc.returncode = returncode
1513                gone.add(proc)
1514                if callback is not None:
1515                    callback(proc)
1516
1517    if timeout is not None and not timeout >= 0:
1518        msg = "timeout must be a positive integer, got %s" % timeout
1519        raise ValueError(msg)
1520    gone = set()
1521    alive = set(procs)
1522    if callback is not None and not callable(callback):
1523        raise TypeError("callback %r is not a callable" % callable)
1524    if timeout is not None:
1525        deadline = _timer() + timeout
1526
1527    while alive:
1528        if timeout is not None and timeout <= 0:
1529            break
1530        for proc in alive:
1531            # Make sure that every complete iteration (all processes)
1532            # will last max 1 sec.
1533            # We do this because we don't want to wait too long on a
1534            # single process: in case it terminates too late other
1535            # processes may disappear in the meantime and their PID
1536            # reused.
1537            max_timeout = 1.0 / len(alive)
1538            if timeout is not None:
1539                timeout = min((deadline - _timer()), max_timeout)
1540                if timeout <= 0:
1541                    break
1542                check_gone(proc, timeout)
1543            else:
1544                check_gone(proc, max_timeout)
1545        alive = alive - gone
1546
1547    if alive:
1548        # Last attempt over processes survived so far.
1549        # timeout == 0 won't make this function wait any further.
1550        for proc in alive:
1551            check_gone(proc, 0)
1552        alive = alive - gone
1553
1554    return (list(gone), list(alive))
1555
1556
1557# =====================================================================
1558# --- CPU related functions
1559# =====================================================================
1560
1561
1562def cpu_count(logical=True):
1563    """Return the number of logical CPUs in the system (same as
1564    os.cpu_count() in Python 3.4).
1565
1566    If *logical* is False return the number of physical cores only
1567    (e.g. hyper thread CPUs are excluded).
1568
1569    Return None if undetermined.
1570
1571    The return value is cached after first call.
1572    If desired cache can be cleared like this:
1573
1574    >>> psutil.cpu_count.cache_clear()
1575    """
1576    if logical:
1577        ret = _psplatform.cpu_count_logical()
1578    else:
1579        ret = _psplatform.cpu_count_physical()
1580    if ret is not None and ret < 1:
1581        ret = None
1582    return ret
1583
1584
1585def cpu_times(percpu=False):
1586    """Return system-wide CPU times as a namedtuple.
1587    Every CPU time represents the seconds the CPU has spent in the
1588    given mode. The namedtuple's fields availability varies depending on the
1589    platform:
1590
1591     - user
1592     - system
1593     - idle
1594     - nice (UNIX)
1595     - iowait (Linux)
1596     - irq (Linux, FreeBSD)
1597     - softirq (Linux)
1598     - steal (Linux >= 2.6.11)
1599     - guest (Linux >= 2.6.24)
1600     - guest_nice (Linux >= 3.2.0)
1601
1602    When *percpu* is True return a list of namedtuples for each CPU.
1603    First element of the list refers to first CPU, second element
1604    to second CPU and so on.
1605    The order of the list is consistent across calls.
1606    """
1607    if not percpu:
1608        return _psplatform.cpu_times()
1609    else:
1610        return _psplatform.per_cpu_times()
1611
1612
1613try:
1614    _last_cpu_times = cpu_times()
1615except Exception:
1616    # Don't want to crash at import time.
1617    _last_cpu_times = None
1618
1619try:
1620    _last_per_cpu_times = cpu_times(percpu=True)
1621except Exception:
1622    # Don't want to crash at import time.
1623    _last_per_cpu_times = None
1624
1625
1626def _cpu_tot_time(times):
1627    """Given a cpu_time() ntuple calculates the total CPU time
1628    (including idle time).
1629    """
1630    tot = sum(times)
1631    if LINUX:
1632        # On Linux guest times are already accounted in "user" or
1633        # "nice" times, so we subtract them from total.
1634        # Htop does the same. References:
1635        # https://github.com/giampaolo/psutil/pull/940
1636        # http://unix.stackexchange.com/questions/178045
1637        # https://github.com/torvalds/linux/blob/
1638        #     447976ef4fd09b1be88b316d1a81553f1aa7cd07/kernel/sched/
1639        #     cputime.c#L158
1640        tot -= getattr(times, "guest", 0)  # Linux 2.6.24+
1641        tot -= getattr(times, "guest_nice", 0)  # Linux 3.2.0+
1642    return tot
1643
1644
1645def _cpu_busy_time(times):
1646    """Given a cpu_time() ntuple calculates the busy CPU time.
1647    We do so by subtracting all idle CPU times.
1648    """
1649    busy = _cpu_tot_time(times)
1650    busy -= times.idle
1651    # Linux: "iowait" is time during which the CPU does not do anything
1652    # (waits for IO to complete). On Linux IO wait is *not* accounted
1653    # in "idle" time so we subtract it. Htop does the same.
1654    # References:
1655    # https://github.com/torvalds/linux/blob/
1656    #     447976ef4fd09b1be88b316d1a81553f1aa7cd07/kernel/sched/cputime.c#L244
1657    busy -= getattr(times, "iowait", 0)
1658    return busy
1659
1660
1661def _cpu_times_deltas(t1, t2):
1662    assert t1._fields == t2._fields, (t1, t2)
1663    field_deltas = []
1664    for field in _psplatform.scputimes._fields:
1665        field_delta = getattr(t2, field) - getattr(t1, field)
1666        # CPU times are always supposed to increase over time
1667        # or at least remain the same and that's because time
1668        # cannot go backwards.
1669        # Surprisingly sometimes this might not be the case (at
1670        # least on Windows and Linux), see:
1671        # https://github.com/giampaolo/psutil/issues/392
1672        # https://github.com/giampaolo/psutil/issues/645
1673        # https://github.com/giampaolo/psutil/issues/1210
1674        # Trim negative deltas to zero to ignore decreasing fields.
1675        # top does the same. Reference:
1676        # https://gitlab.com/procps-ng/procps/blob/v3.3.12/top/top.c#L5063
1677        field_delta = max(0, field_delta)
1678        field_deltas.append(field_delta)
1679    return _psplatform.scputimes(*field_deltas)
1680
1681
1682def cpu_percent(interval=None, percpu=False):
1683    """Return a float representing the current system-wide CPU
1684    utilization as a percentage.
1685
1686    When *interval* is > 0.0 compares system CPU times elapsed before
1687    and after the interval (blocking).
1688
1689    When *interval* is 0.0 or None compares system CPU times elapsed
1690    since last call or module import, returning immediately (non
1691    blocking). That means the first time this is called it will
1692    return a meaningless 0.0 value which you should ignore.
1693    In this case is recommended for accuracy that this function be
1694    called with at least 0.1 seconds between calls.
1695
1696    When *percpu* is True returns a list of floats representing the
1697    utilization as a percentage for each CPU.
1698    First element of the list refers to first CPU, second element
1699    to second CPU and so on.
1700    The order of the list is consistent across calls.
1701
1702    Examples:
1703
1704      >>> # blocking, system-wide
1705      >>> psutil.cpu_percent(interval=1)
1706      2.0
1707      >>>
1708      >>> # blocking, per-cpu
1709      >>> psutil.cpu_percent(interval=1, percpu=True)
1710      [2.0, 1.0]
1711      >>>
1712      >>> # non-blocking (percentage since last call)
1713      >>> psutil.cpu_percent(interval=None)
1714      2.9
1715      >>>
1716    """
1717    global _last_cpu_times
1718    global _last_per_cpu_times
1719    blocking = interval is not None and interval > 0.0
1720    if interval is not None and interval < 0:
1721        raise ValueError("interval is not positive (got %r)" % interval)
1722
1723    def calculate(t1, t2):
1724        times_delta = _cpu_times_deltas(t1, t2)
1725
1726        all_delta = _cpu_tot_time(times_delta)
1727        busy_delta = _cpu_busy_time(times_delta)
1728
1729        try:
1730            busy_perc = (busy_delta / all_delta) * 100
1731        except ZeroDivisionError:
1732            return 0.0
1733        else:
1734            return round(busy_perc, 1)
1735
1736    # system-wide usage
1737    if not percpu:
1738        if blocking:
1739            t1 = cpu_times()
1740            time.sleep(interval)
1741        else:
1742            t1 = _last_cpu_times
1743            if t1 is None:
1744                # Something bad happened at import time. We'll
1745                # get a meaningful result on the next call. See:
1746                # https://github.com/giampaolo/psutil/pull/715
1747                t1 = cpu_times()
1748        _last_cpu_times = cpu_times()
1749        return calculate(t1, _last_cpu_times)
1750    # per-cpu usage
1751    else:
1752        ret = []
1753        if blocking:
1754            tot1 = cpu_times(percpu=True)
1755            time.sleep(interval)
1756        else:
1757            tot1 = _last_per_cpu_times
1758            if tot1 is None:
1759                # Something bad happened at import time. We'll
1760                # get a meaningful result on the next call. See:
1761                # https://github.com/giampaolo/psutil/pull/715
1762                tot1 = cpu_times(percpu=True)
1763        _last_per_cpu_times = cpu_times(percpu=True)
1764        for t1, t2 in zip(tot1, _last_per_cpu_times):
1765            ret.append(calculate(t1, t2))
1766        return ret
1767
1768
1769# Use separate global vars for cpu_times_percent() so that it's
1770# independent from cpu_percent() and they can both be used within
1771# the same program.
1772_last_cpu_times_2 = _last_cpu_times
1773_last_per_cpu_times_2 = _last_per_cpu_times
1774
1775
1776def cpu_times_percent(interval=None, percpu=False):
1777    """Same as cpu_percent() but provides utilization percentages
1778    for each specific CPU time as is returned by cpu_times().
1779    For instance, on Linux we'll get:
1780
1781      >>> cpu_times_percent()
1782      cpupercent(user=4.8, nice=0.0, system=4.8, idle=90.5, iowait=0.0,
1783                 irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
1784      >>>
1785
1786    *interval* and *percpu* arguments have the same meaning as in
1787    cpu_percent().
1788    """
1789    global _last_cpu_times_2
1790    global _last_per_cpu_times_2
1791    blocking = interval is not None and interval > 0.0
1792    if interval is not None and interval < 0:
1793        raise ValueError("interval is not positive (got %r)" % interval)
1794
1795    def calculate(t1, t2):
1796        nums = []
1797        times_delta = _cpu_times_deltas(t1, t2)
1798        all_delta = _cpu_tot_time(times_delta)
1799        # "scale" is the value to multiply each delta with to get percentages.
1800        # We use "max" to avoid division by zero (if all_delta is 0, then all
1801        # fields are 0 so percentages will be 0 too. all_delta cannot be a
1802        # fraction because cpu times are integers)
1803        scale = 100.0 / max(1, all_delta)
1804        for field_delta in times_delta:
1805            field_perc = field_delta * scale
1806            field_perc = round(field_perc, 1)
1807            # make sure we don't return negative values or values over 100%
1808            field_perc = min(max(0.0, field_perc), 100.0)
1809            nums.append(field_perc)
1810        return _psplatform.scputimes(*nums)
1811
1812    # system-wide usage
1813    if not percpu:
1814        if blocking:
1815            t1 = cpu_times()
1816            time.sleep(interval)
1817        else:
1818            t1 = _last_cpu_times_2
1819            if t1 is None:
1820                # Something bad happened at import time. We'll
1821                # get a meaningful result on the next call. See:
1822                # https://github.com/giampaolo/psutil/pull/715
1823                t1 = cpu_times()
1824        _last_cpu_times_2 = cpu_times()
1825        return calculate(t1, _last_cpu_times_2)
1826    # per-cpu usage
1827    else:
1828        ret = []
1829        if blocking:
1830            tot1 = cpu_times(percpu=True)
1831            time.sleep(interval)
1832        else:
1833            tot1 = _last_per_cpu_times_2
1834            if tot1 is None:
1835                # Something bad happened at import time. We'll
1836                # get a meaningful result on the next call. See:
1837                # https://github.com/giampaolo/psutil/pull/715
1838                tot1 = cpu_times(percpu=True)
1839        _last_per_cpu_times_2 = cpu_times(percpu=True)
1840        for t1, t2 in zip(tot1, _last_per_cpu_times_2):
1841            ret.append(calculate(t1, t2))
1842        return ret
1843
1844
1845def cpu_stats():
1846    """Return CPU statistics."""
1847    return _psplatform.cpu_stats()
1848
1849
1850if hasattr(_psplatform, "cpu_freq"):
1851
1852    def cpu_freq(percpu=False):
1853        """Return CPU frequency as a nameduple including current,
1854        min and max frequency expressed in Mhz.
1855
1856        If *percpu* is True and the system supports per-cpu frequency
1857        retrieval (Linux only) a list of frequencies is returned for
1858        each CPU. If not a list with one element is returned.
1859        """
1860        ret = _psplatform.cpu_freq()
1861        if percpu:
1862            return ret
1863        else:
1864            num_cpus = float(len(ret))
1865            if num_cpus == 0:
1866                return None
1867            elif num_cpus == 1:
1868                return ret[0]
1869            else:
1870                currs, mins, maxs = 0.0, 0.0, 0.0
1871                set_none = False
1872                for cpu in ret:
1873                    currs += cpu.current
1874                    # On Linux if /proc/cpuinfo is used min/max are set
1875                    # to None.
1876                    if LINUX and cpu.min is None:
1877                        set_none = True
1878                        continue
1879                    mins += cpu.min
1880                    maxs += cpu.max
1881
1882                current = currs / num_cpus
1883
1884                if set_none:
1885                    min_ = max_ = None
1886                else:
1887                    min_ = mins / num_cpus
1888                    max_ = maxs / num_cpus
1889
1890                return _common.scpufreq(current, min_, max_)
1891
1892    __all__.append("cpu_freq")
1893
1894
1895if hasattr(os, "getloadavg") or hasattr(_psplatform, "getloadavg"):
1896    # Perform this hasattr check once on import time to either use the
1897    # platform based code or proxy straight from the os module.
1898    if hasattr(os, "getloadavg"):
1899        getloadavg = os.getloadavg
1900    else:
1901        getloadavg = _psplatform.getloadavg
1902
1903    __all__.append("getloadavg")
1904
1905
1906# =====================================================================
1907# --- system memory related functions
1908# =====================================================================
1909
1910
1911def virtual_memory():
1912    """Return statistics about system memory usage as a namedtuple
1913    including the following fields, expressed in bytes:
1914
1915     - total:
1916       total physical memory available.
1917
1918     - available:
1919       the memory that can be given instantly to processes without the
1920       system going into swap.
1921       This is calculated by summing different memory values depending
1922       on the platform and it is supposed to be used to monitor actual
1923       memory usage in a cross platform fashion.
1924
1925     - percent:
1926       the percentage usage calculated as (total - available) / total * 100
1927
1928     - used:
1929        memory used, calculated differently depending on the platform and
1930        designed for informational purposes only:
1931        macOS: active + wired
1932        BSD: active + wired + cached
1933        Linux: total - free
1934
1935     - free:
1936       memory not being used at all (zeroed) that is readily available;
1937       note that this doesn't reflect the actual memory available
1938       (use 'available' instead)
1939
1940    Platform-specific fields:
1941
1942     - active (UNIX):
1943       memory currently in use or very recently used, and so it is in RAM.
1944
1945     - inactive (UNIX):
1946       memory that is marked as not used.
1947
1948     - buffers (BSD, Linux):
1949       cache for things like file system metadata.
1950
1951     - cached (BSD, macOS):
1952       cache for various things.
1953
1954     - wired (macOS, BSD):
1955       memory that is marked to always stay in RAM. It is never moved to disk.
1956
1957     - shared (BSD):
1958       memory that may be simultaneously accessed by multiple processes.
1959
1960    The sum of 'used' and 'available' does not necessarily equal total.
1961    On Windows 'available' and 'free' are the same.
1962    """
1963    global _TOTAL_PHYMEM
1964    ret = _psplatform.virtual_memory()
1965    # cached for later use in Process.memory_percent()
1966    _TOTAL_PHYMEM = ret.total
1967    return ret
1968
1969
1970def swap_memory():
1971    """Return system swap memory statistics as a namedtuple including
1972    the following fields:
1973
1974     - total:   total swap memory in bytes
1975     - used:    used swap memory in bytes
1976     - free:    free swap memory in bytes
1977     - percent: the percentage usage
1978     - sin:     no. of bytes the system has swapped in from disk (cumulative)
1979     - sout:    no. of bytes the system has swapped out from disk (cumulative)
1980
1981    'sin' and 'sout' on Windows are meaningless and always set to 0.
1982    """
1983    return _psplatform.swap_memory()
1984
1985
1986# =====================================================================
1987# --- disks/paritions related functions
1988# =====================================================================
1989
1990
1991def disk_usage(path):
1992    """Return disk usage statistics about the given *path* as a
1993    namedtuple including total, used and free space expressed in bytes
1994    plus the percentage usage.
1995    """
1996    return _psplatform.disk_usage(path)
1997
1998
1999def disk_partitions(all=False):
2000    """Return mounted partitions as a list of
2001    (device, mountpoint, fstype, opts) namedtuple.
2002    'opts' field is a raw string separated by commas indicating mount
2003    options which may vary depending on the platform.
2004
2005    If *all* parameter is False return physical devices only and ignore
2006    all others.
2007    """
2008    def pathconf(path, name):
2009        try:
2010            return os.pathconf(path, name)
2011        except (OSError, AttributeError):
2012            pass
2013
2014    ret = _psplatform.disk_partitions(all)
2015    if POSIX:
2016        new = []
2017        for item in ret:
2018            nt = item._replace(
2019                maxfile=pathconf(item.mountpoint, 'PC_NAME_MAX'),
2020                maxpath=pathconf(item.mountpoint, 'PC_PATH_MAX'))
2021            new.append(nt)
2022        return new
2023    else:
2024        return ret
2025
2026
2027def disk_io_counters(perdisk=False, nowrap=True):
2028    """Return system disk I/O statistics as a namedtuple including
2029    the following fields:
2030
2031     - read_count:  number of reads
2032     - write_count: number of writes
2033     - read_bytes:  number of bytes read
2034     - write_bytes: number of bytes written
2035     - read_time:   time spent reading from disk (in ms)
2036     - write_time:  time spent writing to disk (in ms)
2037
2038    Platform specific:
2039
2040     - busy_time: (Linux, FreeBSD) time spent doing actual I/Os (in ms)
2041     - read_merged_count (Linux): number of merged reads
2042     - write_merged_count (Linux): number of merged writes
2043
2044    If *perdisk* is True return the same information for every
2045    physical disk installed on the system as a dictionary
2046    with partition names as the keys and the namedtuple
2047    described above as the values.
2048
2049    If *nowrap* is True it detects and adjust the numbers which overflow
2050    and wrap (restart from 0) and add "old value" to "new value" so that
2051    the returned numbers will always be increasing or remain the same,
2052    but never decrease.
2053    "disk_io_counters.cache_clear()" can be used to invalidate the
2054    cache.
2055
2056    On recent Windows versions 'diskperf -y' command may need to be
2057    executed first otherwise this function won't find any disk.
2058    """
2059    kwargs = dict(perdisk=perdisk) if LINUX else {}
2060    rawdict = _psplatform.disk_io_counters(**kwargs)
2061    if not rawdict:
2062        return {} if perdisk else None
2063    if nowrap:
2064        rawdict = _wrap_numbers(rawdict, 'psutil.disk_io_counters')
2065    nt = getattr(_psplatform, "sdiskio", _common.sdiskio)
2066    if perdisk:
2067        for disk, fields in rawdict.items():
2068            rawdict[disk] = nt(*fields)
2069        return rawdict
2070    else:
2071        return nt(*[sum(x) for x in zip(*rawdict.values())])
2072
2073
2074disk_io_counters.cache_clear = functools.partial(
2075    _wrap_numbers.cache_clear, 'psutil.disk_io_counters')
2076disk_io_counters.cache_clear.__doc__ = "Clears nowrap argument cache"
2077
2078
2079# =====================================================================
2080# --- network related functions
2081# =====================================================================
2082
2083
2084def net_io_counters(pernic=False, nowrap=True):
2085    """Return network I/O statistics as a namedtuple including
2086    the following fields:
2087
2088     - bytes_sent:   number of bytes sent
2089     - bytes_recv:   number of bytes received
2090     - packets_sent: number of packets sent
2091     - packets_recv: number of packets received
2092     - errin:        total number of errors while receiving
2093     - errout:       total number of errors while sending
2094     - dropin:       total number of incoming packets which were dropped
2095     - dropout:      total number of outgoing packets which were dropped
2096                     (always 0 on macOS and BSD)
2097
2098    If *pernic* is True return the same information for every
2099    network interface installed on the system as a dictionary
2100    with network interface names as the keys and the namedtuple
2101    described above as the values.
2102
2103    If *nowrap* is True it detects and adjust the numbers which overflow
2104    and wrap (restart from 0) and add "old value" to "new value" so that
2105    the returned numbers will always be increasing or remain the same,
2106    but never decrease.
2107    "disk_io_counters.cache_clear()" can be used to invalidate the
2108    cache.
2109    """
2110    rawdict = _psplatform.net_io_counters()
2111    if not rawdict:
2112        return {} if pernic else None
2113    if nowrap:
2114        rawdict = _wrap_numbers(rawdict, 'psutil.net_io_counters')
2115    if pernic:
2116        for nic, fields in rawdict.items():
2117            rawdict[nic] = _common.snetio(*fields)
2118        return rawdict
2119    else:
2120        return _common.snetio(*[sum(x) for x in zip(*rawdict.values())])
2121
2122
2123net_io_counters.cache_clear = functools.partial(
2124    _wrap_numbers.cache_clear, 'psutil.net_io_counters')
2125net_io_counters.cache_clear.__doc__ = "Clears nowrap argument cache"
2126
2127
2128def net_connections(kind='inet'):
2129    """Return system-wide socket connections as a list of
2130    (fd, family, type, laddr, raddr, status, pid) namedtuples.
2131    In case of limited privileges 'fd' and 'pid' may be set to -1
2132    and None respectively.
2133    The *kind* parameter filters for connections that fit the
2134    following criteria:
2135
2136    +------------+----------------------------------------------------+
2137    | Kind Value | Connections using                                  |
2138    +------------+----------------------------------------------------+
2139    | inet       | IPv4 and IPv6                                      |
2140    | inet4      | IPv4                                               |
2141    | inet6      | IPv6                                               |
2142    | tcp        | TCP                                                |
2143    | tcp4       | TCP over IPv4                                      |
2144    | tcp6       | TCP over IPv6                                      |
2145    | udp        | UDP                                                |
2146    | udp4       | UDP over IPv4                                      |
2147    | udp6       | UDP over IPv6                                      |
2148    | unix       | UNIX socket (both UDP and TCP protocols)           |
2149    | all        | the sum of all the possible families and protocols |
2150    +------------+----------------------------------------------------+
2151
2152    On macOS this function requires root privileges.
2153    """
2154    return _psplatform.net_connections(kind)
2155
2156
2157def net_if_addrs():
2158    """Return the addresses associated to each NIC (network interface
2159    card) installed on the system as a dictionary whose keys are the
2160    NIC names and value is a list of namedtuples for each address
2161    assigned to the NIC. Each namedtuple includes 5 fields:
2162
2163     - family: can be either socket.AF_INET, socket.AF_INET6 or
2164               psutil.AF_LINK, which refers to a MAC address.
2165     - address: is the primary address and it is always set.
2166     - netmask: and 'broadcast' and 'ptp' may be None.
2167     - ptp: stands for "point to point" and references the
2168            destination address on a point to point interface
2169            (typically a VPN).
2170     - broadcast: and *ptp* are mutually exclusive.
2171
2172    Note: you can have more than one address of the same family
2173    associated with each interface.
2174    """
2175    has_enums = sys.version_info >= (3, 4)
2176    if has_enums:
2177        import socket
2178    rawlist = _psplatform.net_if_addrs()
2179    rawlist.sort(key=lambda x: x[1])  # sort by family
2180    ret = collections.defaultdict(list)
2181    for name, fam, addr, mask, broadcast, ptp in rawlist:
2182        if has_enums:
2183            try:
2184                fam = socket.AddressFamily(fam)
2185            except ValueError:
2186                if WINDOWS and fam == -1:
2187                    fam = _psplatform.AF_LINK
2188                elif (hasattr(_psplatform, "AF_LINK") and
2189                        _psplatform.AF_LINK == fam):
2190                    # Linux defines AF_LINK as an alias for AF_PACKET.
2191                    # We re-set the family here so that repr(family)
2192                    # will show AF_LINK rather than AF_PACKET
2193                    fam = _psplatform.AF_LINK
2194        if fam == _psplatform.AF_LINK:
2195            # The underlying C function may return an incomplete MAC
2196            # address in which case we fill it with null bytes, see:
2197            # https://github.com/giampaolo/psutil/issues/786
2198            separator = ":" if POSIX else "-"
2199            while addr.count(separator) < 5:
2200                addr += "%s00" % separator
2201        ret[name].append(_common.snicaddr(fam, addr, mask, broadcast, ptp))
2202    return dict(ret)
2203
2204
2205def net_if_stats():
2206    """Return information about each NIC (network interface card)
2207    installed on the system as a dictionary whose keys are the
2208    NIC names and value is a namedtuple with the following fields:
2209
2210     - isup: whether the interface is up (bool)
2211     - duplex: can be either NIC_DUPLEX_FULL, NIC_DUPLEX_HALF or
2212               NIC_DUPLEX_UNKNOWN
2213     - speed: the NIC speed expressed in mega bits (MB); if it can't
2214              be determined (e.g. 'localhost') it will be set to 0.
2215     - mtu: the maximum transmission unit expressed in bytes.
2216    """
2217    return _psplatform.net_if_stats()
2218
2219
2220# =====================================================================
2221# --- sensors
2222# =====================================================================
2223
2224
2225# Linux, macOS
2226if hasattr(_psplatform, "sensors_temperatures"):
2227
2228    def sensors_temperatures(fahrenheit=False):
2229        """Return hardware temperatures. Each entry is a namedtuple
2230        representing a certain hardware sensor (it may be a CPU, an
2231        hard disk or something else, depending on the OS and its
2232        configuration).
2233        All temperatures are expressed in celsius unless *fahrenheit*
2234        is set to True.
2235        """
2236        def convert(n):
2237            if n is not None:
2238                return (float(n) * 9 / 5) + 32 if fahrenheit else n
2239
2240        ret = collections.defaultdict(list)
2241        rawdict = _psplatform.sensors_temperatures()
2242
2243        for name, values in rawdict.items():
2244            while values:
2245                label, current, high, critical = values.pop(0)
2246                current = convert(current)
2247                high = convert(high)
2248                critical = convert(critical)
2249
2250                if high and not critical:
2251                    critical = high
2252                elif critical and not high:
2253                    high = critical
2254
2255                ret[name].append(
2256                    _common.shwtemp(label, current, high, critical))
2257
2258        return dict(ret)
2259
2260    __all__.append("sensors_temperatures")
2261
2262
2263# Linux
2264if hasattr(_psplatform, "sensors_fans"):
2265
2266    def sensors_fans():
2267        """Return fans speed. Each entry is a namedtuple
2268        representing a certain hardware sensor.
2269        All speed are expressed in RPM (rounds per minute).
2270        """
2271        return _psplatform.sensors_fans()
2272
2273    __all__.append("sensors_fans")
2274
2275
2276# Linux, Windows, FreeBSD, macOS
2277if hasattr(_psplatform, "sensors_battery"):
2278
2279    def sensors_battery():
2280        """Return battery information. If no battery is installed
2281        returns None.
2282
2283         - percent: battery power left as a percentage.
2284         - secsleft: a rough approximation of how many seconds are left
2285                     before the battery runs out of power. May be
2286                     POWER_TIME_UNLIMITED or POWER_TIME_UNLIMITED.
2287         - power_plugged: True if the AC power cable is connected.
2288        """
2289        return _psplatform.sensors_battery()
2290
2291    __all__.append("sensors_battery")
2292
2293
2294# =====================================================================
2295# --- other system related functions
2296# =====================================================================
2297
2298
2299def boot_time():
2300    """Return the system boot time expressed in seconds since the epoch."""
2301    # Note: we are not caching this because it is subject to
2302    # system clock updates.
2303    return _psplatform.boot_time()
2304
2305
2306def users():
2307    """Return users currently connected on the system as a list of
2308    namedtuples including the following fields.
2309
2310     - user: the name of the user
2311     - terminal: the tty or pseudo-tty associated with the user, if any.
2312     - host: the host name associated with the entry, if any.
2313     - started: the creation time as a floating point number expressed in
2314       seconds since the epoch.
2315    """
2316    return _psplatform.users()
2317
2318
2319# =====================================================================
2320# --- Windows services
2321# =====================================================================
2322
2323
2324if WINDOWS:
2325
2326    def win_service_iter():
2327        """Return a generator yielding a WindowsService instance for all
2328        Windows services installed.
2329        """
2330        return _psplatform.win_service_iter()
2331
2332    def win_service_get(name):
2333        """Get a Windows service by *name*.
2334        Raise NoSuchProcess if no service with such name exists.
2335        """
2336        return _psplatform.win_service_get(name)
2337
2338
2339# =====================================================================
2340
2341
2342def test():  # pragma: no cover
2343    from ._common import bytes2human
2344    from ._compat import get_terminal_size
2345
2346    today_day = datetime.date.today()
2347    templ = "%-10s %5s %5s %7s %7s %5s %6s %6s %6s  %s"
2348    attrs = ['pid', 'memory_percent', 'name', 'cmdline', 'cpu_times',
2349             'create_time', 'memory_info', 'status', 'nice', 'username']
2350    print(templ % ("USER", "PID", "%MEM", "VSZ", "RSS", "NICE",  # NOQA
2351                   "STATUS", "START", "TIME", "CMDLINE"))
2352    for p in process_iter(attrs, ad_value=None):
2353        if p.info['create_time']:
2354            ctime = datetime.datetime.fromtimestamp(p.info['create_time'])
2355            if ctime.date() == today_day:
2356                ctime = ctime.strftime("%H:%M")
2357            else:
2358                ctime = ctime.strftime("%b%d")
2359        else:
2360            ctime = ''
2361        if p.info['cpu_times']:
2362            cputime = time.strftime("%M:%S",
2363                                    time.localtime(sum(p.info['cpu_times'])))
2364        else:
2365            cputime = ''
2366
2367        user = p.info['username'] or ''
2368        if not user and POSIX:
2369            try:
2370                user = p.uids()[0]
2371            except Error:
2372                pass
2373        if user and WINDOWS and '\\' in user:
2374            user = user.split('\\')[1]
2375        user = user[:9]
2376        vms = bytes2human(p.info['memory_info'].vms) if \
2377            p.info['memory_info'] is not None else ''
2378        rss = bytes2human(p.info['memory_info'].rss) if \
2379            p.info['memory_info'] is not None else ''
2380        memp = round(p.info['memory_percent'], 1) if \
2381            p.info['memory_percent'] is not None else ''
2382        nice = int(p.info['nice']) if p.info['nice'] else ''
2383        if p.info['cmdline']:
2384            cmdline = ' '.join(p.info['cmdline'])
2385        else:
2386            cmdline = p.info['name']
2387        status = p.info['status'][:5] if p.info['status'] else ''
2388
2389        line = templ % (
2390            user[:10],
2391            p.info['pid'],
2392            memp,
2393            vms,
2394            rss,
2395            nice,
2396            status,
2397            ctime,
2398            cputime,
2399            cmdline)
2400        print(line[:get_terminal_size()[0]])  # NOQA
2401
2402
2403del memoize_when_activated, division
2404if sys.version_info[0] < 3:
2405    del num, x
2406
2407if __name__ == "__main__":
2408    test()
2409