summaryrefslogtreecommitdiff
path: root/jurt
diff options
context:
space:
mode:
authorStephan Bergmann <sbergman@redhat.com>2014-12-09 12:51:40 +0100
committerStephan Bergmann <sbergman@redhat.com>2014-12-09 13:17:03 +0100
commit6ddde10b4006ece33bc358a391a13e108a35f6fa (patch)
tree2a1b66691b588c2cb931934133fc911b052ae61b /jurt
parent4c66ce8ec8f67d3bc2db5c79de68f4bda26d2e60 (diff)
rhbz#1036877: Join Java AsynchronousFinalizer thread well before exit
AsynchronousFinalizer was originally added as 870a4401c05beec3d31c1f6055a64591edd0a9d9 "INTEGRATION: CWS mtg1: #i57753# Avoid long-running finalize methods" referring to <https://issues.apache.org/ooo/show_bug.cgi?id=57753> " Fix JNI-UNO bridge so that the JVM doesn't run out of memory when a destructor locks the SolarMutex." It is unclear to me how relevant "If JVMs are getting more mature and should no longer have problems with long-running finalize methods, this class could be removed again" really is in practice. After all, advice on hotspot-gc-devel is to avoid finalize() if possible (<http://mail.openjdk.java.net/pipermail/hotspot-gc-dev/2014-June/010215.html> "Re: History of finalizer execution and gc progress?"). So stick with this approach of home-grown draining for now (where a home-grown approach using PhantomReferencens would need a dedicated draining thread, too, so would not have much benefit over the existing code in practice). Timely termination of AsynchronousFinalizer threads is achieved by using a dedicated thread per bridge and joining it in the remote bridge's dispose() resp. the JNI environment's new java_env_dispose. Change-Id: Idcef2dbf361a1de22f60db73828f59e85711aea7
Diffstat (limited to 'jurt')
-rw-r--r--jurt/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory.java15
-rw-r--r--jurt/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge.java12
-rw-r--r--jurt/com/sun/star/lib/util/AsynchronousFinalizer.java71
3 files changed, 60 insertions, 38 deletions
diff --git a/jurt/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory.java b/jurt/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory.java
index edcceca44757..e249062fa07e 100644
--- a/jurt/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory.java
+++ b/jurt/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory.java
@@ -57,6 +57,10 @@ final class ProxyFactory {
}
}
+ public void dispose() throws InterruptedException {
+ asynchronousFinalizer.drain();
+ }
+
public static XBridge getBridge(Object obj) {
if (Proxy.isProxyClass(obj.getClass())) {
InvocationHandler h = Proxy.getInvocationHandler(obj);
@@ -126,13 +130,10 @@ final class ProxyFactory {
@Override
protected void finalize() {
- AsynchronousFinalizer.add(new AsynchronousFinalizer.Job() {
+ decrementDebugCount();
+ asynchronousFinalizer.add(new AsynchronousFinalizer.Job() {
public void run() throws Throwable {
- try {
- request("release", null);
- } finally {
- decrementDebugCount();
- }
+ request("release", null);
}
});
}
@@ -187,4 +188,6 @@ final class ProxyFactory {
private final RequestHandler requestHandler;
private final XBridge bridge;
+ private final AsynchronousFinalizer asynchronousFinalizer =
+ new AsynchronousFinalizer();
}
diff --git a/jurt/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge.java b/jurt/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge.java
index 722f825e6ba5..48784283a99a 100644
--- a/jurt/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge.java
+++ b/jurt/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge.java
@@ -499,7 +499,12 @@ public class java_remote_bridge
try {
_messageDispatcher.terminate();
- _xConnection.close();
+ try {
+ _xConnection.close();
+ } catch (com.sun.star.io.IOException e) {
+ System.err.println(
+ getClass().getName() + ".dispose - IOException:" + e);
+ }
if (Thread.currentThread() != _messageDispatcher
&& _messageDispatcher.isAlive())
@@ -519,6 +524,8 @@ public class java_remote_bridge
// assert _java_environment instanceof java_environment;
((java_environment) _java_environment).revokeAllProxies();
+ proxyFactory.dispose();
+
if (DEBUG) {
if (_life_count != 0) {
System.err.println(getClass().getName()
@@ -535,9 +542,6 @@ public class java_remote_bridge
} catch (InterruptedException e) {
System.err.println(getClass().getName()
+ ".dispose - InterruptedException:" + e);
- } catch (com.sun.star.io.IOException e) {
- System.err.println(getClass().getName() + ".dispose - IOException:"
- + e);
}
}
diff --git a/jurt/com/sun/star/lib/util/AsynchronousFinalizer.java b/jurt/com/sun/star/lib/util/AsynchronousFinalizer.java
index 4dcd69a97e1f..71743b25241b 100644
--- a/jurt/com/sun/star/lib/util/AsynchronousFinalizer.java
+++ b/jurt/com/sun/star/lib/util/AsynchronousFinalizer.java
@@ -35,6 +35,37 @@ import java.util.LinkedList;
* long-running finalize methods, this class could be removed again.</p>
*/
public final class AsynchronousFinalizer {
+ public AsynchronousFinalizer() {
+ thread = new Thread("AsynchronousFinalizer") {
+ @Override
+ public void run() {
+ for (;;) {
+ Job j;
+ synchronized (queue) {
+ for (;;) {
+ if (done) {
+ return;
+ }
+ if (!queue.isEmpty()) {
+ break;
+ }
+ try {
+ queue.wait();
+ } catch (InterruptedException e) {
+ return;
+ }
+ }
+ j = queue.remove(0);
+ }
+ try {
+ j.run();
+ } catch (Throwable e) {}
+ }
+ }
+ };
+ thread.start();
+ }
+
/**
* Add a job to be executed asynchronously.
*
@@ -43,7 +74,7 @@ public final class AsynchronousFinalizer {
*
* @param job represents the body of some finalize method; must not be null.
*/
- public static void add(Job job) {
+ public void add(Job job) {
synchronized (queue) {
boolean first = queue.isEmpty();
queue.add(job);
@@ -53,6 +84,14 @@ public final class AsynchronousFinalizer {
}
}
+ public void drain() throws InterruptedException {
+ synchronized (queue) {
+ done = true;
+ queue.notify();
+ }
+ thread.join();
+ }
+
/**
* An interface to represent bodies of finalize methods.
*
@@ -65,31 +104,7 @@ public final class AsynchronousFinalizer {
void run() throws Throwable;
}
- private static final LinkedList<Job> queue = new LinkedList<Job>();
-
- static {
- Thread t = new Thread("AsynchronousFinalizer") {
- @Override
- public void run() {
- for (;;) {
- Job j;
- synchronized (queue) {
- while (queue.isEmpty()) {
- try {
- queue.wait();
- } catch (InterruptedException e) {}
- }
- j = queue.remove(0);
- }
- try {
- j.run();
- } catch (Throwable e) {}
- }
- }
- };
- t.setDaemon(true);
- t.start();
- }
-
- private AsynchronousFinalizer() {}
+ private final LinkedList<Job> queue = new LinkedList<Job>();
+ private final Thread thread;
+ private boolean done = false;
}