diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java index f5118329ea..9f43bcf1ee 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java @@ -53,8 +53,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.StampedLock; import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull; @@ -77,8 +76,8 @@ public class PlatformManager { private final AtomicBoolean initialized = new AtomicBoolean(); private final AtomicBoolean configured = new AtomicBoolean(); - private final ReadWriteLock platformsLock = new ReentrantReadWriteLock(); - private final ReadWriteLock preferencesLock = new ReentrantReadWriteLock(); + private final StampedLock platformsLock = new StampedLock(); + private final StampedLock preferencesLock = new StampedLock(); /** * Create a new platform manager. @@ -106,11 +105,11 @@ public void register(Platform platform) { // Just add the platform to the list of platforms: we'll pick favorites // once all the platforms have been loaded - platformsLock.writeLock().lock(); + long stamp = platformsLock.writeLock(); try { platforms.add(platform); } finally { - platformsLock.writeLock().unlock(); + platformsLock.unlockWrite(stamp); } // Make sure that versions are in sync @@ -137,40 +136,40 @@ public boolean unregister(Platform platform) { checkNotNull(platform); boolean removed; - platformsLock.writeLock().lock(); + long platformsStamp = platformsLock.writeLock(); try { removed = platforms.remove(platform); + } finally { + platformsLock.unlockWrite(platformsStamp); + } - if (removed) { - LOGGER.info("Unregistering " + platform.getClass().getCanonicalName() + " from WorldEdit"); + if (removed) { + LOGGER.info("Unregistering " + platform.getClass().getCanonicalName() + " from WorldEdit"); - boolean choosePreferred = false; + boolean choosePreferred = false; - preferencesLock.writeLock().lock(); + long preferencesStamp = preferencesLock.writeLock(); - try { - // Check whether this platform was chosen to be the preferred one - // for any capability and be sure to remove it - Iterator> it = preferences.entrySet().iterator(); - while (it.hasNext()) { - Entry entry = it.next(); - if (entry.getValue().equals(platform)) { - entry.getKey().uninitialize(this, entry.getValue()); - it.remove(); - choosePreferred = true; // Have to choose new favorites - } + try { + // Check whether this platform was chosen to be the preferred one + // for any capability and be sure to remove it + Iterator> it = preferences.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + if (entry.getValue().equals(platform)) { + entry.getKey().uninitialize(this, entry.getValue()); + it.remove(); + choosePreferred = true; // Have to choose new favorites } - } finally { - preferencesLock.writeLock().unlock(); } + } finally { + preferencesLock.unlockWrite(preferencesStamp); + } - if (choosePreferred) { - choosePreferred(); - } + if (choosePreferred) { + choosePreferred(); } - } finally { - platformsLock.writeLock().unlock(); } return removed; @@ -184,24 +183,33 @@ public boolean unregister(Platform platform) { * @throws NoCapablePlatformException thrown if no platform is capable */ public Platform queryCapability(Capability capability) throws NoCapablePlatformException { - preferencesLock.readLock().lock(); + checkNotNull(capability); + + long stamp = preferencesLock.tryOptimisticRead(); + Platform platform = preferences.get(capability); + boolean hasNoPreferences = platform == null && preferences.isEmpty(); + + if (!preferencesLock.validate(stamp)) { + stamp = preferencesLock.readLock(); + try { + platform = preferences.get(capability); + hasNoPreferences = platform == null && preferences.isEmpty(); + } finally { + preferencesLock.unlockRead(stamp); + } + } - try { - Platform platform = preferences.get(checkNotNull(capability)); - if (platform != null) { - return platform; - } else { - if (preferences.isEmpty()) { - // Not all platforms registered, this is being called too early! - throw new NoCapablePlatformException( - "Not all platforms have been registered yet!" - + " Please wait until WorldEdit is initialized." - ); - } - throw new NoCapablePlatformException("No platform was found supporting " + capability.name()); + if (platform != null) { + return platform; + } else { + if (hasNoPreferences) { + // Not all platforms registered, this is being called too early! + throw new NoCapablePlatformException( + "Not all platforms have been registered yet!" + + " Please wait until WorldEdit is initialized." + ); } - } finally { - preferencesLock.readLock().unlock(); + throw new NoCapablePlatformException("No platform was found supporting " + capability.name()); } } @@ -212,31 +220,37 @@ private void choosePreferred() { for (Capability capability : Capability.values()) { Platform preferred = findMostPreferred(capability); if (preferred != null) { - preferencesLock.writeLock().lock(); + Platform oldPreferred; + long stamp = preferencesLock.writeLock(); try { - Platform oldPreferred = preferences.put(capability, preferred); - // only (re)initialize if it changed - if (preferred != oldPreferred) { - // uninitialize if needed - if (oldPreferred != null) { - capability.uninitialize(this, oldPreferred); - } - capability.initialize(this, preferred); - } + oldPreferred = preferences.put(capability, preferred); } finally { - preferencesLock.writeLock().unlock(); + preferencesLock.unlockWrite(stamp); + } + // only (re)initialize if it changed + if (preferred != oldPreferred) { + // uninitialize if needed + if (oldPreferred != null) { + capability.uninitialize(this, oldPreferred); + } + capability.initialize(this, preferred); } } } - preferencesLock.readLock().lock(); - try { - // Fire configuration event - if (preferences.containsKey(Capability.CONFIGURATION) && configured.compareAndSet(false, true)) { - worldEdit.getEventBus().post(new ConfigurationLoadEvent(queryCapability(Capability.CONFIGURATION).getConfiguration())); + long stamp = preferencesLock.tryOptimisticRead(); + boolean hasConfiguration = preferences.containsKey(Capability.CONFIGURATION); + if (!preferencesLock.validate(stamp)) { + stamp = preferencesLock.readLock(); + try { + hasConfiguration = preferences.containsKey(Capability.CONFIGURATION); + } finally { + preferencesLock.unlockRead(stamp); } - } finally { - preferencesLock.readLock().unlock(); + } + // Fire configuration event + if (hasConfiguration && configured.compareAndSet(false, true)) { + worldEdit.getEventBus().post(new ConfigurationLoadEvent(queryCapability(Capability.CONFIGURATION).getConfiguration())); } } @@ -270,12 +284,18 @@ private void choosePreferred() { * @return a list of platforms */ public List getPlatforms() { - platformsLock.readLock().lock(); - try { - return new ArrayList<>(platforms); - } finally { - platformsLock.readLock().unlock(); + long stamp = platformsLock.tryOptimisticRead(); + List platformsCopy = new ArrayList<>(platforms); + if (!platformsLock.validate(stamp)) { + stamp = platformsLock.readLock(); + try { + platformsCopy = new ArrayList<>(platforms); + } finally { + platformsLock.unlockRead(stamp); + } } + + return platformsCopy; } /**