Use ctypes in subprocess for bug #448858.
authorZac Medico <zmedico@gentoo.org>
Sun, 30 Dec 2012 09:33:10 +0000 (01:33 -0800)
committerZac Medico <zmedico@gentoo.org>
Sun, 30 Dec 2012 09:33:10 +0000 (01:33 -0800)
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 [new file with mode: 0644]
pym/portage/dbapi/vartree.py

diff --git a/pym/portage/dbapi/_SyncfsProcess.py b/pym/portage/dbapi/_SyncfsProcess.py
new file mode 100644 (file)
index 0000000..7518214
--- /dev/null
@@ -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
index 840e796f1e72156cc6f9c569c6aa9a959015e7b0..7a930e553fd789bf7c813e0e1ebcc368c91e07e5 100644 (file)
@@ -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,