1 |
This updated patch is fixed to prevent ebuild-ipc processes from |
2 |
hanging around in some cases like bug #345455: |
3 |
|
4 |
https://bugs.gentoo.org/show_bug.cgi?id=345455 |
5 |
|
6 |
I'll be maintaining this patch in the following branch: |
7 |
|
8 |
https://github.com/zmedico/portage/tree/bug_524328 |
9 |
|
10 |
From 5e37cd413b8c18830cd378dfe85cc3211cebe636 Mon Sep 17 00:00:00 2001 |
11 |
From: Zac Medico <zmedico@g.o> |
12 |
Date: Tue, 7 Oct 2014 21:52:08 -0700 |
13 |
Subject: [PATCH] bin/ebuild-ipc.py: use threading if available |
14 |
|
15 |
If threading is available then use a thread instead of a fork for |
16 |
writing to the fifo. This has the advantage of avoiding a possible |
17 |
python futex deadlock following fork as reported in bug #524328. |
18 |
|
19 |
X-Gentoo-Bug: 524328 |
20 |
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=524328 |
21 |
--- |
22 |
bin/ebuild-ipc.py | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- |
23 |
1 file changed, 52 insertions(+), 1 deletion(-) |
24 |
|
25 |
diff --git a/bin/ebuild-ipc.py b/bin/ebuild-ipc.py |
26 |
index 3e6d90c..9963b5c 100755 |
27 |
--- a/bin/ebuild-ipc.py |
28 |
+++ b/bin/ebuild-ipc.py |
29 |
@@ -5,6 +5,7 @@ |
30 |
# This is a helper which ebuild processes can use |
31 |
# to communicate with portage's main python process. |
32 |
|
33 |
+import dummy_threading |
34 |
import logging |
35 |
import os |
36 |
import pickle |
37 |
@@ -13,6 +14,11 @@ import signal |
38 |
import sys |
39 |
import time |
40 |
|
41 |
+try: |
42 |
+ import threading |
43 |
+except ImportError: |
44 |
+ threading = dummy_threading |
45 |
+ |
46 |
def debug_signal(signum, frame): |
47 |
import pdb |
48 |
pdb.set_trace() |
49 |
@@ -46,9 +52,10 @@ portage._disable_legacy_globals() |
50 |
|
51 |
from portage.util._async.ForkProcess import ForkProcess |
52 |
from portage.util._eventloop.global_event_loop import global_event_loop |
53 |
+from _emerge.AbstractPollTask import AbstractPollTask |
54 |
from _emerge.PipeReader import PipeReader |
55 |
|
56 |
-class FifoWriter(ForkProcess): |
57 |
+class FifoWriterFork(ForkProcess): |
58 |
|
59 |
__slots__ = ('buf', 'fifo',) |
60 |
|
61 |
@@ -58,6 +65,44 @@ class FifoWriter(ForkProcess): |
62 |
f.write(self.buf) |
63 |
return os.EX_OK |
64 |
|
65 |
+class FifoWriterThread(AbstractPollTask): |
66 |
+ |
67 |
+ __slots__ = ('buf', 'fifo', '_thread',) |
68 |
+ |
69 |
+ def _start(self): |
70 |
+ self._registered = True |
71 |
+ self._thread = threading.Thread(target=self._write_fifo) |
72 |
+ self._thread.daemon = True |
73 |
+ self._thread.start() |
74 |
+ |
75 |
+ def _write_fifo(self): |
76 |
+ with open(self.fifo, 'wb', 0) as f: |
77 |
+ f.write(self.buf) |
78 |
+ # Thread-safe callback to EventLoop |
79 |
+ self.scheduler.timeout_add(0, self._exit_cb, os.EX_OK) |
80 |
+ |
81 |
+ def _exit_cb(self, returncode): |
82 |
+ if self.returncode is None: |
83 |
+ self.returncode = returncode |
84 |
+ self._unregister() |
85 |
+ self.wait() |
86 |
+ return False |
87 |
+ |
88 |
+ def _cancel(self): |
89 |
+ # Do not join the thread, since it could block indefinitely |
90 |
+ # when opening/writing the fifo (as in bug #345455). Since |
91 |
+ # there's no way to force thread termination, simply allow |
92 |
+ # the daemon thread to terminate when the main thread |
93 |
+ # terminates. This class is only instantiated once, so there |
94 |
+ # will be no more than a single thread writing to self.fifo |
95 |
+ # during the life of the program (no chance of multiple |
96 |
+ # threads interfering with eachother). |
97 |
+ self.scheduler.timeout_add(0, |
98 |
+ self._exit_cb, -signal.SIGINT) |
99 |
+ |
100 |
+ def _unregister(self): |
101 |
+ self._registered = False |
102 |
+ |
103 |
class EbuildIpc(object): |
104 |
|
105 |
# Timeout for each individual communication attempt (we retry |
106 |
@@ -210,6 +255,12 @@ class EbuildIpc(object): |
107 |
# considerations. This helps to avoid possible race conditions |
108 |
# from interference between timeouts and blocking IO operations. |
109 |
msg = portage.localization._('during write') |
110 |
+ if threading is dummy_threading: |
111 |
+ # Try to avoid this fork due to possible |
112 |
+ # python deadlock (bug #524328). |
113 |
+ FifoWriter = FifoWriterFork |
114 |
+ else: |
115 |
+ FifoWriter = FifoWriterThread |
116 |
retval = self._run_writer(FifoWriter(buf=pickle.dumps(args), |
117 |
fifo=self.ipc_in_fifo, scheduler=global_event_loop()), msg) |
118 |
|
119 |
-- |
120 |
1.8.5.5 |