From 7ebb2f54877edb28621c33e380f8777b1b1dc201 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Sun, 30 Dec 2012 01:33:10 -0800 Subject: Use ctypes in subprocess for bug #448858. Isolate ctypes usage in a subprocess, in order to avoid potential problems with stale cached libraries as described in bug #448858, comment #14 (also see http://bugs.python.org/issue14597). --- pym/portage/dbapi/_SyncfsProcess.py | 53 +++++++++++++++++++++++++++++++++++++ pym/portage/dbapi/vartree.py | 47 ++++++++++---------------------- 2 files changed, 67 insertions(+), 33 deletions(-) create mode 100644 pym/portage/dbapi/_SyncfsProcess.py diff --git a/pym/portage/dbapi/_SyncfsProcess.py b/pym/portage/dbapi/_SyncfsProcess.py new file mode 100644 index 000000000..7518214ec --- /dev/null +++ b/pym/portage/dbapi/_SyncfsProcess.py @@ -0,0 +1,53 @@ +# Copyright 2012 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +from portage import os +from portage.util._ctypes import find_library, LoadLibrary +from portage.util._async.ForkProcess import ForkProcess + +class SyncfsProcess(ForkProcess): + """ + Isolate ctypes usage in a subprocess, in order to avoid + potential problems with stale cached libraries as + described in bug #448858, comment #14 (also see + http://bugs.python.org/issue14597). + """ + + __slots__ = ('paths',) + + @staticmethod + def _get_syncfs(): + + filename = find_library("c") + if filename is not None: + library = LoadLibrary(filename) + if library is not None: + try: + return library.syncfs + except AttributeError: + pass + + return None + + def _run(self): + + syncfs_failed = False + syncfs = self._get_syncfs() + + if syncfs is not None: + for path in self.paths: + try: + fd = os.open(path, os.O_RDONLY) + except OSError: + pass + else: + try: + if syncfs(fd) != 0: + # Happens with PyPy (bug #446610) + syncfs_failed = True + finally: + os.close(fd) + + if syncfs is None or syncfs_failed: + return 1 + return os.EX_OK diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py index 840e796f1..7a930e553 100644 --- a/pym/portage/dbapi/vartree.py +++ b/pym/portage/dbapi/vartree.py @@ -11,6 +11,7 @@ portage.proxy.lazyimport.lazyimport(globals(), 'portage.data:portage_gid,portage_uid,secpass', 'portage.dbapi.dep_expand:dep_expand', 'portage.dbapi._MergeProcess:MergeProcess', + 'portage.dbapi._SyncfsProcess:SyncfsProcess', 'portage.dep:dep_getkey,isjustname,isvalidatom,match_from_list,' + \ 'use_reduce,_get_slot_re,_slot_separator,_repo_separator', 'portage.eapi:_get_eapi_attrs', @@ -29,7 +30,6 @@ portage.proxy.lazyimport.lazyimport(globals(), 'portage.util.env_update:env_update', 'portage.util.listdir:dircache,listdir', 'portage.util.movefile:movefile', - 'portage.util._ctypes:find_library,LoadLibrary', 'portage.util._dyn_libs.PreservedLibsRegistry:PreservedLibsRegistry', 'portage.util._dyn_libs.LinkageMapELF:LinkageMapELF@LinkageMap', 'portage.util._async.SchedulerInterface:SchedulerInterface', @@ -4731,28 +4731,22 @@ class dblink(object): "merge-sync" not in self.settings.features: return - syncfs_failed = False - syncfs = _get_syncfs() + returncode = None + if platform.system() == "Linux": - if syncfs is not None: + paths = [] for path in self._device_path_map.values(): - if path is False: - continue - try: - fd = os.open(path, os.O_RDONLY) - except OSError: - pass - else: - try: - if syncfs(fd) != 0: - # Happens with PyPy (bug #446610) - syncfs_failed = True - except OSError: - pass - finally: - os.close(fd) + if path is not False: + paths.append(path) + paths = tuple(paths) + + proc = SyncfsProcess(paths=paths, + scheduler=(self._scheduler or + SchedulerInterface(EventLoop(main=False)))) + proc.start() + returncode = proc.wait() - if syncfs is None or syncfs_failed: + if returncode is None or returncode != os.EX_OK: try: proc = subprocess.Popen(["sync"]) except EnvironmentError: @@ -4938,19 +4932,6 @@ class dblink(object): finally: self.unlockdb() -def _get_syncfs(): - if platform.system() == "Linux": - filename = find_library("c") - if filename is not None: - library = LoadLibrary(filename) - if library is not None: - try: - return library.syncfs - except AttributeError: - pass - - return None - def merge(mycat, mypkg, pkgloc, infloc, myroot=None, settings=None, myebuild=None, mytree=None, mydbapi=None, vartree=None, prev_mtimes=None, blockers=None, -- cgit v1.2.3-1-g7c22