Change in vdsm[master]: signals: Better handle signals to non-main threads

dkuznets at redhat.com dkuznets at redhat.com
Mon Jun 30 08:34:06 UTC 2014


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 <dkuznets at redhat.com>
---
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 <dkuznets at redhat.com>


More information about the vdsm-patches mailing list