From: Zac Medico Date: Fri, 13 Aug 2010 06:11:53 +0000 (-0700) Subject: Refactor interaction between EbuildIpcDaemon and ExitCommand. X-Git-Tag: v2.2_rc68~249 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=28744162a6ed820a632efc77f44a3e1074b9af72;p=portage.git Refactor interaction between EbuildIpcDaemon and ExitCommand. --- diff --git a/pym/_emerge/EbuildIpcDaemon.py b/pym/_emerge/EbuildIpcDaemon.py index 2f4d8933c..0715dc1f0 100644 --- a/pym/_emerge/EbuildIpcDaemon.py +++ b/pym/_emerge/EbuildIpcDaemon.py @@ -2,6 +2,7 @@ # Distributed under the terms of the GNU General Public License v2 import array +import errno import pickle from portage import os from _emerge.FifoIpcDaemon import FifoIpcDaemon @@ -40,7 +41,26 @@ class EbuildIpcDaemon(FifoIpcDaemon): obj = pickle.loads(buf.tostring()) cmd_key = obj[0] cmd_handler = self.commands[cmd_key] - cmd_handler(obj, self._send_reply) + reply = cmd_handler(obj) + try: + self._send_reply(reply) + except OSError as e: + if e.errno == errno.ENXIO: + # This happens if the client side has been killed. + pass + else: + raise + + # Allow the command to execute hooks after its reply + # has been sent. This hook is used by the 'exit' + # command to kill the ebuild process. For some + # reason, the ebuild-ipc helper hangs up the + # ebuild process if it is waiting for a reply + # when we try to kill the ebuild process. + reply_hook = getattr(cmd_handler, + 'reply_hook', None) + if reply_hook is not None: + reply_hook() self._unregister_if_appropriate(event) return self._registered diff --git a/pym/portage/tests/ebuild/test_ipc_daemon.py b/pym/portage/tests/ebuild/test_ipc_daemon.py index bd27a38d1..48412a1c3 100644 --- a/pym/portage/tests/ebuild/test_ipc_daemon.py +++ b/pym/portage/tests/ebuild/test_ipc_daemon.py @@ -15,24 +15,22 @@ from _emerge.TaskScheduler import TaskScheduler class ExitCommand(object): def __init__(self): - self.callback = None + self.reply_hook = None self.exitcode = None - def __call__(self, argv, send_reply): - duplicate = False + def __call__(self, argv): + if self.exitcode is not None: # Ignore all but the first call, since if die is called # then we certainly want to honor that exitcode, even # the ebuild process manages to send a second exit # command. - duplicate = True + self.reply_hook = None else: self.exitcode = int(argv[1]) # (stdout, stderr, returncode) - send_reply(('', '', 0)) - if not duplicate and self.callback is not None: - self.callback() + return ('', '', 0) class IpcDaemonTestCase(TestCase): @@ -62,7 +60,7 @@ class IpcDaemonTestCase(TestCase): def exit_command_callback(): daemon.cancel() proc.cancel() - exit_command.callback = exit_command_callback + exit_command.reply_hook = exit_command_callback task_scheduler.add(daemon) task_scheduler.add(proc) task_scheduler.run()