//Analyze these implementations of the various sync primitives //Assume a correct implementation of locks is provided for you //Do these implementations satisfy the safety and liveness requirements? Safety: No. Liveness: Yes. //Condition Variables void condition_wait(lock_t *lock, condition_t *cond){ lock_release(lock); /* 1 */ enter_critical(); block(&cond->wait_queue); leave_critical(); lock_acquire(lock); } //Explanation: Suppose thread1 calls condition_wait. Then at location 1, it is preempted. Then thread2 is run, and it calls condition_signal. Signal is supposed to unblock a blocked thread, but since thread1 never blocked, there is nothing for thread2 to unblock, resulting in a lost wakeup. //Semaphores void semaphore_up(semaphore_t *sem){ enter_critical(); ++sem->value; unblock_one(&sem->wait_queue); leave_critical(); } void semaphore_down(semaphore_t *sem) { enter_critical(); if(sem->value <= 0){ block(&sem->wait_queue); } --sem->value; leave_critical(); } //Explanation: Thread 1 calls down when the value is 0, so it blocks. Then thread 2 comes along and calls up, setting the value to 1 and unblocking thread 1 and putting it on the ready queue. However, Thread 3 is already on the ready queue and runs before thread 1, calling down. It sets the value to 0. Then thread 1 resumes at --sem->value and sets the value to -1. This violates the working of semaphore_down, precisely because we didn't check if sem->value was > 0 after we were woken up after the block(). //Barriers void barrier_wait(barrier_t *bar){ enter_critical(); if(--bar->value > 0){ block(&bar->wait_queue); ++bar->value; } else{ unblock_all(&bar->wait_queue); ++bar->value; } leave_critical(); } //Explanation: Suppose bar->value is currently 1, and there are four threads in the system, 3 are already waiting at the barrier. Thread4 is the last of the four threads to call barrier_wait. Thread 4 will unblock the other threads and increment bar->value back to 1. If thread4 then calls barrier_wait immediately after (the specs allow this), thread4 will trigger an unblock again, returning immediately since there are no threads to unblock (and value is incremented to 1 again). However many times thread4 calls barrier_wait, bar->value will not be greater than 1 after barrier_wait returns. This goes against the specification of barriers.