public inbox for gentoo-portage-dev@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-portage-dev] [PATCH] bin/ebuild-ipc.py: nonblocking fifo write
@ 2014-10-09 18:50 Zac Medico
  0 siblings, 0 replies; only message in thread
From: Zac Medico @ 2014-10-09 18:50 UTC (permalink / raw
  To: gentoo-portage-dev

Use nonblocking write instead of a fork for writing to the fifo.
This has the advantage of avoiding a possible python futex deadlock
following fork as reported in bug #524328.

X-Gentoo-Bug: 524328
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=524328
---
 bin/ebuild-ipc.py | 64 ++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 56 insertions(+), 8 deletions(-)

diff --git a/bin/ebuild-ipc.py b/bin/ebuild-ipc.py
index 3e6d90c..b47ee23 100755
--- a/bin/ebuild-ipc.py
+++ b/bin/ebuild-ipc.py
@@ -5,6 +5,7 @@
 # This is a helper which ebuild processes can use
 # to communicate with portage's main python process.
 
+import errno
 import logging
 import os
 import pickle
@@ -44,19 +45,66 @@ import portage
 portage._internal_caller = True
 portage._disable_legacy_globals()
 
-from portage.util._async.ForkProcess import ForkProcess
 from portage.util._eventloop.global_event_loop import global_event_loop
+from _emerge.AbstractPollTask import AbstractPollTask
 from _emerge.PipeReader import PipeReader
 
-class FifoWriter(ForkProcess):
+RETURNCODE_WRITE_FAILED = 2
 
-	__slots__ = ('buf', 'fifo',)
+class FifoWriter(AbstractPollTask):
 
-	def _run(self):
-		# Atomically write the whole buffer into the fifo.
-		with open(self.fifo, 'wb', 0) as f:
-			f.write(self.buf)
-		return os.EX_OK
+	__slots__ = ('buf', 'fifo', '_fd', '_reg_id',)
+
+	def _start(self):
+		try:
+			self._fd = os.open(self.fifo, os.O_WRONLY|os.O_NONBLOCK)
+		except OSError as e:
+			if e.errno == errno.ENXIO:
+				# This happens if the daemon has been killed.
+				self.returncode = RETURNCODE_WRITE_FAILED
+				self._unregister()
+				self._async_wait()
+				return
+			else:
+				raise
+		self._reg_id = self.scheduler.io_add_watch(
+			self._fd,
+			self.scheduler.IO_OUT | self.scheduler.IO_HUP | \
+			self._exceptional_events, self._output_handler)
+		self._registered = True
+
+	def _output_handler(self, fd, event):
+		if event & self.scheduler.IO_OUT:
+			# The whole buf should be able to fit in the fifo with
+			# a single write call, so there's no valid reason for
+			# os.write to raise EAGAIN here.
+			buf = self.buf
+			while buf:
+				buf = buf[os.write(fd, buf):]
+			self.returncode = os.EX_OK
+			self._unregister()
+			self.wait()
+			return False
+		else:
+			self._unregister_if_appropriate(event)
+			if not self._registered:
+				self.returncode = RETURNCODE_WRITE_FAILED
+				self.wait()
+				return False
+		return True
+
+	def _cancel(self):
+		self.returncode = self._cancelled_returncode
+		self._unregister()
+
+	def _unregister(self):
+		self._registered = False
+		if self._reg_id is not None:
+			self.scheduler.source_remove(self._reg_id)
+			self._reg_id = None
+		if self._fd is not None:
+			os.close(self._fd)
+			self._fd = None
 
 class EbuildIpc(object):
 
-- 
1.8.5.5


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2014-10-09 18:50 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-10-09 18:50 [gentoo-portage-dev] [PATCH] bin/ebuild-ipc.py: nonblocking fifo write Zac Medico

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox