❄️

OS - Final Notes

Week 9 - Condition Variables

How to implement what is called the ‘wait function’ for threads?

💡
The child needs to tell something to the parent, something like: I’m done!

volatile int done = 0;

void *child(void *arg) {
	printf("child\n");
	done = 1;
	return NULL;
}

int main(int argc, char *agrv[]) {
	pthread_t c;
	pthread_create(&c, NULL, child, NULL);
	while(done == 0) 
		; // spin
	print("parent: end\n");
	return 0;
}

BUT:

NOTE THAT:

Definition of a Condition Variable



💡
Using Mutex ⇒ Having sleep and wake functions.

Wait()

CASE: if there is no done’ variable

CASE: if there is no lock

💡
Always hold the lock when calling signal or wait

Producer/Consumer’s Problems



CASE:

PROBLEM:

NEED:

💡
Use condition variables

A Broken Solution



CASE: with just a single P/C, then a Broken Solution works, but not for more P/C



PROBLEM 1:

SOLUTION: use ‘while’ instead of ‘if

💡
Always use ‘while’ loops while using condition variables

PROBLEM 2: wake up the wrong guy!



SOLUTION: use TWO condition variables, one for empty, one for full



The correct P/C solution



Week 10 - Semaphore

Can use Semaphore as both locks and condition variables

Definition of Semaphore

#include <semaphore.h>
sem_t s;
sem_init(&s, 0, 1);
// 1 is sem value
// 0 is show that the semaphore shares threads in same process.

Binary Semaphore (Lock)

sem_t m;
sem_init(&m, 0, X = 1);

sem_wait(&m);
// critical section
sem_post(&m);

NOTE: the init value of X is 1 because the critical section should contain only 1 thread.

X is equal to the number of shared resources

Semaphore for Ordering

sem_t s;

void *child(void *arg) {
	printf("child\n");
	sem_post(&s);
	return NULL;
}

int main(int argc, char *argv[]) {
	sem_init(&s, 0, X = 0);
	printf("Parent begins\n");
	pthread_t c;
	pthread_create(&c, NULL, child, NULL);
	sem_wait(&s); // wait for the child
	printf("Parent ends");
	return 0;
}

NOTE: X should be 0, so the parent will go to sleep! There is NO share resource!

CASE: the parent is interrupted immediately after creating the child, then the order will also be correct

Setting the Value of a Semaphore

The P/C (bounded) problem



PROBLEM: race condition happens when MAX > 1 - Two or More threads try to edit the same thing.

Use ‘lock’

NOTE: put the lock right just before and after the critical section only to avoid deadlock

PRACTICE: we allow many threads to read data at the same time, as long as they do not make any updates to data.

NOTE: for different operations, use different locks.

The dining philosophers

while (1) {
	think();
	get_forks(p);
	eat();
	put_forks(p);
}

int left(int p) { return p; }
int right(int p) { return (p + 1) % 5; }
void get_forks(int p) {
	sem_wait(&fork[left(p)]);
	sem_wait(&fork[right(p)]);
}
void put_forks(int p) {
	sem_post(&fork[left(p)]);
	sem_post(&fork[right(p)]);
}

PROBLEM: deadlock again! when every one gets their left fork.

Breaking the Dependency in get_forks()
void get_forks(int p) {
	if (p == 4) {
		sem_wait(&forks[right(p)]);
		sem_wait(&forks[left(p)]);
	} else {
		sem_wait(&forks[left(p)]);
		sem_wait(&forks[right(p)]);
	}
}

Thread throttling



Summary

Week 11 - I/O Devices

System Architecture



A canonical device

A protocol is a step-by-step rule including order, format, and content.
Polling: always checks the status

PROBLEM: wasting CPU time (polling)

Lowering CPU Overhead with Interrupts

SOLUTION: use a hardware interrupt



⚠️
Not to use interrupts in networks ⇒ OS livelock

More efficient data movement with DMA

SOLUTION: Direct Memory Access (DMA)

Methods of device interaction

  1. I/O instruction: privileged, OS controls devices
  1. Memory-mapped I/O: hardware makes device registers available as if they were memory locations

Process ↔️ OS ↔️ Devices
  • OS must stay between the Process and Devices to control the behavior.
  • To make sure the user doesn't abuse the devices.

The device driver



Hard Disk Drives

Interface

Some assumptions

Basic geometry

A disk may have one or more platters, each has 2 sides, called a surface
The rate of rotation is often measured in Rotations Per Minute (RPM) and typical modern values are in the 7200 → 15000 RPM range.

Simple disk drive

PROBLEM: single-track latency → rotational delay

PROBLEM: in multiple tracks → seek time = disk head move to correct track

SOLUTION: Track skew

NOTE: other details

I/O time

TI/O=Tseek+Trotation+TtransferT_{I/O} = T_{seek} + T_{rotation} + T_{transfer}
RI/O=SizetransferTI/OR_{I/O} = \frac{Size_{transfer}}{T_{I/O}}


Disk scheduling

Shortest Seek Time First - SSTF

Pick the nearest track to complete first

PROBLEM:

Elevator - SCAN - C-SCAN

Shortest Positioning Time First

Other scheduling issues

Week 12 - Redundant Arrays of Inexpensive Disks (RAID)

Overview

Advantages of RAID:

Interface and RAID internals

Fault Model

Assumptions

How to evaluate a RAID

Three axes:

RAID 0: Striping

Chunk size

Evaluating RAID Performance

S=AmountofDataTimetoaccess=10MB210ms=47.62MB/sS = \frac{Amount\,of\,Data}{Time\,to\,access}=\frac{10\,MB}{210\,ms}=47.62\,MB/s
R=AmountofDataTimetoaccess=10KB10.195ms=0.981MB/sR = \frac{Amount\,of\,Data}{Time\,to\,access}=\frac{10\,KB}{10.195\,ms}=0.981\,MB/s

RAID 0: Striping (cont)

RAID 1: Mirroring

RAID 4: Saving space with parity

RAID 5: Rotating Parity

RAID Comparison

Files and Directories

Creating files



fd

Read/write but not sequentially

Shared file table entries

Writing immediately with fsync()

Remaining files (move)

Getting information about files

Removing files

Making directories

Making directories

Removing directories

Hard links

Remove files completely by removing all of the hard-linked files

Symbolic links - soft links

⚠️
Can cause dangling problems

Permission bits and access control lists

Making and mounting a file syste

Week 13 - File System Implementation

⚠️
vsfs - Very Simple File System

Overall Organization

File organization: The inode


Example - Inode




SUMMARY

Directory organization

Free space management

Access paths: reading and writing

Reading a file from disk

ℹ️
inode number → inode block → pointers → data blocks
ℹ️
root inode number should be well known, such as 2


Caching and buffering

Fast file system

Solution 1: small block size

Policies: how to allocate files and directories

Large-file exception

SUMMARY: Put related things together → group blocks

Week 14 - Crash Consistency: FSCK and Journaling

Challenge faced by a file system is how to update persistent data structures despite the presence of a power loss or system crash

crash-consistency problem

Methods:

A detailed example

PROBLEM: 3 separately write()s to the disk, then

Crash scenarios

  1. Just the Data Block is written to disk: file is not updated despite the data block being changed ⇒ Still OK
  1. Just the inode is written to disk: pointer to data block is updated, but there is no data at all! then the reads will get garbage ⇒ Inconsistency!
  1. Just the bitmap is written to disk: the data block is marked as used, but there is no data, and no one can use it ⇒ Space leak.
  1. The inode and the bitmap are written: consistency metadata but there is garbage
  1. The inode and the data block are written: can read the right data, but, inconsistency, 2 files can point to the same block.
  1. The bitmap and data block are written: the block is marked as used, the data block is used, but no one can use it. Inconsistency.

Solution 1: fsck

PROBLEMS of fsck:

Solution 2: Journaling - write-ahead logging

Data journaling

Recovery

Batch log updates

Buffer all updates into a global transaction → file system can avoid excessive write traffic to this in many cases.

Make the log finite

Sometimes journaling log is called a circular log

Add other steps to the basic

  1. Free: sometime later, mark the transaction free in the journal by updating the journal superblock

PROBLEM: data block is written TWICE, so it is expensive

Solution: Metadata Journaling (Ordered Journaling)

Put only the metadata (inode, bitmap) in the log

Blocked reuse

Timeline of the two kinds of journaling