|
| 1 | +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
| 2 | +From: HaHaWTH <id_cn00@outlook.com> |
| 3 | +Date: Fri, 5 Apr 2024 11:47:01 +0800 |
| 4 | +Subject: [PATCH] virtual-thread-for-AsyncScheduler |
| 5 | + |
| 6 | + |
| 7 | +diff --git a/src/main/java/com/github/ruviolence/reaper/BeastConfig.java b/src/main/java/com/github/ruviolence/reaper/BeastConfig.java |
| 8 | +index 5ed1e87ab91adcf7f49025747c8567e093f551a2..6a4a1a4b15ff0a52704d9ea18be896fe8dfc648a 100644 |
| 9 | +--- a/src/main/java/com/github/ruviolence/reaper/BeastConfig.java |
| 10 | ++++ b/src/main/java/com/github/ruviolence/reaper/BeastConfig.java |
| 11 | +@@ -150,6 +150,12 @@ public class BeastConfig { |
| 12 | + RegionFile.deflater.setLevel(chunkCompressionLevel); |
| 13 | + } |
| 14 | + |
| 15 | ++ public static boolean virtualThreadForScheduler; |
| 16 | ++ |
| 17 | ++ private static void virtualThreadForScheduler() { |
| 18 | ++ virtualThreadForScheduler = getBoolean("virtual-thread-for-scheduler", false); |
| 19 | ++ } |
| 20 | ++ |
| 21 | + public static int portalTravelCacheLife; |
| 22 | + public static boolean portalTravelInstantExpire; |
| 23 | + private static void portalTravel() { |
| 24 | +diff --git a/src/main/java/com/homomc/beast/virtualthreads/DirectVirtualThreadService.java b/src/main/java/com/homomc/beast/virtualthreads/DirectVirtualThreadService.java |
| 25 | +new file mode 100644 |
| 26 | +index 0000000000000000000000000000000000000000..6bb13e68e92c3d940bd114a3ab9af14c73a0df99 |
| 27 | +--- /dev/null |
| 28 | ++++ b/src/main/java/com/homomc/beast/virtualthreads/DirectVirtualThreadService.java |
| 29 | +@@ -0,0 +1,46 @@ |
| 30 | ++package com.homomc.beast.virtualthreads; |
| 31 | ++ |
| 32 | ++ |
| 33 | ++import java.util.concurrent.ThreadFactory; |
| 34 | ++ |
| 35 | ++/** |
| 36 | ++ * An implementation of {@link VirtualThreadService} that can create virtual threads directly. |
| 37 | ++ * |
| 38 | ++ */ |
| 39 | ++final class DirectVirtualThreadService extends VirtualThreadService { |
| 40 | ++ |
| 41 | ++ private DirectVirtualThreadService() { |
| 42 | ++ super(); |
| 43 | ++ } |
| 44 | ++ |
| 45 | ++ @Override |
| 46 | ++ public ThreadFactory createFactory() { |
| 47 | ++ // Disabled until Minecraft requires servers to have a Java version that can read class files compiled with functionality from Java 19+ on preview / Java 21+ on stable |
| 48 | ++ throw new UnsupportedOperationException(); |
| 49 | ++// return Thread.ofVirtual().factory(); |
| 50 | ++ } |
| 51 | ++ |
| 52 | ++ @Override |
| 53 | ++ public Thread start( Runnable task) { |
| 54 | ++ // Disabled until Minecraft requires servers to have a Java version that can read class files compiled with functionality from Java 19+ on preview / Java 21+ on stable |
| 55 | ++ throw new UnsupportedOperationException(); |
| 56 | ++// Objects.requireNonNull(task, "The task to start a virtual thread cannot be null"); |
| 57 | ++// return Thread.ofVirtual().start(task); |
| 58 | ++ } |
| 59 | ++ |
| 60 | ++ /** |
| 61 | ++ * @return A functional {@link DirectVirtualThreadService}. |
| 62 | ++ * @throws Throwable If creating virtual threads directly is not supported by the current runtime. |
| 63 | ++ * This could be any {@link Throwable}, including an {@link Exception} or an {@link Error}. |
| 64 | ++ */ |
| 65 | ++ static DirectVirtualThreadService create() throws Throwable { |
| 66 | ++ // Disabled until Minecraft requires servers to have a Java version that can read class files compiled with functionality from Java 19+ on preview / Java 21+ on stable |
| 67 | ++ throw new UnsupportedOperationException(); |
| 68 | ++// var service = new DirectVirtualThreadService(); |
| 69 | ++// // Run some tests to verify |
| 70 | ++// service.runTest(); |
| 71 | ++// // If we end up here, it works |
| 72 | ++// return service; |
| 73 | ++ } |
| 74 | ++ |
| 75 | ++} |
| 76 | +\ No newline at end of file |
| 77 | +diff --git a/src/main/java/com/homomc/beast/virtualthreads/ReflectionVirtualThreadService.java b/src/main/java/com/homomc/beast/virtualthreads/ReflectionVirtualThreadService.java |
| 78 | +new file mode 100644 |
| 79 | +index 0000000000000000000000000000000000000000..f12f96eb793ad8fc0d1c2a4bd461031e841064f0 |
| 80 | +--- /dev/null |
| 81 | ++++ b/src/main/java/com/homomc/beast/virtualthreads/ReflectionVirtualThreadService.java |
| 82 | +@@ -0,0 +1,71 @@ |
| 83 | ++package com.homomc.beast.virtualthreads; |
| 84 | ++ |
| 85 | ++import java.lang.reflect.Method; |
| 86 | ++import java.util.Objects; |
| 87 | ++import java.util.concurrent.ThreadFactory; |
| 88 | ++ |
| 89 | ++/** |
| 90 | ++ * An implementation of {@link VirtualThreadService} that can create virtual threads using Java reflection. |
| 91 | ++ * |
| 92 | ++ */ |
| 93 | ++final class ReflectionVirtualThreadService extends VirtualThreadService { |
| 94 | ++ |
| 95 | ++ /** |
| 96 | ++ * The {@link Thread}#ofVirtual() method. |
| 97 | ++ */ |
| 98 | ++ private final Method Thread_ofVirtual_method; |
| 99 | ++ |
| 100 | ++ /** |
| 101 | ++ * The {@link Thread}.Builder#factory() method. |
| 102 | ++ */ |
| 103 | ++ private final Method Thread_Builder_factory_method; |
| 104 | ++ |
| 105 | ++ /** |
| 106 | ++ * The {@link Thread}.Builder#start(Runnable) method. |
| 107 | ++ */ |
| 108 | ++ private final Method Thread_Builder_start_method; |
| 109 | ++ |
| 110 | ++ private ReflectionVirtualThreadService() throws Throwable { |
| 111 | ++ this.Thread_ofVirtual_method = Objects.requireNonNull(Thread.class.getMethod("ofVirtual")); |
| 112 | ++ // The Thread.Builder class |
| 113 | ++ Class<?> Thread_Builder_class = Objects.requireNonNull(Class.forName("java.lang.Thread$Builder")); |
| 114 | ++ this.Thread_Builder_factory_method = Objects.requireNonNull(Thread_Builder_class.getMethod("factory")); |
| 115 | ++ this.Thread_Builder_start_method = Objects.requireNonNull(Thread_Builder_class.getMethod("start", Runnable.class)); |
| 116 | ++ } |
| 117 | ++ |
| 118 | ++ @Override |
| 119 | ++ public ThreadFactory createFactory() { |
| 120 | ++ try { |
| 121 | ++ return (ThreadFactory) this.Thread_Builder_factory_method.invoke(this.Thread_ofVirtual_method.invoke(null)); |
| 122 | ++ } catch (Exception e) { |
| 123 | ++ // This should not be possible because it was tested in create() |
| 124 | ++ throw new RuntimeException(e); |
| 125 | ++ } |
| 126 | ++ } |
| 127 | ++ |
| 128 | ++ @Override |
| 129 | ++ public Thread start( Runnable task) { |
| 130 | ++ Objects.requireNonNull(task, "The task to start a virtual thread cannot be null"); |
| 131 | ++ try { |
| 132 | ++ return (Thread) this.Thread_Builder_start_method.invoke(this.Thread_ofVirtual_method.invoke(null), task); |
| 133 | ++ } catch (Exception e) { |
| 134 | ++ // This should not be possible because it was tested in create() |
| 135 | ++ throw new RuntimeException(e); |
| 136 | ++ } |
| 137 | ++ } |
| 138 | ++ |
| 139 | ++ /** |
| 140 | ++ * @return A functional {@link ReflectionVirtualThreadService}. |
| 141 | ++ * @throws Throwable If creating virtual threads via reflection is not supported by the current runtime. |
| 142 | ++ * This could be any {@link Throwable}, including an {@link Exception} or an {@link Error}. |
| 143 | ++ */ |
| 144 | ++ static ReflectionVirtualThreadService create() throws Throwable { |
| 145 | ++ // This will already throw something if the reflection fails |
| 146 | ++ ReflectionVirtualThreadService service = new ReflectionVirtualThreadService(); |
| 147 | ++ // Run some tests to verify |
| 148 | ++ service.runTest(); |
| 149 | ++ // If we end up here, it works |
| 150 | ++ return service; |
| 151 | ++ } |
| 152 | ++ |
| 153 | ++} |
| 154 | +\ No newline at end of file |
| 155 | +diff --git a/src/main/java/com/homomc/beast/virtualthreads/VirtualThreadService.java b/src/main/java/com/homomc/beast/virtualthreads/VirtualThreadService.java |
| 156 | +new file mode 100644 |
| 157 | +index 0000000000000000000000000000000000000000..91ff46293e9a82be0f935851f87b7d4108ec5eac |
| 158 | +--- /dev/null |
| 159 | ++++ b/src/main/java/com/homomc/beast/virtualthreads/VirtualThreadService.java |
| 160 | +@@ -0,0 +1,94 @@ |
| 161 | ++package com.homomc.beast.virtualthreads; |
| 162 | ++ |
| 163 | ++import java.util.concurrent.ThreadFactory; |
| 164 | ++ |
| 165 | ++/** |
| 166 | ++ * An abstract service to create virtual threads. |
| 167 | ++ */ |
| 168 | ++public abstract class VirtualThreadService { |
| 169 | ++ |
| 170 | ++ /** |
| 171 | ++ * @return A {@link ThreadFactory} that produces virtual threads. |
| 172 | ++ */ |
| 173 | ++ public abstract ThreadFactory createFactory(); |
| 174 | ++ |
| 175 | ++ /** |
| 176 | ++ * @param task The runnable for the thread to execute. |
| 177 | ++ * @return A virtual thread that has been started with the given task. |
| 178 | ++ */ |
| 179 | ++ public abstract Thread start(Runnable task); |
| 180 | ++ |
| 181 | ++ /** |
| 182 | ++ * Runs a test on the {@link #createFactory} and {@link #start} methods, |
| 183 | ++ * which certainly throws some {@link Throwable} if something goes wrong. |
| 184 | ++ */ |
| 185 | ++ protected void runTest() throws Throwable { |
| 186 | ++ // This will definitely throw something if it doesn't work |
| 187 | ++ try { |
| 188 | ++ this.start(() -> {}).join(); |
| 189 | ++ } catch (InterruptedException ignored) {} // Except InterruptedException, we don't care about that one |
| 190 | ++ try { |
| 191 | ++ Thread thread = this.createFactory().newThread(() -> {}); |
| 192 | ++ thread.start(); |
| 193 | ++ thread.join(); |
| 194 | ++ } catch (InterruptedException ignored) {} // Except InterruptedException, we don't care about that one |
| 195 | ++ // If we end up here, it works |
| 196 | ++ } |
| 197 | ++ |
| 198 | ++ private static boolean initialized = false; |
| 199 | ++ |
| 200 | ++ /** |
| 201 | ++ * The {@link VirtualThreadService} for the current runtime, |
| 202 | ++ * or null if virtual threads are not supported, or if not {@link #initialized} yet. |
| 203 | ++ */ |
| 204 | ++ private static VirtualThreadService implementation; |
| 205 | ++ |
| 206 | ++ /** |
| 207 | ++ * @return Whether virtual threads are supported on the current runtime. |
| 208 | ++ */ |
| 209 | ++ public static boolean isSupported() { |
| 210 | ++ return get() != null; |
| 211 | ++ } |
| 212 | ++ |
| 213 | ++ /** |
| 214 | ++ * @return The {@link VirtualThreadService} for the current runtime, |
| 215 | ++ * or null if virtual threads are not {@linkplain #isSupported() supported}. |
| 216 | ++ * |
| 217 | ++ * This method is thread-safe only after the first time it has been fully run. |
| 218 | ++ */ |
| 219 | ++ public static VirtualThreadService get() { |
| 220 | ++ if (!initialized) { |
| 221 | ++ initialized = true; |
| 222 | ++ try { |
| 223 | ++ implementation = DirectVirtualThreadService.create(); |
| 224 | ++ } catch (Throwable ignored) { |
| 225 | ++ try { |
| 226 | ++ implementation = ReflectionVirtualThreadService.create(); |
| 227 | ++ } catch (Throwable ignored2) {} |
| 228 | ++ } |
| 229 | ++ } |
| 230 | ++ return implementation; |
| 231 | ++ } |
| 232 | ++ |
| 233 | ++ /** |
| 234 | ++ * The minimum major version of Java that is known to support using virtual threads |
| 235 | ++ * (although possibly behind a feature preview flag). |
| 236 | ++ */ |
| 237 | ++ public static final int minimumJavaMajorVersionWithFeaturePreview = 19; |
| 238 | ++ |
| 239 | ++ /** |
| 240 | ++ * The minimum major version of Java that is known to support using virtual threads |
| 241 | ++ * even without any feature preview flags. |
| 242 | ++ */ |
| 243 | ++ public static final int minimumJavaMajorVersionWithoutFeaturePreview = 21; |
| 244 | ++ |
| 245 | ++ public static int getJavaMajorVersion() { |
| 246 | ++ String version = System.getProperty("java.version"); |
| 247 | ++ if (version.startsWith("1.")) { |
| 248 | ++ return version.charAt(2) - '0'; |
| 249 | ++ } |
| 250 | ++ int dotIndex = version.indexOf("."); |
| 251 | ++ return Integer.parseInt(dotIndex == -1 ? version : version.substring(0, dotIndex)); |
| 252 | ++ } |
| 253 | ++ |
| 254 | ++} |
| 255 | +\ No newline at end of file |
| 256 | +diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java |
| 257 | +index eaf8692877d95170f87cc637c30e72419206b970..06fbebbb4b4e7789e50e348304e5e311f3b8d7a4 100644 |
| 258 | +--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java |
| 259 | ++++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java |
| 260 | +@@ -25,30 +25,42 @@ package org.bukkit.craftbukkit.scheduler; |
| 261 | + |
| 262 | + import com.destroystokyo.paper.ServerSchedulerReportingWrapper; |
| 263 | + import com.google.common.util.concurrent.ThreadFactoryBuilder; |
| 264 | ++import com.homomc.beast.virtualthreads.VirtualThreadService; |
| 265 | + import org.bukkit.plugin.Plugin; |
| 266 | + |
| 267 | ++import java.lang.reflect.Method; |
| 268 | + import java.util.ArrayList; |
| 269 | + import java.util.Iterator; |
| 270 | + import java.util.List; |
| 271 | +-import java.util.concurrent.Executor; |
| 272 | +-import java.util.concurrent.Executors; |
| 273 | +-import java.util.concurrent.SynchronousQueue; |
| 274 | +-import java.util.concurrent.ThreadPoolExecutor; |
| 275 | +-import java.util.concurrent.TimeUnit; |
| 276 | ++import java.util.concurrent.*; |
| 277 | + |
| 278 | + public class CraftAsyncScheduler extends CraftScheduler { |
| 279 | + |
| 280 | +- private final ThreadPoolExecutor executor = new ThreadPoolExecutor( |
| 281 | +- 4, Integer.MAX_VALUE,30L, TimeUnit.SECONDS, new SynchronousQueue<>(), |
| 282 | +- new ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %1$d").build()); |
| 283 | ++ private Executor executor; |
| 284 | + private final Executor management = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder() |
| 285 | + .setNameFormat("Craft Async Scheduler Management Thread").build()); |
| 286 | + private final List<CraftTask> temp = new ArrayList<>(); |
| 287 | + |
| 288 | + CraftAsyncScheduler() { |
| 289 | + super(true); |
| 290 | +- executor.allowCoreThreadTimeOut(true); |
| 291 | +- executor.prestartAllCoreThreads(); |
| 292 | ++ if (VirtualThreadService.getJavaMajorVersion() >= VirtualThreadService.minimumJavaMajorVersionWithoutFeaturePreview && com.github.ruviolence.reaper.BeastConfig.virtualThreadForScheduler) { |
| 293 | ++ try { |
| 294 | ++ Method newThreadPerTaskExecutor = Executors.class.getMethod("newThreadPerTaskExecutor", ThreadFactory.class); |
| 295 | ++ executor = (Executor) newThreadPerTaskExecutor.invoke(null, VirtualThreadService.get().createFactory()); |
| 296 | ++ return; |
| 297 | ++ } catch (Exception ignored) { |
| 298 | ++ System.err.println("Failed to create Virtual Thread executor! Fallback to default executor."); |
| 299 | ++ } |
| 300 | ++ } |
| 301 | ++ |
| 302 | ++ executor = new ThreadPoolExecutor( |
| 303 | ++ 4, Integer.MAX_VALUE, 30L, TimeUnit.SECONDS, new SynchronousQueue<>(), |
| 304 | ++ new ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %1$d").build()); |
| 305 | ++ |
| 306 | ++ ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor; |
| 307 | ++ |
| 308 | ++ threadPoolExecutor.allowCoreThreadTimeOut(true); |
| 309 | ++ threadPoolExecutor.prestartAllCoreThreads(); |
| 310 | + } |
| 311 | + |
| 312 | + @Override |
0 commit comments