Open angelsl opened 4 years ago
It's possible for user tasks to have an empty cmdline too, if argv was NULL when it was exec-ed.
htop
is using this method because it is also used by ps
and top
. See https://stackoverflow.com/a/12231039/3342190 .
The correct way to check for a kernel thread is to check if its parent PID is 2.
I could not find any document that guarentees this behavior. Plus, kthreadd
only presents in linux 2.6+. See the link above ("On newer kernels (CentOS 6.x has 2.6.32) all kernel-threads seem to be a child of kthreadd. On older kernels (CentOS 5.x has 2.6.18) I see kernel-threads are a child of kthread (without the extra d) OR are a child of init.").
Even if we are dropping support for older kernels, there are better ways to do this: https://stackoverflow.com/a/56369641/3342190 . It is well documented, and works for 2.6+.
This PF_KTHREAD
approach was actually discussed in #761, but eventually not accepted.
This simply asserts that it is the method, but doesn't cite anything. I took a cursory glance through the source of procps-ng and I can't find any feature in ps
and top
that actually distinguishes kernel tasks from user tasks. The only relevant mention of this is in top
's manpage, which says:
6. COMMAND -- Command Name or Command Line
Display the command line used to start a task or the name of the associated program. You toggle between command line and name with 'c', which is both a command-line option and an interactive command.
When you've chosen to display command lines, processes without a command line (like kernel threads) will be shown with only the program name in brackets, as in this example:
[kthreadd]
...which doesn't actually say that they distinguish kthreads from user threads, just that kthreads (having no cmdline) will be displayed like so.
I could not find any document that guarentees this behavior.
Indeed there isn't, though it has been this way ever since kthreadd
was introduced. (v2.6.22) And I don't imagine this changing, because there is a reason it is PID 2—we want init
to be PID 1, but kthreadd
needs to be launched before init
can actually start executing because init
will do things that cause kthreads to be created. So we have to create init
so it gets PID 1, and before scheduling init
we create kthreadd
. So kthreadd
gets PID 2. There can be no user process that gets PID 2 because init
isn't scheduled until kthreadd
is created.
But yeah I agree, it's probably better to go with checking PF_KTHREAD
. Since it is exposed in procfs, it is now userspace-visible behaviour, and with Linux's don't-break-userspace guarantees, we can rely on this behaviour.
For kernels < v2.6.27 (which we should check via uname or such) when PF_KTHREAD was introduced, then we can fall back to checking cmdline.
I don't think this current way of checking for kthread is correct anyway, because it is entirely possible for user threads to end up with a NULL cmdline. (That's the entire reason I stumbled upon this issue. I was confused for 10-15 minutes why some process appeared in top
but not htop
—which I usually set to hide kernel threads, and I didn't expect that to be the problem..)
For kernels < v2.6.27 (which we should check via uname or such) when PF_KTHREAD was introduced, then we can fall back to checking cmdline.
A check or switch will be great. It's here if you wan't to make a PR: https://github.com/hishamhm/htop/blob/master/linux/LinuxProcessList.c#L695
It's possible for user tasks to have an empty
cmdline
too, ifargv
wasNULL
when it was exec-ed. (Rare, but it happens.)The correct way to check for a kernel thread is to check if its parent PID is 2. Although this kind of is a kernel implementation detail, currently:
kthreadd
is guaranteed to be PID 2 because it is started right afterinit
is created (but beforeinit
is scheduled)kthreadd
, so all kernel threads have PPID ofkthreadd
, which is 2.Alternatively, you could check for zero
vsize
but not a zombie. (This is of course impossible for a userspace process.) (Credits to this SO answer for this.)I'll make a PR if I have time.