commit: bb2484afc217058267b5ba5d2d792bc1c46203b7 Author: Zac Medico <zmedico <AT> gentoo <DOT> org> AuthorDate: Mon Apr 23 02:27:53 2018 +0000 Commit: Zac Medico <zmedico <AT> gentoo <DOT> org> CommitDate: Mon Apr 23 02:38:53 2018 +0000 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=bb2484af
Scheduler: fix create_world_atom event loop recursion (bug 653848) Generate world atoms while the event loop is not running, since otherwise portdbapi match calls in the create_world_atom function could trigger event loop recursion. Bug: https://bugs.gentoo.org/653848 pym/_emerge/Scheduler.py | 19 ++++++++++++++----- pym/_emerge/create_world_atom.py | 6 ++++-- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/pym/_emerge/Scheduler.py b/pym/_emerge/Scheduler.py index 71fe3e07d..6778708bb 100644 --- a/pym/_emerge/Scheduler.py +++ b/pym/_emerge/Scheduler.py @@ -448,6 +448,7 @@ class Scheduler(PollScheduler): self._pkg_cache = {} self._digraph = None self._mergelist = [] + self._world_atoms = None self._deep_system_deps.clear() return @@ -456,6 +457,18 @@ class Scheduler(PollScheduler): self._digraph = graph_config.graph self._mergelist = graph_config.mergelist + # Generate world atoms while the event loop is not running, + # since otherwise portdbapi match calls in the create_world_atom + # function could trigger event loop recursion. + self._world_atoms = {} + for pkg in self._mergelist: + if getattr(pkg, 'operation', None) != 'merge': + continue + atom = create_world_atom(pkg, self._args_set, + pkg.root_config, before_install=True) + if atom is not None: + self._world_atoms[pkg] = atom + if "--nodeps" in self.myopts or \ (self._max_jobs is not True and self._max_jobs < 2): # save some memory @@ -1939,11 +1952,7 @@ class Scheduler(PollScheduler): atom = None if pkg.operation != "uninstall": - # Do this before acquiring the lock, since it queries the - # portdbapi which can call the global event loop, triggering - # a concurrent call to this method or something else that - # needs an exclusive (non-reentrant) lock on the world file. - atom = create_world_atom(pkg, args_set, root_config) + atom = self._world_atoms.get(pkg) try: diff --git a/pym/_emerge/create_world_atom.py b/pym/_emerge/create_world_atom.py index 74b0fa5d7..947f8088a 100644 --- a/pym/_emerge/create_world_atom.py +++ b/pym/_emerge/create_world_atom.py @@ -11,7 +11,7 @@ if sys.hexversion >= 0x3000000: else: _unicode = unicode -def create_world_atom(pkg, args_set, root_config): +def create_world_atom(pkg, args_set, root_config, before_install=False): """Create a new atom for the world file if one does not exist. If the argument atom is precise enough to identify a specific slot then a slot atom will be returned. Atoms that are in the system set may also be stored @@ -83,11 +83,13 @@ def create_world_atom(pkg, args_set, root_config): # If there is no installed package matching the SLOT atom, # it probably changed SLOT spontaneously due to USE=multislot, # so just record an unslotted atom. - if vardb.match(slot_atom): + if vardb.match(slot_atom) or before_install: # Now verify that the argument is precise # enough to identify a specific slot. matches = mydb.match(arg_atom) matched_slots = set() + if before_install: + matched_slots.add(pkg.slot) if mydb is vardb: for cpv in matches: matched_slots.add(mydb._pkg_str(cpv, None).slot)