Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/psutil/_psposix.py @ 1:56ad4e20f292 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
| author | guerler |
|---|---|
| date | Fri, 31 Jul 2020 00:32:28 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:d30785e31577 | 1:56ad4e20f292 |
|---|---|
| 1 # Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 """Routines common to all posix systems.""" | |
| 6 | |
| 7 import glob | |
| 8 import os | |
| 9 import signal | |
| 10 import sys | |
| 11 import time | |
| 12 | |
| 13 from ._common import memoize | |
| 14 from ._common import sdiskusage | |
| 15 from ._common import TimeoutExpired | |
| 16 from ._common import usage_percent | |
| 17 from ._compat import ChildProcessError | |
| 18 from ._compat import FileNotFoundError | |
| 19 from ._compat import InterruptedError | |
| 20 from ._compat import PermissionError | |
| 21 from ._compat import ProcessLookupError | |
| 22 from ._compat import PY3 | |
| 23 from ._compat import unicode | |
| 24 | |
| 25 if sys.version_info >= (3, 4): | |
| 26 import enum | |
| 27 else: | |
| 28 enum = None | |
| 29 | |
| 30 | |
| 31 __all__ = ['pid_exists', 'wait_pid', 'disk_usage', 'get_terminal_map'] | |
| 32 | |
| 33 | |
| 34 def pid_exists(pid): | |
| 35 """Check whether pid exists in the current process table.""" | |
| 36 if pid == 0: | |
| 37 # According to "man 2 kill" PID 0 has a special meaning: | |
| 38 # it refers to <<every process in the process group of the | |
| 39 # calling process>> so we don't want to go any further. | |
| 40 # If we get here it means this UNIX platform *does* have | |
| 41 # a process with id 0. | |
| 42 return True | |
| 43 try: | |
| 44 os.kill(pid, 0) | |
| 45 except ProcessLookupError: | |
| 46 return False | |
| 47 except PermissionError: | |
| 48 # EPERM clearly means there's a process to deny access to | |
| 49 return True | |
| 50 # According to "man 2 kill" possible error values are | |
| 51 # (EINVAL, EPERM, ESRCH) | |
| 52 else: | |
| 53 return True | |
| 54 | |
| 55 | |
| 56 # Python 3.5 signals enum (contributed by me ^^): | |
| 57 # https://bugs.python.org/issue21076 | |
| 58 if enum is not None and hasattr(signal, "Signals"): | |
| 59 Negsignal = enum.IntEnum( | |
| 60 'Negsignal', dict([(x.name, -x.value) for x in signal.Signals])) | |
| 61 | |
| 62 def negsig_to_enum(num): | |
| 63 """Convert a negative signal value to an enum.""" | |
| 64 try: | |
| 65 return Negsignal(num) | |
| 66 except ValueError: | |
| 67 return num | |
| 68 else: | |
| 69 def negsig_to_enum(num): | |
| 70 return num | |
| 71 | |
| 72 | |
| 73 def wait_pid(pid, timeout=None, proc_name=None, | |
| 74 _waitpid=os.waitpid, | |
| 75 _timer=getattr(time, 'monotonic', time.time), | |
| 76 _min=min, | |
| 77 _sleep=time.sleep, | |
| 78 _pid_exists=pid_exists): | |
| 79 """Wait for a process PID to terminate. | |
| 80 | |
| 81 If the process terminated normally by calling exit(3) or _exit(2), | |
| 82 or by returning from main(), the return value is the positive integer | |
| 83 passed to *exit(). | |
| 84 | |
| 85 If it was terminated by a signal it returns the negated value of the | |
| 86 signal which caused the termination (e.g. -SIGTERM). | |
| 87 | |
| 88 If PID is not a children of os.getpid() (current process) just | |
| 89 wait until the process disappears and return None. | |
| 90 | |
| 91 If PID does not exist at all return None immediately. | |
| 92 | |
| 93 If *timeout* != None and process is still alive raise TimeoutExpired. | |
| 94 timeout=0 is also possible (either return immediately or raise). | |
| 95 """ | |
| 96 if pid <= 0: | |
| 97 raise ValueError("can't wait for PID 0") # see "man waitpid" | |
| 98 interval = 0.0001 | |
| 99 flags = 0 | |
| 100 if timeout is not None: | |
| 101 flags |= os.WNOHANG | |
| 102 stop_at = _timer() + timeout | |
| 103 | |
| 104 def sleep(interval): | |
| 105 # Sleep for some time and return a new increased interval. | |
| 106 if timeout is not None: | |
| 107 if _timer() >= stop_at: | |
| 108 raise TimeoutExpired(timeout, pid=pid, name=proc_name) | |
| 109 _sleep(interval) | |
| 110 return _min(interval * 2, 0.04) | |
| 111 | |
| 112 # See: https://linux.die.net/man/2/waitpid | |
| 113 while True: | |
| 114 try: | |
| 115 retpid, status = os.waitpid(pid, flags) | |
| 116 except InterruptedError: | |
| 117 interval = sleep(interval) | |
| 118 except ChildProcessError: | |
| 119 # This has two meanings: | |
| 120 # - PID is not a child of os.getpid() in which case | |
| 121 # we keep polling until it's gone | |
| 122 # - PID never existed in the first place | |
| 123 # In both cases we'll eventually return None as we | |
| 124 # can't determine its exit status code. | |
| 125 while _pid_exists(pid): | |
| 126 interval = sleep(interval) | |
| 127 return | |
| 128 else: | |
| 129 if retpid == 0: | |
| 130 # WNOHANG flag was used and PID is still running. | |
| 131 interval = sleep(interval) | |
| 132 continue | |
| 133 elif os.WIFEXITED(status): | |
| 134 # Process terminated normally by calling exit(3) or _exit(2), | |
| 135 # or by returning from main(). The return value is the | |
| 136 # positive integer passed to *exit(). | |
| 137 return os.WEXITSTATUS(status) | |
| 138 elif os.WIFSIGNALED(status): | |
| 139 # Process exited due to a signal. Return the negative value | |
| 140 # of that signal. | |
| 141 return negsig_to_enum(-os.WTERMSIG(status)) | |
| 142 # elif os.WIFSTOPPED(status): | |
| 143 # # Process was stopped via SIGSTOP or is being traced, and | |
| 144 # # waitpid() was called with WUNTRACED flag. PID is still | |
| 145 # # alive. From now on waitpid() will keep returning (0, 0) | |
| 146 # # until the process state doesn't change. | |
| 147 # # It may make sense to catch/enable this since stopped PIDs | |
| 148 # # ignore SIGTERM. | |
| 149 # interval = sleep(interval) | |
| 150 # continue | |
| 151 # elif os.WIFCONTINUED(status): | |
| 152 # # Process was resumed via SIGCONT and waitpid() was called | |
| 153 # # with WCONTINUED flag. | |
| 154 # interval = sleep(interval) | |
| 155 # continue | |
| 156 else: | |
| 157 # Should never happen. | |
| 158 raise ValueError("unknown process exit status %r" % status) | |
| 159 | |
| 160 | |
| 161 def disk_usage(path): | |
| 162 """Return disk usage associated with path. | |
| 163 Note: UNIX usually reserves 5% disk space which is not accessible | |
| 164 by user. In this function "total" and "used" values reflect the | |
| 165 total and used disk space whereas "free" and "percent" represent | |
| 166 the "free" and "used percent" user disk space. | |
| 167 """ | |
| 168 if PY3: | |
| 169 st = os.statvfs(path) | |
| 170 else: | |
| 171 # os.statvfs() does not support unicode on Python 2: | |
| 172 # - https://github.com/giampaolo/psutil/issues/416 | |
| 173 # - http://bugs.python.org/issue18695 | |
| 174 try: | |
| 175 st = os.statvfs(path) | |
| 176 except UnicodeEncodeError: | |
| 177 if isinstance(path, unicode): | |
| 178 try: | |
| 179 path = path.encode(sys.getfilesystemencoding()) | |
| 180 except UnicodeEncodeError: | |
| 181 pass | |
| 182 st = os.statvfs(path) | |
| 183 else: | |
| 184 raise | |
| 185 | |
| 186 # Total space which is only available to root (unless changed | |
| 187 # at system level). | |
| 188 total = (st.f_blocks * st.f_frsize) | |
| 189 # Remaining free space usable by root. | |
| 190 avail_to_root = (st.f_bfree * st.f_frsize) | |
| 191 # Remaining free space usable by user. | |
| 192 avail_to_user = (st.f_bavail * st.f_frsize) | |
| 193 # Total space being used in general. | |
| 194 used = (total - avail_to_root) | |
| 195 # Total space which is available to user (same as 'total' but | |
| 196 # for the user). | |
| 197 total_user = used + avail_to_user | |
| 198 # User usage percent compared to the total amount of space | |
| 199 # the user can use. This number would be higher if compared | |
| 200 # to root's because the user has less space (usually -5%). | |
| 201 usage_percent_user = usage_percent(used, total_user, round_=1) | |
| 202 | |
| 203 # NB: the percentage is -5% than what shown by df due to | |
| 204 # reserved blocks that we are currently not considering: | |
| 205 # https://github.com/giampaolo/psutil/issues/829#issuecomment-223750462 | |
| 206 return sdiskusage( | |
| 207 total=total, used=used, free=avail_to_user, percent=usage_percent_user) | |
| 208 | |
| 209 | |
| 210 @memoize | |
| 211 def get_terminal_map(): | |
| 212 """Get a map of device-id -> path as a dict. | |
| 213 Used by Process.terminal() | |
| 214 """ | |
| 215 ret = {} | |
| 216 ls = glob.glob('/dev/tty*') + glob.glob('/dev/pts/*') | |
| 217 for name in ls: | |
| 218 assert name not in ret, name | |
| 219 try: | |
| 220 ret[os.stat(name).st_rdev] = name | |
| 221 except FileNotFoundError: | |
| 222 pass | |
| 223 return ret |
