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