Skip to content

Commit

Permalink
Fixed #18251 -- Removed a deadlock possibility in apploading
Browse files Browse the repository at this point in the history
Thanks to harm for the report and comments.
  • Loading branch information
akaariai committed May 11, 2012
1 parent 3673795 commit 4073dd4
Showing 1 changed file with 11 additions and 6 deletions.
17 changes: 11 additions & 6 deletions django/db/models/loading.py
Expand Up @@ -6,9 +6,9 @@
from django.utils.importlib import import_module
from django.utils.module_loading import module_has_submodule

import imp
import sys
import os
import threading

__all__ = ('get_apps', 'get_app', 'get_models', 'get_model', 'register_models',
'load_app', 'app_cache_ready')
Expand Down Expand Up @@ -39,7 +39,6 @@ class AppCache(object):
handled = {},
postponed = [],
nesting_level = 0,
write_lock = threading.RLock(),
_get_models_cache = {},
)

Expand All @@ -54,7 +53,13 @@ def _populate(self):
"""
if self.loaded:
return
self.write_lock.acquire()
# Note that we want to use the import lock here - the app loading is
# in many cases initiated implicitly by importing, and thus it is
# possible to end up in deadlock when one thread initiates loading
# without holding the importer lock and another thread then tries to
# import something which also lauches the app loading. For details of
# this situation see #18251.
imp.acquire_lock()
try:
if self.loaded:
return
Expand All @@ -67,7 +72,7 @@ def _populate(self):
self.load_app(app_name)
self.loaded = True
finally:
self.write_lock.release()
imp.release_lock()

def _label_for(self, app_mod):
"""
Expand Down Expand Up @@ -138,7 +143,7 @@ def get_app(self, app_label, emptyOK=False):
the app has no models in it and 'emptyOK' is True, returns None.
"""
self._populate()
self.write_lock.acquire()
imp.acquire_lock()
try:
for app_name in settings.INSTALLED_APPS:
if app_label == app_name.split('.')[-1]:
Expand All @@ -151,7 +156,7 @@ def get_app(self, app_label, emptyOK=False):
return mod
raise ImproperlyConfigured("App with label %s could not be found" % app_label)
finally:
self.write_lock.release()
imp.release_lock()

def get_app_errors(self):
"Returns the map of known problems with the INSTALLED_APPS."
Expand Down

0 comments on commit 4073dd4

Please sign in to comment.