Thread overview | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
December 02, 2017 scope(exit) and Ctrl-C | ||||
---|---|---|---|---|
| ||||
I wonder why `scope(exit)` code is not executed when the program is terminated with Ctrl-C. For example: ``` import std.stdio; import core.thread; void main() { scope (exit) { writeln("Cleanup"); } writeln("Waiting..."); Thread.sleep(10.seconds); writeln("Done waiting..."); } ``` If I wait 10 seconds, I get "Cleanup" output. But if I use Ctrl-C to terminate the program before 10 seconds elapse, there's no "Cleanup" output. Is it intentional? Is there any method to cleanup on Ctrl-C? |
December 01, 2017 Re: scope(exit) and Ctrl-C | ||||
---|---|---|---|---|
| ||||
Posted in reply to Wanderer | On 12/01/2017 04:41 PM, Wanderer wrote: > I wonder why `scope(exit)` code is not executed when the program is terminated with Ctrl-C. > > For example: > > ``` > import std.stdio; > import core.thread; > > void main() > { > scope (exit) > { > writeln("Cleanup"); > } > writeln("Waiting..."); > Thread.sleep(10.seconds); > writeln("Done waiting..."); > } > ``` > > If I wait 10 seconds, I get "Cleanup" output. > But if I use Ctrl-C to terminate the program before 10 seconds elapse, there's no "Cleanup" output. > > Is it intentional? > Is there any method to cleanup on Ctrl-C? Combined your code with this solution: http://forum.dlang.org/post/isawmurvxjyldcwddsfj@forum.dlang.org import core.thread; import std.stdio; import core.sys.posix.signal; // Note: This one is thread-local; make shared or __gshared if needed bool doQuit; extern(C) void handler(int num) nothrow @nogc @system { printf("Caught signal %d\n",num); doQuit = true; } void main(string[] args) { signal(SIGINT, &handler); scope (exit) { writeln("Cleanup"); } writeln("Waiting..."); foreach (_; 0 .. 100) { Thread.sleep(100.msecs); if (doQuit) { break; } } writeln("Done waiting..."); } Ali |
December 02, 2017 Re: scope(exit) and Ctrl-C | ||||
---|---|---|---|---|
| ||||
Posted in reply to Wanderer | On Saturday, 2 December 2017 at 00:41:19 UTC, Wanderer wrote:
> I wonder why `scope(exit)` code is not executed when the program is terminated with Ctrl-C.
It depends on what your operating system is. On win32, I believe it does run. On Linux (and I think Mac) you need to set a signal handler to catch the ctrl c.
But this is intentional - there is no generic, reliable, cross-platform way of handling it natively. So you need to know the system and code it yourself. Not super hard but does take a bit of effort in your code.
|
December 02, 2017 Re: scope(exit) and Ctrl-C | ||||
---|---|---|---|---|
| ||||
Posted in reply to Wanderer | On Saturday, 2 December 2017 at 00:41:19 UTC, Wanderer wrote: > I wonder why `scope(exit)` code is not executed when the program is terminated with Ctrl-C. Which OS? > For example: > > ``` > import std.stdio; > import core.thread; > > void main() > { > scope (exit) > { > writeln("Cleanup"); > } > writeln("Waiting..."); > Thread.sleep(10.seconds); > writeln("Done waiting..."); > } > ``` > > If I wait 10 seconds, I get "Cleanup" output. > But if I use Ctrl-C to terminate the program before 10 seconds elapse, there's no "Cleanup" output. > > Is it intentional? It's normal. Ctrl-C (under UNIX, Linux) sends SIGINT to the process. There are two options: 1. Handle this interrupt in your programm (But then: What about Ctrl-\ and SIQUIT)? 2. Prevent the generation of SIGINT: Put the terminal into raw mode [1] > Is there any method to cleanup on Ctrl-C? Yes. Take option 1. or option 2. [1] https://linux.die.net/man/3/cbreak "The raw and noraw routines place the terminal into or out of raw mode. Raw mode is similar to cbreak mode, in that characters typed are immediately passed through to the user program. The differences are that in raw mode, the interrupt, quit, suspend, and flow control characters are all passed through uninterpreted, instead of generating a signal. The behavior of the BREAK key depends on other bits in the tty driver that are not set by curses." |
December 02, 2017 Re: scope(exit) and Ctrl-C | ||||
---|---|---|---|---|
| ||||
Posted in reply to Wanderer | On Saturday, 2 December 2017 at 00:41:19 UTC, Wanderer wrote: > Is there any method to cleanup on Ctrl-C? // ---------------------------------- import std.stdio; import core.thread; extern(C) void signal(int sig, void function(int)); extern(C) void exit(int exit_val); extern(C) void handle(int sig) { writeln("Control-C was pressed..aborting program....goodbye..."); // do more stuff? exit(-1); } void main() { enum SIGINT = 2; signal(SIGINT,&handle); scope (exit){ writeln("Cleanup"); } writeln("Waiting..."); Thread.sleep(10.seconds); writeln("Done waiting..."); } // --------------------------------- |
December 02, 2017 Re: scope(exit) and Ctrl-C | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On Saturday, 2 December 2017 at 01:26:14 UTC, Adam D. Ruppe wrote:
> On Saturday, 2 December 2017 at 00:41:19 UTC, Wanderer wrote:
>> I wonder why `scope(exit)` code is not executed when the program is terminated with Ctrl-C.
>
> It depends on what your operating system is. On win32, I believe it does run. On Linux (and I think Mac) you need to set a signal handler to catch the ctrl c.
>
> But this is intentional - there is no generic, reliable, cross-platform way of handling it natively. So you need to know the system and code it yourself. Not super hard but does take a bit of effort in your code.
On Windows 10 it does not run.
Thanks for the info, I dig around and truly there's no "general" way to do this.
|
December 02, 2017 Re: scope(exit) and Ctrl-C | ||||
---|---|---|---|---|
| ||||
Posted in reply to codephantom | On Saturday, 2 December 2017 at 03:52:19 UTC, codephantom wrote:
> On Saturday, 2 December 2017 at 00:41:19 UTC, Wanderer wrote:
>> Is there any method to cleanup on Ctrl-C?
>
> // ----------------------------------
> import std.stdio;
> import core.thread;
>
> extern(C) void signal(int sig, void function(int));
> extern(C) void exit(int exit_val);
>
> extern(C) void handle(int sig)
> {
> writeln("Control-C was pressed..aborting program....goodbye...");
> // do more stuff?
> exit(-1);
> }
>
> void main()
> {
> enum SIGINT = 2;
> signal(SIGINT,&handle);
>
> scope (exit){ writeln("Cleanup"); }
>
> writeln("Waiting...");
> Thread.sleep(10.seconds);
> writeln("Done waiting...");
> }
> // ---------------------------------
Thanks! This works. But it seems a little bit suspicions that D's type for handler function has `nothrow` `@nogc` and `@system`. I wonder why is that?
|
December 02, 2017 Re: scope(exit) and Ctrl-C | ||||
---|---|---|---|---|
| ||||
Posted in reply to Wanderer | On Saturday, 2 December 2017 at 04:28:57 UTC, Wanderer wrote:
> Thanks! This works. But it seems a little bit suspicions that D's type for handler function has `nothrow` `@nogc` and `@system`. I wonder why is that?
Signal handlers are ridiculously limited in what they are allowed to do. Really, you should just set a global variable from the handler and check it on the outside.
|
December 01, 2017 Re: scope(exit) and Ctrl-C | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On Sat, Dec 02, 2017 at 04:38:29AM +0000, Adam D. Ruppe via Digitalmars-d-learn wrote: > On Saturday, 2 December 2017 at 04:28:57 UTC, Wanderer wrote: > > Thanks! This works. But it seems a little bit suspicions that D's type for handler function has `nothrow` `@nogc` and `@system`. I wonder why is that? > > Signal handlers are ridiculously limited in what they are allowed to do. Really, you should just set a global variable from the handler and check it on the outside. Signal handlers can potentially be invoked while inside a non-reentrant libc or OS function, so trying to do anything that (indirectly or otherwise) calls that function will cause havoc to your program. Also, while the signal handler is running, some (all?) further signals may be blocked, meaning that your program might miss an important signal if your sig handler takes too long to run. Furthermore, the signal may have happened in the middle of your own code, so race conditions may apply (e.g. if you're modifying global data in both). So yeah, in general the signal handler should do as little as possible, usually set a flag or something to indicate that a signal has been received, and let the main program do the actual work of responding to the signal, outside of signal handler context. A neat trick I learned years ago is the so-called self-pipe trick, which is especially useful when your main program has a select/epoll loop. Basically, you use the Posix pipe() function to create a read/write pipe, and add the read end to your select/epoll fd set. Then in the signal handler you write to the write end of the pipe (e.g., write the signal number) and return. (The write() function is one of the few OS functions that's safe to call inside a signal handler.) Now you can do the "real" signal processing in your select/epoll loop when the read end of the pipe indicates that it's ready for reads. This lets you avoid the above problems with restrictions in signal handler context, and also integrates nicely into your event loop, so that you can be sure that you're done with whatever it is your other event loops are doing when you actually get around to processing the signal. T -- There's light at the end of the tunnel. It's the oncoming train. |
December 02, 2017 Re: scope(exit) and Ctrl-C | ||||
---|---|---|---|---|
| ||||
Posted in reply to Wanderer | On Saturday, 2 December 2017 at 04:28:57 UTC, Wanderer wrote:
> Thanks! This works. But it seems a little bit suspicions that D's type for handler function has `nothrow` `@nogc` and `@system`. I wonder why is that?
During execution of that handler, it make sense to prohibit the allocation of any GC memory, and prohibit the throwing of any exceptions. I presume that's why they're there (??)
@system is default
(btw, change -1 to 1 in the exit function, i.e. -1 is not valid, 0..255 is valid.. but some of those you should avoid using).
|
Copyright © 1999-2021 by the D Language Foundation