My understanding is that when you System.exit all threads associated with the JVM process are killed. That's what I meant by "nuclear Thread.interrupt".
It's the same issue as was raised about System.exit implicitly ending control flow or implicitly closing open file handles - a process could be relying on the behavior of implicitly killing all threads and not have another cleanup mechanism On Sun, Feb 27, 2022, 5:16 PM David Holmes <david.hol...@oracle.com> wrote: > On 28/02/2022 3:20 am, Ethan McCue wrote: > > 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 > > What has Thread.interrupt got to do with System.exit ? > > David > > > 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 <zjx001...@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 <et...@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 <fo...@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" <et...@mccue.dev> > >>>>> To: "core-libs-dev" <core-libs-dev@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 > >>>> > >>> > >> >