| #!/usr/bin/env python |
| |
| # Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Routines common to all posix systems.""" |
| |
| import os |
| import errno |
| import psutil |
| import sys |
| import time |
| import glob |
| |
| from psutil._error import TimeoutExpired |
| from psutil._common import nt_diskinfo, usage_percent, memoize |
| |
| |
| def pid_exists(pid): |
| """Check whether pid exists in the current process table.""" |
| if pid < 0: |
| return False |
| try: |
| os.kill(pid, 0) |
| except OSError: |
| e = sys.exc_info()[1] |
| return e.errno == errno.EPERM |
| else: |
| return True |
| |
| def wait_pid(pid, timeout=None): |
| """Wait for process with pid 'pid' to terminate and return its |
| exit status code as an integer. |
| |
| If pid is not a children of os.getpid() (current process) just |
| waits until the process disappears and return None. |
| |
| If pid does not exist at all return None immediately. |
| |
| Raise TimeoutExpired on timeout expired. |
| """ |
| def check_timeout(delay): |
| if timeout is not None: |
| if timer() >= stop_at: |
| raise TimeoutExpired(pid) |
| time.sleep(delay) |
| return min(delay * 2, 0.04) |
| |
| timer = getattr(time, 'monotonic', time.time) |
| if timeout is not None: |
| waitcall = lambda: os.waitpid(pid, os.WNOHANG) |
| stop_at = timer() + timeout |
| else: |
| waitcall = lambda: os.waitpid(pid, 0) |
| |
| delay = 0.0001 |
| while 1: |
| try: |
| retpid, status = waitcall() |
| except OSError: |
| err = sys.exc_info()[1] |
| if err.errno == errno.EINTR: |
| delay = check_timeout(delay) |
| continue |
| elif err.errno == errno.ECHILD: |
| # This has two meanings: |
| # - pid is not a child of os.getpid() in which case |
| # we keep polling until it's gone |
| # - pid never existed in the first place |
| # In both cases we'll eventually return None as we |
| # can't determine its exit status code. |
| while 1: |
| if pid_exists(pid): |
| delay = check_timeout(delay) |
| else: |
| return |
| else: |
| raise |
| else: |
| if retpid == 0: |
| # WNOHANG was used, pid is still running |
| delay = check_timeout(delay) |
| continue |
| # process exited due to a signal; return the integer of |
| # that signal |
| if os.WIFSIGNALED(status): |
| return os.WTERMSIG(status) |
| # process exited using exit(2) system call; return the |
| # integer exit(2) system call has been called with |
| elif os.WIFEXITED(status): |
| return os.WEXITSTATUS(status) |
| else: |
| # should never happen |
| raise RuntimeError("unknown process exit status") |
| |
| def get_disk_usage(path): |
| """Return disk usage associated with path.""" |
| st = os.statvfs(path) |
| free = (st.f_bavail * st.f_frsize) |
| total = (st.f_blocks * st.f_frsize) |
| used = (st.f_blocks - st.f_bfree) * st.f_frsize |
| percent = usage_percent(used, total, _round=1) |
| # NB: the percentage is -5% than what shown by df due to |
| # reserved blocks that we are currently not considering: |
| # http://goo.gl/sWGbH |
| return nt_diskinfo(total, used, free, percent) |
| |
| @memoize |
| def _get_terminal_map(): |
| ret = {} |
| ls = glob.glob('/dev/tty*') + glob.glob('/dev/pts/*') |
| for name in ls: |
| assert name not in ret |
| try: |
| ret[os.stat(name).st_rdev] = name |
| except OSError: |
| err = sys.exc_info()[1] |
| if err.errno != errno.ENOENT: |
| raise |
| return ret |