digitalmars.D.learn - scope(exit) and Ctrl-C
- Wanderer (22/22) Dec 01 2017 I wonder why `scope(exit)` code is not executed when the program
- =?UTF-8?Q?Ali_=c3=87ehreli?= (30/57) Dec 01 2017 Combined your code with this solution:
- Adam D. Ruppe (8/10) Dec 01 2017 It depends on what your operating system is. On win32, I believe
- Wanderer (4/14) Dec 01 2017 On Windows 10 it does not run.
- Jacob Carlborg (7/10) Dec 02 2017 Since the "scope" block is not executed, does that also mean that the
- kdevel (19/41) Dec 01 2017 It's normal. Ctrl-C (under UNIX, Linux) sends SIGINT to the
- codephantom (23/24) Dec 01 2017 // ----------------------------------
- Wanderer (4/28) Dec 01 2017 Thanks! This works. But it seems a little bit suspicions that D's
- Adam D. Ruppe (4/7) Dec 01 2017 Signal handlers are ridiculously limited in what they are allowed
- H. S. Teoh (29/37) Dec 01 2017 Signal handlers can potentially be invoked while inside a non-reentrant
- Patrick Schluter (3/17) Dec 02 2017 On Linux you can use signalfd() for that, but nice trick if you
- H. S. Teoh (7/26) Dec 02 2017 Ha! I've been using Linux for decades now and this is the first time I'm
- Adam D. Ruppe (3/6) Dec 02 2017 In the same vein, make sure you read about timerfd and eventfd
- codephantom (7/10) Dec 01 2017 During execution of that handler, it make sense to prohibit the
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?
Dec 01 2017
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
Dec 01 2017
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.
Dec 01 2017
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:On Windows 10 it does not run. Thanks for the info, I dig around and truly there's no "general" way to do this.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.
Dec 01 2017
On 2017-12-02 02:26, Adam D. Ruppe wrote: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.Since the "scope" block is not executed, does that also mean that the runtime is not shutdown? If that's the case, does it make sense to have a generic signal handler in druntime that aborts the application and shuts down the druntime in a graceful way? -- /Jacob Carlborg
Dec 02 2017
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."
Dec 01 2017
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..."); } // ---------------------------------
Dec 01 2017
On Saturday, 2 December 2017 at 03:52:19 UTC, codephantom wrote:On Saturday, 2 December 2017 at 00:41:19 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?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..."); } // ---------------------------------
Dec 01 2017
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.
Dec 01 2017
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: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.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.
Dec 01 2017
On Saturday, 2 December 2017 at 04:49:26 UTC, H. S. Teoh wrote:On Sat, Dec 02, 2017 at 04:38:29AM +0000, Adam D. Ruppe via Digitalmars-d-learn wrote:On Linux you can use signalfd() for that, but nice trick if you want Posix portability.[...]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). [...]
Dec 02 2017
On Sat, Dec 02, 2017 at 11:32:17AM +0000, Patrick Schluter via Digitalmars-d-learn wrote:On Saturday, 2 December 2017 at 04:49:26 UTC, H. S. Teoh wrote:Ha! I've been using Linux for decades now and this is the first time I'm aware of this function. Should simplify my code when I'm not planning to be Posix-portable. Thanks! T -- Heads I win, tails you lose.On Sat, Dec 02, 2017 at 04:38:29AM +0000, Adam D. Ruppe via Digitalmars-d-learn wrote:On Linux you can use signalfd() for that, but nice trick if you want Posix portability.[...]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). [...]
Dec 02 2017
On Sunday, 3 December 2017 at 02:56:38 UTC, H. S. Teoh wrote:Ha! I've been using Linux for decades now and this is the first time I'm aware of this function. Should simplify my code when I'm not planning to be Posix-portable. Thanks!In the same vein, make sure you read about timerfd and eventfd too. They rok.
Dec 02 2017
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).
Dec 01 2017