Semaphore P() implementation · Thread 1 Thread 2 Calls P() Semaphore count is now 1...
Transcript of Semaphore P() implementation · Thread 1 Thread 2 Calls P() Semaphore count is now 1...
![Page 1: Semaphore P() implementation · Thread 1 Thread 2 Calls P() Semaphore count is now 1 spinlock_release(…) Calls V() Increments count to 1 Calls wchan_wakeone 1 P(struct semaphore*](https://reader030.fdocuments.us/reader030/viewer/2022040121/5ec7d289c663a35a161d2c49/html5/thumbnails/1.jpg)
1 P(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 while (sem->sem_count == 0) {
4 wchan_lock(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 wchan_sleep(sem->sem_wchan);
7 spinlock_acquire(&sem->sem_lock);
8 }
9 sem->sem_count--;
10 spinlock_release(&sem->sem_lock);
11 }
Semaphore P() implementation
![Page 2: Semaphore P() implementation · Thread 1 Thread 2 Calls P() Semaphore count is now 1 spinlock_release(…) Calls V() Increments count to 1 Calls wchan_wakeone 1 P(struct semaphore*](https://reader030.fdocuments.us/reader030/viewer/2022040121/5ec7d289c663a35a161d2c49/html5/thumbnails/2.jpg)
1 P(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 while (sem->sem_count == 0) {
5 spinlock_release(&sem->sem_lock);
4 wchan_lock(sem->sem_wchan);
6 wchan_sleep(sem->sem_wchan);
7 spinlock_acquire(&sem->sem_lock);
8 }
9 sem->sem_count--;
10 spinlock_release(&sem->sem_lock);
11 }
What if we swapped lines 4 and 5?
![Page 3: Semaphore P() implementation · Thread 1 Thread 2 Calls P() Semaphore count is now 1 spinlock_release(…) Calls V() Increments count to 1 Calls wchan_wakeone 1 P(struct semaphore*](https://reader030.fdocuments.us/reader030/viewer/2022040121/5ec7d289c663a35a161d2c49/html5/thumbnails/3.jpg)
Thread 1 Thread 2
Calls P()
Semaphore count is initially 0
spinlock_release(…)
1 P(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 while (sem->sem_count == 0) {
5 spinlock_release(&sem->sem_lock);
4 wchan_lock(sem->sem_wchan);
6 wchan_sleep(sem->sem_wchan);
7 spinlock_acquire(&sem->sem_lock);
8 }
9 sem->sem_count--;
10 spinlock_release(&sem->sem_lock);
11 }
1 V(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 sem->sem_count++;
4 wchan_wakeone(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 }
Incorrect implementation
![Page 4: Semaphore P() implementation · Thread 1 Thread 2 Calls P() Semaphore count is now 1 spinlock_release(…) Calls V() Increments count to 1 Calls wchan_wakeone 1 P(struct semaphore*](https://reader030.fdocuments.us/reader030/viewer/2022040121/5ec7d289c663a35a161d2c49/html5/thumbnails/4.jpg)
Thread 1 Thread 2
Calls P()
Semaphore count is now 1
spinlock_release(…) Calls V()
Increments count to 1 Calls wchan_wakeone
1 P(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 while (sem->sem_count == 0) {
5 spinlock_release(&sem->sem_lock);
4 wchan_lock(sem->sem_wchan);
6 wchan_sleep(sem->sem_wchan);
7 spinlock_acquire(&sem->sem_lock);
8 }
9 sem->sem_count--;
10 spinlock_release(&sem->sem_lock);
11 }
1 V(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 sem->sem_count++;
4 wchan_wakeone(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 }
Either context switch or just very slow execution (e.g., pipeline stall, cache miss, etc.)
Incorrect implementation
![Page 5: Semaphore P() implementation · Thread 1 Thread 2 Calls P() Semaphore count is now 1 spinlock_release(…) Calls V() Increments count to 1 Calls wchan_wakeone 1 P(struct semaphore*](https://reader030.fdocuments.us/reader030/viewer/2022040121/5ec7d289c663a35a161d2c49/html5/thumbnails/5.jpg)
Thread 1 Thread 2
Calls P()
Semaphore count is now 1
spinlock_release(…) Calls V()
Increments count to 1 Calls wchan_wakeone
1 P(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 while (sem->sem_count == 0) {
5 spinlock_release(&sem->sem_lock);
4 wchan_lock(sem->sem_wchan);
6 wchan_sleep(sem->sem_wchan);
7 spinlock_acquire(&sem->sem_lock);
8 }
9 sem->sem_count--;
10 spinlock_release(&sem->sem_lock);
11 }
1 V(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 sem->sem_count++;
4 wchan_wakeone(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 }
Either context switch or just very slow execution (e.g., pipeline stall, cache miss, etc.)
wchan_lock(…)
wchan_sleep(…)
Incorrect implementation
![Page 6: Semaphore P() implementation · Thread 1 Thread 2 Calls P() Semaphore count is now 1 spinlock_release(…) Calls V() Increments count to 1 Calls wchan_wakeone 1 P(struct semaphore*](https://reader030.fdocuments.us/reader030/viewer/2022040121/5ec7d289c663a35a161d2c49/html5/thumbnails/6.jpg)
Thread 1 Thread 2
Calls P()
Semaphore count is now 1
spinlock_release(…) Calls V()
Increments count to 1 Calls wchan_wakeone
1 P(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 while (sem->sem_count == 0) {
5 spinlock_release(&sem->sem_lock);
4 wchan_lock(sem->sem_wchan);
6 wchan_sleep(sem->sem_wchan);
7 spinlock_acquire(&sem->sem_lock);
8 }
9 sem->sem_count--;
10 spinlock_release(&sem->sem_lock);
11 }
1 V(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 sem->sem_count++;
4 wchan_wakeone(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 }
Either context switch or just very slow execution (e.g., pipeline stall, cache miss, etc.)
wchan_lock(…)
wchan_sleep(…)
Thread 1 misses the wake up signal and blocks on P() even though count is 1.
Incorrect implementation
![Page 7: Semaphore P() implementation · Thread 1 Thread 2 Calls P() Semaphore count is now 1 spinlock_release(…) Calls V() Increments count to 1 Calls wchan_wakeone 1 P(struct semaphore*](https://reader030.fdocuments.us/reader030/viewer/2022040121/5ec7d289c663a35a161d2c49/html5/thumbnails/7.jpg)
Thread 1 Thread 2
Calls P()
Semaphore count is initially 0
wchan_lock(sem->sem_wchan)
spinlock_release(…)
1 P(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 while (sem->sem_count == 0) {
4 wchan_lock(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 wchan_sleep(sem->sem_wchan);
7 spinlock_acquire(&sem->sem_lock);
8 }
9 sem->sem_count--;
10 spinlock_release(&sem->sem_lock);
11 }
1 V(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 sem->sem_count++;
4 wchan_wakeone(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 }
Correct implementation
![Page 8: Semaphore P() implementation · Thread 1 Thread 2 Calls P() Semaphore count is now 1 spinlock_release(…) Calls V() Increments count to 1 Calls wchan_wakeone 1 P(struct semaphore*](https://reader030.fdocuments.us/reader030/viewer/2022040121/5ec7d289c663a35a161d2c49/html5/thumbnails/8.jpg)
Thread 1 Thread 2
Calls P()
Semaphore count is now 1
Calls V()
Increments count to 1. Calls wchan_wakeone Spins inside wchan_wakeone while trying to acquire the channel lock.
1 P(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 while (sem->sem_count == 0) {
4 wchan_lock(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 wchan_sleep(sem->sem_wchan);
7 spinlock_acquire(&sem->sem_lock);
8 }
9 sem->sem_count--;
10 spinlock_release(&sem->sem_lock);
11 }
1 V(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 sem->sem_count++;
4 wchan_wakeone(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 }
Either context switch or just very slow execution (e.g., pipeline stall, cache miss, etc.)
Correct implementation
wchan_lock(sem->sem_wchan)
spinlock_release(…)
![Page 9: Semaphore P() implementation · Thread 1 Thread 2 Calls P() Semaphore count is now 1 spinlock_release(…) Calls V() Increments count to 1 Calls wchan_wakeone 1 P(struct semaphore*](https://reader030.fdocuments.us/reader030/viewer/2022040121/5ec7d289c663a35a161d2c49/html5/thumbnails/9.jpg)
Thread 1 Thread 2
Calls P()
Semaphore count is now 1
Calls V()
Increments count to 1. Calls wchan_wakeone Spins inside wchan_wakeone while trying to acquire the channel lock.
1 P(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 while (sem->sem_count == 0) {
4 wchan_lock(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 wchan_sleep(sem->sem_wchan);
7 spinlock_acquire(&sem->sem_lock);
8 }
9 sem->sem_count--;
10 spinlock_release(&sem->sem_lock);
11 }
1 V(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 sem->sem_count++;
4 wchan_wakeone(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 }
Either context switch or just very slow execution (e.g., pipeline stall, cache miss, etc.)
Correct implementation
wchan_sleep(…)
wchan_wakeone(…)
spinlock_acquire(…) wchan_sleep releases the channel lock, which allows wchan_wakeone to complete. This in turn wakes up thread 1.
spinlock_release(…)
wchan_lock(sem->sem_wchan)
spinlock_release(…)
![Page 10: Semaphore P() implementation · Thread 1 Thread 2 Calls P() Semaphore count is now 1 spinlock_release(…) Calls V() Increments count to 1 Calls wchan_wakeone 1 P(struct semaphore*](https://reader030.fdocuments.us/reader030/viewer/2022040121/5ec7d289c663a35a161d2c49/html5/thumbnails/10.jpg)
Thread 1 Thread 2
Calls P()
wchan_sleep(…)
1 P(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 while (sem->sem_count == 0) {
4 wchan_lock(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 wchan_sleep(sem->sem_wchan);
7 spinlock_acquire(&sem->sem_lock);
8 }
9 sem->sem_count--;
10 spinlock_release(&sem->sem_lock);
11 }
1 V(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 sem->sem_count++;
4 wchan_wakeone(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 }
However, our implementation does not provide FIFO ordering.
Thread 3
In the ready queue
![Page 11: Semaphore P() implementation · Thread 1 Thread 2 Calls P() Semaphore count is now 1 spinlock_release(…) Calls V() Increments count to 1 Calls wchan_wakeone 1 P(struct semaphore*](https://reader030.fdocuments.us/reader030/viewer/2022040121/5ec7d289c663a35a161d2c49/html5/thumbnails/11.jpg)
Thread 1 Thread 2
Calls P()
wchan_sleep(…) Calls V()
1 P(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 while (sem->sem_count == 0) {
4 wchan_lock(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 wchan_sleep(sem->sem_wchan);
7 spinlock_acquire(&sem->sem_lock);
8 }
9 sem->sem_count--;
10 spinlock_release(&sem->sem_lock);
11 }
1 V(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 sem->sem_count++;
4 wchan_wakeone(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 }
However, our implementation does not provide FIFO ordering.
wchan_wakeone(…)
Thread 3
spinlock_release(…)
In the ready queue
Wakes thread 1 up. Thread 1 added to the end of the ready queue
![Page 12: Semaphore P() implementation · Thread 1 Thread 2 Calls P() Semaphore count is now 1 spinlock_release(…) Calls V() Increments count to 1 Calls wchan_wakeone 1 P(struct semaphore*](https://reader030.fdocuments.us/reader030/viewer/2022040121/5ec7d289c663a35a161d2c49/html5/thumbnails/12.jpg)
Thread 1 Thread 2
Calls P()
wchan_sleep(…) Calls V()
1 P(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 while (sem->sem_count == 0) {
4 wchan_lock(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 wchan_sleep(sem->sem_wchan);
7 spinlock_acquire(&sem->sem_lock);
8 }
9 sem->sem_count--;
10 spinlock_release(&sem->sem_lock);
11 }
1 V(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 sem->sem_count++;
4 wchan_wakeone(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 }
However, our implementation does not provide FIFO ordering.
wchan_wakeone(…)
Thread 3
Gets scheduled spinlock_release(…)
Calls P()
Decrements count from 1 to 0
spinlock_release(…)
![Page 13: Semaphore P() implementation · Thread 1 Thread 2 Calls P() Semaphore count is now 1 spinlock_release(…) Calls V() Increments count to 1 Calls wchan_wakeone 1 P(struct semaphore*](https://reader030.fdocuments.us/reader030/viewer/2022040121/5ec7d289c663a35a161d2c49/html5/thumbnails/13.jpg)
Thread 1 Thread 2
Calls P()
wchan_sleep(…) Calls V()
1 P(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 while (sem->sem_count == 0) {
4 wchan_lock(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 wchan_sleep(sem->sem_wchan);
7 spinlock_acquire(&sem->sem_lock);
8 }
9 sem->sem_count--;
10 spinlock_release(&sem->sem_lock);
11 }
1 V(struct semaphore* sem) {
2 spinlock_acquire(&sem->sem_lock);
3 sem->sem_count++;
4 wchan_wakeone(sem->sem_wchan);
5 spinlock_release(&sem->sem_lock);
6 }
However, our implementation does not provide FIFO ordering.
wchan_wakeone(…)
Thread 3
Gets scheduled spinlock_release(…)
Calls P()
Decrements count from 1 to 0
spinlock_release(…)
spinlock_acquire(…)
sem->sem_count == 0
…
wchan_sleep(…)
Thread 1 goes back to sleep