digitalmars.D - Linux signal handling - notifying a condition variable
- Jim King (20/20) Mar 15 2018 I am trying to add graceful shutdown support to a test harness.
- Adam D. Ruppe (8/10) Mar 15 2018 Looks like notify actually can throw an exception... the way I
- Jim King (11/21) Mar 15 2018 Thanks for that suggestion; I was in the middle of implementing
- Adam D. Ruppe (17/23) Mar 15 2018 well, what's your thread doing? In the case I used this pattern,
- Adam D. Ruppe (5/5) Mar 15 2018 Alternatively btw you can use the pthreads C functions
- Dmitry Olshansky (8/28) Mar 15 2018 Another option if you are on linux is to use eventfd. Then you
- Patrick Schluter (4/15) Mar 15 2018 There's also signalfd which is quite practical to change signals
- Dmitry Olshansky (4/22) Mar 15 2018 Indeed, handling SIGINT termination in an event loop is easiest.
- Patrick Schluter (4/11) Mar 15 2018 signalfd [1] is a good solution on Linux.
- James E. King III (7/20) Mar 16 2018 Thank you, this looks like the best solution. On further reading
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
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
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: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.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
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
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
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: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.On Thursday, 15 March 2018 at 16:51:59 UTC, Jim King wrote: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.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...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
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:There's also signalfd which is quite practical to change signals in select/poll/epoll events.[...]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.
Mar 15 2018
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:Indeed, handling SIGINT termination in an event loop is easiest. Just need to mask the signal out, somewhat counter-intuitively.On Thursday, 15 March 2018 at 17:30:50 UTC, Jim King wrote:There's also signalfd which is quite practical to change signals in select/poll/epoll events.[...]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.
Mar 15 2018
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
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: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.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 16 2018