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 |