Explicit fences

This commit is contained in:
themode 2022-03-25 10:12:04 +01:00
parent 0fc9cab6ab
commit edabb19891
5 changed files with 37 additions and 68 deletions

View File

@ -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();
} }
} }
} }

View File

@ -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;
} }

View File

@ -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();
} }
} }
} }

View File

@ -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;
} }
} }

View File

@ -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) {