minecraft-src/net/minecraft/util/ThreadingDetector.java
2025-07-04 01:41:11 +03:00

89 lines
2.6 KiB
Java

package net.minecraft.util;
import com.mojang.logging.LogUtils;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import net.minecraft.CrashReport;
import net.minecraft.CrashReportCategory;
import net.minecraft.ReportedException;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
public class ThreadingDetector {
private static final Logger LOGGER = LogUtils.getLogger();
private final String name;
private final Semaphore lock = new Semaphore(1);
private final Lock stackTraceLock = new ReentrantLock();
@Nullable
private volatile Thread threadThatFailedToAcquire;
@Nullable
private volatile ReportedException fullException;
public ThreadingDetector(String name) {
this.name = name;
}
public void checkAndLock() {
boolean bl = false;
try {
this.stackTraceLock.lock();
if (!this.lock.tryAcquire()) {
this.threadThatFailedToAcquire = Thread.currentThread();
bl = true;
this.stackTraceLock.unlock();
try {
this.lock.acquire();
} catch (InterruptedException var6) {
Thread.currentThread().interrupt();
}
throw this.fullException;
}
} finally {
if (!bl) {
this.stackTraceLock.unlock();
}
}
}
public void checkAndUnlock() {
try {
this.stackTraceLock.lock();
Thread thread = this.threadThatFailedToAcquire;
if (thread != null) {
ReportedException reportedException = makeThreadingException(this.name, thread);
this.fullException = reportedException;
this.lock.release();
throw reportedException;
}
this.lock.release();
} finally {
this.stackTraceLock.unlock();
}
}
public static ReportedException makeThreadingException(String accessed, @Nullable Thread thread) {
String string = (String)Stream.of(Thread.currentThread(), thread)
.filter(Objects::nonNull)
.map(ThreadingDetector::stackTrace)
.collect(Collectors.joining("\n"));
String string2 = "Accessing " + accessed + " from multiple threads";
CrashReport crashReport = new CrashReport(string2, new IllegalStateException(string2));
CrashReportCategory crashReportCategory = crashReport.addCategory("Thread dumps");
crashReportCategory.setDetail("Thread dumps", string);
LOGGER.error("Thread dumps: \n" + string);
return new ReportedException(crashReport);
}
private static String stackTrace(Thread thread) {
return thread.getName() + ": \n\tat " + (String)Arrays.stream(thread.getStackTrace()).map(Object::toString).collect(Collectors.joining("\n\tat "));
}
}