From 6d07a7c2fa547ff5ad24d1b192e9fc84eadfe845 Mon Sep 17 00:00:00 2001 From: Player <sfPlayer1@users.noreply.github.com> Date: Sun, 14 Feb 2021 17:41:08 +0000 Subject: [PATCH] Make event registration thread safe (#1305) (cherry picked from commit be996d2566ad2f23321b9343ac08a06080d57ab2) --- .../net/fabricmc/fabric/api/event/Event.java | 2 +- .../impl/base/event/ArrayBackedEvent.java | 29 ++++++++++++------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/fabric-api-base/src/main/java/net/fabricmc/fabric/api/event/Event.java b/fabric-api-base/src/main/java/net/fabricmc/fabric/api/event/Event.java index c3c652f6f..8016d5db2 100644 --- a/fabric-api-base/src/main/java/net/fabricmc/fabric/api/event/Event.java +++ b/fabric-api-base/src/main/java/net/fabricmc/fabric/api/event/Event.java @@ -28,7 +28,7 @@ public abstract class Event<T> { * always refer to an instance containing all code that should be * executed upon event emission. */ - protected T invoker; + protected volatile T invoker; /** * Returns the invoker instance. diff --git a/fabric-api-base/src/main/java/net/fabricmc/fabric/impl/base/event/ArrayBackedEvent.java b/fabric-api-base/src/main/java/net/fabricmc/fabric/impl/base/event/ArrayBackedEvent.java index bc62e358b..99c1ecebf 100644 --- a/fabric-api-base/src/main/java/net/fabricmc/fabric/impl/base/event/ArrayBackedEvent.java +++ b/fabric-api-base/src/main/java/net/fabricmc/fabric/impl/base/event/ArrayBackedEvent.java @@ -18,6 +18,8 @@ package net.fabricmc.fabric.impl.base.event; import java.lang.reflect.Array; import java.util.Arrays; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.Function; import net.fabricmc.fabric.api.event.Event; @@ -26,6 +28,7 @@ class ArrayBackedEvent<T> extends Event<T> { private final Class<? super T> type; private final Function<T[], T> invokerFactory; private final T dummyInvoker; + private final Lock lock = new ReentrantLock(); private T[] handlers; ArrayBackedEvent(Class<? super T> type, T dummyInvoker, Function<T[], T> invokerFactory) { @@ -35,12 +38,12 @@ class ArrayBackedEvent<T> extends Event<T> { update(); } + @SuppressWarnings("unchecked") void update() { if (handlers == null) { if (dummyInvoker != null) { invoker = dummyInvoker; } else { - //noinspection unchecked invoker = invokerFactory.apply((T[]) Array.newInstance(type, 0)); } } else if (handlers.length == 1) { @@ -50,21 +53,27 @@ class ArrayBackedEvent<T> extends Event<T> { } } + @SuppressWarnings("unchecked") @Override public void register(T listener) { if (listener == null) { throw new NullPointerException("Tried to register a null listener!"); } - if (handlers == null) { - //noinspection unchecked - handlers = (T[]) Array.newInstance(type, 1); - handlers[0] = listener; - } else { - handlers = Arrays.copyOf(handlers, handlers.length + 1); - handlers[handlers.length - 1] = listener; - } + lock.lock(); - update(); + try { + if (handlers == null) { + handlers = (T[]) Array.newInstance(type, 1); + handlers[0] = listener; + } else { + handlers = Arrays.copyOf(handlers, handlers.length + 1); + handlers[handlers.length - 1] = listener; + } + + update(); + } finally { + lock.unlock(); + } } }