Comment by cryptonector

4 years ago

fork() and the exec system calls exist because they were easy to implement in the 70s on PDPs, and fork() was cheap enough then, but much more importantly, it got the shell developers out of having to write and evolve a more complex API in the kernel. With fork/exec a shell developer could try lots of variations for executing a pipe command w/o having to develop any more kernel code.

For example, until BSD came along, not much had to change in kernel land for any shell. Job control meant that the shell would need to put all the processes for a job in the same pgrp, and also there was a need to add `setsid()`.

Hm a lot of that doesn't match my understanding, which is more like:

1. Unix has fork() because it was influenced by Multics. I don't have the citation now, but I think some parts of Unix were from ITSS, perhaps the hierarchical file system, and some were from Multics. It was a drastic simplification of those systems, but with the same ideas.

---

2. The shell developer and the kernel developer were really the same person -- Ken Thompson. I link to his original paper in this post [1]. The original Thompson shell had pipelines and redirects, which are most of what happens between fork() and exec() in a shell.

Also of note is a video by Stephen Bourne who says that Ken Thompson being away at Berkeley was a good time to turn his shell into a programming language (Bourne shell) [2].

Similarly, I read that Bill Joy added chroot() to Unix simply because he needed it for something he was doing one time (building another Unix system, I would imagine).

---

3. Bill Joy also added job control to the kernel and the terminal for his csh shell. It's a very tightly coupled and ugly design.

So the key point is that we shouldn't assume any notion of "shell developers" or "APIs". The kernel developer and the shell developer were really the same person -- Thompson and Joy.

Unix is more of a holistic system than a modular one; it's porous by design!

---

Since job control, it appears that have been almost no system calls added for a shell. Although I have a feeling a few fcntl() operations were added for a shell, i.e. the difference between dup2() and fcntl(F_DUPFD). But I don't remember the argument offhand.

So I think the history is basically what usually happens -- once the same person stops working on 2 sides of an interface, the interface calcifies. It's a little like the relationship between ISAs and C. So we will probably have fork() forever, but that doesn't mean there can't be evolution in a better direction.

[1] Unix Shell: History and Trivia

https://www.oilshell.org/blog/2021/08/history-trivia.html

[2] https://www.oilshell.org/blog/2022/03/middle-out.html#more-w...

  • Re (2), yes, they may have been the same person, but developing user-land code and kernel-land code are still different activities. The latter takes more effort and time -- certainly it must have in the 70s.