Dima Kuznetsov has uploaded a new change for review. Change subject: signals: Better handle signals to non-main threads ......................................................................
signals: Better handle signals to non-main threads There is an issue with using signal.pause() and threads in python. The signal might arrive to a non-main thread, and not get processed (because only the main thread handles signals) until the main thread receives its own signal. The issue is documented and tracked here: https://bugzilla.redhat.com/show_bug.cgi?id=1114434 Change-Id: I5dbcd00cec22ef12f2b6253b016dcbd0aa889583 Signed-off-by: Dima Kuznetsov <[email protected]> --- M lib/vdsm/utils.py M vdsm/supervdsmServer M vdsm/vdsm 3 files changed, 54 insertions(+), 2 deletions(-) git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/92/29392/1 diff --git a/lib/vdsm/utils.py b/lib/vdsm/utils.py index 2ba5762..35c8387 100644 --- a/lib/vdsm/utils.py +++ b/lib/vdsm/utils.py @@ -1141,3 +1141,55 @@ def prependDefer(self, func, *args, **kwargs): self._finally.insert(0, (func, args, kwargs)) + + +_signalPoller = None + + +def _getSignalPoller(): + ''' + This function creates a select.poll object that can be used in the same + manner as signal.pause(). The poll object returns each time a signal was + received by the process. + + This function has to be called from the main thread. + ''' + if _signalPoller is None: + (fd_r, fd_w) = os.pipe() + + # The write end is going to be written to from a c-level signal + # handler, so it is a good idea to make sure it does not block. + flags = fcntl.fcntl(fd_w, fcntl.F_GETFL, 0) + flags |= os.O_NONBLOCK + fcntl.fcntl(fd_w, fcntl.F_SETFL, flags) + + # This call must be done from the main thread. + signal.set_wakeup_fd(fd_w) + + poller = select.poll() + poller.register(fd_r, select.POLLIN) + + global _signalPoller + _signalPoller = poller + + return _signalPoller + + +def waitForSignal(): + ''' + This function acts like signal.pause(), it returns after a signal was + received and handled. Unlike signal.pause(), it will wake up even if other + thread caught the signal while this function was called. + ''' + poller = _getSignalPoller() + try: + events = poller.poll() + for (fd, flags) in events: + if flags & select.POLLIN: + os.read(fd, 1) + except select.error as e: + # Signal was received in this thread while poll() was active + if (e.args[0] == errno.EINTR): + return + logging.error('Received error while waiting for signal', + exc_info=True) diff --git a/vdsm/supervdsmServer b/vdsm/supervdsmServer index a63caa2..0b0a13f 100755 --- a/vdsm/supervdsmServer +++ b/vdsm/supervdsmServer @@ -446,7 +446,7 @@ sourceroutethread.start() while _running: - signal.pause() + utils.waitForSignal() log.debug("Terminated normally") finally: diff --git a/vdsm/vdsm b/vdsm/vdsm index cbc16ff..9752320 100755 --- a/vdsm/vdsm +++ b/vdsm/vdsm @@ -83,7 +83,7 @@ cif.start() try: while running[0]: - signal.pause() + utils.waitForSignal() profile.stop() finally: -- To view, visit http://gerrit.ovirt.org/29392 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I5dbcd00cec22ef12f2b6253b016dcbd0aa889583 Gerrit-PatchSet: 1 Gerrit-Project: vdsm Gerrit-Branch: master Gerrit-Owner: Dima Kuznetsov <[email protected]> _______________________________________________ vdsm-patches mailing list [email protected] https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches
