Traditional UNIX Locking Primitives

This section examines the earlier uni-processor (UP) UNIX synchronization primitives starting with 5th Edition UNIX and going up to SVR4.0. Over this twenty-year time period, the implementation stayed remarkably similar. As noted in his book Lions Commentary on UNIX 6th Edition-with Source Code [LION96], John Lions notes that the early mechanisms for handling critical sections of code were “totally inappropriate in a multi-processor system.”

As mentioned earlier, in UP UNIX implementations, the kernel needed to protect data structures in the case when a process went to sleep or when handling interrupts. The reasons a process might sleep include: waiting for I/O, waiting for a lock owned by another process, or giving up the CPU to another process after using up its timeslice.

If a process needs to access some resource such as a buffer cache buffer that is currently in use, it will issue a sleep() call specifying the address of the resource it requires. A swtch() call is made to relinquish control of the CPU, allowing another process to run. For example, to wait on a busy buffer, the following code sequence is made:

if (bp->b_flags & B_BUSY) {
    bp->b_flags |= B_WANTED;
    sleep(bp, PRIBIO);

The address of the structure on which the process is waiting (called the wait channel) is stored in the p_wchan field of the proc structure. The priority argument passed to sleep() will be described in more detail later in the chapter. Note for now though that ...

Get UNIX Filesystems: Evolution, Design, and Implementation now with O’Reilly online learning.

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.