Skip to content
Snippets Groups Projects
Commit b14f9cc2 authored by Stepan Sindelar's avatar Stepan Sindelar
Browse files

[GR-6629] NFI Context can deal with being accessed from multiple threads.

PullRequest: fastr/1258
parents 1b08727c 89af22dd
No related branches found
No related tags found
No related merge requests found
...@@ -186,13 +186,14 @@ final class TruffleNFI_Context extends RFFIContext { ...@@ -186,13 +186,14 @@ final class TruffleNFI_Context extends RFFIContext {
} }
} }
private void initCallbacksAddress() { @TruffleBoundary
private long initCallbacksAddress() {
// get the address of the native thread local // get the address of the native thread local
try { try {
Node bind = Message.createInvoke(1).createNode(); Node bind = Message.createInvoke(1).createNode();
Node executeNode = Message.createExecute(1).createNode(); Node executeNode = Message.createExecute(1).createNode();
TruffleObject getCallbacksAddressFunction = (TruffleObject) ForeignAccess.sendInvoke(bind, DLL.findSymbol("Rinternals_getCallbacksAddress", null).asTruffleObject(), "bind", "(): sint64"); TruffleObject getCallbacksAddressFunction = (TruffleObject) ForeignAccess.sendInvoke(bind, DLL.findSymbol("Rinternals_getCallbacksAddress", null).asTruffleObject(), "bind", "(): sint64");
callbacksAddress = (long) ForeignAccess.sendExecute(executeNode, getCallbacksAddressFunction); return (long) ForeignAccess.sendExecute(executeNode, getCallbacksAddressFunction);
} catch (InteropException ex) { } catch (InteropException ex) {
throw RInternalError.shouldNotReachHere(ex); throw RInternalError.shouldNotReachHere(ex);
} }
...@@ -222,22 +223,47 @@ final class TruffleNFI_Context extends RFFIContext { ...@@ -222,22 +223,47 @@ final class TruffleNFI_Context extends RFFIContext {
} }
private long callbacks; private long callbacks;
@CompilationFinal private boolean singleThreadOnly = true;
@CompilationFinal private long callbacksAddressThread;
@CompilationFinal private long callbacksAddress; @CompilationFinal private long callbacksAddress;
private long lastCallbacksAddressThread;
private long lastCallbacksAddress;
private long pushCallbacks() { private long pushCallbacks() {
if (callbacksAddress == 0) { if (callbacksAddress == 0) {
CompilerDirectives.transferToInterpreterAndInvalidate(); CompilerDirectives.transferToInterpreterAndInvalidate();
initCallbacksAddress(); callbacksAddress = initCallbacksAddress();
callbacksAddressThread = Thread.currentThread().getId();
} }
long oldCallbacks = UnsafeAdapter.UNSAFE.getLong(callbacksAddress);
assert callbacks != 0L; assert callbacks != 0L;
assert callbacksAddress != 0L; if (singleThreadOnly && callbacksAddressThread == Thread.currentThread().getId()) {
UnsafeAdapter.UNSAFE.putLong(callbacksAddress, callbacks); // Fast path for contexts used only from a single thread
long oldCallbacks = UnsafeAdapter.UNSAFE.getLong(callbacksAddress);
assert callbacksAddress != 0L;
UnsafeAdapter.UNSAFE.putLong(callbacksAddress, callbacks);
return oldCallbacks;
}
// Slow path: cache the address, but reinitialize it if the thread has changed, without
// transfer to interpreter this time.
boolean reinitialize = singleThreadOnly || lastCallbacksAddressThread != Thread.currentThread().getId();
if (singleThreadOnly) {
CompilerDirectives.transferToInterpreterAndInvalidate();
singleThreadOnly = false;
}
if (reinitialize) {
lastCallbacksAddress = initCallbacksAddress();
lastCallbacksAddressThread = Thread.currentThread().getId();
}
long oldCallbacks = UnsafeAdapter.UNSAFE.getLong(lastCallbacksAddress);
assert lastCallbacksAddress != 0L;
assert lastCallbacksAddressThread == Thread.currentThread().getId();
UnsafeAdapter.UNSAFE.putLong(lastCallbacksAddress, callbacks);
return oldCallbacks; return oldCallbacks;
} }
private void popCallbacks(long beforeValue) { private void popCallbacks(long beforeValue) {
assert UnsafeAdapter.UNSAFE.getLong(callbacksAddress) == callbacks : "invalid nesting of native calling contexts"; assert !singleThreadOnly || UnsafeAdapter.UNSAFE.getLong(callbacksAddress) == callbacks : "invalid nesting of native calling contexts";
assert singleThreadOnly || UnsafeAdapter.UNSAFE.getLong(lastCallbacksAddress) == callbacks : "invalid nesting of native calling contexts";
UnsafeAdapter.UNSAFE.putLong(callbacksAddress, beforeValue); UnsafeAdapter.UNSAFE.putLong(callbacksAddress, beforeValue);
} }
......
...@@ -30,11 +30,4 @@ import com.oracle.truffle.r.runtime.data.RFunction; ...@@ -30,11 +30,4 @@ import com.oracle.truffle.r.runtime.data.RFunction;
public abstract class TruffleRLanguage extends TruffleLanguage<RContext> { public abstract class TruffleRLanguage extends TruffleLanguage<RContext> {
public abstract HashMap<String, RFunction> getBuiltinFunctionCache(); public abstract HashMap<String, RFunction> getBuiltinFunctionCache();
@Override
protected boolean isThreadAccessAllowed(Thread thread, boolean singleThreaded) {
// FastR does not support access to a single context from multiple threads, mainly because
// it has to maintain thread local variables on the native side.
return Thread.currentThread() == thread;
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment