Skip to content

Commit fdee96e

Browse files
Add support for ReadWriteLock in ParparVM (#4347)
* Add ReadWriteLock support to ParparVM Implemented java.util.concurrent.locks.ReadWriteLock and ReentrantReadWriteLock in vm/JavaAPI. Added integration tests in vm/tests/src/test/java/com/codename1/tools/translator/ReadWriteLockIntegrationTest.java. * Add ReadWriteLock support to ParparVM Implemented java.util.concurrent.locks.ReadWriteLock and ReentrantReadWriteLock in vm/JavaAPI. Added integration tests in vm/tests/src/test/java/com/codename1/tools/translator/ReadWriteLockIntegrationTest.java. --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent b799800 commit fdee96e

File tree

3 files changed

+1021
-0
lines changed

3 files changed

+1021
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package java.util.concurrent.locks;
2+
3+
public interface ReadWriteLock {
4+
Lock readLock();
5+
Lock writeLock();
6+
}
Lines changed: 384 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,384 @@
1+
package java.util.concurrent.locks;
2+
3+
import java.util.Collection;
4+
import java.util.HashMap;
5+
import java.util.Map;
6+
import java.util.concurrent.TimeUnit;
7+
8+
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable {
9+
private static final long serialVersionUID = -6992448646407690164L;
10+
11+
/** Inner class providing readlock */
12+
private ReadLock readerLock;
13+
/** Inner class providing writelock */
14+
private WriteLock writerLock;
15+
16+
/** Performs all synchronization mechanics */
17+
private transient Object sync;
18+
19+
private transient Thread writer;
20+
private transient int writeHolds;
21+
private transient int readers;
22+
private transient Map<Thread, Integer> readHolds;
23+
24+
public ReentrantReadWriteLock() {
25+
this(false);
26+
}
27+
28+
public ReentrantReadWriteLock(boolean fair) {
29+
sync = new Object();
30+
readerLock = new ReadLock(this);
31+
writerLock = new WriteLock(this);
32+
readHolds = new HashMap<Thread, Integer>();
33+
}
34+
35+
public Lock readLock() { return readerLock; }
36+
public Lock writeLock() { return writerLock; }
37+
38+
public static class ReadLock implements Lock, java.io.Serializable {
39+
private static final long serialVersionUID = -5992448646407690164L;
40+
private final ReentrantReadWriteLock lock;
41+
42+
protected ReadLock(ReentrantReadWriteLock lock) {
43+
this.lock = lock;
44+
}
45+
46+
public void lock() {
47+
synchronized (lock.sync) {
48+
Thread current = Thread.currentThread();
49+
// If there is a writer, and it's not us, we wait.
50+
// (Reentrancy: writer can acquire read lock)
51+
boolean interrupted = false;
52+
while (lock.writer != null && lock.writer != current) {
53+
try {
54+
lock.sync.wait();
55+
} catch (InterruptedException e) {
56+
interrupted = true;
57+
}
58+
}
59+
60+
lock.readers++;
61+
Integer count = lock.readHolds.get(current);
62+
if (count == null) {
63+
lock.readHolds.put(current, 1);
64+
} else {
65+
lock.readHolds.put(current, count + 1);
66+
}
67+
if (interrupted) {
68+
Thread.currentThread().interrupt();
69+
}
70+
}
71+
}
72+
73+
public void lockInterruptibly() throws InterruptedException {
74+
synchronized (lock.sync) {
75+
if (Thread.interrupted()) throw new InterruptedException();
76+
Thread current = Thread.currentThread();
77+
while (lock.writer != null && lock.writer != current) {
78+
lock.sync.wait();
79+
}
80+
lock.readers++;
81+
Integer count = lock.readHolds.get(current);
82+
if (count == null) {
83+
lock.readHolds.put(current, 1);
84+
} else {
85+
lock.readHolds.put(current, count + 1);
86+
}
87+
}
88+
}
89+
90+
public boolean tryLock() {
91+
synchronized (lock.sync) {
92+
Thread current = Thread.currentThread();
93+
if (lock.writer != null && lock.writer != current) {
94+
return false;
95+
}
96+
lock.readers++;
97+
Integer count = lock.readHolds.get(current);
98+
if (count == null) {
99+
lock.readHolds.put(current, 1);
100+
} else {
101+
lock.readHolds.put(current, count + 1);
102+
}
103+
return true;
104+
}
105+
}
106+
107+
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
108+
long nanos = unit.toNanos(timeout);
109+
long end = System.currentTimeMillis() + unit.toMillis(timeout);
110+
111+
synchronized (lock.sync) {
112+
if (Thread.interrupted()) throw new InterruptedException();
113+
Thread current = Thread.currentThread();
114+
115+
if (lock.writer == null || lock.writer == current) {
116+
lock.readers++;
117+
Integer count = lock.readHolds.get(current);
118+
if (count == null) {
119+
lock.readHolds.put(current, 1);
120+
} else {
121+
lock.readHolds.put(current, count + 1);
122+
}
123+
return true;
124+
}
125+
126+
long remaining = unit.toMillis(timeout);
127+
while (remaining > 0 && lock.writer != null && lock.writer != current) {
128+
lock.sync.wait(remaining);
129+
if (lock.writer == null || lock.writer == current) {
130+
lock.readers++;
131+
Integer count = lock.readHolds.get(current);
132+
if (count == null) {
133+
lock.readHolds.put(current, 1);
134+
} else {
135+
lock.readHolds.put(current, count + 1);
136+
}
137+
return true;
138+
}
139+
remaining = end - System.currentTimeMillis();
140+
}
141+
return false;
142+
}
143+
}
144+
145+
public void unlock() {
146+
synchronized (lock.sync) {
147+
Thread current = Thread.currentThread();
148+
Integer count = lock.readHolds.get(current);
149+
if (count == null || count <= 0) {
150+
throw new IllegalMonitorStateException();
151+
}
152+
int c = count - 1;
153+
if (c == 0) {
154+
lock.readHolds.remove(current);
155+
} else {
156+
lock.readHolds.put(current, c);
157+
}
158+
lock.readers--;
159+
if (lock.readers == 0) {
160+
lock.sync.notifyAll(); // Notify potential writers
161+
}
162+
}
163+
}
164+
165+
public Condition newCondition() {
166+
throw new UnsupportedOperationException();
167+
}
168+
169+
public String toString() {
170+
return super.toString() + "[ReadLock]";
171+
}
172+
}
173+
174+
public static class WriteLock implements Lock, java.io.Serializable {
175+
private static final long serialVersionUID = -4992448646407690164L;
176+
private final ReentrantReadWriteLock lock;
177+
178+
protected WriteLock(ReentrantReadWriteLock lock) {
179+
this.lock = lock;
180+
}
181+
182+
public void lock() {
183+
synchronized (lock.sync) {
184+
Thread current = Thread.currentThread();
185+
if (lock.writer == current) {
186+
lock.writeHolds++;
187+
return;
188+
}
189+
190+
boolean interrupted = false;
191+
while (lock.readers > 0 || lock.writer != null) {
192+
try {
193+
lock.sync.wait();
194+
} catch (InterruptedException e) {
195+
interrupted = true;
196+
}
197+
}
198+
lock.writer = current;
199+
lock.writeHolds = 1;
200+
if (interrupted) {
201+
Thread.currentThread().interrupt();
202+
}
203+
}
204+
}
205+
206+
public void lockInterruptibly() throws InterruptedException {
207+
synchronized (lock.sync) {
208+
if (Thread.interrupted()) throw new InterruptedException();
209+
Thread current = Thread.currentThread();
210+
if (lock.writer == current) {
211+
lock.writeHolds++;
212+
return;
213+
}
214+
while (lock.readers > 0 || lock.writer != null) {
215+
lock.sync.wait();
216+
}
217+
lock.writer = current;
218+
lock.writeHolds = 1;
219+
}
220+
}
221+
222+
public boolean tryLock() {
223+
synchronized (lock.sync) {
224+
Thread current = Thread.currentThread();
225+
if (lock.writer == current) {
226+
lock.writeHolds++;
227+
return true;
228+
}
229+
if (lock.readers == 0 && lock.writer == null) {
230+
lock.writer = current;
231+
lock.writeHolds = 1;
232+
return true;
233+
}
234+
return false;
235+
}
236+
}
237+
238+
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
239+
long nanos = unit.toNanos(timeout);
240+
long end = System.currentTimeMillis() + unit.toMillis(timeout);
241+
242+
synchronized (lock.sync) {
243+
if (Thread.interrupted()) throw new InterruptedException();
244+
Thread current = Thread.currentThread();
245+
if (lock.writer == current) {
246+
lock.writeHolds++;
247+
return true;
248+
}
249+
if (lock.readers == 0 && lock.writer == null) {
250+
lock.writer = current;
251+
lock.writeHolds = 1;
252+
return true;
253+
}
254+
255+
long remaining = unit.toMillis(timeout);
256+
while (remaining > 0) {
257+
lock.sync.wait(remaining);
258+
if (lock.writer == current) { // re-check after wait? No, logic above covers it.
259+
lock.writeHolds++;
260+
return true;
261+
}
262+
if (lock.readers == 0 && lock.writer == null) {
263+
lock.writer = current;
264+
lock.writeHolds = 1;
265+
return true;
266+
}
267+
remaining = end - System.currentTimeMillis();
268+
}
269+
return false;
270+
}
271+
}
272+
273+
public void unlock() {
274+
synchronized (lock.sync) {
275+
if (lock.writer != Thread.currentThread()) {
276+
throw new IllegalMonitorStateException();
277+
}
278+
lock.writeHolds--;
279+
if (lock.writeHolds == 0) {
280+
lock.writer = null;
281+
lock.sync.notifyAll(); // Notify waiting readers or writers
282+
}
283+
}
284+
}
285+
286+
public Condition newCondition() {
287+
// Simplified condition implementation reusing ReentrantLock's style if needed
288+
// But Condition for WriteLock usually requires full AQS support.
289+
// The ReentrantLock implementation uses ConditionObject which is tied to the lock instance.
290+
// I should probably support it if possible, but ReadWriteLock conditions are only supported for WriteLock.
291+
// For now, throwing UnsupportedOperationException as implementing Condition correctly for RWLock is non-trivial without AQS.
292+
throw new UnsupportedOperationException();
293+
}
294+
295+
public boolean isHeldByCurrentThread() {
296+
synchronized (lock.sync) {
297+
return lock.writer == Thread.currentThread();
298+
}
299+
}
300+
301+
public int getHoldCount() {
302+
synchronized (lock.sync) {
303+
return (lock.writer == Thread.currentThread()) ? lock.writeHolds : 0;
304+
}
305+
}
306+
307+
public String toString() {
308+
return super.toString() + "[WriteLock]";
309+
}
310+
}
311+
312+
public final boolean isFair() {
313+
return false;
314+
}
315+
316+
protected Thread getOwner() {
317+
synchronized (sync) {
318+
return writer;
319+
}
320+
}
321+
322+
public int getReadLockCount() {
323+
synchronized (sync) {
324+
return readers;
325+
}
326+
}
327+
328+
public boolean isWriteLocked() {
329+
synchronized (sync) {
330+
return writer != null;
331+
}
332+
}
333+
334+
public boolean isWriteLockedByCurrentThread() {
335+
synchronized (sync) {
336+
return writer == Thread.currentThread();
337+
}
338+
}
339+
340+
public int getWriteHoldCount() {
341+
synchronized (sync) {
342+
return (writer == Thread.currentThread()) ? writeHolds : 0;
343+
}
344+
}
345+
346+
public int getReadHoldCount() {
347+
synchronized (sync) {
348+
Integer count = readHolds.get(Thread.currentThread());
349+
return (count == null) ? 0 : count;
350+
}
351+
}
352+
353+
protected Collection<Thread> getQueuedWriterThreads() {
354+
throw new RuntimeException("Not implemented");
355+
}
356+
357+
protected Collection<Thread> getQueuedReaderThreads() {
358+
throw new RuntimeException("Not implemented");
359+
}
360+
361+
public final boolean hasQueuedThreads() {
362+
throw new RuntimeException("Not implemented");
363+
}
364+
365+
public final boolean hasQueuedThread(Thread thread) {
366+
throw new RuntimeException("Not implemented");
367+
}
368+
369+
public final int getQueueLength() {
370+
throw new RuntimeException("Not implemented");
371+
}
372+
373+
protected Collection<Thread> getQueuedThreads() {
374+
throw new RuntimeException("Not implemented");
375+
}
376+
377+
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
378+
s.defaultReadObject();
379+
sync = new Object();
380+
readHolds = new HashMap<Thread, Integer>();
381+
readerLock = new ReadLock(this);
382+
writerLock = new WriteLock(this);
383+
}
384+
}

0 commit comments

Comments
 (0)