Skip to content

Instantly share code, notes, and snippets.

@Brunomachadob
Last active September 17, 2018 14:14
Show Gist options
  • Save Brunomachadob/5301d34f78a4b3554dc0fbd398594c5d to your computer and use it in GitHub Desktop.
Save Brunomachadob/5301d34f78a4b3554dc0fbd398594c5d to your computer and use it in GitHub Desktop.
Multi threaded access requested by thread Thread[http-nio-8778-exec-1,5,main] but is not allowed for language(s) js

Problem with multi threaded systems on GraalJS

This is an oversimplified example extracted from ThrustJS and it's server lib http to show the result when we try to use Apache Tomcat to serve an API, using Nashorn and GraalJS.

When we navigate to http://localhost:8778/servlet using GraalJS we get an exception:

java.lang.IllegalStateException: Multi threaded access requested by thread Thread[http-nio-8778-exec-1,5,main] but is not allowed for language(s) js.
	com.oracle.truffle.polyglot.PolyglotContextImpl.throwDeniedThreadAccess(PolyglotContextImpl.java:545)
	com.oracle.truffle.polyglot.PolyglotContextImpl.checkAllThreadAccesses(PolyglotContextImpl.java:464)
	com.oracle.truffle.polyglot.PolyglotContextImpl.enterThreadChanged(PolyglotContextImpl.java:383)
	com.oracle.truffle.polyglot.PolyglotContextImpl.enter(PolyglotContextImpl.java:344)
	com.oracle.truffle.polyglot.PolyglotValue$PolyglotNode.execute(PolyglotValue.java:512)
	org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callProxy(OptimizedCallTarget.java:269)
	org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callRoot(OptimizedCallTarget.java:258)
	org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callBoundary(OptimizedCallTarget.java:248)
	org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.doInvoke(OptimizedCallTarget.java:230)
	org.graalvm.compiler.truffle.runtime.GraalTVMCI.callProfiled(GraalTVMCI.java:86)
	com.oracle.truffle.api.impl.Accessor.callProfiled(Accessor.java:702)
	com.oracle.truffle.polyglot.VMAccessor.callProfiled(VMAccessor.java:75)
	com.oracle.truffle.polyglot.PolyglotValue$Interop.executeVoid(PolyglotValue.java:1370)
	org.graalvm.polyglot.Value.executeVoid(Value.java:333)
	javax.servlet.http.HttpServlet$$JSJavaAdapter.service(Unknown Source)

Dependencies

Obs: Change the 6th line of the example with the correct path to the tomcat jar.

Running with Nashorn

$JAVA_HOME/bin/jjs -strict --language=es6 tomcatServer.js

Running with GraalJS

$GRAAL_HOME/bin/js --jvm --js.nashorn-compat=true --strict tomcatServer.js
const File = Java.type('java.io.File')
const ClassLoader = Java.type("java.lang.ClassLoader")
const URL = Java.type("java.net.URL")
const URLClassLoader = Java.type("java.net.URLClassLoader")
classLoadJar('/home/brunomachadob/git/http/test/.lib/jars/tomcat-embed-core-9.0.2.jar')
const HttpServlet = Java.type("javax.servlet.http.HttpServlet")
const Tomcat = Java.type("org.apache.catalina.startup.Tomcat")
init()
function init() {
const port = 8778;
const tomcat = new Tomcat()
const ctx = tomcat.addContext("", new File(__DIR__).getAbsolutePath())
ctx.setAllowCasualMultipartParsing(true)
let ServletClass = Java.extend(HttpServlet, {
service: function (request, response) {
response.setStatus(200)
response.setContentType('text/html; charset=utf-8')
response.getWriter().println('MySimpleServletResponse')
response.flushBuffer()
}
});
Tomcat.addServlet(ctx, "myServlet", new ServletClass())
ctx.addServletMappingDecoded('/servlet', "myServlet")
tomcat.setPort(port)
const connector = tomcat.getConnector();
connector.setProperty("compression", "on");
connector.setProperty("compressionMinSize", '1024');
connector.setProperty("compressableMimeType", 'text/html,text/xml,text/css,application/json,application/javascript');
tomcat.start()
print("Running on port " + port + "...")
tomcat.getServer().await()
}
function classLoadJar(jarPath) {
try {
const jarFile = new File(jarPath)
if (jarFile.exists()) {
const method = URLClassLoader.class.getDeclaredMethod('addURL', URL.class)
method.setAccessible(true)
method.invoke(ClassLoader.getSystemClassLoader(), jarFile.toURI().toURL())
} else {
throw new Error('File not found')
}
} catch (e) {
throw new Error("[ERROR] Cannot load jar '" + jarPath + "': " + e.message)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment