[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