The UNIX Time-Sharing System
Lecture Notes for CS 190
Spring 2015
John Ousterhout
- 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
- 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 problem 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
- Files:
- Uninterpreted collections of bytes
- (vs. record-oriented, or multiple formats)
- Variable-length files, can grow dynamically
- (vs. pre-declared lengths)
- Buffer cache in kernel, delayed writes
- (vs. buffering at application level)
- Simple read-write kernel calls:
- write(fd, buffer, count)
- Same APIs for sequential and random-access (implicit
access position maintained by kernel)
- Kernel copies to/from user buffers
- Prevailing approach at the time:
- No buffer cache in kernel
- DMA between device and user space
- Complex control blocks
- Separate APIs for sequential and random access
- Asynchronous I/O interface (start I/O, etc.)
- Hierarchical name structure:
- Directories stored just like other files
- (vs. different on-disk structures)
- Hierarchical names
- Working directory
- Device-independent I/O:
- Open just like files
- (vs. different kernel calls to open each kind of device)
- Same kernel calls for reading and writing
- (vs. different control block structures for every device)
- Mountable file systems
- Combine multiple trees into one tree
- Extremely simple mechanism
- Access control:
- Simple 6-bit scheme (subsequently extended to 9 bits)
- Too restrictive?
- Compare to complex ACLs with inheritance, etc.
- Set-user-id
- (vs. implement all system functionality in the kernel)
- Processes:
- Multiple processes/user!
- (vs. only 1; previously, processes were extremely heavyweight)
- 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
- Standard mechanism for passing textual arguments to
programs.
- (vs. every command interprets entire command line: limits
shell capabilities)
- Programs inherit open files from their parents
- Standard I/O: always read from descriptor 0,
write to descriptor 1
- (vs. start with clean slate: makes pipelines impossible)
- Commands and shells:
- Processes as building blocks
- Shell is stand-alone program
- (vs. built into kernel)
- Different users can have different shells
- Allows new shells to develop
- Commands are just names of files
- (vs. fixed built-in command set)
- Simple path mechanism
- Personal commands; run my programs just like
system programs
- One process for each command
- Perform 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
- 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 40KBytes of object code
- One tenth the size of Multics
- One final example: what happens when a file is deleted
while open?
- Windows: don't allow deletion
- Or, even worse, the file can be deleted, but name
is still locked down
- Unix: name is deleted and can be reused; file contents
persist as long as file is open.