From b5dd74c3d8d8b2263d9a980deafeb65bbd04e7f8 Mon Sep 17 00:00:00 2001 From: Mike Jensen Date: Mon, 3 Mar 2014 16:02:12 -0700 Subject: [PATCH 1/4] Adds the Deque interface, and allows LinkedList to implement that interface. This also changes ConcurrentLinkedQueue to implement the Queue interface, and just throw exceptions for operations which are not currently implemented. --- classpath/java/util/Deque.java | 31 ++++ classpath/java/util/LinkedList.java | 174 +++++++++++++++++- .../concurrent/ConcurrentLinkedQueue.java | 99 +++++++++- 3 files changed, 296 insertions(+), 8 deletions(-) create mode 100644 classpath/java/util/Deque.java diff --git a/classpath/java/util/Deque.java b/classpath/java/util/Deque.java new file mode 100644 index 0000000000..2739965411 --- /dev/null +++ b/classpath/java/util/Deque.java @@ -0,0 +1,31 @@ +/* Copyright (c) 2008-2014, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.util; + +public interface Deque extends Queue { + public boolean offerFirst(T e); + public void push(T e); + public void addFirst(T element); + public boolean offerLast(T e); + public void addLast(T element); + public T peekFirst(); + public T getFirst(); + public T peekLast(); + public T getLast(); + public T pollFirst(); + public T removeFirst(); + public T pop(); + public T pollLast(); + public T removeLast(); + public Iterator descendingIterator(); + public boolean removeLastOccurrence(Object o); + public boolean removeFirstOccurrence(Object o); +} diff --git a/classpath/java/util/LinkedList.java b/classpath/java/util/LinkedList.java index e161a7714e..d42c6961b2 100644 --- a/classpath/java/util/LinkedList.java +++ b/classpath/java/util/LinkedList.java @@ -10,7 +10,7 @@ package java.util; -public class LinkedList extends AbstractSequentialList { +public class LinkedList extends AbstractSequentialList implements Deque { private Cell front; private Cell rear; private int size; @@ -85,14 +85,17 @@ public class LinkedList extends AbstractSequentialList { } } + @Override public int size() { return size; } + @Override public boolean contains(Object element) { return find(element) != null; } + @Override public int indexOf(Object element) { int i = 0; for (Cell c = front; c != null; c = c.next) { @@ -104,6 +107,7 @@ public class LinkedList extends AbstractSequentialList { return -1; } + @Override public int lastIndexOf(Object element) { int i = size; for (Cell c = rear; c != null; c = c.prev) { @@ -115,16 +119,24 @@ public class LinkedList extends AbstractSequentialList { return -1; } + @Override + public boolean offer(T element) { + return add(element); + } + + @Override public boolean add(T element) { addLast(element); return true; } + @Override public boolean addAll(Collection collection) { for (T t: collection) add(t); return true; } + @Override public void add(int index, T element) { if (index == 0) { addFirst(element); @@ -135,10 +147,31 @@ public class LinkedList extends AbstractSequentialList { } } + @Override + public boolean offerFirst(T e) { + addFirst(e); + + return true; + } + + @Override + public void push(T e) { + addFirst(e); + } + + @Override public void addFirst(T element) { addFirst(new Cell(element, null, null)); } + @Override + public boolean offerLast(T e) { + addLast(e); + + return true; + } + + @Override public void addLast(T element) { addLast(new Cell(element, null, null)); } @@ -147,6 +180,7 @@ public class LinkedList extends AbstractSequentialList { return find(index).value; } + @Override public T set(int index, T value) { Cell c = find(index); T old = c.value; @@ -154,6 +188,21 @@ public class LinkedList extends AbstractSequentialList { return old; } + @Override + public T peek() { + return peekFirst(); + } + + @Override + public T peekFirst() { + if (front != null) { + return front.value; + } else { + return null; + } + } + + @Override public T getFirst() { if (front != null) { return front.value; @@ -161,7 +210,17 @@ public class LinkedList extends AbstractSequentialList { throw new NoSuchElementException(); } } + + @Override + public T peekLast() { + if (rear != null) { + return rear.value; + } else { + return null; + } + } + @Override public T getLast() { if (rear != null) { return rear.value; @@ -170,27 +229,57 @@ public class LinkedList extends AbstractSequentialList { } } + @Override public T remove(int index) { Cell c = find(index); remove(c); return c.value; } + @Override public boolean isEmpty() { return size() == 0; } - public T removeFirst() { + @Override + public T poll() { + return pollFirst(); + } + + @Override + public T pollFirst() { if (front != null) { T v = front.value; remove(front); return v; } else { - throw new NoSuchElementException(); + return null; } } - public T removeLast() { + @Override + public T removeFirst() { + T result = pollFirst(); + + if (result == null) { + throw new NoSuchElementException(); + } else { + return result; + } + } + + @Override + public T pop() { + return removeFirst(); + } + + @Override + public T remove() { + return removeFirst(); + } + + @Override + public T pollLast() { if (rear != null) { T v = rear.value; remove(rear); @@ -200,6 +289,18 @@ public class LinkedList extends AbstractSequentialList { } } + @Override + public T removeLast() { + T result = pollLast(); + + if (result == null) { + throw new NoSuchElementException(); + } else { + return result; + } + } + + @Override public boolean remove(Object element) { Cell c = find(element); if (c == null) { @@ -210,15 +311,23 @@ public class LinkedList extends AbstractSequentialList { } } + @Override public void clear() { front = rear = null; size = 0; } + @Override public Iterator iterator() { return listIterator(); } + @Override + public ListIterator listIterator() { + return listIterator(0); + } + + @Override public ListIterator listIterator(int index) { MyIterator it = new MyIterator(); for (int i = 0; i < index; ++i) { @@ -227,14 +336,67 @@ public class LinkedList extends AbstractSequentialList { return it; } - public ListIterator listIterator() { - return listIterator(0); + @Override + public Iterator descendingIterator() { + final ListIterator li = listIterator(size()); + + return new Iterator() { + @Override + public T next() { + return li.previous(); + } + + @Override + public boolean hasNext() { + return li.hasPrevious(); + } + + @Override + public void remove() { + li.remove(); + } + }; } + @Override public String toString() { return Collections.toString(this); } + @Override + public T element() { + T result = peek(); + if (result == null) { + throw new NoSuchElementException(); + } else { + return result; + } + } + + @Override + public boolean removeFirstOccurrence(Object o) { + int index = indexOf(o); + if (index > 0) { + remove(index); + + return true; + } else { + return false; + } + } + + @Override + public boolean removeLastOccurrence(Object o) { + int lastIndex = lastIndexOf(o); + if (lastIndex > 0) { + remove(lastIndex); + + return true; + } else { + return false; + } + } + private static class Cell { public T value; public Cell prev; diff --git a/classpath/java/util/concurrent/ConcurrentLinkedQueue.java b/classpath/java/util/concurrent/ConcurrentLinkedQueue.java index 93105317f2..357f8a7ded 100644 --- a/classpath/java/util/concurrent/ConcurrentLinkedQueue.java +++ b/classpath/java/util/concurrent/ConcurrentLinkedQueue.java @@ -1,8 +1,13 @@ package java.util.concurrent; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Queue; + import avian.Atomic; -public class ConcurrentLinkedQueue { +public class ConcurrentLinkedQueue implements Queue { private static final long QueueHead; private static final long QueueTail; private static final long NodeNext; @@ -25,11 +30,20 @@ public class ConcurrentLinkedQueue { private volatile Node head = new Node(null, null); private volatile Node tail = head; + @Override public void clear() { - // todo: can we safely make this O(1)? + // TODO - can we safely make this O(1)? while (poll() != null) { } } + @Override + public boolean offer(T element) { + add(element); + + return true; + } + + @Override public boolean add(T value) { Node n = new Node(value, null); while (true) { @@ -48,14 +62,36 @@ public class ConcurrentLinkedQueue { return true; } + @Override public T peek() { return poll(false); } + @Override + public T element() { + T result = peek(); + if (result == null) { + throw new NoSuchElementException(); + } else { + return result; + } + } + + @Override public T poll() { return poll(true); } + @Override + public T remove() { + T result = poll(); + if (result == null) { + throw new NoSuchElementException(); + } else { + return result; + } + } + private T poll(boolean remove) { while (true) { Node h = head; @@ -90,4 +126,63 @@ public class ConcurrentLinkedQueue { this.next = next; } } + + @Override + public int size() { + // TODO - implement + throw new UnsupportedOperationException(); + } + + @Override + public boolean isEmpty() { + return size() == 0; + } + + @Override + public boolean contains(Object element) { + // TODO - implement + throw new UnsupportedOperationException(); + } + + @Override + public boolean containsAll(Collection c) { + // TODO - implement + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(Collection collection) { + // TODO - implement + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object element) { + // TODO - implement + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(Collection c) { + // TODO - implement + throw new UnsupportedOperationException(); + } + + @Override + public Object[] toArray() { + // TODO - implement + throw new UnsupportedOperationException(); + } + + @Override + public S[] toArray(S[] array) { + // TODO - implement + throw new UnsupportedOperationException(); + } + + @Override + public Iterator iterator() { + // TODO - implement + throw new UnsupportedOperationException(); + } } From 7dd799476ad4b01de27eadaf4551c5f53603e70d Mon Sep 17 00:00:00 2001 From: Mike Jensen Date: Mon, 3 Mar 2014 16:04:56 -0700 Subject: [PATCH 2/4] Interfaces and the foundation for a ReentrantLock implementation --- .../java/util/concurrent/locks/Condition.java | 24 +++++ .../java/util/concurrent/locks/Lock.java | 22 +++++ .../util/concurrent/locks/LockSupport.java | 89 +++++++++++++++++++ .../util/concurrent/locks/ReadWriteLock.java | 16 ++++ 4 files changed, 151 insertions(+) create mode 100644 classpath/java/util/concurrent/locks/Condition.java create mode 100644 classpath/java/util/concurrent/locks/Lock.java create mode 100644 classpath/java/util/concurrent/locks/LockSupport.java create mode 100644 classpath/java/util/concurrent/locks/ReadWriteLock.java diff --git a/classpath/java/util/concurrent/locks/Condition.java b/classpath/java/util/concurrent/locks/Condition.java new file mode 100644 index 0000000000..7a021eb289 --- /dev/null +++ b/classpath/java/util/concurrent/locks/Condition.java @@ -0,0 +1,24 @@ +/* Copyright (c) 2008-2014, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.util.concurrent.locks; + +import java.util.Date; +import java.util.concurrent.TimeUnit; + +public interface Condition { + public void await(); + public boolean await(long time, TimeUnit unit); + public long awaitNanos(long nanosTimeout); + public void awaitUninterruptibly(); + public boolean awaitUntil(Date deadline); + public void signal(); + public void signalAll(); +} diff --git a/classpath/java/util/concurrent/locks/Lock.java b/classpath/java/util/concurrent/locks/Lock.java new file mode 100644 index 0000000000..f2fb9b0792 --- /dev/null +++ b/classpath/java/util/concurrent/locks/Lock.java @@ -0,0 +1,22 @@ +/* Copyright (c) 2008-2014, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.util.concurrent.locks; + +import java.util.concurrent.TimeUnit; + +public interface Lock { + public void lock(); + public void lockInterruptibly() throws InterruptedException; + public Condition newCondition(); + public boolean tryLock(); + public boolean tryLock(long time, TimeUnit unit) throws InterruptedException; + public void unlock(); +} diff --git a/classpath/java/util/concurrent/locks/LockSupport.java b/classpath/java/util/concurrent/locks/LockSupport.java new file mode 100644 index 0000000000..1f547c465d --- /dev/null +++ b/classpath/java/util/concurrent/locks/LockSupport.java @@ -0,0 +1,89 @@ +/* Copyright (c) 2008-2014, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.util.concurrent.locks; + +import sun.misc.Unsafe; + +public class LockSupport { + private LockSupport() { + // can't construct + } + + private static final Unsafe unsafe; + private static final long parkBlockerOffset; + + static { + unsafe = Unsafe.getUnsafe(); + try { + parkBlockerOffset = unsafe.objectFieldOffset(java.lang.Thread.class.getDeclaredField("parkBlocker")); + } catch (Exception ex) { + throw new Error(ex); + } + } + + private static void setBlocker(Thread t, Object arg) { + unsafe.putObject(t, parkBlockerOffset, arg); + } + + public static void unpark(Thread thread) { + if (thread != null) { + unsafe.unpark(thread); + } + } + + public static void park(Object blocker) { + doParkNanos(blocker, 0L); + } + + public static void parkNanos(Object blocker, long nanos) { + if (nanos <= 0) { + return; + } + + doParkNanos(blocker, nanos); + } + + private static void doParkNanos(Object blocker, long nanos) { + Thread t = Thread.currentThread(); + setBlocker(t, blocker); + unsafe.park(false, nanos); + setBlocker(t, null); + } + + public static void parkUntil(Object blocker, long deadline) { + Thread t = Thread.currentThread(); + setBlocker(t, blocker); + unsafe.park(true, deadline); + setBlocker(t, null); + } + + public static Object getBlocker(Thread t) { + if (t == null) { + throw new NullPointerException(); + } + + return unsafe.getObjectVolatile(t, parkBlockerOffset); + } + + public static void park() { + unsafe.park(false, 0L); + } + + public static void parkNanos(long nanos) { + if (nanos > 0) { + unsafe.park(false, nanos); + } + } + + public static void parkUntil(long deadline) { + unsafe.park(true, deadline); + } +} diff --git a/classpath/java/util/concurrent/locks/ReadWriteLock.java b/classpath/java/util/concurrent/locks/ReadWriteLock.java new file mode 100644 index 0000000000..a4804e5fa4 --- /dev/null +++ b/classpath/java/util/concurrent/locks/ReadWriteLock.java @@ -0,0 +1,16 @@ +/* Copyright (c) 2008-2014, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.util.concurrent.locks; + +public interface ReadWriteLock { + public Lock readLock(); + public Lock writeLock(); +} From d5e3acd7a5a5fb2515ca8b4c79fa9ebda69a72f7 Mon Sep 17 00:00:00 2001 From: Mike Jensen Date: Mon, 3 Mar 2014 16:45:28 -0700 Subject: [PATCH 3/4] Add parkBlocker variable to Thread.java --- classpath/java/lang/Thread.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/classpath/java/lang/Thread.java b/classpath/java/lang/Thread.java index 095691d342..5d99c2f092 100644 --- a/classpath/java/lang/Thread.java +++ b/classpath/java/lang/Thread.java @@ -14,6 +14,9 @@ import java.util.Map; import java.util.WeakHashMap; public class Thread implements Runnable { + // set and accessed from within LockSupport + protected volatile Object parkBlocker; + private long peer; private volatile boolean interrupted; private volatile boolean unparked; From d94fc8f009c7a2c6657b179d3b0ca30e69fdd45c Mon Sep 17 00:00:00 2001 From: Mike Jensen Date: Tue, 4 Mar 2014 11:21:14 -0700 Subject: [PATCH 4/4] Fix for travis build failure for needing to initialize the new field in Thread. --- src/classpath-avian.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index dbbf821828..e49d4fa0c1 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -52,7 +52,7 @@ class MyClasspath : public Classpath { const unsigned NormalPriority = 5; return vm::makeThread - (t, 0, 0, 0, 0, NewState, NormalPriority, 0, 0, 0, + (t, 0, 0, 0, 0, 0, NewState, NormalPriority, 0, 0, 0, root(t, Machine::AppLoader), 0, 0, group, 0); }