Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/ikvm-fork.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjfrijters <jfrijters>2015-05-29 19:01:25 +0300
committerjfrijters <jfrijters>2015-05-29 19:01:25 +0300
commitdd8612ba6cb52669d0a87015c8dfe61ba3b2271e (patch)
treebe3d231941eee08dd2fa038f2f6d2163885e3119
parent8c1f4b82c64ab915af3ca8edc68f449690599b36 (diff)
Bug fix. ReferenceQueue should not keep registered (but not yet enqueued) Reference objects alive.
-rw-r--r--openjdk/java/lang/ref/ReferenceQueue.java208
1 files changed, 208 insertions, 0 deletions
diff --git a/openjdk/java/lang/ref/ReferenceQueue.java b/openjdk/java/lang/ref/ReferenceQueue.java
new file mode 100644
index 00000000..1d58d9bb
--- /dev/null
+++ b/openjdk/java/lang/ref/ReferenceQueue.java
@@ -0,0 +1,208 @@
+/*
+ Copyright (C) 2014-2015 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+
+package java.lang.ref;
+
+public class ReferenceQueue<T>
+{
+ static final ReferenceQueue ENQUEUED = new ReferenceQueue();
+ static final ReferenceQueue NULL = new ReferenceQueue();
+ private volatile Link<T> activeHead;
+ private volatile Reference<T> head;
+ final Object lock = new Object();
+ volatile boolean waitingForGC;
+
+ private final class GCNotification {
+ protected void finalize() {
+ waitingForGC = false;
+ synchronized (lock) {
+ lock.notifyAll();
+ }
+ }
+ }
+
+ // NOTE a known problem with this approach is that the WeakReference will not be available
+ // after we've become only finalizer reachable
+ private static class Link<T> extends cli.System.WeakReference {
+ Link<T> next;
+
+ Link(Reference<T> ref) {
+ super(ref);
+ }
+
+ Reference<T> get() {
+ return (Reference<T>)get_Target();
+ }
+ }
+
+ public Reference<? extends T> poll()
+ {
+ if (head == null && (activeHead == null || waitingForGC)) {
+ return null;
+ }
+ synchronized (lock) {
+ return pollImpl();
+ }
+ }
+
+ private Reference<? extends T> pollImpl()
+ {
+ if (head == null) {
+ if (activeHead == null || waitingForGC) {
+ return null;
+ }
+ scanActiveList();
+ if (head == null) {
+ waitingForGC = true;
+ new GCNotification();
+ return null;
+ }
+ }
+ Reference<T> ref = head;
+ head = ref.next;
+ ref.next = null;
+ ref.queue = NULL;
+ return ref;
+ }
+
+ public Reference<? extends T> remove(long timeout) throws IllegalArgumentException, InterruptedException
+ {
+ if (timeout < 0)
+ throw new IllegalArgumentException("Negative timeout value");
+
+ synchronized (lock) {
+ long expiration = 0;
+ for (;;) {
+ Reference<? extends T> ref = pollImpl();
+ if (ref != null)
+ return ref;
+
+ if (timeout == 0) {
+ lock.wait();
+ } else {
+ long now = System.currentTimeMillis();
+ if (expiration == 0) {
+ expiration = now + timeout;
+ if (expiration < 0) {
+ expiration = Long.MAX_VALUE;
+ }
+ }
+ if (now >= expiration) {
+ return null;
+ }
+ lock.wait(expiration - now);
+ }
+ }
+ }
+ }
+
+ public Reference<? extends T> remove() throws InterruptedException
+ {
+ return remove(0);
+ }
+
+ final void clear(Reference<T> ref)
+ {
+ synchronized (lock) {
+ if (ref.queue != ENQUEUED) {
+ ref.queue = NULL;
+ }
+ }
+ }
+
+ final boolean enqueue(Reference<T> ref)
+ {
+ synchronized (lock) {
+ if (ref.queue != ENQUEUED && ref.queue != NULL) {
+ ref.queue = ENQUEUED;
+
+ if (ref.isStrongOrNullRef()) {
+ ref.next = head;
+ head = ref;
+ lock.notifyAll();
+ return true;
+ }
+
+ Link<T> prev = null;
+ Link<T> curr = activeHead;
+
+ while (curr != null) {
+ if (curr.get() == ref) {
+ if (prev == null) {
+ activeHead = curr.next;
+ } else {
+ prev.next = curr.next;
+ }
+ ref.next = head;
+ head = ref;
+ lock.notifyAll();
+ return true;
+ }
+ prev = curr;
+ curr = curr.next;
+ }
+ }
+ }
+ return false;
+ }
+
+ final void addToActiveList(Reference<T> ref)
+ {
+ Link<T> link = new Link<T>(ref);
+ synchronized (lock) {
+ link.next = activeHead;
+ activeHead = link;
+ if (link.next == null) {
+ lock.notifyAll();
+ }
+ }
+ }
+
+ private void scanActiveList()
+ {
+ Link<T> prev = null;
+ Link<T> curr = activeHead;
+
+ while (curr != null) {
+ Reference<T> ref = curr.get();
+ if (ref == null || !ref.isActive()) {
+ Link<T> next = curr.next;
+ if (prev == null) {
+ activeHead = next;
+ } else {
+ prev.next = next;
+ }
+ if (ref != null) {
+ ref.next = head;
+ ref.queue = ENQUEUED;
+ head = ref;
+ }
+ curr = next;
+ continue;
+ }
+ prev = curr;
+ curr = curr.next;
+ }
+ }
+}