diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -159,6 +159,104 @@ def new_module(name): return type(_io)(name) +# Module-level locking ######################################################## + +# A dict mapping module names to weakrefs of _ModuleLock instances +_module_locks = {} +# A dict mapping thread ids to _ModuleLock instances +_blocking_on = {} + +class _ModuleLock: + """A recursive lock implementation which is able to detect deadlocks + (e.g. thread 1 trying to take locks A then B, and thread 2 trying to + take locks B then A). + """ + + def __init__(self, name): + self.lock = _thread.allocate_lock() + self.wakeup = _thread.allocate_lock() + self.name = name + self.owner = None + self.count = 0 + self.waiters = 0 + + def has_deadlock(self): + # Deadlock avoidance for concurrent circular imports. + me = _thread.get_ident() + tid = self.owner + while True: + lock = _blocking_on.get(tid) + if lock is None: + return False + tid = lock.owner + if tid == me: + return True + + def acquire(self, avoid_deadlocks=False): + tid = _thread.get_ident() + _blocking_on[tid] = self + try: + while True: + with self.lock: + if self.count == 0 or self.owner == tid: + self.owner = tid + self.count += 1 + return True + if avoid_deadlocks and self.has_deadlock(): + return False + if self.wakeup.acquire(False): + self.waiters += 1 + self.wakeup.acquire() + self.wakeup.release() + finally: + del _blocking_on[tid] + + def release(self): + tid = _thread.get_ident() + with self.lock: + if self.owner != tid: + raise RuntimeError("cannot release un-acquired lock") + assert self.count > 0 + self.count -= 1 + if self.count == 0: + self.owner = None + if self.waiters: + self.waiters -= 1 + self.wakeup.release() + + def __repr__(self): + return "_ModuleLock(%r) at %d" % (self.name, id(self)) + + +# The following two functions are for consumption by Python/import.c. + +def _get_module_lock(name): + """Get or create the module lock for a given module name. + + Should only be called with the import lock taken.""" + lock = None + if name in _module_locks: + lock = _module_locks[name]() + if lock is None: + lock = _ModuleLock(name) + def cb(_): + del _module_locks[name] + _module_locks[name] = _weakref.ref(lock, cb) + return lock + +def _lock_unlock_module(name): + """Release the global import lock, and acquires then release the + module lock for a given module name. + This is used to ensure a module is completely initialized, in the + event it is being imported by another thread. + + Should only be called with the import lock taken.""" + lock = _get_module_lock(name) + _imp.release_lock() + if lock.acquire(avoid_deadlocks=True): + lock.release() + + # Finder/loader utility code ################################################## _PYCACHE = '__pycache__' @@ -258,12 +356,15 @@ def module_for_loader(fxn): else: module.__package__ = fullname.rpartition('.')[0] try: + module.__initializing__ = True # If __package__ was not set above, __import__() will do it later. return fxn(self, module, *args, **kwargs) except: if not is_reload: del sys.modules[fullname] raise + finally: + module.__initializing__ = False _wrap(module_for_loader_wrapper, fxn) return module_for_loader_wrapper @@ -922,7 +1023,8 @@ def _find_module(name, path): if not sys.meta_path: _warnings.warn('sys.meta_path is empty', ImportWarning) for finder in sys.meta_path: - loader = finder.find_module(name, path) + with _ImportLockContext(): + loader = finder.find_module(name, path) if loader is not None: # The parent import may have already imported this module. if name not in sys.modules: @@ -952,8 +1054,7 @@ def _sanity_check(name, package, level): _ERR_MSG = 'No module named {!r}' -def _find_and_load(name, import_): - """Find and load the module.""" +def _find_and_load_unlocked(name, import_): path = None parent = name.rpartition('.')[0] if parent: @@ -999,6 +1100,19 @@ def _find_and_load(name, import_): return module +def _find_and_load(name, import_): + """Find and load the module, and release the import lock.""" + try: + lock = _get_module_lock(name) + finally: + _imp.release_lock() + lock.acquire() + try: + return _find_and_load_unlocked(name, import_) + finally: + lock.release() + + def _gcd_import(name, package=None, level=0): """Import and return the module based on its name, the package the call is being made from, and the level adjustment. @@ -1011,17 +1125,17 @@ def _gcd_import(name, package=None, leve _sanity_check(name, package, level) if level > 0: name = _resolve_name(name, package, level) - with _ImportLockContext(): - try: - module = sys.modules[name] - if module is None: - message = ("import of {} halted; " - "None in sys.modules".format(name)) - raise ImportError(message, name=name) - return module - except KeyError: - pass # Don't want to chain the exception + _imp.acquire_lock() + if name not in sys.modules: return _find_and_load(name, _gcd_import) + module = sys.modules[name] + if module is None: + _imp.release_lock() + message = ("import of {} halted; " + "None in sys.modules".format(name)) + raise ImportError(message, name=name) + _lock_unlock_module(name) + return module def _handle_fromlist(module, fromlist, import_): @@ -1139,7 +1253,17 @@ def _setup(sys_module, _imp_module): continue else: raise ImportError('importlib requires posix or nt') + + try: + thread_module = BuiltinImporter.load_module('_thread') + except ImportError: + # Python was built without threads + thread_module = None + weakref_module = BuiltinImporter.load_module('_weakref') + setattr(self_module, '_os', os_module) + setattr(self_module, '_thread', thread_module) + setattr(self_module, '_weakref', weakref_module) setattr(self_module, 'path_sep', path_sep) setattr(self_module, 'path_separators', set(path_separators)) # Constants diff --git a/Lib/importlib/test/test_locks.py b/Lib/importlib/test/test_locks.py new file mode 100644 --- /dev/null +++ b/Lib/importlib/test/test_locks.py @@ -0,0 +1,101 @@ +from importlib import _bootstrap +try: + import threading +except ImportError: + threading = None +import time +import unittest +import weakref + +from test import support +from test import lock_tests + + +LockType = _bootstrap._ModuleLock +Bunch = lock_tests.Bunch + + +@unittest.skipUnless(threading, "threads needed for this test") +class ModuleLockAsRLockTests(lock_tests.RLockTests): + locktype = staticmethod(lambda: LockType("some_lock")) + + # _is_owned() unsupported + test__is_owned = None + # acquire(blocking=False) unsupported + test_try_acquire = None + test_try_acquire_contended = None + # `with` unsupported + test_with = None + # acquire(timeout=...) unsupported + test_timeout = None + # _release_save() unsupported + test_release_save_unacquired = None + + +@unittest.skipUnless(threading, "threads needed for this test") +class DeadlockAvoidanceTests(unittest.TestCase): + + def run_deadlock_avoidance_test(self, create_deadlock): + NLOCKS = 10 + locks = [LockType(str(i)) for i in range(NLOCKS)] + pairs = [(locks[i], locks[(i+1)%NLOCKS]) for i in range(NLOCKS)] + if create_deadlock: + NTHREADS = NLOCKS + else: + NTHREADS = NLOCKS - 1 + barrier = threading.Barrier(NTHREADS) + results = [] + def f(): + a, b = pairs.pop() + ra = a.acquire(avoid_deadlocks=True) + barrier.wait() + rb = b.acquire(avoid_deadlocks=True) + results.append((ra, rb)) + if rb: + b.release() + if ra: + a.release() + Bunch(f, NTHREADS).wait_for_finished() + self.assertEqual(len(results), NTHREADS) + return results + + def test_deadlock(self): + results = self.run_deadlock_avoidance_test(True) + # One of the threads detected a potential deadlock on its second + # acquire() call. + self.assertEqual(results.count((True, False)), 1) + self.assertEqual(results.count((True, True)), len(results) - 1) + + def test_no_deadlock(self): + results = self.run_deadlock_avoidance_test(False) + self.assertEqual(results.count((True, False)), 0) + self.assertEqual(results.count((True, True)), len(results)) + + +class LifetimeTests(unittest.TestCase): + + def test_lock_lifetime(self): + name = "xyzzy" + self.assertNotIn(name, _bootstrap._module_locks) + lock = _bootstrap._get_module_lock(name) + self.assertIn(name, _bootstrap._module_locks) + wr = weakref.ref(lock) + del lock + support.gc_collect() + self.assertNotIn(name, _bootstrap._module_locks) + self.assertIs(wr(), None) + + def test_all_locks(self): + support.gc_collect() + self.assertEqual(0, len(_bootstrap._module_locks)) + + +@support.reap_threads +def test_main(): + support.run_unittest(ModuleLockAsRLockTests, + DeadlockAvoidanceTests, + LifetimeTests) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -166,7 +166,7 @@ def visiblename(name, all=None, obj=None if name in {'__builtins__', '__doc__', '__file__', '__path__', '__module__', '__name__', '__slots__', '__package__', '__cached__', '__author__', '__credits__', '__date__', - '__version__', '__qualname__'}: + '__version__', '__qualname__', '__initializing__'}: return 0 # Private names are hidden, but special names are displayed. if name.startswith('__') and name.endswith('__'): return 1 diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py --- a/Lib/test/lock_tests.py +++ b/Lib/test/lock_tests.py @@ -247,7 +247,6 @@ class RLockTests(BaseLockTests): # Cannot release an unacquired lock lock = self.locktype() self.assertRaises(RuntimeError, lock.release) - self.assertRaises(RuntimeError, lock._release_save) lock.acquire() lock.acquire() lock.release() @@ -255,6 +254,17 @@ class RLockTests(BaseLockTests): lock.release() lock.release() self.assertRaises(RuntimeError, lock.release) + + def test_release_save_unacquired(self): + # Cannot _release_save an unacquired lock + lock = self.locktype() + self.assertRaises(RuntimeError, lock._release_save) + lock.acquire() + lock.acquire() + lock.release() + lock.acquire() + lock.release() + lock.release() self.assertRaises(RuntimeError, lock._release_save) def test_different_thread(self): diff --git a/Lib/test/test_pkg.py b/Lib/test/test_pkg.py --- a/Lib/test/test_pkg.py +++ b/Lib/test/test_pkg.py @@ -23,6 +23,8 @@ def cleanout(root): def fixdir(lst): if "__builtins__" in lst: lst.remove("__builtins__") + if "__initializing__" in lst: + lst.remove("__initializing__") return lst 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 @@ -12,7 +12,7 @@ import time import shutil import unittest from test.support import ( - verbose, import_module, run_unittest, TESTFN, reap_threads) + verbose, import_module, run_unittest, TESTFN, reap_threads, forget) threading = import_module('threading') def task(N, done, done_tasks, errors): @@ -187,7 +187,7 @@ class ThreadedImportTests(unittest.TestC contents = contents % {'delay': delay} with open(os.path.join(TESTFN, name + ".py"), "wb") as f: f.write(contents.encode('utf-8')) - self.addCleanup(sys.modules.pop, name, None) + self.addCleanup(forget, name) results = [] def import_ab(): @@ -204,6 +204,21 @@ class ThreadedImportTests(unittest.TestC t2.join() self.assertEqual(set(results), {'a', 'b'}) + def test_side_effect_import(self): + code = """if 1: + import threading + def target(): + import random + t = threading.Thread(target=target) + t.start() + t.join()""" + sys.path.insert(0, os.curdir) + self.addCleanup(sys.path.remove, os.curdir) + with open(TESTFN + ".py", "wb") as f: + f.write(code.encode('utf-8')) + self.addCleanup(forget, TESTFN) + __import__(TESTFN) + @reap_threads def test_main(): diff --git a/Lib/token.py b/Lib/token.py --- a/Lib/token.py +++ b/Lib/token.py @@ -70,7 +70,7 @@ NT_OFFSET = 256 tok_name = {value: name for name, value in globals().items() - if isinstance(value, int)} + if isinstance(value, int) and not name.startswith('_')} __all__.extend(tok_name.values()) def ISTERMINAL(x): diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -1370,47 +1370,7 @@ PyImport_ImportModule(const char *name) PyObject * PyImport_ImportModuleNoBlock(const char *name) { - PyObject *nameobj, *modules, *result; -#ifdef WITH_THREAD - long me; -#endif - - /* Try to get the module from sys.modules[name] */ - modules = PyImport_GetModuleDict(); - if (modules == NULL) - return NULL; - - nameobj = PyUnicode_FromString(name); - if (nameobj == NULL) - return NULL; - result = PyDict_GetItem(modules, nameobj); - if (result != NULL) { - Py_DECREF(nameobj); - Py_INCREF(result); - return result; - } - PyErr_Clear(); -#ifdef WITH_THREAD - /* check the import lock - * me might be -1 but I ignore the error here, the lock function - * takes care of the problem */ - me = PyThread_get_thread_ident(); - if (import_lock_thread == -1 || import_lock_thread == me) { - /* no thread or me is holding the lock */ - result = PyImport_Import(nameobj); - } - else { - PyErr_Format(PyExc_ImportError, - "Failed to import %R because the import lock" - "is held by another thread.", - nameobj); - result = NULL; - } -#else - result = PyImport_Import(nameobj); -#endif - Py_DECREF(nameobj); - return result; + return PyImport_ImportModule(name); } @@ -1420,11 +1380,13 @@ PyImport_ImportModuleLevelObject(PyObjec int level) { _Py_IDENTIFIER(__import__); + _Py_IDENTIFIER(__initializing__); _Py_IDENTIFIER(__package__); _Py_IDENTIFIER(__path__); _Py_IDENTIFIER(__name__); _Py_IDENTIFIER(_find_and_load); _Py_IDENTIFIER(_handle_fromlist); + _Py_IDENTIFIER(_lock_unlock_module); _Py_static_string(single_dot, "."); PyObject *abs_name = NULL; PyObject *builtins_import = NULL; @@ -1607,16 +1569,48 @@ PyImport_ImportModuleLevelObject(PyObjec goto error_with_unlock; } else if (mod != NULL) { + PyObject *value; + int initializing = 0; + Py_INCREF(mod); + /* Only call _bootstrap._lock_unlock_module() if __initializing__ is true. */ + value = _PyObject_GetAttrId(mod, &PyId___initializing__); + if (value == NULL) + PyErr_Clear(); + else { + initializing = PyObject_IsTrue(value); + Py_DECREF(value); + if (initializing == -1) + PyErr_Clear(); + } + if (initializing > 0) { + /* _bootstrap._lock_unlock_module() releases the import lock */ + value = _PyObject_CallMethodObjIdArgs(interp->importlib, + &PyId__lock_unlock_module, abs_name, + NULL); + if (value == NULL) + goto error; + Py_DECREF(value); + } + else { +#ifdef WITH_THREAD + if (_PyImport_ReleaseLock() < 0) { + PyErr_SetString(PyExc_RuntimeError, "not holding the import lock"); + goto error; + } +#endif + } } else { + /* _bootstrap._find_and_load() releases the import lock */ mod = _PyObject_CallMethodObjIdArgs(interp->importlib, &PyId__find_and_load, abs_name, builtins_import, NULL); if (mod == NULL) { - goto error_with_unlock; + goto error; } } + /* From now on we don't hold the import lock anymore. */ if (PyObject_Not(fromlist)) { if (level == 0 || PyUnicode_GET_LENGTH(name) > 0) { @@ -1625,12 +1619,12 @@ PyImport_ImportModuleLevelObject(PyObjec PyObject *borrowed_dot = _PyUnicode_FromId(&single_dot); if (borrowed_dot == NULL) { - goto error_with_unlock; + goto error; } partition = PyUnicode_Partition(name, borrowed_dot); if (partition == NULL) { - goto error_with_unlock; + goto error; } front = PyTuple_GET_ITEM(partition, 0); @@ -1656,7 +1650,7 @@ PyImport_ImportModuleLevelObject(PyObjec abs_name_len - cut_off); Py_DECREF(front); if (to_return == NULL) { - goto error_with_unlock; + goto error; } final_mod = PyDict_GetItem(interp->modules, to_return); @@ -1682,6 +1676,8 @@ PyImport_ImportModuleLevelObject(PyObjec fromlist, builtins_import, NULL); } + goto error; + error_with_unlock: #ifdef WITH_THREAD if (_PyImport_ReleaseLock() < 0) { diff --git a/Python/importlib.h b/Python/importlib.h index 292308fc78123e9fa10c7131bb110c47559975dd..80f27b1a1e2f58c567c87e9ffee9a76188c702dd GIT binary patch literal 180267 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 G%l`+ch|9(R