psutil 7.x calls ``os.pidfd_open(pid, 0)`` to wait for a process. On some Linux kernels (e.g. systemd-managed daemons whose pid was already reaped, or arm64 6.x boxes) ``pidfd_open`` returns ``EINVAL`` instead of ``ESRCH`` for a non-existent pid. psutil's ``wait_pid_pidfd_open``
()
| 84 | |
| 85 | |
| 86 | def _patch_psutil_pidfd_open_einval() -> None: |
| 87 | """ |
| 88 | psutil 7.x calls ``os.pidfd_open(pid, 0)`` to wait for a process. |
| 89 | On some Linux kernels (e.g. systemd-managed daemons whose pid was |
| 90 | already reaped, or arm64 6.x boxes) ``pidfd_open`` returns ``EINVAL`` |
| 91 | instead of ``ESRCH`` for a non-existent pid. psutil's |
| 92 | ``wait_pid_pidfd_open`` only falls back to the legacy ``waitpid`` path |
| 93 | for ``ESRCH``/``EMFILE``/``ENFILE``/``ENODEV`` -- ``EINVAL`` propagates |
| 94 | out of fixture teardown and shows up as ``ERROR at teardown of <test>`` |
| 95 | even when the test itself was skipped or passed. Treat ``EINVAL`` the |
| 96 | same as ``ESRCH``. |
| 97 | """ |
| 98 | try: |
| 99 | import errno as _errno |
| 100 | |
| 101 | from psutil import _psposix |
| 102 | except ImportError: |
| 103 | return |
| 104 | # psutil <5.10 doesn't expose wait_pid_pidfd_open; nothing to patch. |
| 105 | if not hasattr(_psposix, "wait_pid_pidfd_open"): |
| 106 | return |
| 107 | if getattr(_psposix.wait_pid_pidfd_open, "_salt_einval_wrap", False): |
| 108 | return |
| 109 | original = _psposix.wait_pid_pidfd_open |
| 110 | |
| 111 | def wrapper(pid, timeout=None): |
| 112 | try: |
| 113 | return original(pid, timeout) |
| 114 | except OSError as exc: |
| 115 | if exc.errno == _errno.EINVAL: |
| 116 | return _psposix.wait_pid_posix(pid, timeout) |
| 117 | raise |
| 118 | |
| 119 | wrapper._salt_einval_wrap = True |
| 120 | _psposix.wait_pid_pidfd_open = wrapper |
| 121 | |
| 122 | |
| 123 | _patch_psutil_pidfd_open_einval() |