mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8197812: (ref) Data race in Finalizer
Reviewed-by: plevart, mchung
This commit is contained in:
parent
0b78370b74
commit
a95d50a5fc
1 changed files with 32 additions and 43 deletions
|
@ -36,18 +36,18 @@ final class Finalizer extends FinalReference<Object> { /* Package-private; must
|
||||||
class */
|
class */
|
||||||
|
|
||||||
private static ReferenceQueue<Object> queue = new ReferenceQueue<>();
|
private static ReferenceQueue<Object> queue = new ReferenceQueue<>();
|
||||||
|
|
||||||
|
/** Head of doubly linked list of Finalizers awaiting finalization. */
|
||||||
private static Finalizer unfinalized = null;
|
private static Finalizer unfinalized = null;
|
||||||
|
|
||||||
|
/** Lock guarding access to unfinalized list. */
|
||||||
private static final Object lock = new Object();
|
private static final Object lock = new Object();
|
||||||
|
|
||||||
private Finalizer
|
private Finalizer next, prev;
|
||||||
next = null,
|
|
||||||
prev = null;
|
|
||||||
|
|
||||||
private boolean hasBeenFinalized() {
|
private Finalizer(Object finalizee) {
|
||||||
return (next == this);
|
super(finalizee, queue);
|
||||||
}
|
// push onto unfinalized
|
||||||
|
|
||||||
private void add() {
|
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
if (unfinalized != null) {
|
if (unfinalized != null) {
|
||||||
this.next = unfinalized;
|
this.next = unfinalized;
|
||||||
|
@ -57,31 +57,6 @@ final class Finalizer extends FinalReference<Object> { /* Package-private; must
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void remove() {
|
|
||||||
synchronized (lock) {
|
|
||||||
if (unfinalized == this) {
|
|
||||||
if (this.next != null) {
|
|
||||||
unfinalized = this.next;
|
|
||||||
} else {
|
|
||||||
unfinalized = this.prev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.next != null) {
|
|
||||||
this.next.prev = this.prev;
|
|
||||||
}
|
|
||||||
if (this.prev != null) {
|
|
||||||
this.prev.next = this.next;
|
|
||||||
}
|
|
||||||
this.next = this; /* Indicates that this has been finalized */
|
|
||||||
this.prev = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Finalizer(Object finalizee) {
|
|
||||||
super(finalizee, queue);
|
|
||||||
add();
|
|
||||||
}
|
|
||||||
|
|
||||||
static ReferenceQueue<Object> getQueue() {
|
static ReferenceQueue<Object> getQueue() {
|
||||||
return queue;
|
return queue;
|
||||||
}
|
}
|
||||||
|
@ -91,11 +66,24 @@ final class Finalizer extends FinalReference<Object> { /* Package-private; must
|
||||||
new Finalizer(finalizee);
|
new Finalizer(finalizee);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runFinalizer(JavaLangAccess jla) {
|
private void deregisterAndRunFinalizer(JavaLangAccess jla) {
|
||||||
synchronized (this) {
|
synchronized (lock) {
|
||||||
if (hasBeenFinalized()) return;
|
if (this.next == this) // already finalized
|
||||||
remove();
|
return;
|
||||||
|
// unlink from unfinalized
|
||||||
|
if (unfinalized == this)
|
||||||
|
unfinalized = this.next;
|
||||||
|
else
|
||||||
|
this.prev.next = this.next;
|
||||||
|
if (this.next != null)
|
||||||
|
this.next.prev = this.prev;
|
||||||
|
this.prev = null;
|
||||||
|
this.next = this; // mark as finalized
|
||||||
}
|
}
|
||||||
|
runFinalizer(jla);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runFinalizer(JavaLangAccess jla) {
|
||||||
try {
|
try {
|
||||||
Object finalizee = this.get();
|
Object finalizee = this.get();
|
||||||
if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
|
if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
|
||||||
|
@ -155,11 +143,8 @@ final class Finalizer extends FinalReference<Object> { /* Package-private; must
|
||||||
return;
|
return;
|
||||||
final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
|
final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
|
||||||
running = true;
|
running = true;
|
||||||
for (;;) {
|
for (Finalizer f; (f = (Finalizer)queue.poll()) != null; )
|
||||||
Finalizer f = (Finalizer)queue.poll();
|
f.deregisterAndRunFinalizer(jla);
|
||||||
if (f == null) break;
|
|
||||||
f.runFinalizer(jla);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -179,11 +164,15 @@ final class Finalizer extends FinalReference<Object> { /* Package-private; must
|
||||||
final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
|
final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
|
||||||
running = true;
|
running = true;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
// "pollFirst" from unfinalized
|
||||||
Finalizer f;
|
Finalizer f;
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
f = unfinalized;
|
f = unfinalized;
|
||||||
if (f == null) break;
|
if (f == null) break;
|
||||||
unfinalized = f.next;
|
unfinalized = f.next;
|
||||||
|
if (unfinalized != null)
|
||||||
|
unfinalized.prev = null;
|
||||||
|
f.next = f; // mark as finalized
|
||||||
}
|
}
|
||||||
f.runFinalizer(jla);
|
f.runFinalizer(jla);
|
||||||
}}});
|
}}});
|
||||||
|
@ -214,7 +203,7 @@ final class Finalizer extends FinalReference<Object> { /* Package-private; must
|
||||||
for (;;) {
|
for (;;) {
|
||||||
try {
|
try {
|
||||||
Finalizer f = (Finalizer)queue.remove();
|
Finalizer f = (Finalizer)queue.remove();
|
||||||
f.runFinalizer(jla);
|
f.deregisterAndRunFinalizer(jla);
|
||||||
} catch (InterruptedException x) {
|
} catch (InterruptedException x) {
|
||||||
// ignore and continue
|
// ignore and continue
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue