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.Nullable;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@ -20,9 +19,9 @@ import java.util.function.Consumer;
non-sealed class EventNodeImpl<T extends Event> implements EventNode<T> {
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
protected ListenerHandle<T> computeValue(Class<?> type) {
protected Handle<T> computeValue(Class<?> type) {
//noinspection unchecked
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) {
forTargetEvents(eventClass, type -> {
ListenerHandle<T> handle = getHandle((Class<T>) type);
Handle.UPDATED.setRelease(handle, false);
Handle<T> handle = handleMap.get(type);
handle.invalidate();
});
final EventNodeImpl<? super T> parent = this.parent;
if (parent != null) parent.invalidateEvent(eventClass);
@ -307,20 +306,9 @@ non-sealed class EventNodeImpl<T extends Event> implements EventNode<T> {
@SuppressWarnings("unchecked")
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 Consumer<E> listener = null;
@SuppressWarnings("unused")
private boolean updated; // Use the UPDATED var handle
private boolean updated;
Handle(Class<E> eventType) {
this.eventType = eventType;
@ -342,13 +330,20 @@ non-sealed class EventNodeImpl<T extends Event> implements EventNode<T> {
return updatedListener() != null;
}
void invalidate() {
this.updated = false;
VarHandle.releaseFence();
}
@Nullable Consumer<E> updatedListener() {
if ((boolean) UPDATED.getAcquire(this)) return listener;
VarHandle.acquireFence();
if (updated) return listener;
synchronized (GLOBAL_CHILD_LOCK) {
if ((boolean) UPDATED.getAcquire(this)) return listener;
if (updated) return listener;
final Consumer<E> listener = createConsumer();
this.listener = listener;
UPDATED.setRelease(this, true);
this.updated = true;
VarHandle.releaseFence();
return listener;
}
}
@ -492,7 +487,7 @@ non-sealed class EventNodeImpl<T extends Event> implements EventNode<T> {
EventListener.Result result = listener.run(event);
if (result == EventListener.Result.EXPIRED) {
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.Nullable;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.ref.SoftReference;
import java.nio.ByteBuffer;
@ -20,18 +19,7 @@ import java.util.function.Supplier;
*/
@ApiStatus.Internal
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;
@SuppressWarnings("unused")
private SoftReference<FramedPacket> packet;
public CachedPacket(@NotNull Supplier<@NotNull ServerPacket> packetSupplier) {
@ -43,7 +31,8 @@ public final class CachedPacket implements SendablePacket {
}
public void invalidate() {
PACKET.setRelease(this, null);
this.packet = null;
VarHandle.releaseFence();
}
public @NotNull ServerPacket packet() {
@ -59,12 +48,13 @@ public final class CachedPacket implements SendablePacket {
private @Nullable FramedPacket updatedCache() {
if (!PacketUtils.CACHED_PACKET)
return null;
@SuppressWarnings("unchecked")
SoftReference<FramedPacket> ref = (SoftReference<FramedPacket>) PACKET.getAcquire(this);
VarHandle.acquireFence();
SoftReference<FramedPacket> ref = packet;
FramedPacket cache;
if (ref == null || (cache = ref.get()) == null) {
cache = PacketUtils.allocateTrimmedPacket(packetSupplier.get());
PACKET.setRelease(this, new SoftReference<>(cache));
this.packet = new SoftReference<>(cache);
VarHandle.releaseFence();
}
return cache;
}

View File

@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.function.Supplier;
@ -14,18 +13,7 @@ import java.util.function.Supplier;
*/
@ApiStatus.Internal
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;
@SuppressWarnings("unused")
private ServerPacket packet;
public LazyPacket(@NotNull Supplier<@NotNull ServerPacket> packetSupplier) {
@ -33,13 +21,14 @@ public final class LazyPacket implements SendablePacket {
}
public @NotNull ServerPacket packet() {
ServerPacket packet = (ServerPacket) PACKET.getAcquire(this);
VarHandle.acquireFence();
ServerPacket packet = this.packet;
if (packet == null) {
synchronized (this) {
packet = (ServerPacket) PACKET.getAcquire(this);
packet = this.packet;
if (packet == null) {
packet = packetSupplier.get();
PACKET.setRelease(this, packet);
this.packet = packet = packetSupplier.get();
VarHandle.releaseFence();
}
}
}

View File

@ -166,7 +166,7 @@ final class TagHandlerImpl implements TagHandler {
private static final class Entry<T> {
final Tag<T> tag;
final T value; // TagHandler type for path-able tags
volatile NBT nbt;
private NBT nbt;
Entry(Tag<T> tag, T value) {
this.tag = tag;
@ -174,8 +174,12 @@ final class TagHandlerImpl implements TagHandler {
}
NBT updatedNbt() {
VarHandle.acquireFence();
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;
}
}

View File

@ -3,22 +3,12 @@ package net.minestom.server.thread;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
final class AcquirableImpl<T> implements Acquirable<T> {
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.
@ -26,7 +16,6 @@ final class AcquirableImpl<T> implements Acquirable<T> {
private static final ReentrantLock GLOBAL_LOCK = new ReentrantLock();
private final T value;
@SuppressWarnings("unused")
private TickThread assignedThread;
public AcquirableImpl(@NotNull T value) {
@ -40,11 +29,13 @@ final class AcquirableImpl<T> implements Acquirable<T> {
@Override
public @NotNull TickThread assignedThread() {
return (TickThread) ASSIGNED_THREAD.getAcquire(this);
VarHandle.acquireFence();
return assignedThread;
}
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) {