The UNIX Time-Sharing System
Classic 1974 paper on UNIX by Ritchie and Thompson.
Perhaps it seems like no big deal?
- We take all of this stuff for granted today.
- Must consider the prevailing state-of-the-art when Unix appeared.
Historical context for Unix:
- Late 1960's
- IBM OS/360: most ambitious commercial OS of its time
- Announced in 1964
- Designed to run on a family of computers
- Ambitious feature set
- Large project
- Very late, very buggy
- Multics: visionary OS: combined many untested technical ideas
- Started in 1964
- Collaboration between MIT, GE, Bell Labs
- Timesharing
- Single level store
- Flexible and powerful sharing
- Dynamic linking
- Security (protection rings)
- Hierarchical file system
- First OS written in a high-level language
- Also very late, very buggy, ultimately not very successful
- Ritchie and Thompson both worked on Multics
- Unix was in many ways a reaction to Multics
Key overall ideas:
- Decompose system into a collection of components
- Each component individually simple and obvious
- Components plug together in obvious ways that are very powerful.
- Eliminate distinctions: power comes from making everything
look the same; find the least common denominator
- Makes everything interchangeable
File data model:
- Before Unix:
- Record-oriented, multiple formats
- File sizes often pre-declared
- Unix:
- Uninterpreted collection of bytes
- Variable-length, can grow dynamically
File system APIs:
- Before Unix:
- No buffer cache in kernel
- DMA between device and user space
- Buffering at application level
- Complex control blocks
- Separate APIs for sequential and random access
- Asynchronous I/O interface (start I/O, etc.)
- Unix:
- Buffer cache in kernel, delayed writes
- Kernel copies to/from user buffers
- Simple read-write kernel calls:
write(fd, start, count)
- Same APIs for sequential and random-access (implicit access position maintained by kernel)
File names and directories
- Before Unix:
- Often just one directory per user
- Directories represented differently on disk than files
- Unix:
- Hierarchical names
- Working directory
- Directories stored just like other files
Devices:
- Before UNIX:
- Different kernel calls for each kind of device
- Different control block structures for every device
- Different name space for each kind of device
- Unix: device-independent I/O:
- Open just like files (devices have file names)
- Same kernel calls for reading and writing
- Drivers in the kernel translate general-purpose commands (read, write) to device-specific control sequences
- ioctl for device-specific functions
Processes:
-
Before Unix:
- One process per user
- Reuse process for different programs
- No shells: command mechanism built into kernel (TOPS-10 example)
-
Unix: multiple processes per user
Passing arguments to processes:
- Before Unix:
- Every command interprets the entire command line
- Unix: standard
argc/argv
mechanism for passing textual arguments to programs
Inheriting open files:
- Before Unix: none
- Each command opens its own files; pipelines impossible
- Unix:
- Open files inherited from parent
- Standard conventions: always read from descriptor 0, write to descriptor 1
- Enables redirection, pipelines
Fork-exec-wait distinction:
- Fork-exec distinction allows parent to tailor environment for child (I/O redirection)
- Exec-wait distinction allows parent to spawn multiple children (pipelines)
- Controversial because of cost of copying address space
Shell programs:
- Before Unix:
- Command interpreter built into kernel
- Fixed built-in command set
- Commands are different from programs (e.g. "run foo", not "foo")
- Unix:
- Shell is user-level program
- Different users can have different shells
- Allows new shells to develop
- Commands are just names of files
- Simple path mechanism
- Personal commands; run my programs just like system programs
- Processes as building blocks
- One process for each command
- Shell performs computations on arguments (wildcard expansion), independent of command
- I/O redirection, pipelines
- Lots of small filters can be combined into powerful pipelines
- Allowed another entire level of (de)composition
- Would have been impossible without several other
ideas:
- Multiple processes
- Fork-exec-wait, file descriptor inheritance
- Device-independent I/O
- Shell as programming language: can automate program invocation!
- Shell scripts:
- Use redirection on the shell itself
- Another entirely new level of programming
- Background processing
- Shell is user-level program
Unix changed the boundary between the kernel and user processes.
Things Unix moved into the kernel:
- Buffer cache
- Control blocks
- Device differences
Things Unix moved out of the kernel:
- Command-line interpreter
- Setuid programs
- Knowledge of file contents
Some of the Unix features had been discussed for earlier systems but were thought to be too complex or expensive.
- Unix did all of this in about 40 KBytes of object code
- One tenth the size of Multics