Only the
fork()/exec()material from these notes is examinable!
Unix originates from Bell Labs (1969-71), much technical language of operating systems originates from Unix: ‘kernel’, ‘shell’, ‘inode’, ‘pipe’, ‘root’. Popularised many concepts such as hierarchical filesystems, byte-oriented files, shell commands as files, I/O redirections, process forking. It also became the basis for POSIX: the ISO standard of operating system interfaces.
It is popular due to its simplicity, ‘high’-level language code, and academic licensing. Which all enabled use in education, portability across machines, and clones, derivatives, and imitators.
Unix was a ‘grass-roots’ project by Dennis Ritchie and Ken Thompson after leaving the much larger and more ambitious Multics project. In response to growing complexity, Unix was written as a deliberately simple system.
Unix: Forking Processes
To create a new process in Unix, you fork (duplicate) the current process.
If you don’t want this, you then exec (replace with) a different program.
int rc = fork();
if (rc < 0) {
// fork failed
exit(1);
} else if (rc == 0) {
// child process
printf("hello from %d", (int) getpid());
} else {
// parent process
printf("hello from %d, parent of %d", (int) getpid(), rc);
}This design allows:
- setup of the new process to be done in code by the parent process e.g. to setup pipes or other IPC channels
- easy to arrange sharing between parent and child (of memory, file descriptors, etc)
- avoids need for a ‘mega-API’ that can control all attributes of a new process created
- good for concurrent servers (pre-threads)
int pipefd[2];
int rc = pipe(pipefd); // create a pipe
if (rc < 0) {
// failed to create pipe
exit(1);
}
rc = fork();
if (rc < 0) { ... }
else if (rc == 0) { // child
// make our stdout the pipe's 'write end'
dup2(pipefd[1], 1);
// close the read end
close(pipefd[0]);
// run the program we care about
execve("/usr/bin/curl", /* args */);
} else { // parent
// close 'write end'
close(pipefd[1]);
// read child process output from 'read end'
int nread = read(pipe, /* other args */);
}Unix: Everything is a File
Instead of special categories for system commands, devices, files (each with their own interface), we maximise the use of the file abstraction. Devices appear as special files, commands are executable files, non-file means of inter-process communication is also access through file descriptors.

| Advantages | Disadvantages |
|---|---|
| avoids special interfaces | not everything is conceptually a file |
| maximises compositionality | seek() can seek within a file but doesn’t apply exactly to things like audio / video |
ioctl() is any operation that doesn’t fit |