From fc4a895aa8efab8526c32adc270f1fccae9ce2c2 Mon Sep 17 00:00:00 2001 From: Heshan Padamsiri Date: Tue, 17 Dec 2024 20:00:47 +0530 Subject: [PATCH] Simple CAS sync --- .../runtime/api/types/semtype/Context.java | 5 +-- .../runtime/api/types/semtype/Env.java | 42 +++++++------------ 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/semtype/Context.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/semtype/Context.java index f4026ace8493..380f81589583 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/semtype/Context.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/semtype/Context.java @@ -49,7 +49,6 @@ public final class Context { public final Map functionMemo = new WeakHashMap<>(); private static final int MAX_CACHE_SIZE = 100; private final Map> typeCheckCacheMemo; - private int drainedPermits = 0; private int nTypeChecking = 0; private Phase phase = Phase.INIT; List typeResolutionPhases = new ArrayList<>(); @@ -135,7 +134,7 @@ public void enterTypeCheckingPhase(SemType t1, SemType t2) { phase = Phase.TYPE_CHECKING; } case TYPE_RESOLUTION -> { - drainedPermits = env.enterTypeCheckingPhase(this, t1, t2); + env.enterTypeCheckingPhase(this, t1, t2); if (collectDiagnostic) { typeCheckPhases.add(new PhaseData()); typeResolutionPhases.removeLast(); @@ -179,7 +178,7 @@ public void exitTypeCheckingPhase() { case TYPE_CHECKING -> { assert nTypeChecking >= 0; if (nTypeChecking == 0) { - env.exitTypeCheckingPhase(this, drainedPermits + 1); + env.exitTypeCheckingPhase(this); if (collectDiagnostic) { typeCheckPhases.removeLast(); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/semtype/Env.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/semtype/Env.java index 9ad83c218ae1..b102c02127fb 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/semtype/Env.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/semtype/Env.java @@ -32,9 +32,8 @@ import java.util.Map; import java.util.Optional; import java.util.WeakHashMap; -import java.util.concurrent.Phaser; -import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Supplier; @@ -51,11 +50,6 @@ public final class Env { // Currently there is no reason to worry about above restrictions since Env is a singleton, but strictly speaking // there is not technical restriction preventing multiple instances of Env. - private static final int TYPE_RESOLUTION_MAX_PERMITS = 10000; - private final Semaphore typeResolutionSemaphore = new Semaphore(TYPE_RESOLUTION_MAX_PERMITS); - - private volatile Phaser typeResolutionPhaser = new Phaser(); - private static final Env INSTANCE = new Env(); // Each atom is created once but will be accessed multiple times during type checking. Also in perfect world we @@ -79,6 +73,8 @@ public final class Env { private final AtomicInteger distinctAtomCount = new AtomicInteger(0); private final TypeCheckSelfDiagnosticsRunner selfDiagnosticsRunner; + private final AtomicLong pendingTypeResolutions = new AtomicLong(0); + private Env() { this.atomTable = new WeakHashMap<>(); this.recListAtoms = new ArrayList<>(); @@ -316,22 +312,13 @@ public Optional atomicTypeByIndex(int index) { // context to enter phase 1. void enterTypeResolutionPhase(Context cx, MutableSemType t) throws InterruptedException { - typeResolutionSemaphore.acquire(); - if (typeResolutionPhaser.isTerminated()) { - synchronized (this) { - if (typeResolutionPhaser.isTerminated()) { - typeResolutionPhaser = new Phaser(); - } - } - } - typeResolutionPhaser.register(); + pendingTypeResolutions.incrementAndGet(); this.selfDiagnosticsRunner.registerTypeResolutionStart(cx, t); } void exitTypeResolutionPhaseAbruptly(Context cx, Exception ex) { try { - typeResolutionSemaphore.release(); - typeResolutionPhaser.arriveAndDeregister(); + pendingTypeResolutions.decrementAndGet(); releaseLock((ReentrantReadWriteLock) atomLock); releaseLock((ReentrantReadWriteLock) recListLock); releaseLock((ReentrantReadWriteLock) recMapLock); @@ -352,20 +339,23 @@ private void releaseLock(ReentrantReadWriteLock lock) { } void exitTypeResolutionPhase(Context cx) { - typeResolutionSemaphore.release(); - typeResolutionPhaser.arriveAndDeregister(); + pendingTypeResolutions.decrementAndGet(); this.selfDiagnosticsRunner.registerTypeResolutionExit(cx); } - int enterTypeCheckingPhase(Context cx, SemType t1, SemType t2) { - int drained = typeResolutionSemaphore.drainPermits(); - typeResolutionPhaser.awaitAdvance(typeResolutionPhaser.arriveAndDeregister()); + void enterTypeCheckingPhase(Context cx, SemType t1, SemType t2) { + long pendingResolutions = pendingTypeResolutions.decrementAndGet(); + while (pendingResolutions > 0) { + try { + Thread.sleep(10); + } catch (InterruptedException ignored) { + } + pendingResolutions = pendingTypeResolutions.get(); + } this.selfDiagnosticsRunner.registerTypeCheckStart(cx, t1, t2); - return drained; } - void exitTypeCheckingPhase(Context cx, int permits) { - typeResolutionSemaphore.release(permits); + void exitTypeCheckingPhase(Context cx) { this.selfDiagnosticsRunner.registerTypeCheckEnd(cx); }