diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java index e5bb3244f4c3098f3746147634d6c4c26528fea1..c90fbc6920c0ebec90256571eebbbc3aec183557 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java @@ -29,10 +29,12 @@ import static com.oracle.truffle.r.ffi.impl.common.RFFIUtils.traceEnabled; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.EnumMap; +import java.util.concurrent.locks.ReentrantLock; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.interop.ForeignAccess; import com.oracle.truffle.api.interop.InteropException; import com.oracle.truffle.api.interop.Message; @@ -43,6 +45,7 @@ import com.oracle.truffle.r.ffi.impl.common.LibPaths; import com.oracle.truffle.r.ffi.impl.common.RFFIUtils; import com.oracle.truffle.r.ffi.impl.nfi.TruffleNFI_DLL.NFIHandle; import com.oracle.truffle.r.ffi.impl.upcalls.Callbacks; +import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.context.RContext.ContextKind; @@ -77,6 +80,9 @@ class UnsafeAdapter { final class TruffleNFI_Context extends RFFIContext { + @CompilationFinal private static boolean hasAccessLock; + private static ReentrantLock accessLock; + TruffleNFI_Context() { super(new TruffleNFI_C(), new TruffleNFI_Base(), new TruffleNFI_Call(), new TruffleNFI_DLL(), new TruffleNFI_UserRng(), new TruffleNFI_Zip(), new TruffleNFI_PCRE(), new TruffleNFI_Lapack(), new TruffleNFI_Stats(), new TruffleNFI_Tools(), new TruffleNFI_REmbed(), new TruffleNFI_Misc()); @@ -231,6 +237,7 @@ final class TruffleNFI_Context extends RFFIContext { @Override public ContextState initialize(RContext context) { RFFIUtils.initializeTracing(); + initializeLock(); if (traceEnabled()) { traceDownCall("initialize"); } @@ -266,6 +273,13 @@ final class TruffleNFI_Context extends RFFIContext { } } + private static synchronized void initializeLock() { + hasAccessLock = FastROptions.SynchronizeNativeCode.getBooleanValue(); + if (hasAccessLock && accessLock == null) { + accessLock = new ReentrantLock(); + } + } + @Override public void beforeDispose(RContext context) { switch (context.getKind()) { @@ -302,4 +316,30 @@ final class TruffleNFI_Context extends RFFIContext { public DLLInfo getRLibDLLInfo() { return rlibDLLInfo; } + + @Override + public void beforeUpcall(boolean canRunGc) { + super.beforeUpcall(canRunGc); + if (hasAccessLock) { + acquireLock(); + } + } + + @Override + public void afterUpcall(boolean canRunGc) { + super.afterUpcall(canRunGc); + if (hasAccessLock) { + releaseLock(); + } + } + + @TruffleBoundary + private void acquireLock() { + accessLock.lock(); + } + + @TruffleBoundary + private void releaseLock() { + accessLock.unlock(); + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java index 982d68f8efb80f69c549df0d455d1b7be7985137..090cd5aa987d71ee1ac1da2c7155bc2e7643cdd2 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java @@ -61,6 +61,7 @@ public enum FastROptions { EmitTmpDir("The directory where to allocate temporary files with deparsed source code.", null, true), EmitTmpHashed("Use an SHA-256 hash as file name to reduce temporary file creation.", true), SpawnUsesPolyglot("use PolyglotEngine for .fastr.context.spwan", false), + SynchronizeNativeCode("allow only one thread to enter packages' native code", false), // Promises optimizations EagerEval("If enabled, overrides all other EagerEval switches (see EagerEvalHelper)", false),