From 296cb7484761a05f7d97841aca0f9ef725cb8076 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 29 Sep 2011 18:26:50 -0600 Subject: [PATCH] add bare-bones ConcurrentLinkedQueue implementation --- classpath/avian/Atomic.java | 10 +++ .../concurrent/ConcurrentLinkedQueue.java | 88 +++++++++++++++++++ src/classpath-avian.cpp | 27 ++++++ 3 files changed, 125 insertions(+) create mode 100644 classpath/avian/Atomic.java create mode 100644 classpath/java/util/concurrent/ConcurrentLinkedQueue.java diff --git a/classpath/avian/Atomic.java b/classpath/avian/Atomic.java new file mode 100644 index 0000000000..1d6ee7569e --- /dev/null +++ b/classpath/avian/Atomic.java @@ -0,0 +1,10 @@ +package avian; + +import java.lang.reflect.Field; + +public class Atomic { + public static native long getOffset(Field field); + + public static native boolean compareAndSwapObject + (Object o, long offset, Object old, Object new_); +} diff --git a/classpath/java/util/concurrent/ConcurrentLinkedQueue.java b/classpath/java/util/concurrent/ConcurrentLinkedQueue.java new file mode 100644 index 0000000000..aa920311ca --- /dev/null +++ b/classpath/java/util/concurrent/ConcurrentLinkedQueue.java @@ -0,0 +1,88 @@ +package java.util.concurrent; + +import avian.Atomic; + +public class ConcurrentLinkedQueue { + private static final long QueueHead; + private static final long QueueTail; + private static final long NodeNext; + + static { + try { + QueueHead = Atomic.getOffset + (ConcurrentLinkedQueue.class.getField("head")); + + QueueTail = Atomic.getOffset + (ConcurrentLinkedQueue.class.getField("tail")); + + NodeNext = Atomic.getOffset + (Node.class.getField("next")); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + } + + private volatile Node head = new Node(null, null); + private volatile Node tail = head; + + public boolean add(T value) { + Node n = new Node(value, null); + while (true) { + Node t = tail; + Node next = tail.next; + if (t == tail) { + if (next != null) { + Atomic.compareAndSwapObject(this, QueueTail, t, next); + } else if (Atomic.compareAndSwapObject(tail, NodeNext, null, n)) { + Atomic.compareAndSwapObject(this, QueueTail, t, n); + break; + } + } + } + + return true; + } + + public T peek() { + return poll(false); + } + + public T poll() { + return poll(true); + } + + public T poll(boolean remove) { + while (true) { + Node h = head; + Node t = tail; + Node next = head.next; + + if (h == head) { + if (h == t) { + if (next != null) { + Atomic.compareAndSwapObject(this, QueueTail, t, next); + } else { + return null; + } + } else { + T value = next.value; + if ((! remove) + || Atomic.compareAndSwapObject(this, QueueHead, h, next)) + { + return value; + } + } + } + } + } + + private static class Node { + public volatile T value; + public volatile Node next; + + public Node(T value, Node next) { + this.value = value; + this.next = next; + } + } +} diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index 7d806ce87e..39cde4ff83 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -605,6 +605,33 @@ Avian_java_lang_Thread_yield t->m->system->yield(); } +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Atomic_getOffset +(Thread* t, object, uintptr_t* arguments) +{ + return fieldOffset + (t, jfieldVmField(t, reinterpret_cast(arguments[0]))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Atomic_compareAndSwapObject +(Thread* t, object, uintptr_t* arguments) +{ + object target = reinterpret_cast(arguments[0]); + int64_t offset; memcpy(&offset, arguments + 1, 8); + uintptr_t expect = arguments[3]; + uintptr_t update = arguments[4]; + + bool success = atomicCompareAndSwap + (&cast(target, offset), expect, update); + + if (success) { + mark(t, target, offset); + } + + return success; +} + extern "C" JNIEXPORT int64_t JNICALL Avian_avian_Classes_primitiveClass (Thread* t, object, uintptr_t* arguments)