mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 05:33:00 +00:00 
			
		
		
		
	Move MainThread config to its own class
This means the config is no longer stored as static fields, which is a little cleaner. Would like to move everything else in the future, but this is a good first step.
This commit is contained in:
		| @@ -12,6 +12,7 @@ import dan200.computercraft.core.ComputerContext; | ||||
| import dan200.computercraft.core.computer.ComputerThread; | ||||
| import dan200.computercraft.core.computer.GlobalEnvironment; | ||||
| import dan200.computercraft.core.computer.mainthread.MainThread; | ||||
| import dan200.computercraft.core.computer.mainthread.MainThreadConfig; | ||||
| import dan200.computercraft.core.lua.CobaltLuaMachine; | ||||
| import dan200.computercraft.core.lua.ILuaMachine; | ||||
| import dan200.computercraft.impl.AbstractComputerCraftAPI; | ||||
| @@ -65,7 +66,7 @@ public final class ServerContext { | ||||
|     private ServerContext(MinecraftServer server) { | ||||
|         this.server = server; | ||||
|         storageDir = server.getWorldPath(FOLDER); | ||||
|         mainThread = new MainThread(); | ||||
|         mainThread = new MainThread(mainThreadConfig); | ||||
|         context = new ComputerContext( | ||||
|             new Environment(server), | ||||
|             new ComputerThread(ConfigSpec.computerThreads.get()), | ||||
| @@ -215,4 +216,16 @@ public final class ServerContext { | ||||
|             return ComputerCraftAPI.MOD_ID + "/" + ComputerCraftAPI.getInstalledVersion(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static final MainThreadConfig mainThreadConfig = new MainThreadConfig() { | ||||
|         @Override | ||||
|         public long maxGlobalTime() { | ||||
|             return TimeUnit.MILLISECONDS.toNanos(ConfigSpec.maxMainGlobalTime.get()); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public long maxComputerTime() { | ||||
|             return TimeUnit.MILLISECONDS.toNanos(ConfigSpec.maxMainComputerTime.get()); | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|   | ||||
| @@ -9,6 +9,7 @@ import dan200.computercraft.core.CoreConfig; | ||||
| import dan200.computercraft.core.Logging; | ||||
| import dan200.computercraft.core.apis.http.NetworkUtils; | ||||
| import dan200.computercraft.core.apis.http.options.Action; | ||||
| import dan200.computercraft.core.computer.mainthread.MainThreadConfig; | ||||
| import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; | ||||
| import dan200.computercraft.shared.platform.PlatformHelper; | ||||
| import org.apache.logging.log4j.LogManager; | ||||
| @@ -155,14 +156,14 @@ public final class ConfigSpec { | ||||
|                     milliseconds. | ||||
|                     Note, we will quite possibly go over this limit, as there's no way to tell how | ||||
|                     long a will take - this aims to be the upper bound of the average time.""") | ||||
|                 .defineInRange("max_main_global_time", (int) TimeUnit.NANOSECONDS.toMillis(CoreConfig.maxMainGlobalTime), 1, Integer.MAX_VALUE); | ||||
|                 .defineInRange("max_main_global_time", (int) TimeUnit.NANOSECONDS.toMillis(MainThreadConfig.DEFAULT_MAX_GLOBAL_TIME), 1, Integer.MAX_VALUE); | ||||
| 
 | ||||
|             maxMainComputerTime = builder | ||||
|                 .comment(""" | ||||
|                     The ideal maximum time a computer can execute for in a tick, in milliseconds. | ||||
|                     Note, we will quite possibly go over this limit, as there's no way to tell how | ||||
|                     long a will take - this aims to be the upper bound of the average time.""") | ||||
|                 .defineInRange("max_main_computer_time", (int) TimeUnit.NANOSECONDS.toMillis(CoreConfig.maxMainComputerTime), 1, Integer.MAX_VALUE); | ||||
|                 .defineInRange("max_main_computer_time", (int) TimeUnit.NANOSECONDS.toMillis(MainThreadConfig.DEFAULT_MAX_COMPUTER_TIME), 1, Integer.MAX_VALUE); | ||||
| 
 | ||||
|             builder.pop(); | ||||
|         } | ||||
| @@ -348,10 +349,6 @@ public final class ConfigSpec { | ||||
|         CoreConfig.defaultComputerSettings = defaultComputerSettings.get(); | ||||
|         Config.commandRequireCreative = commandRequireCreative.get(); | ||||
| 
 | ||||
|         // Execution | ||||
|         CoreConfig.maxMainGlobalTime = TimeUnit.MILLISECONDS.toNanos(maxMainGlobalTime.get()); | ||||
|         CoreConfig.maxMainComputerTime = TimeUnit.MILLISECONDS.toNanos(maxMainComputerTime.get()); | ||||
| 
 | ||||
|         // Update our log filter if needed. | ||||
|         var logFilter = MarkerFilter.createFilter( | ||||
|             Logging.COMPUTER_ERROR.getName(), | ||||
|   | ||||
| @@ -9,7 +9,6 @@ import dan200.computercraft.core.apis.http.options.AddressRule; | ||||
| 
 | ||||
| import java.util.List; | ||||
| import java.util.OptionalInt; | ||||
| import java.util.concurrent.TimeUnit; | ||||
| 
 | ||||
| /** | ||||
|  * Config options for ComputerCraft's Lua runtime. | ||||
| @@ -25,9 +24,6 @@ public final class CoreConfig { | ||||
|     public static boolean disableLua51Features = false; | ||||
|     public static String defaultComputerSettings = ""; | ||||
| 
 | ||||
|     public static long maxMainGlobalTime = TimeUnit.MILLISECONDS.toNanos(10); | ||||
|     public static long maxMainComputerTime = TimeUnit.MILLISECONDS.toNanos(5); | ||||
| 
 | ||||
|     public static boolean httpEnabled = true; | ||||
|     public static boolean httpWebsocketEnabled = true; | ||||
|     public static List<AddressRule> httpRules = List.of( | ||||
|   | ||||
| @@ -18,7 +18,6 @@ import java.util.Map; | ||||
| /** | ||||
|  * Implementation of {@link IComputerAccess}/{@link IComputerSystem} for usage by externally registered APIs. | ||||
|  * | ||||
|  * @see dan200.computercraft.api.ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory) | ||||
|  * @see ILuaAPIFactory | ||||
|  * @see ApiWrapper | ||||
|  */ | ||||
|   | ||||
| @@ -4,7 +4,6 @@ | ||||
| 
 | ||||
| package dan200.computercraft.core.computer.mainthread; | ||||
| 
 | ||||
| import dan200.computercraft.core.CoreConfig; | ||||
| import dan200.computercraft.core.metrics.MetricsObserver; | ||||
| 
 | ||||
| import java.util.HashSet; | ||||
| @@ -20,7 +19,7 @@ import java.util.TreeSet; | ||||
|  * {@link MainThread} starts cool, and runs as many tasks as it can in the current {@link #budget}ns. Any external tasks | ||||
|  * (those run by tile entities, etc...) will also consume the budget | ||||
|  * <p> | ||||
|  * Next tick, we add {@link CoreConfig#maxMainGlobalTime} to our budget (clamp it to that value too). If we're still | ||||
|  * Next tick, we add {@link MainThreadConfig#maxGlobalTime()} to our budget (clamp it to that value too). If we're still | ||||
|  * over budget, then we should not execute <em>any</em> work (either as part of {@link MainThread} or externally). | ||||
|  */ | ||||
| public final class MainThread implements MainThreadScheduler { | ||||
| @@ -35,6 +34,8 @@ public final class MainThread implements MainThreadScheduler { | ||||
|         return at < bt ? -1 : 1; | ||||
|     }); | ||||
| 
 | ||||
|     final MainThreadConfig config; | ||||
| 
 | ||||
|     /** | ||||
|      * The set of executors which went over budget in a previous tick, and are waiting for their time to run down. | ||||
|      * | ||||
| @@ -66,6 +67,11 @@ public final class MainThread implements MainThreadScheduler { | ||||
|     private long minimumTime = 0; | ||||
| 
 | ||||
|     public MainThread() { | ||||
|         this(MainThreadConfig.DEFAULT); | ||||
|     } | ||||
| 
 | ||||
|     public MainThread(MainThreadConfig config) { | ||||
|         this.config = config; | ||||
|     } | ||||
| 
 | ||||
|     void queue(MainThreadExecutor executor) { | ||||
| @@ -79,7 +85,7 @@ public final class MainThread implements MainThreadScheduler { | ||||
|             var newRuntime = minimumTime; | ||||
| 
 | ||||
|             // Slow down new computers a little bit. | ||||
|             if (executor.virtualTime == 0) newRuntime += CoreConfig.maxMainComputerTime; | ||||
|             if (executor.virtualTime == 0) newRuntime += config.maxComputerTime(); | ||||
| 
 | ||||
|             executor.virtualTime = Math.max(newRuntime, executor.virtualTime); | ||||
| 
 | ||||
| @@ -110,7 +116,8 @@ public final class MainThread implements MainThreadScheduler { | ||||
|         // Of course, we'll go over the MAX_TICK_TIME most of the time, but eventually that overrun will accumulate | ||||
|         // and we'll skip a whole tick - bringing the average back down again. | ||||
|         currentTick++; | ||||
|         budget = Math.min(budget + CoreConfig.maxMainGlobalTime, CoreConfig.maxMainGlobalTime); | ||||
|         var maxGlobal = config.maxGlobalTime(); | ||||
|         budget = Math.min(budget + maxGlobal, maxGlobal); | ||||
|         canExecute = budget > 0; | ||||
| 
 | ||||
|         // Cool down any warm computers. | ||||
|   | ||||
| @@ -0,0 +1,50 @@ | ||||
| // SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers | ||||
| // | ||||
| // SPDX-License-Identifier: MPL-2.0 | ||||
| 
 | ||||
| package dan200.computercraft.core.computer.mainthread; | ||||
| 
 | ||||
| import java.util.concurrent.TimeUnit; | ||||
| 
 | ||||
| /** | ||||
|  * Options to configure the {@link MainThread}. | ||||
|  */ | ||||
| public interface MainThreadConfig { | ||||
|     /** | ||||
|      * The default value for {@link #maxGlobalTime()}. | ||||
|      */ | ||||
|     long DEFAULT_MAX_GLOBAL_TIME = TimeUnit.MILLISECONDS.toNanos(10); | ||||
| 
 | ||||
|     /** | ||||
|      * The default value for {@link #maxComputerTime()}. | ||||
|      */ | ||||
|     long DEFAULT_MAX_COMPUTER_TIME = TimeUnit.MILLISECONDS.toNanos(5); | ||||
| 
 | ||||
|     /** | ||||
|      * The default config. | ||||
|      */ | ||||
|     MainThreadConfig DEFAULT = new Basic(DEFAULT_MAX_GLOBAL_TIME, DEFAULT_MAX_COMPUTER_TIME); | ||||
| 
 | ||||
|     /** | ||||
|      * The ideal maximum time that can be spent executing tasks in a tick, in nanoseconds. | ||||
|      * | ||||
|      * @return The max time a that can be spent executing tasks in a single tick. | ||||
|      */ | ||||
|     long maxGlobalTime(); | ||||
| 
 | ||||
|     /** | ||||
|      * The ideal maximum time a computer can execute for in a tick, in nanoseconds. | ||||
|      * | ||||
|      * @return The max time a computer can execute in a single tick. | ||||
|      */ | ||||
|     long maxComputerTime(); | ||||
| 
 | ||||
|     /** | ||||
|      * A basic implementation of {@link MainThreadConfig}, which works on constant values. | ||||
|      * | ||||
|      * @param maxGlobalTime   See {@link MainThreadConfig#maxGlobalTime()}. | ||||
|      * @param maxComputerTime See {@link MainThreadConfig#maxComputerTime()}. | ||||
|      */ | ||||
|     record Basic(long maxGlobalTime, long maxComputerTime) implements MainThreadConfig { | ||||
|     } | ||||
| } | ||||
| @@ -5,7 +5,6 @@ | ||||
| package dan200.computercraft.core.computer.mainthread; | ||||
| 
 | ||||
| import dan200.computercraft.api.peripheral.WorkMonitor; | ||||
| import dan200.computercraft.core.CoreConfig; | ||||
| import dan200.computercraft.core.computer.Computer; | ||||
| import dan200.computercraft.core.metrics.Metrics; | ||||
| import dan200.computercraft.core.metrics.MetricsObserver; | ||||
| @@ -22,7 +21,7 @@ import java.util.concurrent.TimeUnit; | ||||
|  * those run elsewhere (such as during the turtle's tick). In order to handle this, the executor goes through three | ||||
|  * stages: | ||||
|  * <p> | ||||
|  * When {@link State#COOL}, the computer is allocated {@link CoreConfig#maxMainComputerTime}ns to execute any work | ||||
|  * When {@link State#COOL}, the computer is allocated {@link MainThreadConfig#maxComputerTime()}ns to execute any work | ||||
|  * this tick. At the beginning of the tick, we execute as many {@link MainThread} tasks as possible, until our | ||||
|  * time-frame or the global time frame has expired. | ||||
|  * <p> | ||||
| @@ -33,13 +32,13 @@ import java.util.concurrent.TimeUnit; | ||||
|  * {@link State#HOT}. This means it will no longer be able to execute {@link MainThread} tasks (though will still | ||||
|  * execute tile entity tasks, in order to prevent the main thread from exhausting work every tick). | ||||
|  * <p> | ||||
|  * At the beginning of the next tick, we increment the budget e by {@link CoreConfig#maxMainComputerTime} and any | ||||
|  * At the beginning of the next tick, we increment the budget e by {@link MainThreadConfig#maxComputerTime()} and any | ||||
|  * {@link State#HOT} executors are marked as {@link State#COOLING}. They will remain cooling until their budget is fully | ||||
|  * replenished (is equal to {@link CoreConfig#maxMainComputerTime}). Note, this is different to {@link MainThread}, | ||||
|  * replenished (is equal to {@link MainThreadConfig#maxComputerTime()}). Note, this is different to {@link MainThread}, | ||||
|  * which allows running when it has any budget left. When cooling, <em>no</em> tasks are executed - be they on the tile | ||||
|  * entity or main thread. | ||||
|  * <p> | ||||
|  * This mechanism means that, on average, computers will use at most {@link CoreConfig#maxMainComputerTime}ns per | ||||
|  * This mechanism means that, on average, computers will use at most {@link MainThreadConfig#maxComputerTime()}ns per | ||||
|  * second, but one task source will not prevent others from executing. | ||||
|  * | ||||
|  * @see MainThread | ||||
| @@ -189,7 +188,7 @@ final class MainThreadExecutor implements MainThreadScheduler.Executor { | ||||
|         // #tickCooling() isn't called, and so we didn't overrun the previous tick. | ||||
|         if (currentTick != scheduler.currentTick()) { | ||||
|             currentTick = scheduler.currentTick(); | ||||
|             budget = CoreConfig.maxMainComputerTime; | ||||
|             budget = scheduler.config.maxComputerTime(); | ||||
|         } | ||||
| 
 | ||||
|         budget -= time; | ||||
| @@ -202,15 +201,16 @@ final class MainThreadExecutor implements MainThreadScheduler.Executor { | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Move this executor forward one tick, replenishing the budget by {@link CoreConfig#maxMainComputerTime}. | ||||
|      * Move this executor forward one tick, replenishing the budget by {@link MainThreadConfig#maxComputerTime()}. | ||||
|      * | ||||
|      * @return Whether this executor has cooled down, and so is safe to run again. | ||||
|      */ | ||||
|     boolean tickCooling() { | ||||
|         state = State.COOLING; | ||||
|         currentTick = scheduler.currentTick(); | ||||
|         budget = Math.min(budget + CoreConfig.maxMainComputerTime, CoreConfig.maxMainComputerTime); | ||||
|         if (budget < CoreConfig.maxMainComputerTime) return false; | ||||
|         var maxTime = scheduler.config.maxComputerTime(); | ||||
|         budget = Math.min(budget + maxTime, maxTime); | ||||
|         if (budget < maxTime) return false; | ||||
| 
 | ||||
|         state = State.COOL; | ||||
|         synchronized (queueLock) { | ||||
|   | ||||
| @@ -10,8 +10,8 @@ import dan200.computercraft.api.lua.ILuaAPI; | ||||
| import dan200.computercraft.api.lua.LuaException; | ||||
| import dan200.computercraft.api.lua.LuaFunction; | ||||
| import dan200.computercraft.core.ComputerContext; | ||||
| import dan200.computercraft.core.CoreConfig; | ||||
| import dan200.computercraft.core.computer.mainthread.MainThread; | ||||
| import dan200.computercraft.core.computer.mainthread.MainThreadConfig; | ||||
| import dan200.computercraft.core.terminal.Terminal; | ||||
| import dan200.computercraft.test.core.computer.BasicEnvironment; | ||||
| import dan200.computercraft.test.core.filesystem.MemoryMount; | ||||
| @@ -46,10 +46,8 @@ public class ComputerBootstrap { | ||||
|     } | ||||
| 
 | ||||
|     public static void run(WritableMount mount, Consumer<Computer> setup, int maxTicks) { | ||||
|         CoreConfig.maxMainComputerTime = CoreConfig.maxMainGlobalTime = Integer.MAX_VALUE; | ||||
| 
 | ||||
|         var term = new Terminal(51, 19, true); | ||||
|         var mainThread = new MainThread(); | ||||
|         var mainThread = new MainThread(new MainThreadConfig.Basic(Integer.MAX_VALUE, Integer.MAX_VALUE)); | ||||
|         var environment = new BasicEnvironment(mount); | ||||
|         var context = new ComputerContext(environment, 1, mainThread); | ||||
|         final var computer = new Computer(context, environment, term, 0); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers | ||||
| // | ||||
| // SPDX-License-Identifier: LicenseRef-CCPL | ||||
| // SPDX-License-Identifier: MPL-2.0 | ||||
| 
 | ||||
| package dan200.computercraft.core.terminal; | ||||
| 
 | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers | ||||
| // | ||||
| // SPDX-License-Identifier: LicenseRef-CCPL | ||||
| // SPDX-License-Identifier: MPL-2.0 | ||||
| 
 | ||||
| package dan200.computercraft.core.terminal; | ||||
| 
 | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers | ||||
| // | ||||
| // SPDX-License-Identifier: LicenseRef-CCPL | ||||
| // SPDX-License-Identifier: MPL-2.0 | ||||
| 
 | ||||
| package dan200.computercraft.test.core; | ||||
| 
 | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers | ||||
| // | ||||
| // SPDX-License-Identifier: LicenseRef-CCPL | ||||
| // SPDX-License-Identifier: MPL-2.0 | ||||
| 
 | ||||
| package dan200.computercraft.test.core.terminal; | ||||
| 
 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jonathan Coates
					Jonathan Coates