EbuildIpcDaemon: handle POLLHUP, bug #401919
diff --git a/pym/_emerge/EbuildIpcDaemon.py b/pym/_emerge/EbuildIpcDaemon.py
index 5795bfb..8414d20 100644
--- a/pym/_emerge/EbuildIpcDaemon.py
+++ b/pym/_emerge/EbuildIpcDaemon.py
@@ -5,7 +5,9 @@
 import logging
 import pickle
 from portage import os
+from portage.exception import TryAgain
 from portage.localization import _
+from portage.locks import lockfile, unlockfile
 from portage.util import writemsg_level
 from _emerge.FifoIpcDaemon import FifoIpcDaemon
 
@@ -83,6 +85,28 @@
 				if reply_hook is not None:
 					reply_hook()
 
+		elif event & self.scheduler.IO_HUP:
+			# This can be triggered due to a race condition which happens when
+			# the previous _reopen_input() call occurs before the writer has
+			# closed the pipe (see bug #401919). It's not safe to re-open
+			# without a lock here, since it's possible that another writer will
+			# write something to the pipe just before we close it, and in that
+			# case the write will be lost. Therefore, try for a non-blocking
+			# lock, and only re-open the pipe if the lock is acquired.
+			lock_filename = os.path.join(
+				os.path.dirname(self.input_fifo), '.ipc_lock')
+			try:
+				lock_obj = lockfile(lock_filename, unlinkfile=True,
+					flags=os.O_NONBLOCK)
+			except TryAgain:
+				# We'll try again when another IO_HUP event arrives.
+				pass
+			else:
+				try:
+					self._reopen_input()
+				finally:
+					unlockfile(lock_obj)
+
 		return True
 
 	def _send_reply(self, reply):