From 4b1a05419df6101c43ce327ae97ea9154f8aa0f9 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 6 Jun 2024 21:30:17 +0200 Subject: [PATCH] Fix #2250 / NetBSD / cmdline: retry on EBUSY. (#2421) `Process.cmdline()` sometimes fail with EBUSY. It usually happens for long cmdlines with lots of arguments. In this case retry getting the cmdline for up to 50 times, and return an empty list as last resort. --- HISTORY.rst | 10 +++++++--- psutil/arch/netbsd/proc.c | 32 ++++++++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index a53590555..bc183170d 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -21,15 +21,19 @@ **Bug fixes** -- 2395_, [OpenBSD]: `pid_exists()`_ erroneously return True if the argument is - a thread ID (TID) instead of a PID (process ID). -- 2254_, [Linux]: offline cpus raise NotImplementedError in cpu_freq() (patch by Shade Gladden) +- 2250_, [NetBSD]: `Process.cmdline()`_ sometimes fail with EBUSY. It usually + happens for long cmdlines with lots of arguments. In this case retry getting + the cmdline for up to 50 times, and return an empty list as last resort. +- 2254_, [Linux]: offline cpus raise NotImplementedError in cpu_freq() (patch + by Shade Gladden) - 2272_: Add pickle support to psutil Exceptions. - 2359_, [Windows], [CRITICAL]: `pid_exists()`_ disagrees with `Process`_ on whether a pid exists when ERROR_ACCESS_DENIED. - 2360_, [macOS]: can't compile on macOS < 10.13. (patch by Ryan Schmidt) - 2362_, [macOS]: can't compile on macOS 10.11. (patch by Ryan Schmidt) - 2365_, [macOS]: can't compile on macOS < 10.9. (patch by Ryan Schmidt) +- 2395_, [OpenBSD]: `pid_exists()`_ erroneously return True if the argument is + a thread ID (TID) instead of a PID (process ID). **Porting notes** diff --git a/psutil/arch/netbsd/proc.c b/psutil/arch/netbsd/proc.c index c645f301e..4cd43c4c7 100644 --- a/psutil/arch/netbsd/proc.c +++ b/psutil/arch/netbsd/proc.c @@ -332,6 +332,8 @@ psutil_proc_cmdline(PyObject *self, PyObject *args) { pid_t pid; int mib[4]; int st; + int attempt; + int max_attempts = 50; size_t len = 0; size_t pos = 0; char *procargs = NULL; @@ -359,10 +361,32 @@ psutil_proc_cmdline(PyObject *self, PyObject *args) { PyErr_NoMemory(); goto error; } - st = sysctl(mib, __arraycount(mib), procargs, &len, NULL, 0); - if (st == -1) { - PyErr_SetFromOSErrnoWithSyscall("sysctl(KERN_PROC_ARGV)"); - goto error; + + while (1) { + st = sysctl(mib, __arraycount(mib), procargs, &len, NULL, 0); + if (st == -1) { + if (errno == EBUSY) { + // Usually happens with TestProcess.test_long_cmdline. See: + // https://github.com/giampaolo/psutil/issues/2250 + attempt += 1; + if (attempt < max_attempts) { + psutil_debug("proc %zu cmdline(): retry on EBUSY", pid); + continue; + } + else { + psutil_debug( + "proc %zu cmdline(): return [] due to EBUSY", pid + ); + free(procargs); + return py_retlist; + } + } + else { + PyErr_SetFromOSErrnoWithSyscall("sysctl(KERN_PROC_ARGV)"); + goto error; + } + } + break; } if (len > 0) {