From 2f3235abef72d61cdcdf549a08e645933698a4ff Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Thu, 17 Mar 2011 14:39:53 -0700 Subject: EbuildIpcDaemon: use non-blocking write This prevents the Scheduler from hanging if the client is killed before we can send the reply, as reported by David James: http://codereview.chromium.org/6713003 This commit depends on ebuild-ipc (the client) opening the other side of this fifo before it sends its request, which has already been added in commit eff879ff0ce7dcc1ce68d5f16de1ec73051f8c18. --- pym/_emerge/EbuildIpcDaemon.py | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'pym/_emerge') diff --git a/pym/_emerge/EbuildIpcDaemon.py b/pym/_emerge/EbuildIpcDaemon.py index efcda9316..5dabe34b3 100644 --- a/pym/_emerge/EbuildIpcDaemon.py +++ b/pym/_emerge/EbuildIpcDaemon.py @@ -1,9 +1,12 @@ -# Copyright 2010 Gentoo Foundation +# Copyright 2010-2011 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 import errno +import logging import pickle from portage import os +from portage.localization import _ +from portage.util import writemsg_level from _emerge.FifoIpcDaemon import FifoIpcDaemon from _emerge.PollConstants import PollConstants @@ -83,7 +86,23 @@ class EbuildIpcDaemon(FifoIpcDaemon): def _send_reply(self, reply): # File streams are in unbuffered mode since we do atomic - # read and write of whole pickles. - output_file = open(self.output_fifo, 'wb', 0) - output_file.write(pickle.dumps(reply)) - output_file.close() + # read and write of whole pickles. Use non-blocking mode so + # we don't hang if the client is killed before we can send + # the reply. We rely on the client opening the other side + # of this fifo before it sends its request, since otherwise + # we'd have a race condition with this open call raising + # ENXIO if the client hasn't opened the fifo yet. + try: + output_fd = os.open(self.output_fifo, + os.O_WRONLY | os.O_NONBLOCK) + try: + os.write(output_fd, pickle.dumps(reply)) + finally: + os.close(output_fd) + except OSError as e: + # This probably means that the client has been killed, + # which causes open to fail with ENXIO. + writemsg_level( + "!!! EbuildIpcDaemon %s: %s\n" % \ + (_('failed to send reply'), e), + level=logging.ERROR, noiselevel=-1) -- cgit v1.2.3-1-g7c22