Treat Folia global tick thread as main thread to fix QueueHandler scheduling errors#6
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a platform-level “main thread” contract so FAWE can treat Folia’s global tick thread as synchronous, avoiding IllegalStateException: Not main thread when QueueHandler runs under Folia scheduling.
Changes:
- Introduces
TaskManager#isMainThread()as a platform-specific main-thread detection hook. - Updates
Fawe.isMainThread()to prefer the activeTaskManagerimplementation for thread detection. - Implements Bukkit/Folia-aware main-thread detection in
BukkitTaskManager(primary thread or Folia global tick thread via reflection).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TaskManager.java | Adds the new isMainThread() platform contract to TaskManager. |
| worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java | Routes Fawe.isMainThread() through the platform TaskManager when available. |
| worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/BukkitTaskManager.java | Implements Bukkit + Folia global tick thread detection for “main thread” semantics. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| private boolean isFoliaGlobalTickThread() { | ||
| try { | ||
| Method method = Bukkit.class.getMethod("isGlobalTickThread"); | ||
| return Boolean.TRUE.equals(method.invoke(null)); | ||
| } catch (ReflectiveOperationException ignored) { | ||
| return false; | ||
| } |
There was a problem hiding this comment.
isFoliaGlobalTickThread() does reflective method lookup on every call and, on non-Folia servers, will throw/catch NoSuchMethodException each time isMainThread() is evaluated off the primary thread. This can become a significant hot-path cost. Cache the presence of Bukkit.isGlobalTickThread() (e.g., resolve the Method once into a static final/lazy field and short-circuit to false when absent) and avoid using exceptions for control flow in the common (non-Folia) case.
| TaskManager taskManager = TaskManager.IMP; | ||
| if (taskManager != null) { | ||
| return taskManager.isMainThread(); | ||
| } | ||
| return instance.thread == Thread.currentThread(); |
There was a problem hiding this comment.
Fawe.isMainThread() is using the deprecated TaskManager.IMP field. This can bypass platform-specific thread detection if IMP is unset while TaskManager.INSTANCE exists, and it also adds new usage of an API marked for removal. Prefer calling TaskManager.taskManager().isMainThread() here (or otherwise retrieving the active TaskManager via the non-deprecated path) and keeping the legacy instance.thread comparison as the fallback if needed.
Motivation
IllegalStateException: Not main threadwhen run from Folia's global region scheduler becauseFawe.isMainThread()only checked the bootstrap thread.Description
TaskManager#isMainThread()to allow platform-specific main-thread detection (file:worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TaskManager.java).Fawe.isMainThread()to prefer the activeTaskManagerimplementation for thread detection and fall back to the legacy bootstrap-thread check (file:worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java).BukkitTaskManager.isMainThread()to return true when eitherBukkit.isPrimaryThread()is true or when running on Folia's global tick thread via reflectiveBukkit.isGlobalTickThread()detection, and added the helperisFoliaGlobalTickThread()(file:worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/BukkitTaskManager.java).Testing
./gradlew :worldedit-bukkit:compileJava :worldedit-core:compileJava --no-daemon, which reached configuration and compilation steps but failed due to an unrelated multi-project configuration error (Task with name 'build' not found in project ':worldedit-libs:cli'), so no full build artifacts or unit tests were produced in this environment.isMainThread()hook can be implemented by platforms; no runtime tests were run here.Codex Task