From fc48db62b564e2011a9a51ff3179ea0379907d56 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 17 Sep 2018 15:02:49 -0400 Subject: [PATCH] Improve native initialization logic, again --- .../natives/util/NativeCodeLoader.java | 61 ++++++++++--------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java b/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java index 692df5375..4b84516da 100644 --- a/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java +++ b/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java @@ -16,13 +16,14 @@ public class NativeCodeLoader implements Supplier { @Override public T get() { - if (selected == null) { - selected = tryLoad(); - } - return selected.object; + return tryLoad().object; } private Variant tryLoad() { + if (selected != null) { + return selected; + } + synchronized (this) { if (selected != null) { return selected; @@ -41,18 +42,15 @@ public class NativeCodeLoader implements Supplier { } public String getLoadedVariant() { - if (selected == null) { - selected = tryLoad(); - } - return selected.name; + return tryLoad().name; } static class Variant { - private boolean available; + private volatile boolean available; private final Runnable setup; private final String name; private final T object; - private boolean hasBeenSetup = false; + private volatile boolean hasBeenSetup = false; Variant(BooleanSupplier available, Runnable setup, String name, T object) { this.available = available.getAsBoolean(); @@ -61,27 +59,34 @@ public class NativeCodeLoader implements Supplier { this.object = object; } - private void setup() { - if (available && !hasBeenSetup) { - try { - setup.run(); - hasBeenSetup = true; - } catch (Exception e) { - available = false; + public T get() { + if (!available) { + return null; + } + + // Make sure setup happens only once + if (!hasBeenSetup) { + synchronized (this) { + // We change availability if need be below, may as well check it again here for sanity. + if (!available) { + return null; + } + + // Okay, now try the setup if we haven't done so yet. + if (!hasBeenSetup) { + try { + setup.run(); + hasBeenSetup = true; + return object; + } catch (Exception e) { + available = false; + return null; + } + } } } - } - public T get() { - if (!hasBeenSetup) { - setup(); - } - - if (available) { - return object; - } - - return null; + return object; } }