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