Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Subject: [gentoo-portage-dev] [PATCH] bin/ebuild-ipc.py: use threading if available
Date: Wed, 08 Oct 2014 23:26:44
Message-Id: 5435C82F.1020902@gentoo.org
1 If threading is available then use a thread instead of a fork for
2 writing to the fifo. This has the advantage of avoiding a possible
3 python futex deadlock following fork as reported in bug #524328.
4
5 X-Gentoo-Bug: 524328
6 X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=524328
7 ---
8 bin/ebuild-ipc.py | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
9 1 file changed, 46 insertions(+), 1 deletion(-)
10
11 diff --git a/bin/ebuild-ipc.py b/bin/ebuild-ipc.py
12 index 3e6d90c..0aaec72 100755
13 --- a/bin/ebuild-ipc.py
14 +++ b/bin/ebuild-ipc.py
15 @@ -5,6 +5,7 @@
16 # This is a helper which ebuild processes can use
17 # to communicate with portage's main python process.
18
19 +import dummy_threading
20 import logging
21 import os
22 import pickle
23 @@ -13,6 +14,11 @@ import signal
24 import sys
25 import time
26
27 +try:
28 + import threading
29 +except ImportError:
30 + threading = dummy_threading
31 +
32 def debug_signal(signum, frame):
33 import pdb
34 pdb.set_trace()
35 @@ -46,9 +52,10 @@ portage._disable_legacy_globals()
36
37 from portage.util._async.ForkProcess import ForkProcess
38 from portage.util._eventloop.global_event_loop import global_event_loop
39 +from _emerge.AbstractPollTask import AbstractPollTask
40 from _emerge.PipeReader import PipeReader
41
42 -class FifoWriter(ForkProcess):
43 +class FifoWriterFork(ForkProcess):
44
45 __slots__ = ('buf', 'fifo',)
46
47 @@ -58,6 +65,38 @@ class FifoWriter(ForkProcess):
48 f.write(self.buf)
49 return os.EX_OK
50
51 +class FifoWriterThread(AbstractPollTask):
52 +
53 + __slots__ = ('buf', 'fifo', '_thread',)
54 +
55 + def _start(self):
56 + self._registered = True
57 + self._thread = threading.Thread(target=self._write_fifo)
58 + self._thread.daemon = True
59 + self._thread.start()
60 +
61 + def _write_fifo(self):
62 + with open(self.fifo, 'wb', 0) as f:
63 + f.write(self.buf)
64 + # Thread-safe callback to EventLoop
65 + self.scheduler.timeout_add(0, self._write_fifo_cb, os.EX_OK)
66 +
67 + def _write_fifo_cb(self, returncode):
68 + self.returncode = returncode
69 + self._unregister()
70 + self.wait()
71 + return False
72 +
73 + def _cancel(self):
74 + # There's currently no way to force thread termination.
75 + pass
76 +
77 + def _unregister(self):
78 + self._registered = False
79 + if self._thread is not None:
80 + self._thread.join()
81 + self._thread = None
82 +
83 class EbuildIpc(object):
84
85 # Timeout for each individual communication attempt (we retry
86 @@ -210,6 +249,12 @@ class EbuildIpc(object):
87 # considerations. This helps to avoid possible race conditions
88 # from interference between timeouts and blocking IO operations.
89 msg = portage.localization._('during write')
90 + if threading is dummy_threading:
91 + # Try to avoid this fork due to possible
92 + # python deadlock (bug #524328).
93 + FifoWriter = FifoWriterFork
94 + else:
95 + FifoWriter = FifoWriterThread
96 retval = self._run_writer(FifoWriter(buf=pickle.dumps(args),
97 fifo=self.ipc_in_fifo, scheduler=global_event_loop()), msg)
98
99 --
100 1.8.5.5

Replies