What Is PID 0?
blog.dave.tf
blog.dave.tf
I sometimes wonder if that is why LLMs can so confidently hallucinate — because they were trained on piles of overconfident human texts.
It's an interesting thing to ponder.
Where's the operator overload? ;)
Whenever you see information that sounds like it could be extremely important to you and your situation (and when being wrong could really hurt you) then no matter how authoritatively the information was delivered that's really when you should invest the time to verify it. Much of the time that investment is just a quick internet search anyway.
And that sentence right there is an example of what I mean. I could write 10 words, 100 words or 1,000 words adding caveats to "People want to listen to folks who are confident," but most people don't want to hear it and they'd tune out. But nine words, they'll listen to and use that, even if it's not right all the time.
This isn't just an "online" issue. Anecdotally, I'd say it's in human nature. I've read plenty lamenting how men are (over)confident at work and garner (unwarranted) success relative to less confident women. And IME, confidence at work is pretty successful, if only because folks _try_ the confident suggestion. The person with a host of caveats might have a better suggestion, but they are less confident in their result, which folks sense and shy away from.
And then there are casual situations (which most of "online" discourse is), where I regularly see strangers confidently offer one another advice which is usually received positively. A lot of the advice is wrong, but that doesn't really matter.
> I sometimes wonder if that is why LLMs can so confidently hallucinate — because they were trained on piles of overconfident human texts.
The LLMs that I have worked with have no concept of "true" and "false". They have no sense of confidence in what they sense.
They _phrase_ it definitively because that's what we want.
"What is the capital of Australia."
"The capital of Australia is Timbuktu."
The LLM doesn't know if that's true. It's just making a statement we asked it to make.
People are extremely susceptible to someone who sounds confident.
Or, well... that's what I think. See, I've not trained an LLM, I have only read about it online, and very little in books I have on the topic. I did some machine learning exercises in university, and that's the extent of my practical knowledge. And as I say that, the impact of my words goes down, right? They are taken less seriously than if someone said all that stuff about LLMs but never said they don't have practical experience. And yet, this makes the information as it is presented more exact, the limitations are clear, so it is more useful.
More useful, but far less appealing... This is a really interesting topic.
From the perspective of a userspace process using standard APIs, I think a more useful approximation is "pid 0 refers to myself". It's what fork returns in the child. It's what you pass in to kill(2) to signal your own entire process group. Probably other variations too.
Command to get when a Linux box was started as opposed to just running uptime -s:
ps -p 2 -o lstart=pid 0 refers to the thing that is running 'myself', not to myself, itself. It is the thing which gave way to allow 'myself' to be executing in the current context.
It is more accurate to say "pid 0 is the source of cpu 'attention' which allows myself 'awareness'", as it discovered I was not idle, and granted me power to proceed with processing ..
ps -p 1 -o lstart=
?In real life the difference should be rarely visible. And then, did we want to know when it started booting or when it became usable. The latter would be rather tricky (even defining what it exactly meant by that).
The author of this post did the only correct thing and checked the kernel's source code, with is the authoritative source for this information.
The conclusions at the end are a bit whacky.
#!/bin/sh
#
# Usage: upto LIMIT COMMAND
# Run COMMAND until LIMIT seconds have passed, then exit.
#
test "$1" -gt 0 || {
printf '%s\n' " Error: first argument must be a positive integer."
exit 1
}
sh -ic '
sleeptime=$1
shift
exec 3>&1 2>&3
{
"$@" >&3
kill 0
} |
{
sleep "${sleeptime}"
kill 0
}
' sh "$@"For practical use I would prefer https://www.man7.org/linux/man-pages/man1/timeout.1.html
With enough work at least some of them could be fixed, maybe even all. But why reinventing the wheel if timeout is contained in coreutils and available on nearly every Linux machine?
On Linux, `getppid` returns 0 if the parent is a process in another PID namespace.
Linux is not the owner of the concept of PID 0. Saying that PID 0 frequently is involved with paging in and out memory is not incorrect.
Scheduler: https://github.com/AnubisLMS/xv6/blob/main/kernel/proc.c#L26...
Page Table Swap: https://github.com/AnubisLMS/xv6/blob/main/kernel/vm.c#L151-...
Linux is indeed not the owner of the concept of PID 0. It's fortunate that I didn't say that! It is, however, not frequently involved with paging in and out memory.
You address this somewhat in the post:
> Going back to the Wikipedia article, it seems the author of that edit wanted to write “swapping”, in the classic Unix V5 sense of swapping out whole processes as a consequence of scheduling. But the edit didn’t clarify that “swapping” was being used in an archaic sense that was likely to confuse the modern reader.
> context switches only the page table directory pointer
Swapping out the the PTD pointer is exactly what I'm thinking of. I'm wrong, because I didn't have the common colloquial meaning of "swapping" (paging out memory to disk) in my mind
I think it's a little strange such a meaning has come to dominate, at least in a classroom setting it is still fairly common to discuss the operation of the scheduler as "swapping pages".
The distinction I was trying to get at was that, in early Unix, all process bytes were being actively streamed to and from disk as part of scheduling because the hardware didn't yet have a concept of virtual memory. So, if you wanted to make a program ready to run, you had to fully load it into memory, and shove anything else out of the way right then and there. That makes the scheduling function 5% deciding what should run, and 95% playing memory sokoban to make that happen.
OTOH, on systems with paged virtual memory, the scheduler is almost entirely "what's a good thing to run?", and implementing that decision is updating a couple of pointers. The only place the memory hierarchy creeps in, is if the scheduling algorithm wants to be fancy and account for things like NUMA nodes in its ranking of tasks.
I think it's reasonable, looking at it in isolation, to describe this part of the kernel as a "swapper", or the operation as "swapping". I think where it turns into a bear trap is when presenting these concepts to folks less familiar with kernel internals, where words like "swap" and "pages" are firmly the domain of the memory subsystem. And so, if I hand them a task and say "this is the swapper", IMO the majority will interpret that as being a component of virtual memory management, and they wouldn't be at fault for thinking that.
Empirically this happened in the 2008 wikipedia edit: "swapping" mutated to "paging" because in modern vmm-land that's a valid synonym, and that in turn became "this task is sometimes called 'sched' for historical reasons, and it handles paging" on the web. And cue a decade of confused students and stackoverflow users asking followups like "but if this task does paging, why does linux have all these kswapd threads?" That to me suggests that, for better or worse, the memory subsystem owns those words now, and the rest of the kernel has to be very careful if it uses them to mean something else, if it wants to avoid casual onlookers creating false associations. Something something naming things is still the hardest thing in computer science :)
His article is probably quite a good discussion of what happens on Linux. It is over-reaching however if it is supposed - as it seems to be in the conlusions - to be talking about modern Unix-likes generally.
PID 0 on NetBSD (and I suspect of Free, DragonFly, Open, etc, as well) simply means the kernel process. Here are a few of the threads that run under the kernel process in NetBSD:
PID PPID CPU LID NLWP PRI NI VSZ RSS WCHAN STAT TTY LTIME COMMAND
0 0 0 118 106 123 0 0 28132 physiod DK- ? 0:00.00 [system]
0 0 0 117 106 125 0 0 28132 pooldrai DK- ? 0:00.00 [system]
0 0 0 116 106 124 0 0 28132 syncer DK- ? 0:00.00 [system]
0 0 0 115 106 126 0 0 28132 pgdaemon DK- ? 0:00.00 [system]
These are all true and authentic threads, they just don't spend any time executing userland code. The work they carry out is, respectively: to carry out I/O to/from buffers in userland, because this may incur page faults and cannot therefore be done in a soft interrupt which has no thread context; to reclaim pages from the pool (slab) allocator; to lazily synchronise dirty buffers back to disk; and to carry out page replacement.All of these listed above carry out memory management, so it is not correct to say that PID 0 "has nothing to do with memory management" or that the Wikipedia article is wrong to discuss paging as a responsibility of PID 0. That's what pgdaemon is doing!
There are many other threads that are part of the kernel process (or "PID 0") on NetBSD - modern kernels generally use a lot of them to carry out all sorts of tasks. A few others on NetBSD include worker thraeds for running asynchronous I/O completions and for processing various kinds of input in the networking stack.
Illumos should also be considered. Looking at its PID 0:
root 0 0 1 1 0 11:22:53 ? 0:02 sched
We can see it is called sched. Why sched? This article talked about the historic role of PID 0 in process swapping. Process swapping is a scheduling problem (like a lot of problems in software). This is why swappers are traditionally called medium-term or memory schedulers. Illumos generally gives most groupings of kernel worker threads their own processes with their own PIDs, but one, called "sched", remains in PID 0, and its responsibility? Process swapping:https://github.com/illumos/illumos-gate/blob/579c23696ac6891...
The Wikipedia article has now been hastily edited, and replaces a claim that was true only of certain Unixes other than Linux with a claim true only of certain Unixes including Linux. Is this an improvement?
Editing Wikipedia is fun, but sometimes it is hard to know where to edit. Here's a simple process to find correctable errors!
(1) Sneak onto your local university's campus.
(2) Sit in any operating systems lecture.
(3) Watch for nonsense in the slides.
(4) Locate the relevant Wikipedia page.
(5) Rewrite the entire two-page section around whatever was on that slide, because chances are it's all nonsense.
One should give links to original sources, i.e. https://kernel.org as far as Linux is concerned. Example: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...
Even if git guarantees that the content is the same (if someone bothers to verify that the SHA-1 is the same and we exclude the possibility of a SHA-1 collision in git, which is yet to be demonstrated).
kernel.org existed before github.
Chapter 4.1: https://www.kernel.org/doc/html/latest/filesystems/proc.html
(Also, I fear that by setting this flag it will break a lot of tools that expect the flag to be 0)
├─kopano-server.service
│ └─2685 n/a
├─systemd-logind.service
│ └─1037 n/a
└─kopano-gateway.service
├─ 959 n/a
├─ 1413 n/a
├─ 52489 n/aHim editing Wikipedia to include his own research is "primary research". Him editing using his own blog post as a a citation is presumably self-promotion. But someone else editing it in seems okay.
But "What is TGID 0?" is much less catchy of a title. Hence, clickbait.
I had some ruby code that called kill(str.to_i) and killed every process when the string wasn't an integer, which is when I painfully found out that to_i returns 0 on invalid strings and kill(0) kills (potentially) a lot of processes.
0 is a special value in the POSIX kill function. It denotes every process in the process group of the caller.
That's it.
(OK, so because of that, a given OS based on POSIX can internally get away with using the value in some ways, to denote some process that nothing in user space would ever know about, let alone try to send a signal to.)
Don't get nerd-sniped! Know the 15 second answer and move on.
There's no reason that Unix couldn't have defined `PID_ALLPROCGRP = -2` instead.
I mean, what do you think came first the development of Unix? The pid taken by the kernel thread used for scheduling, or a special value to a syscall when someone realised "hey, maybe being able to kill the entire process group would be handy. What spare values do we have we can use to indicate that?"
(And remember, POSIX codified existing practice. Unices don't use pid 0 for a reason because POSIX says so; POSIX says so because that's what Unices did)
Ah, but for that we have to long beyond/before Linux. kill(0, signal) existed before a line of Linux was written.
Linux followed the existing POSIX spec which gave it PID 0 to do whatever.