为什么 ps 在列出完整命令行参数时不退出?

AJM*_*eld 5 process kill ps process-management

任何时候我尝试运行ps使其输出任何进程的参数的方式运行该命令或另一个类似命令时,该命令都会运行并生成输出,但随后会冻结,进入永远不会退出的“不间断睡眠”状态。

\n

目前,我有 17 个冻结进程仍然坐在那里(摘自top -u $USER):

\n
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND\n 8807 foo_user  20   0   28912   2984   2680 D   0.0  0.0   0:00.10 ps\n14040 foo_user  20   0   29124   3108   2796 D   0.0  0.0   0:00.14 ps\n14342 foo_user  20   0   28912   2972   2668 D   0.0  0.0   0:00.10 ps\n15528 foo_user  20   0   28912   3028   2724 D   0.0  0.0   0:00.10 ps\n16677 foo_user  20   0   28912   2992   2692 D   0.0  0.0   0:00.11 ps\n18723 foo_user  20   0   28912   3000   2696 D   0.0  0.0   0:00.12 ps\n19427 foo_user  20   0   29124   3080   2772 D   0.0  0.0   0:00.14 ps\n19587 foo_user  20   0   29124   3108   2804 D   0.0  0.0   0:00.08 ps\n19917 foo_user  20   0   29124   3056   2748 D   0.0  0.0   0:00.08 ps\n20267 foo_user  20   0   29124   3056   2760 D   0.0  0.0   0:00.10 ps\n20566 foo_user  20   0   29124   1604   1412 D   0.0  0.0   0:00.09 ps\n21189 foo_user  20   0   28912   2940   2648 D   0.0  0.0   0:00.10 ps\n21296 foo_user  20   0   28912   1524   1332 D   0.0  0.0   0:00.10 ps\n21674 foo_user  20   0   28840   3208   2648 D   0.0  0.0   0:00.07 pgrep\n26220 foo_user  20   0   28912   2968   2672 D   0.0  0.0   0:00.10 ps\n
Run Code Online (Sandbox Code Playgroud)\n

除了 之外pgrep,所有这些最初都是从 bash shell 在 ssh 会话中启动的;此后,我手动终止了sshdbash进程,但子ps进程仍然存在。pid 21674 是我按下内部尝试以 \xe2\x80\x94 方式列出命令行参数的pgrep结果,导致在等待时也冻结ctoptoppgrep输出时也冻结。

\n

我已经排除了某些正在运行的进程的参数在某种程度上“脏”(太长?包含控制字符?)并导致这种情况的可能性,因为即使在尝试显示我知道的一个特定 PID 的参数时也会发生冻结是安全且正常的,例如:

\n
foo_user@my_machine:~$ ps 14040\n  PID TTY      STAT   TIME COMMAND\n14040 ?        D      0:00 ps -aux\n
Run Code Online (Sandbox Code Playgroud)\n

(它也以完全相同的方式冻结,现在 pid 22620 在上面的列表中。)

\n

但是,使用ps未列出完整进程命令行的参数运行不会导致此冻结。我能够成功运行ps -u $USERor top -u $USER,获取输出,并使这些进程正常退出。

\n

冻结的进程不会响应任何标准输入,包括通常会退出或挂起正在运行的进程的控制字符,如ctrlC或。ctrlZ他们也不响应任何信号;即使发送 SIGKILL (通过kill -9)也不会使这些进程退出。

\n

请注意,这是一个多用户系统,我没有超级用户访问权限。

\n

为什么这些进程会像这样冻结,以及如何在不冻结列表进程的情况下列出进程的参数?

\n
\n

我运行了@StephenKitt 建议的一些命令。

\n

第一个命令简单地给出了一个错误:

\n
foo_user@my_machine:~$ strace -p 8807\nstrace: attach: ptrace(PTRACE_ATTACH, ...): Operation not permitted\nCould not attach to process.  If your uid matches the uid of the target\nprocess, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try\nagain as the root user.  For more details, see /etc/sysctl.d/10-ptrace.conf\n
Run Code Online (Sandbox Code Playgroud)\n

第二个命令显示,由于某种原因, ps 命令仍然打开并读取每一个/proc/*/cmdline,而不仅仅是指定的一个。

\n
foo_user@my_machine:~$ strace ps 14040\n\xe2\x8b\xae\n\xe2\x8b\xae\nstat("/proc/30825", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0\nopen("/proc/30825/stat", O_RDONLY)      = 6\nread(6, "30825 (gvfsd-network) S 1 2650 2"..., 2048) = 186\nclose(6)                                = 0\nopen("/proc/30825/status", O_RDONLY)    = 6\nread(6, "Name:\\tgvfsd-network\\nState:\\tS (sl"..., 2048) = 1000\nclose(6)                                = 0\nopen("/proc/30825/cmdline", O_RDONLY)   = 6\nread(6, "/usr/lib/gvfs/gvfsd-network\\0--sp"..., 131072) = 70\nread(6, "", 131002)                     = 0\nclose(6)                                = 0\nstat("/proc/30849", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0\nopen("/proc/30849/stat", O_RDONLY)      = 6\nread(6, "30849 (chrome) S 1 1750 1750 0 -"..., 2048) = 216\nclose(6)                                = 0\nopen("/proc/30849/status", O_RDONLY)    = 6\nread(6, "Name:\\tchrome\\nState:\\tS (sleeping)"..., 2048) = 1005\nclose(6)                                = 0\nopen("/proc/30849/cmdline", O_RDONLY)   = 6\nread(6, \n
Run Code Online (Sandbox Code Playgroud)\n

这是该命令输出的结尾,此时它以与其他ps命令冻结相同的方式冻结。

\n
\n

运行ps -q $pid -o args确实有效,列出指定 PID 的参数而不冻结。该标志使 ps 明确避免读取除指定进程之外的任何进程的进程文件。

\n