diff --git a/django/apps/registry.py b/django/apps/registry.py index a0cd5e0abf..fcd5f576e6 100644 --- a/django/apps/registry.py +++ b/django/apps/registry.py @@ -1,11 +1,11 @@ from collections import Counter, defaultdict, OrderedDict import os import sys +import threading import warnings from django.core.exceptions import ImproperlyConfigured from django.utils import lru_cache -from django.utils.module_loading import import_lock from django.utils._os import upath from .base import AppConfig @@ -44,6 +44,9 @@ class Apps(object): # Whether the registry is populated. self.ready = False + # Lock for thread-safe population. + self._lock = threading.Lock() + # Pending lookups for lazy relations. self._pending_lookups = {} @@ -61,10 +64,10 @@ class Apps(object): """ if self.ready: return - # Since populate() may be a side effect of imports, and since it will - # itself import modules, an ABBA deadlock between threads would be - # possible if we didn't take the import lock. See #18251. - with import_lock(): + + # populate() might be called by two threads in parallel on servers + # that create threads before initializing the WSGI callable. + with self._lock: if self.ready: return diff --git a/django/utils/module_loading.py b/django/utils/module_loading.py index bd012cd55b..a6fe7aebcb 100644 --- a/django/utils/module_loading.py +++ b/django/utils/module_loading.py @@ -1,6 +1,5 @@ from __future__ import absolute_import # Avoid importing `importlib` from this package. -from contextlib import contextmanager import copy import imp from importlib import import_module @@ -36,18 +35,6 @@ def import_by_path(dotted_path, error_prefix=''): return attr -@contextmanager -def import_lock(): - """ - Context manager that aquires the import lock. - """ - imp.acquire_lock() - try: - yield - finally: - imp.release_lock() - - def autodiscover_modules(*args, **kwargs): """ Auto-discover INSTALLED_APPS modules and fail silently when