* [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