www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Linux signal handling - notifying a condition variable

reply Jim King <jking apache.org> writes:
I am trying to add graceful shutdown support to a test harness.  
In the test harness, a server class consumes a thread to accept 
connections and service them.  In order to stop the server, it 
has to be interrupted.  This interruption mechanism is based on 
core.sync.condition.

I want to add a signal handler so that if SIGINT is received, the 
server is interrupted and stops gracefully.

In going through the signal documentation it looks like the 
signal handler must be a "nothrow  nogc" variety.  Makes sense - 
there's very little you can do in a signal handler.

I tried carrying this down through to a class that ends up 
calling core.sync.condition.Condition.notifyAll(), however that 
method is not declared as "nothrow  nogc", therefore I assume 
that means I cannot use core.sync.condition.Condition from a 
signal handler.  It would seem to me that a notify mechanism in a 
condition variable implementation perhaps could throw, but I 
wouldn't expect it to do any garbage collection.

How is one supposed to intercept SIGINT and notify a condition 
variable?  Is this a deficiency in the standard library?

- Jim
Mar 15 2018
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 15 March 2018 at 16:51:59 UTC, Jim King wrote:
 In going through the signal documentation it looks like the 
 signal handler must be a "nothrow  nogc" variety.
Looks like notify actually can throw an exception... the way I usually do signal handlers is just set a global variable: __global bool interrupted = false; void sigint_handler() { interrupted = true; } then in the main loop check that periodically... idk if that'd work well withthe condition variable though, I have never actually used that...
Mar 15 2018
parent reply Jim King <jking apache.org> writes:
On Thursday, 15 March 2018 at 17:12:24 UTC, Adam D. Ruppe wrote:
 On Thursday, 15 March 2018 at 16:51:59 UTC, Jim King wrote:
 In going through the signal documentation it looks like the 
 signal handler must be a "nothrow  nogc" variety.
Looks like notify actually can throw an exception... the way I usually do signal handlers is just set a global variable: __global bool interrupted = false; void sigint_handler() { interrupted = true; } then in the main loop check that periodically... idk if that'd work well withthe condition variable though, I have never actually used that...
Thanks for that suggestion; I was in the middle of implementing that. The problem with that is that it requires a busy loop to detect it. It is far better to block on condition variables than to have a busy loop. I agree condition variable notify could throw if the condition variable is not in the correct state. I think it would be possible for someone to catch this and make sure it does not throw, but the " nogc" part of it seems a bit more involved. Condition variables (and mutexes) are supposed to be usable from a signal handler.
Mar 15 2018
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 15 March 2018 at 17:30:50 UTC, Jim King wrote:
 The problem with that is that it requires a busy loop to detect 
 it.
well, what's your thread doing? In the case I used this pattern, it was blocking on a call to select() anyway, so when it returned with EINTR, that was a good opportunity to check the flag before waiting for the next event. But of course that isn't always going to be the case...
 I think it would be possible for someone to catch this and make 
 sure it does not throw, but the " nogc" part of it seems a bit 
 more involved.  Condition variables (and mutexes) are supposed 
 to be usable from a signal handler.
Yeah, I think this is just an oversight. See, the throw on error previously didn't work well with nogc (you could do it, but the catcher would have to free the exception object which most code wouldn't do) and the newest dmd version changes that. But the library developer would still have to verify it and add the nogc annotation themselves. Of course, it is still throwing, but you can catch in the signal handler to make it nothrow at that point. So I'd say probably file a bug and/or open a PR yourself to add the nogc annotation to those methods and it'll probably work next release.
Mar 15 2018
parent Adam D. Ruppe <destructionator gmail.com> writes:
Alternatively btw you can use the pthreads C functions

    import core.sys.posix.pthread;

which shuld also be nogc right now. The condition class wraps 
those on Linux fairly thinly; using the C functions should be 
little more trouble.
Mar 15 2018
prev sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On Thursday, 15 March 2018 at 17:30:50 UTC, Jim King wrote:
 On Thursday, 15 March 2018 at 17:12:24 UTC, Adam D. Ruppe wrote:
 On Thursday, 15 March 2018 at 16:51:59 UTC, Jim King wrote:
 In going through the signal documentation it looks like the 
 signal handler must be a "nothrow  nogc" variety.
Looks like notify actually can throw an exception... the way I usually do signal handlers is just set a global variable: __global bool interrupted = false; void sigint_handler() { interrupted = true; } then in the main loop check that periodically... idk if that'd work well withthe condition variable though, I have never actually used that...
Thanks for that suggestion; I was in the middle of implementing that. The problem with that is that it requires a busy loop to detect it. It is far better to block on condition variables than to have a busy loop.
Another option if you are on linux is to use eventfd. Then you can trigger it with simple write on eventfd descriptor. As far as waiting goes it’s either read on descriptor or poll/select. f it seems a bit more involved.
 Condition variables (and mutexes) are supposed to be usable 
 from a signal handler.
However I’d be super careful about mutexes with signal handlers. Really self-pipe trick or eventfd seems way more signal safe.
Mar 15 2018
parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Thursday, 15 March 2018 at 19:23:26 UTC, Dmitry Olshansky 
wrote:
 On Thursday, 15 March 2018 at 17:30:50 UTC, Jim King wrote:
 [...]
Another option if you are on linux is to use eventfd. Then you can trigger it with simple write on eventfd descriptor. As far as waiting goes it’s either read on descriptor or poll/select. f it seems a bit more involved.
 [...]
However I’d be super careful about mutexes with signal handlers. Really self-pipe trick or eventfd seems way more signal safe.
There's also signalfd which is quite practical to change signals in select/poll/epoll events.
Mar 15 2018
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On Thursday, 15 March 2018 at 19:36:44 UTC, Patrick Schluter 
wrote:
 On Thursday, 15 March 2018 at 19:23:26 UTC, Dmitry Olshansky 
 wrote:
 On Thursday, 15 March 2018 at 17:30:50 UTC, Jim King wrote:
 [...]
Another option if you are on linux is to use eventfd. Then you can trigger it with simple write on eventfd descriptor. As far as waiting goes it’s either read on descriptor or poll/select. f it seems a bit more involved.
 [...]
However I’d be super careful about mutexes with signal handlers. Really self-pipe trick or eventfd seems way more signal safe.
There's also signalfd which is quite practical to change signals in select/poll/epoll events.
Indeed, handling SIGINT termination in an event loop is easiest. Just need to mask the signal out, somewhat counter-intuitively.
Mar 15 2018
prev sibling parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Thursday, 15 March 2018 at 16:51:59 UTC, Jim King wrote:
 I am trying to add graceful shutdown support to a test harness.
  In the test harness, a server class consumes a thread to 
 accept connections and service them.  In order to stop the 
 server, it has to be interrupted.  This interruption mechanism 
 is based on core.sync.condition.

 I want to add a signal handler so that if SIGINT is received, 
 the server is interrupted and stops gracefully.
signalfd [1] is a good solution on Linux. core.sys.linux.sys.signalfd; [1]: http://man7.org/linux/man-pages/man2/signalfd.2.html
Mar 15 2018
parent James E. King III <jking apache.org> writes:
On Thursday, 15 March 2018 at 19:43:09 UTC, Patrick Schluter 
wrote:
 On Thursday, 15 March 2018 at 16:51:59 UTC, Jim King wrote:
 I am trying to add graceful shutdown support to a test harness.
  In the test harness, a server class consumes a thread to 
 accept connections and service them.  In order to stop the 
 server, it has to be interrupted.  This interruption mechanism 
 is based on core.sync.condition.

 I want to add a signal handler so that if SIGINT is received, 
 the server is interrupted and stops gracefully.
signalfd [1] is a good solution on Linux. core.sys.linux.sys.signalfd; [1]: http://man7.org/linux/man-pages/man2/signalfd.2.html
Thank you, this looks like the best solution. On further reading I found that it is not safe to use condition variables from signal handlers, per the documentation in https://linux.die.net/man/3/pthread_cond_signal.
Mar 16 2018