Thread overview
Proper way to exit with specific exit code?
Sep 17
drathier
Sep 17
IGotD-
Sep 18
IGotD-
September 17
What's the proper way to exit with a specific exit code?

I found a bunch of old threads discussing this, making sure destructors run and the runtime terminates properly, all of which seemingly concluding that it's sad that there isn't a way to do this easily, but hopefully things have changed in the last 5-10 years and I'm just missing the obvious solution.
September 17
On Thu, Sep 17, 2020 at 02:58:48PM +0000, drathier via Digitalmars-d-learn wrote:
> What's the proper way to exit with a specific exit code?
> 
> I found a bunch of old threads discussing this, making sure destructors run and the runtime terminates properly, all of which seemingly concluding that it's sad that there isn't a way to do this easily, but hopefully things have changed in the last 5-10 years and I'm just missing the obvious solution.

AFAIK, there still isn't an "official" way to do this besides return
the exit code from main().  My go-to solution is to declare an
ExitException that's explicitly caught by main():

	class ExitException : Exception {
		int returnCode;
		this() { super("exit"); }
	}

	void exit(int rc=0) { throw new ExitException(rc); }

	int main(string[] args) {
		try {
			... // your code here
			exit(123);
			...
		} catch (ExitException e) {
			return e.returnCode;
		}
		return 0;
	}

Caveat: this may or may not do the Right Thing(tm) in a multithreaded
application.


T

-- 
Talk is cheap. Whining is actually free. -- Lars Wirzenius
September 17
On Thursday, 17 September 2020 at 14:58:48 UTC, drathier wrote:
> What's the proper way to exit with a specific exit code?
>
> I found a bunch of old threads discussing this, making sure destructors run and the runtime terminates properly, all of which seemingly concluding that it's sad that there isn't a way to do this easily, but hopefully things have changed in the last 5-10 years and I'm just missing the obvious solution.

The only way is to return from main. The thing is that druntime runs initialization before main and then returning from main it runs all the tear down code including cleaning up the GC. This means there is no equivalent of the exit function in the C library. Calling exit from D means that there will be no cleanup in D environment.

This is a bit limiting for my needs for example. I would like that exiting from main will not tear down the D runtime because my system is a message driven system and main just sets up the program and then returns but the programs continues to react on messages. Many libraries like Qt circumvents this just by parking the main thread as a event handler but this doesn't fit my system and will waste one thread resource. Finally to exit the program I have equivalent to the C library exit function. Creating a similar exit function in D would be trivial really.
September 17
On 9/17/20 12:46 PM, IGotD- wrote:
> The only way is to return from main. The thing is that druntime runs initialization before main and then returning from main it runs all the tear down code including cleaning up the GC. This means there is no equivalent of the exit function in the C library. Calling exit from D means that there will be no cleanup in D environment.
...

I never considered this -- so when I call core.stdc.stdlib : exit, none of my destructors get called?

Presumably also not scope(exit) blocks?

If this is the case, could we simply add a publically-accessible shutdown hook in the runtime?

September 17
On Thu, Sep 17, 2020 at 09:53:07PM -0400, James Blachly via Digitalmars-d-learn wrote: [...]
> I never considered this -- so when I call core.stdc.stdlib : exit, none of my destructors get called?

Yes.


> Presumably also not scope(exit) blocks?

Yes.


> If this is the case, could we simply add a publically-accessible shutdown hook in the runtime?

That's the obvious solution, except that actually implementing it is not so simple.  When you have multiple threads listening for each other and/or doing work, there is no 100% guaranteed way of cleanly shutting all of them down at the same time.  You can't just clean up the calling thread and leave the others running, because the other threads might hold references to your data, etc..  But there's no universal protocol for shutting down the other threads too -- they could be in a busy loop with some long-running computation, or they may not be checking for thread messages, or they could be in a server loop that is designed to keep running, etc..  It's one of those annoying things that reduce to the halting problem in the general case.

Unless we adopt some kind of exit protocol that will apply to *all* threads in *all* D programs, I don't see any way to implement something that will work in the general case.


T

-- 
If blunt statements had a point, they wouldn't be blunt...
September 18
On Friday, 18 September 2020 at 05:02:21 UTC, H. S. Teoh wrote:
>
> That's the obvious solution, except that actually implementing it is not so simple.  When you have multiple threads listening for each other and/or doing work, there is no 100% guaranteed way of cleanly shutting all of them down at the same time.  You can't just clean up the calling thread and leave the others running, because the other threads might hold references to your data, etc..  But there's no universal protocol for shutting down the other threads too -- they could be in a busy loop with some long-running computation, or they may not be checking for thread messages, or they could be in a server loop that is designed to keep running, etc..  It's one of those annoying things that reduce to the halting problem in the general case.
>
> Unless we adopt some kind of exit protocol that will apply to *all* threads in *all* D programs, I don't see any way to implement something that will work in the general case.
>
>
> T

I think a pragmatic solution is just to mutex protect the D exit function in case several threads tries to use simultaneously. Then if more threads call exit, it will do nothing as the first one that called exit actually do the tear down.

Also, it should be responsibility of the program to ensure that its tear down code runs before calling the D exit function. That's the only way I can think of because waiting for all other threads to release their resources and exit isn't really realistic either as that might do that the program exit never happens. Whatever you do you, you have to resort to some "manual" solution".

I suggest keeping it simple and stupid.

September 18
On Fri, Sep 18, 2020 at 08:20:59AM +0000, IGotD- via Digitalmars-d-learn wrote:
> On Friday, 18 September 2020 at 05:02:21 UTC, H. S. Teoh wrote:
> > 
> > That's the obvious solution, except that actually implementing it is not so simple.  When you have multiple threads listening for each other and/or doing work, there is no 100% guaranteed way of cleanly shutting all of them down at the same time.  You can't just clean up the calling thread and leave the others running, because the other threads might hold references to your data, etc..  But there's no universal protocol for shutting down the other threads too -- they could be in a busy loop with some long-running computation, or they may not be checking for thread messages, or they could be in a server loop that is designed to keep running, etc..  It's one of those annoying things that reduce to the halting problem in the general case.
[...]
> I think a pragmatic solution is just to mutex protect the D exit function in case several threads tries to use simultaneously. Then if more threads call exit, it will do nothing as the first one that called exit actually do the tear down.

That does not solve the problem.  If thread 1 calls exit but thread 2 is still running and processing data via a shared reference with thread 1's data, you absolutely do not want to run dtors and tear-down code until thread 2 is done, otherwise you have a problem.

OTOH, waiting for thread 2 to finish first comes with its own problems: what if thread 2 never calls exit?  Then no cleanup will be done, which may not be desirable either (maybe you had thread 1 call exit because you wanted to release unused resources).


> Also, it should be responsibility of the program to ensure that its tear down code runs before calling the D exit function. That's the only way I can think of because waiting for all other threads to release their resources and exit isn't really realistic either as that might do that the program exit never happens. Whatever you do you, you have to resort to some "manual" solution".
[...]

If you're prepared to do manual teardown, then you do not need a D-specific exit function. Just call core.sys.stdc.stdlib.exit and call it a day. :-)


T

-- 
Never trust an operating system you don't have source for! -- Martin Schulze
September 19
On 2020-09-17 16:58, drathier wrote:
> What's the proper way to exit with a specific exit code?
> 
> I found a bunch of old threads discussing this, making sure destructors run and the runtime terminates properly, all of which seemingly concluding that it's sad that there isn't a way to do this easily, but hopefully things have changed in the last 5-10 years and I'm just missing the obvious solution.

The proper way is:

int main()
{
    return 42;
}

I highly recommend against trying to terminate the application using `exit` or any other way. Just let the control flow return back to the `main` function.

-- 
/Jacob Carlborg