diff options
| author | François Freitag <mail+github@franek.fr> | 2017-02-25 12:56:24 -0800 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2017-02-25 15:56:24 -0500 |
| commit | fba4f831bc75369c975a95c9b7774e9e89f8a2f9 (patch) | |
| tree | 93f861a5ae714b1b18d8be012f7299a22eef47f5 /django | |
| parent | 12745d8a4f89b00f360cb6102a25ab244135098c (diff) | |
Fixed #27176 -- Raised an exception for reentrant calls to apps.populate().
Thanks to Aymeric Augustin, Harry Percival, and Tim Graham.
Diffstat (limited to 'django')
| -rw-r--r-- | django/apps/registry.py | 14 |
1 files changed, 9 insertions, 5 deletions
diff --git a/django/apps/registry.py b/django/apps/registry.py index 870c454067..2c14ab627d 100644 --- a/django/apps/registry.py +++ b/django/apps/registry.py @@ -44,7 +44,8 @@ class Apps: self.apps_ready = self.models_ready = self.ready = False # Lock for thread-safe population. - self._lock = threading.Lock() + self._lock = threading.RLock() + self.loading = False # Maps ("app_label", "modelname") tuples to lists of functions to be # called when the corresponding model is ready. Used by this class's @@ -72,10 +73,13 @@ class Apps: if self.ready: return - # app_config should be pristine, otherwise the code below won't - # guarantee that the order matches the order in INSTALLED_APPS. - if self.app_configs: + # An RLock prevents other threads from entering this section. The + # compare and set operation below is atomic. + if self.loading: + # Prevent reentrant calls to avoid running AppConfig.ready() + # methods twice. raise RuntimeError("populate() isn't reentrant") + self.loading = True # Phase 1: initialize app configs and import app modules. for entry in installed_apps: @@ -345,7 +349,7 @@ class Apps: raise AppRegistryNotReady("App registry isn't ready yet.") self.stored_app_configs.append(self.app_configs) self.app_configs = OrderedDict() - self.apps_ready = self.models_ready = self.ready = False + self.apps_ready = self.models_ready = self.loading = self.ready = False self.clear_cache() self.populate(installed) |
