[m-rev.] for review: [java] Run finalisers only if main/2 returns normally
Paul Bone
paul at bone.id.au
Tue Dec 30 17:13:41 AEDT 2014
Branches: master
For review by anyone. The correct behaviour was discussed recently on the
developers list with Julien.
---
[java] Run finalisers only if main/2 returns normally
finalisers should be executed only if main/2 returns normally, it does not
throw an exception. The C backends probably already do this correctly but
the Java backend did not. I have not checked the C# or Erlang backends.
java/runtime/MercuryThreadPool.java:
Add a parameter to the shutdown() method to specify whether the backend
is aborting.
In runMain(), run finalisers only if the runtime is exiting normally.
java/runtime/MercuryRuntime.java:
Add a parameter to the finalise() method allowing standalone Java
applications to specify whether or not they are aborting when the
finalise the RTS.
doc/reference_manual.texi:
Specify this behaviour.
samples/java_interface/standalone_java/JavaMain.java:
Conform to changes in MercuryRuntime.java.
---
doc/reference_manual.texi | 2 ++
java/runtime/MercuryRuntime.java | 15 +++++++++++----
java/runtime/MercuryThreadPool.java | 19 +++++++++++++++----
samples/java_interface/standalone_java/JavaMain.java | 6 ++++--
4 files changed, 32 insertions(+), 10 deletions(-)
diff --git a/doc/reference_manual.texi b/doc/reference_manual.texi
index d9b355c..da7cd0b 100644
--- a/doc/reference_manual.texi
+++ b/doc/reference_manual.texi
@@ -4835,6 +4835,8 @@ If @samp{finalpredname/arity} terminates with an uncaught exception then
the program will immediately abort execution. No predicates specified
by other @samp{finalise} directives that have not yet been executed will
be executed.
+If @samp{main/2} terminates with an uncaught exception then no predicates
+specified by any @samp{finalise} directives will be executed.
@samp{finalize} is also allowed as a synonym for @samp{finalise}.
diff --git a/java/runtime/MercuryRuntime.java b/java/runtime/MercuryRuntime.java
index b3b8391..5ad41b2 100644
--- a/java/runtime/MercuryRuntime.java
+++ b/java/runtime/MercuryRuntime.java
@@ -50,15 +50,22 @@ public class MercuryRuntime
* Finalise the runtime system.
* This _must_ be called at the normal end of any program. It runs
* finalisers and stops the thread pool.
- * This will wait for the thread pool to shutdown.
+ * This will wait for the thread pool to shutdown (unless aborting).
+ * @param abort True if the program is aborting. If this is true
+ * finalisers will not be executed and we will not wait for the thread
+ * pool to finish shutting down.
*/
- public static void finalise() {
+ public static void finalise(boolean abort) {
MercuryThreadPool pool;
pool = getThreadPool();
- JavaInternal.run_finalisers();
+ if (!abort) {
+ JavaInternal.run_finalisers();
+ }
pool.shutdown();
- pool.waitForShutdown();
+ if (!abort) {
+ pool.waitForShutdown();
+ }
}
}
diff --git a/java/runtime/MercuryThreadPool.java b/java/runtime/MercuryThreadPool.java
index 676f2ef..90fa9c3 100644
--- a/java/runtime/MercuryThreadPool.java
+++ b/java/runtime/MercuryThreadPool.java
@@ -93,6 +93,9 @@ public class MercuryThreadPool
// Has a shutdown request been received (protected by tasks_lock)
private boolean shutdown_request;
+ // Shutdown because the program is aborting (if true then don't run
+ // finalisers).
+ private boolean shutdown_abort;
// True if worker threads should exit (the pool is shutting down).
private boolean shutdown_now;
// True if the thread pool is running (including starting up and
@@ -129,6 +132,7 @@ public class MercuryThreadPool
*/
tasks = new ArrayDeque<Task>(size*4);
shutdown_request = false;
+ shutdown_abort = false;
shutdown_now = false;
running = false;
num_tasks_submitted = 0;
@@ -495,7 +499,8 @@ public class MercuryThreadPool
num_tasks_submitted = this.num_tasks_submitted;
num_tasks_completed = this.num_tasks_completed;
okay_to_shutdown =
- (num_tasks_submitted == num_tasks_completed);
+ (num_tasks_submitted == num_tasks_completed) ||
+ shutdown_abort;
will_shutdown = okay_to_shutdown && shutdown_request;
if (!will_shutdown) {
@@ -648,12 +653,13 @@ public class MercuryThreadPool
* This method is asynchronous, it will not wait for the thread pool to
* shutdown.
*/
- public boolean shutdown()
+ public boolean shutdown(boolean abort)
{
tasks_lock.lock();
try {
if (running && !shutdown_request) {
shutdown_request = true;
+ shutdown_abort = abort;
} else {
return false;
}
@@ -676,10 +682,13 @@ public class MercuryThreadPool
run_main_and_shutdown = new Runnable() {
public void run() {
+ boolean aborted = true;
+
try {
run_main.run();
+ aborted = false;
} finally {
- shutdown();
+ shutdown(aborted);
}
}
};
@@ -703,7 +712,9 @@ public class MercuryThreadPool
* until the program is finished
*/
run();
- jmercury.runtime.JavaInternal.run_finalisers();
+ if (!shutdown_abort) {
+ jmercury.runtime.JavaInternal.run_finalisers();
+ }
/*
* We always wait for the thread pool to shutdown as worker
* threads may either be completing work or reporting the reason
diff --git a/samples/java_interface/standalone_java/JavaMain.java b/samples/java_interface/standalone_java/JavaMain.java
index 4a0d164..c010972 100644
--- a/samples/java_interface/standalone_java/JavaMain.java
+++ b/samples/java_interface/standalone_java/JavaMain.java
@@ -35,9 +35,11 @@ public class JavaMain {
// This call will invoke any finalisers specified using
// ':- finalise' declarations in the set of Mercury libraries we
// are using. It also tells the thread pool to shutdown, if the
- // thread pool is not running then this does nothing.
+ // thread pool is not running then this does nothing. Set the
+ // parameter to "true" if the program is aborting (finalisers
+ // will be skipped).
//
- MercuryRuntime.finalise();
+ MercuryRuntime.finalise(false);
// The Mercury exit status (as set by io.set_exit_status/1) may
// be read from the MercuryRuntime class.
--
2.1.3
More information about the reviews
mailing list