Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Subject: [gentoo-portage-dev] Re: [PATCH] bin/ebuild-ipc.py: use threading if available
Date: Thu, 09 Oct 2014 04:18:33
Message-Id: 54360C92.20202@gentoo.org
In Reply to: [gentoo-portage-dev] [PATCH] bin/ebuild-ipc.py: use threading if available by Zac Medico
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

Replies