From 78871d07dc22b56852dd028c85207068e94176f2 Mon Sep 17 00:00:00 2001 From: Gergely Sarkozi Date: Wed, 15 Apr 2020 09:39:39 +0200 Subject: [PATCH] Make JavaClassLoader thread-safe (Fixes #3137) (#3144) * Make PluginClassLoader thread-safe (fixes #3137) * Clean up implementation of MT safe class loader Co-authored-by: Aikar --- ...96-Make-JavaPluginLoader-thread-safe.patch | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 Spigot-API-Patches/0196-Make-JavaPluginLoader-thread-safe.patch diff --git a/Spigot-API-Patches/0196-Make-JavaPluginLoader-thread-safe.patch b/Spigot-API-Patches/0196-Make-JavaPluginLoader-thread-safe.patch new file mode 100644 index 000000000..a2a00d142 --- /dev/null +++ b/Spigot-API-Patches/0196-Make-JavaPluginLoader-thread-safe.patch @@ -0,0 +1,57 @@ +From eae57c232e30ee963d3ca6f69a5dc10179be5858 Mon Sep 17 00:00:00 2001 +From: Trigary +Date: Wed, 15 Apr 2020 01:24:55 -0400 +Subject: [PATCH] Make JavaPluginLoader thread-safe + + +diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java +index 8ff228ce..c0884f27 100644 +--- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java +@@ -52,6 +52,8 @@ public final class JavaPluginLoader implements PluginLoader { + final Server server; + private final Pattern[] fileFilters = new Pattern[]{Pattern.compile("\\.jar$")}; + private final Map> classes = new ConcurrentHashMap>(); ++ private final Map classLoadLock = new java.util.HashMap(); // Paper ++ private final Map classLoadLockCount = new java.util.HashMap(); // Paper + private final List loaders = new CopyOnWriteArrayList(); + + /** +@@ -191,6 +193,14 @@ public final class JavaPluginLoader implements PluginLoader { + + @Nullable + Class getClassByName(final String name) { ++ // Paper start - make MT safe ++ java.util.concurrent.locks.ReentrantReadWriteLock lock; ++ synchronized (classLoadLock) { ++ lock = classLoadLock.computeIfAbsent(name, (x) -> new java.util.concurrent.locks.ReentrantReadWriteLock()); ++ classLoadLockCount.compute(name, (x, prev) -> prev != null ? prev + 1 : 1); ++ } ++ lock.writeLock().lock();try { ++ // Paper end + Class cachedClass = classes.get(name); + + if (cachedClass != null) { +@@ -205,6 +215,19 @@ public final class JavaPluginLoader implements PluginLoader { + } + } + } ++ // Paper start - make MT safe ++ } finally { ++ synchronized (classLoadLock) { ++ lock.writeLock().unlock(); ++ if (classLoadLockCount.get(name) == 1) { ++ classLoadLock.remove(name); ++ classLoadLockCount.remove(name); ++ } else { ++ classLoadLockCount.compute(name, (x, prev) -> prev - 1); ++ } ++ } ++ } ++ // Paper end + return null; + } + +-- +2.25.1 +