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 |