Looking at The Evolution of the Unix Time-sharing System

Looking at The Evolution of the Unix Time-sharing System

How Unix design influenced an entire history of operating systems

Evolution of the Unix Time-Sharing System

The Evolution of the Unix Time-Sharing System is an article by Denis Ritchie describing the early history of the UNIX operating system, including creation and design of some of (almost) unique features of the the operating system such as it's filesystem, process controlls, I/O redirection and a few more. Surprisingly, almost 50 years later, we're experiencing almost the same features (ofc with many more new cool stuff) but it's fascinating to see how much of the design still is within the current Unix-based operating systems such as linux.

While I'm highly recommending reading the original article, I find it fun to track some of mysteries I was facing at work lately:

Zombie Town

With adaption of new fork system call, forking (fork) a new process and executing (exec) the child command has become somewhat of an standard. Investitaging the actual process, reminded me of chasing a BUG which mysteriousy brought down some of our BSD machines at work. It turned out, somehow one f our daemons running as root is producing zombie processes without attending them. Although a zombie process is merely just a few structs in kernel memory, leaving them unattended may lead to unexpected behaviors. In our case, the zombie processes caused the root user to exceed it's maximum running processes limit (kern.maxprocperuid) causing the system to stop working. So what was the issue?

Ever wondered what actually happens between forking a new process, clonning the current process to an almost exact copy of it's own and actually executing the child command? and what actually can go wrong between these two calls? Well, the process mentioned above is the same routine the popen function does on FreeBSD libc library. It forks the process, closes all of it's parent open file descriptors and executing the child command. Since before calling _execv command, we're still running the same code as parent, if the code crashes, it crashes like the parent process crashed, not the child command.

Still I'm not quiet sure why the code crashes in the child process calling _close before executing the _execv system call but a quick fix was to install a SIGCHLD handler, closing the child zombie process.

Know Thy Builtins

As ritchie continues, when addapting the new multiprocessing capability with design of the new fork system call, they discovered that the chdir command stopeed working. Investigation through the process, they relasized now that when shell forks the chdir procss, it executed fine and actually did change the current working directory but since it's not changing it's parent process (the running shell), after termination, the shell is still in the same directory as before.

I actually found a similar BUG in one of our programs a few month before, when a fellow programmer modified a shell script adding pull path names to every commands including the cd command. since /bin/cd is a binary and can't effect the parent shell process (the same reason above), the script was end up doing it's stuff in a wrong directory. so it's Important to notice that cd command is actually a built-in shell command, capable of changing current shell working directory:

$ type cd
cd is a shell builtin

So, what's the use of the cd binary command? I'm not quiet sure but one example I find was to check which directories we have access to visit:

find . -type d -exec /bin/cd {} \; -print