From 5fb5a692fa6a40d80cfd593060d973d287ad1127 Mon Sep 17 00:00:00 2001 From: Theia Vogel Date: Fri, 25 Jun 2021 14:21:32 -0700 Subject: [PATCH] Fix AssetServer::get_asset_loader deadlock A thread could take the extension_to_loader_index read lock, and then have the `server.loader` write lock taken in add_loader before it can. Then add_loader can't take the extension_to_loader_index lock, and the program deadlocks. Fixed by descoping the extension_to_loader_index lock, since get_asset_loader doesn't need to hold the lock for the duration, just to get a copiable usize. The block might not be needed, I think I could have gotten away with just inserting a `copied()` call into the chain, but I wanted to make the reasoning clear for future maintainers. --- crates/bevy_asset/src/asset_server.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/bevy_asset/src/asset_server.rs b/crates/bevy_asset/src/asset_server.rs index 2810b03b861c9..d5a331909de34 100644 --- a/crates/bevy_asset/src/asset_server.rs +++ b/crates/bevy_asset/src/asset_server.rs @@ -134,11 +134,13 @@ impl AssetServer { &self, extension: &str, ) -> Result>, AssetServerError> { - self.server - .extension_to_loader_index - .read() - .get(extension) - .map(|index| self.server.loaders.read()[*index].clone()) + let index = { + // scope map to drop lock as soon as possible + let map = self.server.extension_to_loader_index.read(); + map.get(extension).copied() + }; + index + .map(|index| self.server.loaders.read()[index].clone()) .ok_or_else(|| AssetServerError::MissingAssetLoader { extensions: vec![extension.to_string()], })