[Python-checkins] cpython: Issue #15781: Fix two small race conditions in import's module locking.

georg.brandl python-checkins at python.org
Sun Sep 9 11:19:03 CEST 2012


http://hg.python.org/cpython/rev/85070f284fd2
changeset:   78900:85070f284fd2
user:        Antoine Pitrou <solipsis at pitrou.net>
date:        Tue Aug 28 00:24:52 2012 +0200
summary:
  Issue #15781: Fix two small race conditions in import's module locking.

files:
  Lib/importlib/_bootstrap.py      |    10 +-
  Lib/test/test_threaded_import.py |    12 +-
  Misc/NEWS                        |     2 +
  Python/import.c                  |     6 +-
  Python/importlib.h               |  7302 +++++++++--------
  5 files changed, 3678 insertions(+), 3654 deletions(-)


diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -268,8 +268,10 @@
 
     Should only be called with the import lock taken."""
     lock = None
-    if name in _module_locks:
+    try:
         lock = _module_locks[name]()
+    except KeyError:
+        pass
     if lock is None:
         if _thread is None:
             lock = _DummyModuleLock(name)
@@ -543,6 +545,9 @@
             # implicitly imports 'locale' and would otherwise trigger an
             # infinite loop.
             module = new_module(fullname)
+            # This must be done before putting the module in sys.modules
+            # (otherwise an optimization shortcut in import.c becomes wrong)
+            module.__initializing__ = True
             sys.modules[fullname] = module
             module.__loader__ = self
             try:
@@ -554,8 +559,9 @@
                     module.__package__ = fullname
                 else:
                     module.__package__ = fullname.rpartition('.')[0]
+        else:
+            module.__initializing__ = True
         try:
-            module.__initializing__ = True
             # If __package__ was not set above, __import__() will do it later.
             return fxn(self, module, *args, **kwargs)
         except:
diff --git a/Lib/test/test_threaded_import.py b/Lib/test/test_threaded_import.py
--- a/Lib/test/test_threaded_import.py
+++ b/Lib/test/test_threaded_import.py
@@ -224,7 +224,17 @@
 
 @reap_threads
 def test_main():
-    run_unittest(ThreadedImportTests)
+    old_switchinterval = None
+    try:
+        old_switchinterval = sys.getswitchinterval()
+        sys.setswitchinterval(0.00000001)
+    except AttributeError:
+        pass
+    try:
+        run_unittest(ThreadedImportTests)
+    finally:
+        if old_switchinterval is not None:
+            sys.setswitchinterval(old_switchinterval)
 
 if __name__ == "__main__":
     test_main()
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -13,6 +13,8 @@
 - Issue #15784: Modify OSError.__str__() to better distinguish between
   errno error numbers and Windows error numbers.
 
+- Issue #15781: Fix two small race conditions in import's module locking.
+
 Library
 -------
 
diff --git a/Python/import.c b/Python/import.c
--- a/Python/import.c
+++ b/Python/import.c
@@ -1408,7 +1408,11 @@
         int initializing = 0;
 
         Py_INCREF(mod);
-        /* Only call _bootstrap._lock_unlock_module() if __initializing__ is true. */
+        /* Optimization: only call _bootstrap._lock_unlock_module() if
+           __initializing__ is true.
+           NOTE: because of this, __initializing__ must be set *before*
+           stuffing the new module in sys.modules.
+         */
         value = _PyObject_GetAttrId(mod, &PyId___initializing__);
         if (value == NULL)
             PyErr_Clear();
diff --git a/Python/importlib.h b/Python/importlib.h
--- a/Python/importlib.h
+++ b/Python/importlib.h
[stripped]

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list