Bug #335777 - Add a 40 second timeout in ebuild-ipc.py, so that if an
authorZac Medico <zmedico@gentoo.org>
Fri, 3 Sep 2010 21:17:12 +0000 (14:17 -0700)
committerZac Medico <zmedico@gentoo.org>
Fri, 3 Sep 2010 21:17:12 +0000 (14:17 -0700)
orphan is left for any reason then it will exit with an error message
instead of hanging indefinitely.

bin/ebuild-ipc.py
pym/portage/exception.py

index 52fb08226448dde211750ba43b2e01e4d6d502a4..b4a1f7767b44a5e79bf718cb1043fce72a36ea69 100755 (executable)
@@ -5,11 +5,13 @@
 # This is a helper which ebuild processes can use
 # to communicate with portage's main python process.
 
+import logging
 import os
 import pickle
 import select
 import signal
 import sys
+import time
 
 def debug_signal(signum, frame):
        import pdb
@@ -30,6 +32,8 @@ import portage
 
 class EbuildIpc(object):
 
+       _COMMUNICATE_TIMEOUT_SECONDS = 40
+
        def __init__(self):
                self.fifo_dir = os.environ['PORTAGE_BUILDDIR']
                self.ipc_in_fifo = os.path.join(self.fifo_dir, '.ipc_in')
@@ -37,13 +41,28 @@ class EbuildIpc(object):
                self.ipc_lock_file = os.path.join(self.fifo_dir, '.ipc_lock')
 
        def communicate(self, args):
+
                # Make locks quiet since unintended locking messages displayed on
                # stdout could corrupt the intended output of this program.
                portage.locks._quiet = True
                lock_obj = portage.locks.lockfile(self.ipc_lock_file, unlinkfile=True)
+               start_time = time.time()
+
                try:
-                       return self._communicate(args)
+                       signal.signal(signal.SIGALRM, portage.exception.AlarmSignal.signal_handler)
+                       signal.alarm(self._COMMUNICATE_TIMEOUT_SECONDS)
+                       returncode = self._communicate(args)
+                       signal.alarm(0)
+                       return returncode
+               except portage.exception.AlarmSignal:
+                       time_elapsed = time.time() - start_time
+                       portage.util.writemsg_level(
+                               ('ebuild-ipc timed out after %d seconds\n') % \
+                               (time_elapsed,),
+                               level=logging.ERROR, noiselevel=-1)
+                       return 1
                finally:
+                       signal.alarm(0)
                        portage.locks.unlockfile(lock_obj)
 
        def _communicate(self, args):
index 9564af98a1298853ac01dd077e8fd3c4dd8b2391..b0f9ad8eb13aed31566685a3eacca01c4d3e2294 100644 (file)
@@ -80,6 +80,20 @@ class TryAgain(PortageException):
        from errno import EAGAIN as errno
        """Try again"""
 
+class TimeoutException(PortageException):
+       from errno import ETIME as errno
+
+class AlarmSignal(TimeoutException):
+       def __init__(self, value, signum=None, frame=None):
+               TimeoutException.__init__(self, value)
+               self.signum = signum
+               self.frame = frame
+
+       @classmethod
+       def signal_handler(cls, signum, frame):
+               raise AlarmSignal("alarm signal",
+                       signum=signum, frame=frame)
+
 class ReadOnlyFileSystem(PortageException):
        """Read-only file system"""