|
13 | 13 | import shlex |
14 | 14 | import typing |
15 | 15 | import time |
| 16 | +import subprocess |
16 | 17 |
|
17 | 18 |
|
18 | 19 | class InternalPlatformUtils(base.InternalPlatformUtils): |
@@ -107,15 +108,12 @@ def _FindPostmaster( |
107 | 108 | assert type(pg_path_e) is str |
108 | 109 | assert type(data_dir_e) is str |
109 | 110 |
|
110 | | - # The regular expression remains the same since the output structure pid, ppid, args is the same |
111 | 111 | regexp = r"^\s*[0-9]+\s+[0-9]+\s+" + pg_path_e + r"(\s+.*)?\s+\-[D]\s+" + data_dir_e + r"(\s+.*)?" |
112 | 112 |
|
113 | | - # Change for macOS: Instead of Linux flag-combo "-ewwo" |
114 | | - # we use the standard POSIX "-eo", which works on macOS without trimming argument strings |
115 | 113 | cmd = [ |
116 | 114 | __class__.C_BASH_EXE, |
117 | 115 | "-c", |
118 | | - "ps -eo \"pid=,ppid=,args=\" | grep -E " + shlex.quote(regexp), |
| 116 | + "ps -ewwo \"pid=,ppid=,args=\" | grep -E " + shlex.quote(regexp), |
119 | 117 | ] |
120 | 118 |
|
121 | 119 | exec_r = os_ops.run( |
@@ -260,46 +258,73 @@ def ProcessIsZombi_soft_check( |
260 | 258 |
|
261 | 259 | # Change for macOS: Instead of reading non-existent /proc/PID/stat, |
262 | 260 | # we make a native call to the system ps and request the status (state) of the process. |
263 | | - cmd = ["ps", "-p", str(pid), "-o", "state="] |
| 261 | + cmd = ["ps", "-p", str(pid), "-wwo", "state="] |
264 | 262 |
|
265 | | - try: |
266 | | - exec_r = os_ops.run( |
267 | | - cmd=cmd, |
268 | | - check=False, |
269 | | - exec_env=__class__.sm_exec_env, |
270 | | - ) |
271 | | - |
272 | | - assert type(exec_r) is OsCommandResult |
273 | | - |
274 | | - # Если процесс не найден (уже завершился и стерт), ps вернет код 1 |
275 | | - if exec_r.returncode != 0: |
276 | | - return False |
| 263 | + exec_r = os_ops.run( |
| 264 | + cmd=cmd, |
| 265 | + check=False, |
| 266 | + exec_env=__class__.sm_exec_env, |
| 267 | + stdout=subprocess.PIPE, |
| 268 | + ) |
277 | 269 |
|
278 | | - proc_status = exec_r.stdout.decode("utf-8", errors="ignore").strip() |
| 270 | + assert type(exec_r) is OsCommandResult |
| 271 | + assert type(exec_r.stdout) is bytes |
279 | 272 |
|
280 | | - if not proc_status: |
281 | | - return False |
| 273 | + # If the process is not found (already terminated and deleted), ps will return code 1 |
| 274 | + if exec_r.returncode == 1: |
| 275 | + return False |
282 | 276 |
|
283 | | - # В BSD-системах статус зомби обозначается буквой 'Z' |
284 | | - return proc_status.startswith("Z") |
| 277 | + if exec_r.returncode != 0: |
| 278 | + return None |
285 | 279 |
|
286 | | - except Exception as e: |
287 | | - # If the file disappeared right during reading, it means the process is completely erased |
288 | | - if __class__._is_file_not_found_exception(e): |
289 | | - return False |
| 280 | + proc_status = exec_r.stdout.decode("utf-8").rstrip() |
290 | 281 |
|
291 | | - return None |
| 282 | + if not proc_status: |
| 283 | + return None |
292 | 284 |
|
293 | | - @staticmethod |
294 | | - def _is_file_not_found_exception(e: Exception) -> bool: |
295 | | - if isinstance(e, FileNotFoundError): |
| 285 | + assert len(proc_status) > 0 |
| 286 | + |
| 287 | + # state The state is given by a sequence of letters, for example, |
| 288 | + # "RWNA". The first letter indicates the run state of the process: |
| 289 | + # |
| 290 | + # D Marks a process in disk (or other short term, uninterruptible) wait.[legacy option] |
| 291 | + # I Marks a process that is idle (sleeping for longer than about 20 seconds). |
| 292 | + # R Marks a runnable process. |
| 293 | + # S Marks a process that is sleeping for less than about 20 seconds. |
| 294 | + # T Marks a stopped process. |
| 295 | + # U Marks a process in uninterruptible wait. |
| 296 | + # Z Marks a dead process (a 'zombie'). |
| 297 | + # |
| 298 | + # Additional characters after these, if any, indicate additional |
| 299 | + # state information: |
| 300 | + # |
| 301 | + # + The process is in the foreground process group of its control terminal. |
| 302 | + # < The process has raised CPU scheduling priority. |
| 303 | + # > The process has specified a soft limit on memory requirements and is currently |
| 304 | + # exceeding that limit; such a process is (necessarily) not swapped. |
| 305 | + # A the process has asked for random page replacement |
| 306 | + # (VA_ANOM, from vadvise(2), for example, lisp(1) in a garbage collect). |
| 307 | + # E The process is trying to exit. |
| 308 | + # L The process has pages locked in core (for example, for raw I/O). |
| 309 | + # N The process has reduced CPU scheduling priority (see setpriority(2)). |
| 310 | + # S The process has asked for FIFO page replacement (VA_SEQL, |
| 311 | + # from vadvise(2), for example, a large image processing |
| 312 | + # program using virtual memory to sequentially address |
| 313 | + # voluminous data). |
| 314 | + # s The process is a session leader. |
| 315 | + # V The process is suspended during a vfork. |
| 316 | + # W The process is swapped out. |
| 317 | + # X The process is being traced or debugged. |
| 318 | + |
| 319 | + ch1 = proc_status[0] |
| 320 | + |
| 321 | + if ch1 == "Z": |
296 | 322 | return True |
297 | 323 |
|
298 | | - if isinstance(e, ExecUtilException): |
299 | | - if e.exit_code == 2: |
300 | | - return True |
| 324 | + if ch1 in "DIRSTU": |
| 325 | + return False |
301 | 326 |
|
302 | | - return False |
| 327 | + return None |
303 | 328 |
|
304 | 329 | T_PID_TO_PPID = typing.Dict[int, int] |
305 | 330 |
|
|
0 commit comments