89 lines
		
	
	
	
		
			2.6 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			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 "));
 | |
| 	}
 | |
| }
 |