aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2018-04-20 23:36:29 -0700
committerZac Medico <zmedico@gentoo.org>2018-04-22 11:30:52 -0700
commit30c69adfc0ffa450ff3a4d4d176023db66171ae7 (patch)
treea5d3dc3907304a7adfe747d8bbec0be11f041664
parentEbuildBuildDir: add async_lock method (bug 614112) (diff)
downloadportage-30c69adfc0ffa450ff3a4d4d176023db66171ae7.tar.gz
portage-30c69adfc0ffa450ff3a4d4d176023db66171ae7.tar.bz2
portage-30c69adfc0ffa450ff3a4d4d176023db66171ae7.zip
AbstractEbuildProcess: use async_lock (bug 614112)
Asynchronously lock the build directory. The asynchronous lock delays creation of the pid, and it's possible for the _wait method to be called before the pid is available. Therefore, AbstractEbuildProcess._wait() must wait for the pid to become available before it can call the SpawnProcess._wait() method. Bug: https://bugs.gentoo.org/614112
-rw-r--r--pym/_emerge/AbstractEbuildProcess.py30
1 files changed, 26 insertions, 4 deletions
diff --git a/pym/_emerge/AbstractEbuildProcess.py b/pym/_emerge/AbstractEbuildProcess.py
index 2aa0c4a35..d481e6046 100644
--- a/pym/_emerge/AbstractEbuildProcess.py
+++ b/pym/_emerge/AbstractEbuildProcess.py
@@ -25,7 +25,7 @@ class AbstractEbuildProcess(SpawnProcess):
__slots__ = ('phase', 'settings',) + \
('_build_dir', '_build_dir_unlock', '_ipc_daemon',
- '_exit_command', '_exit_timeout_id')
+ '_exit_command', '_exit_timeout_id', '_start_future')
_phases_without_builddir = ('clean', 'cleanrm', 'depend', 'help',)
_phases_interactive_whitelist = ('config',)
@@ -130,15 +130,19 @@ class AbstractEbuildProcess(SpawnProcess):
# since we're not displaying to a terminal anyway.
self.settings['NOCOLOR'] = 'true'
+ start_ipc_daemon = False
if self._enable_ipc_daemon:
self.settings.pop('PORTAGE_EBUILD_EXIT_FILE', None)
if self.phase not in self._phases_without_builddir:
+ start_ipc_daemon = True
if 'PORTAGE_BUILDDIR_LOCKED' not in self.settings:
self._build_dir = EbuildBuildDir(
scheduler=self.scheduler, settings=self.settings)
- self._build_dir.lock()
- self.settings['PORTAGE_IPC_DAEMON'] = "1"
- self._start_ipc_daemon()
+ self._start_future = self._build_dir.async_lock()
+ self._start_future.add_done_callback(
+ functools.partial(self._start_post_builddir_lock,
+ start_ipc_daemon=start_ipc_daemon))
+ return
else:
self.settings.pop('PORTAGE_IPC_DAEMON', None)
else:
@@ -159,6 +163,19 @@ class AbstractEbuildProcess(SpawnProcess):
else:
self.settings.pop('PORTAGE_EBUILD_EXIT_FILE', None)
+ self._start_post_builddir_lock(start_ipc_daemon=start_ipc_daemon)
+
+ def _start_post_builddir_lock(self, lock_future=None, start_ipc_daemon=False):
+ if lock_future is not None:
+ if lock_future is not self._start_future:
+ raise AssertionError('lock_future is not self._start_future')
+ self._start_future = None
+ lock_future.result()
+
+ if start_ipc_daemon:
+ self.settings['PORTAGE_IPC_DAEMON'] = "1"
+ self._start_ipc_daemon()
+
if self.fd_pipes is None:
self.fd_pipes = {}
null_fd = None
@@ -375,6 +392,11 @@ class AbstractEbuildProcess(SpawnProcess):
Execution of the failsafe code will automatically become a fatal
error at the same time as event loop recursion is disabled.
"""
+ # SpawnProcess._wait() requires the pid, so wait here for the
+ # pid to become available.
+ while self._start_future is not None:
+ self.scheduler.run_until_complete(self._start_future)
+
SpawnProcess._wait(self)
if self._build_dir is not None: