Skip to content

Commit a9be28f

Browse files
Implement Lock and ReentrantLock APIs in JavaAPI
Implemented `java.util.concurrent.locks.Lock` and `java.util.concurrent.locks.ReentrantLock` interfaces and classes in `vm/JavaAPI`. Added `java.util.concurrent.TimeUnit`. Updated `java.lang.Thread` with `interrupt0`, `sleep(long, int)` and updated `join` implementation. Added integration tests in `vm/tests` to verify locking behavior using the BytecodeTranslator.
1 parent 7af2bce commit a9be28f

File tree

6 files changed

+1172
-4
lines changed

6 files changed

+1172
-4
lines changed

vm/JavaAPI/src/java/lang/Thread.java

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,21 @@ public final int getPriority(){
122122
* Interrupts this thread. In an implementation conforming to the CLDC Specification, this operation is not required to cancel or clean up any pending I/O operations that the thread may be waiting for.
123123
*/
124124
public void interrupt(){
125+
interrupt0();
125126
}
126127

128+
private native void interrupt0();
129+
130+
public static boolean interrupted() {
131+
return currentThread().isInterrupted(true);
132+
}
133+
134+
public boolean isInterrupted() {
135+
return isInterrupted(false);
136+
}
137+
138+
private native boolean isInterrupted(boolean clearInterrupted);
139+
127140
/**
128141
* Tests if this thread is alive. A thread is alive if it has been started and has not yet died.
129142
*/
@@ -135,12 +148,46 @@ public final boolean isAlive(){
135148
* Waits for this thread to die.
136149
*/
137150
public final void join() throws java.lang.InterruptedException{
138-
// not very efficient but we don't use this method much...
139-
while(alive) {
140-
sleep(30);
151+
join(0);
152+
}
153+
154+
public final synchronized void join(long millis) throws java.lang.InterruptedException {
155+
long base = System.currentTimeMillis();
156+
long now = 0;
157+
158+
if (millis < 0) {
159+
throw new IllegalArgumentException("timeout value is negative");
160+
}
161+
162+
if (millis == 0) {
163+
while (isAlive()) {
164+
wait(0);
165+
}
166+
} else {
167+
while (isAlive()) {
168+
long delay = millis - now;
169+
if (delay <= 0) {
170+
break;
171+
}
172+
wait(delay);
173+
now = System.currentTimeMillis() - base;
174+
}
141175
}
142176
}
143177

178+
public final synchronized void join(long millis, int nanos) throws java.lang.InterruptedException {
179+
if (millis < 0) {
180+
throw new IllegalArgumentException("timeout value is negative");
181+
}
182+
if (nanos < 0 || nanos > 999999) {
183+
throw new IllegalArgumentException("nanosecond timeout value out of range");
184+
}
185+
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
186+
millis++;
187+
}
188+
join(millis);
189+
}
190+
144191
/**
145192
* Invoked from native code...
146193
*/
@@ -155,7 +202,10 @@ private void runImpl(long tid) {
155202
t.printStackTrace();
156203
}
157204
activeThreads--;
158-
alive = false;
205+
synchronized(this) {
206+
alive = false;
207+
notifyAll();
208+
}
159209
}
160210

161211
/**
@@ -183,6 +233,19 @@ public final void setPriority(int newPriority){
183233
*/
184234
public static native void sleep(long millis) throws java.lang.InterruptedException;
185235

236+
public static void sleep(long millis, int nanos) throws java.lang.InterruptedException {
237+
if (millis < 0) {
238+
throw new IllegalArgumentException("timeout value is negative");
239+
}
240+
if (nanos < 0 || nanos > 999999) {
241+
throw new IllegalArgumentException("nanosecond timeout value out of range");
242+
}
243+
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
244+
millis++;
245+
}
246+
sleep(millis);
247+
}
248+
186249
/**
187250
* Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread.
188251
* The result is that two threads are running concurrently: the current thread (which returns from the call to the start method) and the other thread (which executes its run method).
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
package java.util.concurrent;
2+
3+
public enum TimeUnit {
4+
NANOSECONDS {
5+
public long toNanos(long d) { return d; }
6+
public long toMicros(long d) { return d / (C1 / C0); }
7+
public long toMillis(long d) { return d / (C2 / C0); }
8+
public long toSeconds(long d) { return d / (C3 / C0); }
9+
public long toMinutes(long d) { return d / (C4 / C0); }
10+
public long toHours(long d) { return d / (C5 / C0); }
11+
public long toDays(long d) { return d / (C6 / C0); }
12+
public long convert(long d, TimeUnit u) { return u.toNanos(d); }
13+
int excessNanos(long d, long m) { return (int)(d - (m*C2)); }
14+
},
15+
MICROSECONDS {
16+
public long toNanos(long d) { return x(d, C1 / C0, MAX / (C1 / C0)); }
17+
public long toMicros(long d) { return d; }
18+
public long toMillis(long d) { return d / (C2 / C1); }
19+
public long toSeconds(long d) { return d / (C3 / C1); }
20+
public long toMinutes(long d) { return d / (C4 / C1); }
21+
public long toHours(long d) { return d / (C5 / C1); }
22+
public long toDays(long d) { return d / (C6 / C1); }
23+
public long convert(long d, TimeUnit u) { return u.toMicros(d); }
24+
int excessNanos(long d, long m) { return (int)((d*C1) - (m*C2)); }
25+
},
26+
MILLISECONDS {
27+
public long toNanos(long d) { return x(d, C2 / C0, MAX / (C2 / C0)); }
28+
public long toMicros(long d) { return x(d, C2 / C1, MAX / (C2 / C1)); }
29+
public long toMillis(long d) { return d; }
30+
public long toSeconds(long d) { return d / (C3 / C2); }
31+
public long toMinutes(long d) { return d / (C4 / C2); }
32+
public long toHours(long d) { return d / (C5 / C2); }
33+
public long toDays(long d) { return d / (C6 / C2); }
34+
public long convert(long d, TimeUnit u) { return u.toMillis(d); }
35+
int excessNanos(long d, long m) { return 0; }
36+
},
37+
SECONDS {
38+
public long toNanos(long d) { return x(d, C3 / C0, MAX / (C3 / C0)); }
39+
public long toMicros(long d) { return x(d, C3 / C1, MAX / (C3 / C1)); }
40+
public long toMillis(long d) { return x(d, C3 / C2, MAX / (C3 / C2)); }
41+
public long toSeconds(long d) { return d; }
42+
public long toMinutes(long d) { return d / (C4 / C3); }
43+
public long toHours(long d) { return d / (C5 / C3); }
44+
public long toDays(long d) { return d / (C6 / C3); }
45+
public long convert(long d, TimeUnit u) { return u.toSeconds(d); }
46+
int excessNanos(long d, long m) { return 0; }
47+
},
48+
MINUTES {
49+
public long toNanos(long d) { return x(d, C4 / C0, MAX / (C4 / C0)); }
50+
public long toMicros(long d) { return x(d, C4 / C1, MAX / (C4 / C1)); }
51+
public long toMillis(long d) { return x(d, C4 / C2, MAX / (C4 / C2)); }
52+
public long toSeconds(long d) { return x(d, C4 / C3, MAX / (C4 / C3)); }
53+
public long toMinutes(long d) { return d; }
54+
public long toHours(long d) { return d / (C5 / C4); }
55+
public long toDays(long d) { return d / (C6 / C4); }
56+
public long convert(long d, TimeUnit u) { return u.toMinutes(d); }
57+
int excessNanos(long d, long m) { return 0; }
58+
},
59+
HOURS {
60+
public long toNanos(long d) { return x(d, C5 / C0, MAX / (C5 / C0)); }
61+
public long toMicros(long d) { return x(d, C5 / C1, MAX / (C5 / C1)); }
62+
public long toMillis(long d) { return x(d, C5 / C2, MAX / (C5 / C2)); }
63+
public long toSeconds(long d) { return x(d, C5 / C3, MAX / (C5 / C3)); }
64+
public long toMinutes(long d) { return x(d, C5 / C4, MAX / (C5 / C4)); }
65+
public long toHours(long d) { return d; }
66+
public long toDays(long d) { return d / (C6 / C5); }
67+
public long convert(long d, TimeUnit u) { return u.toHours(d); }
68+
int excessNanos(long d, long m) { return 0; }
69+
},
70+
DAYS {
71+
public long toNanos(long d) { return x(d, C6 / C0, MAX / (C6 / C0)); }
72+
public long toMicros(long d) { return x(d, C6 / C1, MAX / (C6 / C1)); }
73+
public long toMillis(long d) { return x(d, C6 / C2, MAX / (C6 / C2)); }
74+
public long toSeconds(long d) { return x(d, C6 / C3, MAX / (C6 / C3)); }
75+
public long toMinutes(long d) { return x(d, C6 / C4, MAX / (C6 / C4)); }
76+
public long toHours(long d) { return x(d, C6 / C5, MAX / (C6 / C5)); }
77+
public long toDays(long d) { return d; }
78+
public long convert(long d, TimeUnit u) { return u.toDays(d); }
79+
int excessNanos(long d, long m) { return 0; }
80+
};
81+
82+
static final long C0 = 1L;
83+
static final long C1 = C0 * 1000L;
84+
static final long C2 = C1 * 1000L;
85+
static final long C3 = C2 * 1000L;
86+
static final long C4 = C3 * 60L;
87+
static final long C5 = C4 * 60L;
88+
static final long C6 = C5 * 24L;
89+
90+
static final long MAX = Long.MAX_VALUE;
91+
92+
static long x(long d, long m, long over) {
93+
if (d > over) return Long.MAX_VALUE;
94+
if (d < -over) return Long.MIN_VALUE;
95+
return d * m;
96+
}
97+
98+
public long convert(long sourceDuration, TimeUnit sourceUnit) {
99+
throw new RuntimeException("Abstract method not implemented");
100+
}
101+
102+
public long toNanos(long duration) {
103+
throw new RuntimeException("Abstract method not implemented");
104+
}
105+
106+
public long toMicros(long duration) {
107+
throw new RuntimeException("Abstract method not implemented");
108+
}
109+
110+
public long toMillis(long duration) {
111+
throw new RuntimeException("Abstract method not implemented");
112+
}
113+
114+
public long toSeconds(long duration) {
115+
throw new RuntimeException("Abstract method not implemented");
116+
}
117+
118+
public long toMinutes(long duration) {
119+
throw new RuntimeException("Abstract method not implemented");
120+
}
121+
122+
public long toHours(long duration) {
123+
throw new RuntimeException("Abstract method not implemented");
124+
}
125+
126+
public long toDays(long duration) {
127+
throw new RuntimeException("Abstract method not implemented");
128+
}
129+
130+
abstract int excessNanos(long d, long m);
131+
132+
public void timedWait(Object obj, long timeout)
133+
throws InterruptedException {
134+
if (timeout > 0) {
135+
long ms = toMillis(timeout);
136+
int ns = excessNanos(timeout, ms);
137+
obj.wait(ms, ns);
138+
}
139+
}
140+
141+
public void timedJoin(Thread thread, long timeout)
142+
throws InterruptedException {
143+
if (timeout > 0) {
144+
long ms = toMillis(timeout);
145+
int ns = excessNanos(timeout, ms);
146+
thread.join(ms, ns);
147+
}
148+
}
149+
150+
public void sleep(long timeout) throws InterruptedException {
151+
if (timeout > 0) {
152+
long ms = toMillis(timeout);
153+
int ns = excessNanos(timeout, ms);
154+
Thread.sleep(ms, ns);
155+
}
156+
}
157+
158+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package java.util.concurrent.locks;
2+
3+
import java.util.concurrent.TimeUnit;
4+
import java.util.Date;
5+
6+
public interface Condition {
7+
void await() throws InterruptedException;
8+
9+
void awaitUninterruptibly();
10+
11+
long awaitNanos(long nanosTimeout) throws InterruptedException;
12+
13+
boolean await(long time, TimeUnit unit) throws InterruptedException;
14+
15+
boolean awaitUntil(Date deadline) throws InterruptedException;
16+
17+
void signal();
18+
19+
void signalAll();
20+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package java.util.concurrent.locks;
2+
3+
import java.util.concurrent.TimeUnit;
4+
5+
public interface Lock {
6+
void lock();
7+
8+
void lockInterruptibly() throws InterruptedException;
9+
10+
boolean tryLock();
11+
12+
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
13+
14+
void unlock();
15+
16+
Condition newCondition();
17+
}

0 commit comments

Comments
 (0)