[m-rev.] for review: [java] Run finalisers only if main/2 returns normally

Paul Bone paul at bone.id.au
Mon Jan 5 15:07:03 AEDT 2015


On Thu, Jan 01, 2015 at 10:28:32PM +1100, Julien Fischer wrote:
>
>
> Hi Paul,
>
> On Tue, 30 Dec 2014, Paul Bone wrote:
>
>> ---
>> [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
>
> Given the behaviour specified below, there is no "probably" about it.
> That's exactly what they do,
>
>> the Java backend did not.  I have not checked the C# or Erlang backends.
>
> The C# backend runs the finalisers when main/2 terminates with an uncaught
> exception (i.e. it implements the "wrong" behaviour).
>
> The Erlang backend appears to be correct.
>
>> 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
>
> s/the/they/
>
>>    finalise the RTS.
>
> A better design IMO would be to have two methods: one that finalises
> the runtime system normally and the other that does an immediate abort,
> for example something like:
>
>     MercuryRuntime.shutdown() // run finalisers, shutdown the thread pool.
>     MercuryRuntime.abort()    // abort immediately.
>

Actually, I'm not sure one way or the other with this.  And the point may be
moot anyway (see below).  On one hand we have:

    boolean aborting = true;

    try {
        do_stuff();
        aborting = false;
    }
    finally {
        MercuryRuntime.finalise(clean_exit);
    }

Which is nice.  Or:

    try {
        do_stuff();
        MercuryRuntime.shutdown();
    }
    catch (java.util.Throwable e) {
        MercuryRuntime.abort();
    }

This seems okay, but it's not ideal because we must remember to call abort
in all the catch blocks.  And the catch blocks must catch everything (so I
used Throwable).  Java doesn't have a block for "all other exceptions" the
way Mercury does, but it does have the finally block which is executed in
all cases: normal return, trapped exception and untrapped exception.  So
it's easier to get the first example correct, especially as programs become
more complex.  Of course you could write:

    boolean aborting = true;

    try {
        do_stuff();
        aborting = false;
    }
    finally {
        if (aborting) {
            MercuryRuntime.abort();
        } else {
            MercuryRuntime.shutdown();
        }
    }

But that's more tedious than either of the other two and programmers often
lack discipline.

Anyway, this may be moot because I'd like shutting down of the thread pool
to be automatic.  Which should be possible I've just not done it yet.  Then
the caller only needs to call finalise to run module finalisers.  So their
code can be:

    do_stuff()
    MercuryRuntime.finalise();

The finalise call may still shut down the thread pool and wait for it to
exit (so that the actions of any other threads are completed before the call
returns) but it won't be mandatory.

So what I'll do is create the finalise(boolean abort) method, like in my
diff.  And also create a finalise() method that calls the first method with
abort=false.  Then applications won't need further changes if the thread
pool is made to shutdown automatically and it's easy to use Java's try
blocks.


-- 
Paul Bone



More information about the reviews mailing list