K. On Sun, Feb 27, 2022, 7:03 PM David Holmes <david.hol...@oracle.com> wrote:
> On 28/02/2022 8:20 am, Ethan McCue wrote: > > 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". > > The process is terminated, the threads are not individually "killed". > All Thread.interrupt does is set a flag and unpark blocked threads (in > some specific cases). There's really no comparison at all. > > David > ----- > > > 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 > > <mailto: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 > > <mailto: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 > > <mailto: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 > > <mailto: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 <mailto:et...@mccue.dev > >> > > >>>>> To: "core-libs-dev" <core-libs-dev@openjdk.java.net > > <mailto: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 > > < > 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 > > <https://grep.app/search?q=java.util.spi.ToolProvider> > > >>>> > > >>> > > >> > > >