This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Re: Patch: finalizer thread - please comment
- To: Bryce McKinlay <bryce at waitaki dot otago dot ac dot nz>
- Subject: Re: Patch: finalizer thread - please comment
- From: Tom Tromey <tromey at redhat dot com>
- Date: 09 Oct 2001 14:26:27 -0600
- Cc: Java Patch List <java-patches at gcc dot gnu dot org>
- References: <8AF23A52-B9EC-11D5-94CC-003065F97F7C@waitaki.otago.ac.nz>
- Reply-To: tromey at redhat dot com
>>>>> "Bryce" == Bryce McKinlay <bryce@waitaki.otago.ac.nz> writes:
Bryce> It looks like user code that calls Runtime.runFinalization() is
Bryce> still going to do the wrong thing, because finalization will
Bryce> then be run in the current thread. I think its sufficient to
Bryce> have runFinalization just notify the finalization thread so
Bryce> that it wakes up and does some work, this seems to be what
Bryce> other JVMs do.
I agree.
Bryce> And calling _Jv_GCInitializeFinalizers from posix-threads.cc
Bryce> doesn't seem right, that should be in _Jv_CreateJavaVM too?
Yes.
New patch appended. What do you think?
I still haven't built a no-threads version, but I will before I check
anything in.
Tom
Index: ChangeLog
from Tom Tromey <tromey@redhat.com>
* gnu/gcj/runtime/natFinalizerThread.cc: New file.
* java/lang/natRuntime.cc: Include FinalizerThread.h.
(runFinalization): Call finalizerReady.
* nogc.cc (_Jv_GCInitializeFinalizers): New function.
* prims.cc: Include VirtualMachineError.h, FinalizerThread.h.
(_Jv_CreateJavaVM): Start the finalizer thread.
* no-threads.cc: Include InternalError.h.
(_Jv_ThreadInitData): Throw InternalError if thread already
running.
(_Jv_ThreadStart): Throw InternalError.
* Makefile.in: Rebuilt.
* Makefile.am (ordinary_java_source_files): Added
FinalizerThread.java.
(nat_source_files): Added natFinalizerThread.cc.
* include/jvm.h (_Jv_GCInitializeFinalizers): Declare.
* boehm.cc (_Jv_GCInitializeFinalizers): New function.
* gnu/gcj/runtime/FirstThread.java (run): Start finalizer thread.
* gnu/gcj/runtime/FinalizerThread.java: New file.
Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.am,v
retrieving revision 1.174
diff -u -r1.174 Makefile.am
--- Makefile.am 2001/10/02 22:49:53 1.174
+++ Makefile.am 2001/10/09 20:09:14
@@ -1137,6 +1137,7 @@
gnu/gcj/protocol/jar/Connection.java \
gnu/gcj/protocol/jar/Handler.java \
gnu/gcj/runtime/FileDeleter.java \
+gnu/gcj/runtime/FinalizerThread.java \
gnu/gcj/runtime/FirstThread.java \
gnu/gcj/runtime/SharedLibLoader.java \
gnu/gcj/runtime/VMClassLoader.java \
@@ -1495,6 +1496,7 @@
gnu/gcj/io/natSimpleSHSStream.cc \
gnu/gcj/io/shs.cc \
gnu/gcj/protocol/core/natCoreInputStream.cc \
+gnu/gcj/runtime/natFinalizerThread.cc \
gnu/gcj/runtime/natFirstThread.cc \
gnu/gcj/runtime/natSharedLibLoader.cc \
java/io/natFile.cc \
Index: boehm.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/boehm.cc,v
retrieving revision 1.28
diff -u -r1.28 boehm.cc
--- boehm.cc 2001/10/02 14:31:42 1.28
+++ boehm.cc 2001/10/09 20:09:17
@@ -544,6 +544,13 @@
#endif /* JV_HASH_SYNCHRONIZATION */
void
+_Jv_GCInitializeFinalizers (void (*notifier) (void))
+{
+ GC_finalize_on_demand = 1;
+ GC_finalizer_notifier = notifier;
+}
+
+void
_Jv_GCRegisterDisappearingLink (jobject *objp)
{
GC_general_register_disappearing_link ((GC_PTR *) objp, (GC_PTR) *objp);
Index: no-threads.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/no-threads.cc,v
retrieving revision 1.7
diff -u -r1.7 no-threads.cc
--- no-threads.cc 2001/09/21 07:46:32 1.7
+++ no-threads.cc 2001/10/09 20:09:17
@@ -1,6 +1,6 @@
// no-thread.cc - Implementation of `no threads' threads.
-/* Copyright (C) 1998, 1999 Free Software Foundation
+/* Copyright (C) 1998, 1999, 2001 Free Software Foundation
This file is part of libgcj.
@@ -13,6 +13,7 @@
#include <gcj/cni.h>
#include <jvm.h>
#include <java/lang/Thread.h>
+#include <java/lang/InternalError.h>
java::lang::Thread *_Jv_OnlyThread = NULL;
@@ -22,7 +23,7 @@
// Don't use JvAssert, since we want this to fail even when compiled
// without assertions.
if (_Jv_OnlyThread)
- JvFail ("only thread already running");
+ throw new java::lang::InternalError (JvNewStringLatin1 ("only thread already running"));
_Jv_OnlyThread = thread;
return NULL;
}
@@ -30,5 +31,5 @@
void
_Jv_ThreadStart (java::lang::Thread *, _Jv_Thread_t *, _Jv_ThreadStartFunc *)
{
- JvFail ("Thread.start called but threads not available");
+ throw new java::lang::InternalError (JvNewStringLatin1 ("Thread.start called but threads not available"));
}
Index: nogc.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/nogc.cc,v
retrieving revision 1.10
diff -u -r1.10 nogc.cc
--- nogc.cc 2001/09/10 01:21:08 1.10
+++ nogc.cc 2001/10/09 20:09:17
@@ -92,6 +92,11 @@
}
void
+_Jv_GCInitializeFinalizers (void (*) (void))
+{
+}
+
+void
_Jv_RunGC (void)
{
}
Index: prims.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/prims.cc,v
retrieving revision 1.59
diff -u -r1.59 prims.cc
--- prims.cc 2001/10/02 13:44:31 1.59
+++ prims.cc 2001/10/09 20:09:18
@@ -53,7 +53,6 @@
#include <java/lang/String.h>
#include <java/lang/Thread.h>
#include <java/lang/ThreadGroup.h>
-#include <gnu/gcj/runtime/FirstThread.h>
#include <java/lang/ArrayIndexOutOfBoundsException.h>
#include <java/lang/ArithmeticException.h>
#include <java/lang/ClassFormatError.h>
@@ -64,7 +63,10 @@
#include <java/lang/reflect/Modifier.h>
#include <java/io/PrintStream.h>
#include <java/lang/UnsatisfiedLinkError.h>
+#include <java/lang/VirtualMachineError.h>
#include <gnu/gcj/runtime/VMClassLoader.h>
+#include <gnu/gcj/runtime/FinalizerThread.h>
+#include <gnu/gcj/runtime/FirstThread.h>
#ifdef USE_LTDL
#include <ltdl.h>
@@ -893,6 +895,21 @@
#endif
_Jv_JNI_Init ();
+
+ _Jv_GCInitializeFinalizers (&::gnu::gcj::runtime::FinalizerThread::finalizerReady);
+
+ // Start the GC finalizer thread. A VirtualMachineError can be
+ // thrown by the runtime if, say, threads aren't available. In this
+ // case finalizers simply won't run.
+ try
+ {
+ using namespace gnu::gcj::runtime;
+ FinalizerThread *ft = new FinalizerThread ();
+ ft->start ();
+ }
+ catch (java::lang::VirtualMachineError *ignore)
+ {
+ }
return 0;
}
Index: gnu/gcj/runtime/FinalizerThread.java
===================================================================
RCS file: FinalizerThread.java
diff -N FinalizerThread.java
--- /dev/null Tue May 5 13:32:27 1998
+++ gnu/gcj/runtime/FinalizerThread.java Tue Oct 9 13:09:18 2001
@@ -0,0 +1,73 @@
+// FinalizerThread.java -- Thread in which finalizers are run.
+
+/* Copyright (C) 2001 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+package gnu.gcj.runtime;
+
+/**
+ * @author Tom Tromey <tromey@redhat.com>
+ * @date October 3, 2001
+ */
+public final class FinalizerThread extends Thread
+{
+ // Finalizers must be run in a thread with no Java-visible locks
+ // held. This qualifies because we don't make the lock visible.
+ private static final Object lock = new Object ();
+
+ // This is true if the finalizer thread started successfully. It
+ // might be false if, for instance, there are no threads on the
+ // current platform. In this situation we run finalizers in the
+ // caller's thread.
+ private static boolean thread_started = false;
+
+ public FinalizerThread ()
+ {
+ super ("LibgcjInternalFinalizerThread");
+ setDaemon (true);
+ }
+
+ // This is called by the runtime when a finalizer is ready to be
+ // run. It simply wakes up the finalizer thread.
+ public static void finalizerReady ()
+ {
+ synchronized (lock)
+ {
+ if (! thread_started)
+ runFinalizers ();
+ else
+ lock.notify ();
+ }
+ }
+
+ // Actually run the finalizers.
+ private static native void runFinalizers ();
+
+ public void run ()
+ {
+ // Wait on a lock. Whenever we wake up, try to invoke the
+ // finalizers.
+ synchronized (lock)
+ {
+ thread_started = true;
+ while (true)
+ {
+ try
+ {
+ lock.wait ();
+ }
+ catch (InterruptedException _)
+ {
+ // Just ignore it. It doesn't hurt to run finalizers
+ // when none are pending.
+ }
+ runFinalizers ();
+ }
+ }
+ }
+}
Index: gnu/gcj/runtime/FirstThread.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/gcj/runtime/FirstThread.java,v
retrieving revision 1.9
diff -u -r1.9 FirstThread.java
--- gnu/gcj/runtime/FirstThread.java 2001/08/26 11:30:08 1.9
+++ gnu/gcj/runtime/FirstThread.java 2001/10/09 20:09:18
@@ -1,6 +1,6 @@
// FirstThread.java - Implementation of very first thread.
-/* Copyright (C) 1998, 1999, 2000 Free Software Foundation
+/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation
This file is part of libgcj.
@@ -33,12 +33,12 @@
this.args = args;
this.is_jar = is_jar;
}
-
+
public void run()
{
if (is_jar)
klass_name = getMain(klass_name);
-
+
if (klass == null)
{
try
@@ -50,7 +50,7 @@
throw new NoClassDefFoundError(klass_name);
}
}
-
+
call_main();
}
Index: gnu/gcj/runtime/natFinalizerThread.cc
===================================================================
RCS file: natFinalizerThread.cc
diff -N natFinalizerThread.cc
--- /dev/null Tue May 5 13:32:27 1998
+++ gnu/gcj/runtime/natFinalizerThread.cc Tue Oct 9 13:09:18 2001
@@ -0,0 +1,22 @@
+// natFinalizerThread.cc - Implementation of FinalizerThread native methods.
+
+/* Copyright (C) 2001 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+#include <config.h>
+
+#include <gcj/cni.h>
+#include <jvm.h>
+
+#include <gnu/gcj/runtime/FinalizerThread.h>
+
+void
+gnu::gcj::runtime::FinalizerThread::runFinalizers ()
+{
+ _Jv_RunFinalizers ();
+}
Index: include/jvm.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/jvm.h,v
retrieving revision 1.41
diff -u -r1.41 jvm.h
--- include/jvm.h 2001/10/02 14:31:45 1.41
+++ include/jvm.h 2001/10/09 20:09:19
@@ -157,6 +157,9 @@
memory. */
void *_Jv_MallocUnchecked (jsize size) __attribute__((__malloc__));
+/* Initialize finalizers. The argument is a function to be called
+ when a finalizer is ready to be run. */
+void _Jv_GCInitializeFinalizers (void (*notifier) (void));
/* Run finalizers for objects ready to be finalized.. */
void _Jv_RunFinalizers (void);
/* Run all finalizers. Should be called only before exit. */
Index: java/lang/natRuntime.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natRuntime.cc,v
retrieving revision 1.18
diff -u -r1.18 natRuntime.cc
--- java/lang/natRuntime.cc 2001/06/15 23:22:02 1.18
+++ java/lang/natRuntime.cc 2001/10/09 20:09:19
@@ -18,6 +18,7 @@
#include <java/lang/UnknownError.h>
#include <java/lang/UnsatisfiedLinkError.h>
#include <gnu/gcj/runtime/FileDeleter.h>
+#include <gnu/gcj/runtime/FinalizerThread.h>
#include <jni.h>
@@ -208,7 +209,7 @@
void
java::lang::Runtime::runFinalization (void)
{
- _Jv_RunFinalizers ();
+ gnu::gcj::runtime::FinalizerThread::finalizerReady ();
}
jlong