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>
>>>>
>>>
>>