我想知道如何区分内核线程和用户线程,以便我正在构建一个进程扫描器。我很难找到两种类型的好定义。
我发现内核线程没有自己的内存,因此/ proc / $ pid / status中没有Vm *值,而/ proc / $ pid / exe上的stat也没有返回任何内容。< / p>
因此,我认为如果进程没有Vm *值且没有inode编号,我可以识别内核线程。我想错了......我的脚本看到了php-cgi进程,有时会被识别为内核进程。
如果发现大多数错误识别的进程都是僵尸,那么后来就会消失。所以我实施了一个简单的检查,看看状态是否为“Z”。如果是这样,请忽略它。 这为我节省了很多误报,但我仍然收到有关php-cgi内核进程的消息。
有谁能告诉我如何以正确的方式区分内核线程和用户线程?
答案 0 :(得分:12)
内核线程与用户空间线程之间存在 的一些明显差异:
/proc/$pid/cmdline
对于内核线程是空的 - 这是ps
和top
用来区分内核线程的方法。
/proc/$pid/exe
符号链接没有内核线程的目标 - 这是有道理的,因为它们在文件系统上没有相应的可执行文件。
更具体地说,readlink()
系统调用返回ENOENT
(“没有这样的文件或目录”),尽管链接本身存在,表示事实这个过程的可执行文件不存在(从来没有)。
因此,检查内核线程的可靠方法应该是在readlink()
上调用/proc/$pid/exe
并检查其返回码。如果成功,则$pid
是用户进程。如果它与ENOENT
一起失败,则stat()
上的额外/proc/$pid/exe
应该告诉刚刚终止的进程内核线程的情况。
/proc/$pid/status
缺少大多数内核线程的几个字段 - 更具体地说是与虚拟内存相关的几个字段。
答案 1 :(得分:4)
正如您在上面的评论中指出的那样,所有用户进程都是init进程的后代(pid = 1)。内核线程不是init进程的后代,因为init是用户进程,而用户进程无法创建内核线程。因此,要检查进程p是否是用户进程而不是内核线程,需要对流程图进行操作并评估init dom p
dom是否为Dominator运算符。具体在Python中:
def is_user_process(p):
if (p=='1'):
print 'User process'
else:
pstat = open('/proc/%s/stat'%p).read().split()
parent = pstat[3]
if (parent=='1'):
print 'User process'
elif (parent=='0'):
print 'Kernel thread'
else:
is_user_process(parent)
答案 2 :(得分:0)
这是一个在bash下运行的版本:
# check if pid is user process and not a kernel thread
is_user_process() {
if [[ $1 -eq 1 ]]; then
return 0
else
parent=$(grep -e '^PPid:' /proc/$1/status | cut -c6-)
if [[ $parent -eq 1 ]]; then
return 0
elif [[ $parent -eq 0 ]]; then
return 1
else
is_user_process $parent
fi
fi
}
要使用它吗
~$ is_user_process `pgrep kthreadd` || echo "kthreadd is kernel process"
这至少对我来说是第一个有用的解决方案,感谢python版本的er0。
答案 3 :(得分:0)
您可以从flags
(see proc(5) manpage)中读取线程/proc/[pid]/stat
的值,并检查它是否设置了PF_KTHREAD
位标志。
PF_KTHREAD
常量本身就是available since 2.6.17,大约十年了,它的值是hasn't changed since then:
#define PF_KTHREAD 0x00200000 /* I am a kernel thread */
即使包含此常量(include/linux/sched.h
)的头文件也不会导出到用户空间,并且在源代码中具有此定义的副本,并且在运行时从用户空间进行了内核版本检查(例如,使用{{3 }}系统调用)应该非常健壮。