mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-04 07:28:19 +01:00
Explicit fences
This commit is contained in:
parent
0fc9cab6ab
commit
edabb19891
@ -7,7 +7,6 @@ import org.jetbrains.annotations.Contract;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.invoke.VarHandle;
|
import java.lang.invoke.VarHandle;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@ -20,9 +19,9 @@ import java.util.function.Consumer;
|
|||||||
non-sealed class EventNodeImpl<T extends Event> implements EventNode<T> {
|
non-sealed class EventNodeImpl<T extends Event> implements EventNode<T> {
|
||||||
static final Object GLOBAL_CHILD_LOCK = new Object();
|
static final Object GLOBAL_CHILD_LOCK = new Object();
|
||||||
|
|
||||||
private final ClassValue<ListenerHandle<T>> handleMap = new ClassValue<>() {
|
private final ClassValue<Handle<T>> handleMap = new ClassValue<>() {
|
||||||
@Override
|
@Override
|
||||||
protected ListenerHandle<T> computeValue(Class<?> type) {
|
protected Handle<T> computeValue(Class<?> type) {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
return new Handle<>((Class<T>) type);
|
return new Handle<>((Class<T>) type);
|
||||||
}
|
}
|
||||||
@ -274,8 +273,8 @@ non-sealed class EventNodeImpl<T extends Event> implements EventNode<T> {
|
|||||||
|
|
||||||
private void invalidateEvent(Class<? extends T> eventClass) {
|
private void invalidateEvent(Class<? extends T> eventClass) {
|
||||||
forTargetEvents(eventClass, type -> {
|
forTargetEvents(eventClass, type -> {
|
||||||
ListenerHandle<T> handle = getHandle((Class<T>) type);
|
Handle<T> handle = handleMap.get(type);
|
||||||
Handle.UPDATED.setRelease(handle, false);
|
handle.invalidate();
|
||||||
});
|
});
|
||||||
final EventNodeImpl<? super T> parent = this.parent;
|
final EventNodeImpl<? super T> parent = this.parent;
|
||||||
if (parent != null) parent.invalidateEvent(eventClass);
|
if (parent != null) parent.invalidateEvent(eventClass);
|
||||||
@ -307,20 +306,9 @@ non-sealed class EventNodeImpl<T extends Event> implements EventNode<T> {
|
|||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
final class Handle<E extends Event> implements ListenerHandle<E> {
|
final class Handle<E extends Event> implements ListenerHandle<E> {
|
||||||
private static final VarHandle UPDATED;
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
UPDATED = MethodHandles.lookup().findVarHandle(EventNodeImpl.Handle.class, "updated", boolean.class);
|
|
||||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Class<E> eventType;
|
private final Class<E> eventType;
|
||||||
private Consumer<E> listener = null;
|
private Consumer<E> listener = null;
|
||||||
@SuppressWarnings("unused")
|
private boolean updated;
|
||||||
private boolean updated; // Use the UPDATED var handle
|
|
||||||
|
|
||||||
Handle(Class<E> eventType) {
|
Handle(Class<E> eventType) {
|
||||||
this.eventType = eventType;
|
this.eventType = eventType;
|
||||||
@ -342,13 +330,20 @@ non-sealed class EventNodeImpl<T extends Event> implements EventNode<T> {
|
|||||||
return updatedListener() != null;
|
return updatedListener() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void invalidate() {
|
||||||
|
this.updated = false;
|
||||||
|
VarHandle.releaseFence();
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable Consumer<E> updatedListener() {
|
@Nullable Consumer<E> updatedListener() {
|
||||||
if ((boolean) UPDATED.getAcquire(this)) return listener;
|
VarHandle.acquireFence();
|
||||||
|
if (updated) return listener;
|
||||||
synchronized (GLOBAL_CHILD_LOCK) {
|
synchronized (GLOBAL_CHILD_LOCK) {
|
||||||
if ((boolean) UPDATED.getAcquire(this)) return listener;
|
if (updated) return listener;
|
||||||
final Consumer<E> listener = createConsumer();
|
final Consumer<E> listener = createConsumer();
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
UPDATED.setRelease(this, true);
|
this.updated = true;
|
||||||
|
VarHandle.releaseFence();
|
||||||
return listener;
|
return listener;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -492,7 +487,7 @@ non-sealed class EventNodeImpl<T extends Event> implements EventNode<T> {
|
|||||||
EventListener.Result result = listener.run(event);
|
EventListener.Result result = listener.run(event);
|
||||||
if (result == EventListener.Result.EXPIRED) {
|
if (result == EventListener.Result.EXPIRED) {
|
||||||
node.removeListener(listener);
|
node.removeListener(listener);
|
||||||
UPDATED.setRelease(this, false);
|
invalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import org.jetbrains.annotations.ApiStatus;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.invoke.VarHandle;
|
import java.lang.invoke.VarHandle;
|
||||||
import java.lang.ref.SoftReference;
|
import java.lang.ref.SoftReference;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@ -20,18 +19,7 @@ import java.util.function.Supplier;
|
|||||||
*/
|
*/
|
||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
public final class CachedPacket implements SendablePacket {
|
public final class CachedPacket implements SendablePacket {
|
||||||
private static final VarHandle PACKET;
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
PACKET = MethodHandles.lookup().findVarHandle(CachedPacket.class, "packet", SoftReference.class);
|
|
||||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Supplier<ServerPacket> packetSupplier;
|
private final Supplier<ServerPacket> packetSupplier;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private SoftReference<FramedPacket> packet;
|
private SoftReference<FramedPacket> packet;
|
||||||
|
|
||||||
public CachedPacket(@NotNull Supplier<@NotNull ServerPacket> packetSupplier) {
|
public CachedPacket(@NotNull Supplier<@NotNull ServerPacket> packetSupplier) {
|
||||||
@ -43,7 +31,8 @@ public final class CachedPacket implements SendablePacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void invalidate() {
|
public void invalidate() {
|
||||||
PACKET.setRelease(this, null);
|
this.packet = null;
|
||||||
|
VarHandle.releaseFence();
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull ServerPacket packet() {
|
public @NotNull ServerPacket packet() {
|
||||||
@ -59,12 +48,13 @@ public final class CachedPacket implements SendablePacket {
|
|||||||
private @Nullable FramedPacket updatedCache() {
|
private @Nullable FramedPacket updatedCache() {
|
||||||
if (!PacketUtils.CACHED_PACKET)
|
if (!PacketUtils.CACHED_PACKET)
|
||||||
return null;
|
return null;
|
||||||
@SuppressWarnings("unchecked")
|
VarHandle.acquireFence();
|
||||||
SoftReference<FramedPacket> ref = (SoftReference<FramedPacket>) PACKET.getAcquire(this);
|
SoftReference<FramedPacket> ref = packet;
|
||||||
FramedPacket cache;
|
FramedPacket cache;
|
||||||
if (ref == null || (cache = ref.get()) == null) {
|
if (ref == null || (cache = ref.get()) == null) {
|
||||||
cache = PacketUtils.allocateTrimmedPacket(packetSupplier.get());
|
cache = PacketUtils.allocateTrimmedPacket(packetSupplier.get());
|
||||||
PACKET.setRelease(this, new SoftReference<>(cache));
|
this.packet = new SoftReference<>(cache);
|
||||||
|
VarHandle.releaseFence();
|
||||||
}
|
}
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server;
|
|||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.invoke.VarHandle;
|
import java.lang.invoke.VarHandle;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@ -14,18 +13,7 @@ import java.util.function.Supplier;
|
|||||||
*/
|
*/
|
||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
public final class LazyPacket implements SendablePacket {
|
public final class LazyPacket implements SendablePacket {
|
||||||
private static final VarHandle PACKET;
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
PACKET = MethodHandles.lookup().findVarHandle(LazyPacket.class, "packet", ServerPacket.class);
|
|
||||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Supplier<ServerPacket> packetSupplier;
|
private final Supplier<ServerPacket> packetSupplier;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private ServerPacket packet;
|
private ServerPacket packet;
|
||||||
|
|
||||||
public LazyPacket(@NotNull Supplier<@NotNull ServerPacket> packetSupplier) {
|
public LazyPacket(@NotNull Supplier<@NotNull ServerPacket> packetSupplier) {
|
||||||
@ -33,13 +21,14 @@ public final class LazyPacket implements SendablePacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull ServerPacket packet() {
|
public @NotNull ServerPacket packet() {
|
||||||
ServerPacket packet = (ServerPacket) PACKET.getAcquire(this);
|
VarHandle.acquireFence();
|
||||||
|
ServerPacket packet = this.packet;
|
||||||
if (packet == null) {
|
if (packet == null) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
packet = (ServerPacket) PACKET.getAcquire(this);
|
packet = this.packet;
|
||||||
if (packet == null) {
|
if (packet == null) {
|
||||||
packet = packetSupplier.get();
|
this.packet = packet = packetSupplier.get();
|
||||||
PACKET.setRelease(this, packet);
|
VarHandle.releaseFence();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,7 @@ final class TagHandlerImpl implements TagHandler {
|
|||||||
private static final class Entry<T> {
|
private static final class Entry<T> {
|
||||||
final Tag<T> tag;
|
final Tag<T> tag;
|
||||||
final T value; // TagHandler type for path-able tags
|
final T value; // TagHandler type for path-able tags
|
||||||
volatile NBT nbt;
|
private NBT nbt;
|
||||||
|
|
||||||
Entry(Tag<T> tag, T value) {
|
Entry(Tag<T> tag, T value) {
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
@ -174,8 +174,12 @@ final class TagHandlerImpl implements TagHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NBT updatedNbt() {
|
NBT updatedNbt() {
|
||||||
|
VarHandle.acquireFence();
|
||||||
NBT nbt = this.nbt;
|
NBT nbt = this.nbt;
|
||||||
if (nbt == null) this.nbt = nbt = tag.writeFunction.apply(value);
|
if (nbt == null) {
|
||||||
|
this.nbt = nbt = tag.writeFunction.apply(value);
|
||||||
|
VarHandle.releaseFence();
|
||||||
|
}
|
||||||
return nbt;
|
return nbt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,22 +3,12 @@ package net.minestom.server.thread;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.invoke.VarHandle;
|
import java.lang.invoke.VarHandle;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
final class AcquirableImpl<T> implements Acquirable<T> {
|
final class AcquirableImpl<T> implements Acquirable<T> {
|
||||||
static final AtomicLong WAIT_COUNTER_NANO = new AtomicLong();
|
static final AtomicLong WAIT_COUNTER_NANO = new AtomicLong();
|
||||||
private static final VarHandle ASSIGNED_THREAD;
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
ASSIGNED_THREAD = MethodHandles.lookup().findVarHandle(AcquirableImpl.class, "assignedThread", TickThread.class);
|
|
||||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global lock used for synchronization.
|
* Global lock used for synchronization.
|
||||||
@ -26,7 +16,6 @@ final class AcquirableImpl<T> implements Acquirable<T> {
|
|||||||
private static final ReentrantLock GLOBAL_LOCK = new ReentrantLock();
|
private static final ReentrantLock GLOBAL_LOCK = new ReentrantLock();
|
||||||
|
|
||||||
private final T value;
|
private final T value;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private TickThread assignedThread;
|
private TickThread assignedThread;
|
||||||
|
|
||||||
public AcquirableImpl(@NotNull T value) {
|
public AcquirableImpl(@NotNull T value) {
|
||||||
@ -40,11 +29,13 @@ final class AcquirableImpl<T> implements Acquirable<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull TickThread assignedThread() {
|
public @NotNull TickThread assignedThread() {
|
||||||
return (TickThread) ASSIGNED_THREAD.getAcquire(this);
|
VarHandle.acquireFence();
|
||||||
|
return assignedThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateThread(@NotNull TickThread thread) {
|
void updateThread(@NotNull TickThread thread) {
|
||||||
ASSIGNED_THREAD.setRelease(this, thread);
|
this.assignedThread = thread;
|
||||||
|
VarHandle.releaseFence();
|
||||||
}
|
}
|
||||||
|
|
||||||
static @Nullable ReentrantLock enter(@NotNull Thread currentThread, @Nullable TickThread elementThread) {
|
static @Nullable ReentrantLock enter(@NotNull Thread currentThread, @Nullable TickThread elementThread) {
|
||||||
|
Loading…
Reference in New Issue
Block a user