Should System.exit be controlled by a Scope Local?

Ethan McCue ethan at mccue.dev
Sun Feb 27 17:20:34 UTC 2022


I think continuations could work for the single threaded case, depending on
their behavior with "finally" blocks. I'm sure there are more caveats once
we add another thread to the mix though. System.exit is a nuclear
Thread.interrupt, so replicating that behavior might be a bit daunting

    private static final class ExitCode {
        volatile Integer code = null;
    }

    private final ScopeLocal<ExitCode> EXIT_CODE = ScopeLocal.newInstance();

    public void overridingExitBehavior(IntConsumer exit, Runnable run) {
        var exitCode = new ExitCode();
        ScopeLocal.with(EXIT_CODE, exitCode).run(() -> {
            // by whatever syntax
            var _ = inContinuation(run);
            if (exitCode.code != null) {
                exit.accept(code.exitCode)
            }
        });
    }

    public void exit(int status) {
        if (EXIT_CODE.isBound()) {
             EXIT_CODE.get().code = status;
             Continuation.yield();
        }
        else {
            Shutdown.exit(status);
        }
    }



On Sun, Feb 27, 2022 at 10:41 AM Glavo <zjx001202 at gmail.com> wrote:

> I think there is a problem with this: `System.exit` contains semantics to
> interrupt the flow of control and exit, and if you implement it that way,
> you might have some program abnormally execute parts of it that should
> never be executed.
>
> Of course, using exceptions like this should solve part of the problem:
>
> class Exit extends Error {
>     final int exitCode;
>     public Exit(int exitCode) {
>         this.exitCode = exitCode;
>     }
>
>     @Override
>     public synchronized Throwable fillInStackTrace() {
>         return this;
>     }
> }
>
> try {
>   Runtime.getRuntime().overridingExitBehavior(exitCode -> {throw new
> Exit(exitCode);}, ...);
> } catch (Exit exit) {
>   ...
> }
>
> However, the calling method may catch this exception unexpectedly, and
> there may be unexpected behavior under multithreading.
> Of course, this part of the problem also exists for the security manager.
> But, if possible, it would be better to have a solution for these
> situations.
> (`Continuation` might help us?)
>
>
>
> On Sun, Feb 27, 2022 at 11:07 PM Ethan McCue <ethan at mccue.dev> wrote:
>
>> That undermines my point some, but I think the overall shape of the use
>> case still makes sense
>>
>> On Sun, Feb 27, 2022 at 8:01 AM Remi Forax <forax at univ-mlv.fr> wrote:
>>
>> > Hi Ethan,
>> > there is a far simpler solution, call org.apache.ivy.run(args, true)
>> > instead of org.apache.ivy.main(args) in your tool provider.
>> >
>> > regards,
>> > Rémi
>> >
>> > ----- Original Message -----
>> > > From: "Ethan McCue" <ethan at mccue.dev>
>> > > To: "core-libs-dev" <core-libs-dev at openjdk.java.net>
>> > > Sent: Saturday, February 26, 2022 11:14:19 PM
>> > > Subject: Should System.exit be controlled by a Scope Local?
>> >
>> > > I have a feeling this has been considered and I might just be
>> > articulating
>> > > the obvious - but:
>> > >
>> > > As called out in JEP 411, one of the remaining legitimate uses of the
>> > > Security Manager is to intercept calls to System.exit. This seems
>> like a
>> > > decent use case for the Scope Local mechanism.
>> > >
>> > >
>> > >    public class Runtime {
>> > >        ...
>> > >        private final ScopeLocal<IntConsumer> EXIT =
>> > > ScopeLocal.newInstance();
>> > >
>> > >        ...
>> > >
>> > >        public void overridingExitBehavior(IntConsumer exit, Runnable
>> > run) {
>> > >            ScopeLocal.with(EXIT, exit).run(run);
>> > >        }
>> > >
>> > >        ...
>> > >
>> > >        public void exit(int status) {
>> > >            if (EXIT.isBound()) {
>> > >                EXIT.get().accept(status);
>> > >            }
>> > >            else {
>> > >                Shutdown.exit(status);
>> > >            }
>> > >        }
>> > >    }
>> > >
>> > >
>> > > One of the likely minor benefits in the scope of things, but related
>> to
>> > the
>> > > parts of the ecosystem I am doodling with so I'll mention it, is that
>> it
>> > > would become possible to wrap "naive" cli programs with the
>> ToolProvider
>> > > SPI without rewriting their code if this System.out, and System.err
>> all
>> > > became reliably configurable.
>> > >
>> > > For instance, Apache Ivy's CLI has a main class that looks like this
>> > >
>> > >
>> >
>> https://github.com/apache/ant-ivy/blob/424fa89419147f50a41b4bdc665d8ea92b5da516/src/java/org/apache/ivy/Main.java
>> > >
>> > >    package org.apache.ivy;
>> > >
>> > >    public final class Main {
>> > >        ...
>> > >
>> > >        public static void main(String[] args) throws Exception {
>> > >            try {
>> > >                run(args, true);
>> > >                System.exit(0);
>> > >            } catch (ParseException ex) {
>> > >                System.err.println(ex.getMessage());
>> > >                System.exit(1);
>> > >            }
>> > >        }
>> > >     }
>> > >
>> > > Making these otherwise static parts of the system configurable would
>> > enable
>> > > a third party library to write
>> > >
>> > >    public final class IvyToolProvider implements ToolProvider {
>> > >        @Override
>> > >        public String name() {
>> > >            return "ivy";
>> > >        }
>> > >
>> > >        @Override
>> > >        public int run(PrintWriter out, PrintWriter err, String...
>> args) {
>> > >            var exit = new AtomicInteger(0);
>> > >            Runtime.getRuntime().overridingExitBehavior(exit::set, ()
>> -> {
>> > >                System.overridingOut(out, () -> {
>> > >                     System.overridingErr(err, Main::main);
>> > >                }
>> > >            };
>> > >            return exit.get();
>> > >        }
>> > >    }
>> > >
>> > > Whether that would be enough to make it so that people other than
>> > Christian
>> > > Stein use the mechanism is anyone's guess, but might be worth a shot.
>> > >
>> > > https://grep.app/search?q=java.util.spi.ToolProvider
>> >
>>
>


More information about the core-libs-dev mailing list