-
Notifications
You must be signed in to change notification settings - Fork 1
/
Semaphore.java
106 lines (89 loc) · 2.37 KB
/
Semaphore.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package nachos.threads;
import nachos.machine.*;
/**
* A <tt>Semaphore</tt> is a synchronization primitive with an unsigned value. A
* semaphore has only two operations:
*
* <ul>
* <li><tt>P()</tt>: waits until the semaphore's value is greater than zero,
* then decrements it.
* <li><tt>V()</tt>: increments the semaphore's value, and wakes up one thread
* waiting in <tt>P()</tt> if possible.
* </ul>
*
* <p>
* Note that this API does not allow a thread to read the value of the semaphore
* directly. Even if you did read the value, the only thing you would know is
* what the value used to be. You don't know what the value is now, because by
* the time you get the value, a context switch might have occurred, and some
* other thread might have called <tt>P()</tt> or <tt>V()</tt>, so the true
* value might now be different.
*/
public class Semaphore {
/**
* Allocate a new semaphore.
*
* @param initialValue the initial value of this semaphore.
*/
public Semaphore(int initialValue) {
value = initialValue;
}
/**
* Atomically wait for this semaphore to become non-zero and decrement it.
*/
public void P() {
boolean intStatus = Machine.interrupt().disable();
if (value == 0) {
waitQueue.waitForAccess(KThread.currentThread());
KThread.sleep();
}
else {
value--;
}
Machine.interrupt().restore(intStatus);
}
/**
* Atomically increment this semaphore and wake up at most one other thread
* sleeping on this semaphore.
*/
public void V() {
boolean intStatus = Machine.interrupt().disable();
KThread thread = waitQueue.nextThread();
if (thread != null) {
thread.ready();
}
else {
value++;
}
Machine.interrupt().restore(intStatus);
}
private static class PingTest implements Runnable {
PingTest(Semaphore ping, Semaphore pong) {
this.ping = ping;
this.pong = pong;
}
public void run() {
for (int i = 0; i < 10; i++) {
ping.P();
pong.V();
}
}
private Semaphore ping;
private Semaphore pong;
}
/**
* Test if this module is working.
*/
public static void selfTest() {
Semaphore ping = new Semaphore(0);
Semaphore pong = new Semaphore(0);
new KThread(new PingTest(ping, pong)).setName("ping").fork();
for (int i = 0; i < 10; i++) {
ping.V();
pong.P();
}
}
private int value;
private ThreadQueue waitQueue = ThreadedKernel.scheduler
.newThreadQueue(false);
}