Bounded Buffer

struct pipe {
	char buf[N];
	unsigned r, w;
	lock_t l;
}

void writec(struct pipe* p, char c) {
	bool ok;
	while (!ok) {
		lock(&p->l);
		ok = p->w - p->r > N;
		if (ok) {
			p->buf[p->w++%N] = c;
		}
		unlock(&p->l);
	}
}

void readc(struct pipe* p, char c) {
	lock(&p->l);
	while (p->w - p->r > 0) {
		return p->buf[p->w++%N];
	}
	unlock(&p->l);
}

Assumptions:

Lock, unlock are memory barriers—however would slow down faster machine. Do we need to use spin locks? (xchal, test_and_set)

bool cas(int* addr, int old, int new) {
	if (*addr == old) {
		*addr = new;
		return true;
	}

return false;
}
void add1(int* p) {
	while (true) {
		int old = *p;
		if (c_a_s(p, old, f(*p))
			return;
	}
}

Can we just use loads + stores?

Both are atomic if storing full words.

(Known as read/write coherence)

Aside: what if we’re in a uniprocessor—does that not work?

disable_interrupts()
do...while
enable_interrupts()

Read/write locks

void lock_for_read(struct wlock* p) {
	while (true) {
		lock(&p->l);
		p->readers++;
		unlock(&p->l);
	}
}

Blocking Mutex

struct mutex {
	lock_t l;
	bool locked;
	proc_t *blocked_list;
}

void acquire(struct mutex* p) {
	while (true) {
		lock(&p->0);
		if (!p->locked) {
			p->locked = true;
			unlock(&p->l);
			return;
		}
		current_process->runnable = false;
		cp->next = p->blocked_list;
		p->blocked_list = cp;
		unlock(&p->l);
		yield();
	}
}

void release(struct mutex* p) {
	lock(&p->l);
	p->locked = false;
	while (p->blocked_list) {
		p->blocked_list->runnable = true;
		p->blocked_list = p->blocked_list->next;
	}
	unlock(&p->l);
}

Semaphore