diff --git a/examples/jse/SampleJseMain.java b/examples/jse/SampleJseMain.java index f706ce2d..b6ac1c1b 100644 --- a/examples/jse/SampleJseMain.java +++ b/examples/jse/SampleJseMain.java @@ -1,18 +1,22 @@ - import org.luaj.vm2.Globals; import org.luaj.vm2.LuaValue; import org.luaj.vm2.lib.jse.JsePlatform; +/** Simple program showing the minimal Java program to launch a script. */ public class SampleJseMain { - public static void main(String[] args) throws Exception { String script = "examples/lua/hello.lua"; // create an environment to run in - Globals _G = JsePlatform.standardGlobals(); - _G.loadFile(script).arg1().call( LuaValue.valueOf(script) ); + Globals globals = JsePlatform.standardGlobals(); + + // Use the convenience function on the globals to load a chunk. + LuaValue chunk = globals.loadFile(script); + + // Use any of the "call()" or "invoke()" functions directly on the chunk. + chunk.call( LuaValue.valueOf(script) ); } diff --git a/examples/jse/SampleMultiThreaded.java b/examples/jse/SampleMultiThreaded.java new file mode 100644 index 00000000..486fa806 --- /dev/null +++ b/examples/jse/SampleMultiThreaded.java @@ -0,0 +1,54 @@ +import java.io.IOException; + +import org.luaj.vm2.Globals; +import org.luaj.vm2.lib.jse.JsePlatform; + +/** Simple toy program illustrating how to run Luaj in multiple threads. + * + * By creating separate Globals in each thread, scripts can be run in each thread. + * + * However note the following: + * - type-related metatables such as LuaNumber.s_metatable are shared by all threads, so are not thread-safe. + * - creating additional threads within a Java element called by lua could result in shared access to globals. + */ +public class SampleMultiThreaded { + + static class Runner implements Runnable { + final String script1, script2; + Runner(String script1, String script2) { + this.script1 = script1; + this.script2 = script2; + } + public void run() { + try { + // Each thread must have its own Globals. + Globals g = JsePlatform.standardGlobals(); + + // Once a Globals is created, it can and should be reused + // within the same thread. + g.loadFile(script1).call(); + g.loadFile(script2).call(); + + } catch ( Exception e ) { + e.printStackTrace(); + } + } + } + + public static void main(final String[] args) throws IOException { + final String script1 = args.length > 0? args[0]: "test/lua/perf/nsieve.lua"; + final String script2 = args.length > 1? args[1]: "test/lua/perf/binarytrees.lua"; + try { + Thread[] thread = new Thread[10]; + for (int i = 0; i < thread.length; ++i) + thread[i] = new Thread(new Runner(script1, script2),"Runner-"+i); + for (int i = 0; i < thread.length; ++i) + thread[i].start(); + for (int i = 0; i < thread.length; ++i) + thread[i].join(); + System.out.println("done"); + } catch ( Exception e ) { + e.printStackTrace(); + } + } +} diff --git a/src/core/org/luaj/vm2/Globals.java b/src/core/org/luaj/vm2/Globals.java index 923df0ca..ee0280ee 100644 --- a/src/core/org/luaj/vm2/Globals.java +++ b/src/core/org/luaj/vm2/Globals.java @@ -56,36 +56,59 @@ import org.luaj.vm2.lib.ResourceFinder; */ public class Globals extends LuaTable { + /** The current default input stream. */ public InputStream STDIN = null; + + /** The current default output stream. */ public PrintStream STDOUT = System.out; + + /** The current default error stream. */ public PrintStream STDERR = System.err; + /** The installed ResourceFinder for looking files by name. */ public ResourceFinder FINDER; + /** The installed compiler. */ public LuaCompiler compiler = null; + /** The currently running thread. Should not be changed by non-library code. */ + public LuaThread running = new LuaThread(this); + + /** The BaseLib instance loaded into this Globals */ public BaseLib baselib; - public LuaValue errorfunc; - - public LuaThread running_thread = new LuaThread(this); - - public DebugLib debuglib; - + /** The PackageLib instance loaded into this Globals */ public PackageLib package_; + /** The DebugLib instance loaded into this Globals, or null if debugging is not enabled */ + public DebugLib debuglib; + + /** The current error handler for this Globals */ + public LuaValue errorfunc; + + /** Check that this object is a Globals object, and return it, otherwise throw an error. */ public Globals checkglobals() { return this; } - public Varargs loadFile(String filename) { - return baselib.loadFile(filename, "bt", this); + /** Convenience function for loading a file. + * @param filename Name of the file to load. + * @return LuaValue that can be call()'ed or invoke()'ed. + * @throws LuaError if the file could not be loaded. + */ + public LuaValue loadFile(String filename) { + Varargs v = baselib.loadFile(filename, "bt", this); + return !v.isnil(1)? v.arg1(): error(v.arg(2).tojstring()); } + /** Function which yields the current thread. + * @param args Arguments to supply as return values in the resume function of the resuming thread. + * @return Values supplied as arguments to the resume() call that reactivates this thread. + */ public Varargs yield(Varargs args) { - if (running_thread == null || running_thread.isMainThread()) + if (running == null || running.isMainThread()) throw new LuaError("cannot yield main thread"); - final LuaThread.State s = running_thread.state; + final LuaThread.State s = running.state; return s.lua_yield(args); } diff --git a/src/core/org/luaj/vm2/LuaThread.java b/src/core/org/luaj/vm2/LuaThread.java index 32071c1b..a9450437 100644 --- a/src/core/org/luaj/vm2/LuaThread.java +++ b/src/core/org/luaj/vm2/LuaThread.java @@ -192,9 +192,9 @@ public class LuaThread extends LuaValue { } public synchronized Varargs lua_resume(LuaThread new_thread, Varargs args) { - LuaThread previous_thread = globals.running_thread; + LuaThread previous_thread = globals.running; try { - globals.running_thread = new_thread; + globals.running = new_thread; this.args = args; if (this.status == STATUS_INITIAL) { this.status = STATUS_RUNNING; @@ -215,9 +215,9 @@ public class LuaThread extends LuaValue { this.args = LuaValue.NONE; this.result = LuaValue.NONE; this.error = null; - globals.running_thread = previous_thread; + globals.running = previous_thread; if (previous_thread != null) - globals.running_thread.state.status =STATUS_RUNNING; + globals.running.state.status =STATUS_RUNNING; } } diff --git a/src/core/org/luaj/vm2/lib/CoroutineLib.java b/src/core/org/luaj/vm2/lib/CoroutineLib.java index d7249d51..abd6c566 100644 --- a/src/core/org/luaj/vm2/lib/CoroutineLib.java +++ b/src/core/org/luaj/vm2/lib/CoroutineLib.java @@ -93,7 +93,7 @@ public class CoroutineLib extends OneArgFunction { final class running extends VarArgFunction { public Varargs invoke(Varargs args) { - final LuaThread r = globals.running_thread; + final LuaThread r = globals.running; return varargsOf(r, valueOf(r.isMainThread())); } } diff --git a/src/core/org/luaj/vm2/lib/DebugLib.java b/src/core/org/luaj/vm2/lib/DebugLib.java index 0b2635fc..fbc4c533 100644 --- a/src/core/org/luaj/vm2/lib/DebugLib.java +++ b/src/core/org/luaj/vm2/lib/DebugLib.java @@ -129,7 +129,7 @@ public class DebugLib extends OneArgFunction { // debug.gethook ([thread]) final class gethook extends VarArgFunction { public Varargs invoke(Varargs args) { - LuaThread t = args.narg() > 0 ? args.checkthread(1): globals.running_thread; + LuaThread t = args.narg() > 0 ? args.checkthread(1): globals.running; return varargsOf( t.hookfunc != null? t.hookfunc: NIL, valueOf((t.hookcall?"c":"")+(t.hookline?"l":"")+(t.hookrtrn?"r":"")), @@ -141,7 +141,7 @@ public class DebugLib extends OneArgFunction { final class getinfo extends VarArgFunction { public Varargs invoke(Varargs args) { int a=1; - LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread; + LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running; LuaValue func = args.arg(a++); String what = args.optjstring(a++, "flnStu"); DebugLib.CallStack callstack = callstack(thread); @@ -204,7 +204,7 @@ public class DebugLib extends OneArgFunction { final class getlocal extends VarArgFunction { public Varargs invoke(Varargs args) { int a=1; - LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread; + LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running; int level = args.checkint(a++); int local = args.checkint(a++); CallFrame f = callstack(thread).getCallFrame(level); @@ -255,7 +255,7 @@ public class DebugLib extends OneArgFunction { final class sethook extends VarArgFunction { public Varargs invoke(Varargs args) { int a=1; - LuaThread t = args.isthread(a)? args.checkthread(a++): globals.running_thread; + LuaThread t = args.isthread(a)? args.checkthread(a++): globals.running; LuaValue func = args.optfunction(a++, null); String str = args.optjstring(a++,""); int count = args.optint(a++,0); @@ -279,7 +279,7 @@ public class DebugLib extends OneArgFunction { final class setlocal extends VarArgFunction { public Varargs invoke(Varargs args) { int a=1; - LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread; + LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running; int level = args.checkint(a++); int local = args.checkint(a++); LuaValue value = args.arg(a++); @@ -339,7 +339,7 @@ public class DebugLib extends OneArgFunction { final class traceback extends VarArgFunction { public Varargs invoke(Varargs args) { int a=1; - LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread; + LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running; String message = args.optjstring(a++, null); int level = args.optint(a++,1); String tb = callstack(thread).traceback(level); @@ -379,7 +379,7 @@ public class DebugLib extends OneArgFunction { } public void onCall(LuaFunction f) { - LuaThread t = globals.running_thread; + LuaThread t = globals.running; if (t.inhook) return; callstack().onCall(f); if (t.hookcall && t.hookfunc != null) @@ -387,7 +387,7 @@ public class DebugLib extends OneArgFunction { } public void onCall(LuaClosure c, Varargs varargs, LuaValue[] stack) { - LuaThread t = globals.running_thread; + LuaThread t = globals.running; if (t.inhook) return; callstack().onCall(c, varargs, stack); if (t.hookcall && t.hookfunc != null) @@ -395,7 +395,7 @@ public class DebugLib extends OneArgFunction { } public void onInstruction(int pc, Varargs v, int top) { - LuaThread t = globals.running_thread; + LuaThread t = globals.running; if (t.inhook) return; callstack().onInstruction(pc, v, top); if (t.hookfunc == null) return; @@ -412,7 +412,7 @@ public class DebugLib extends OneArgFunction { } public void onReturn() { - LuaThread t = globals.running_thread; + LuaThread t = globals.running; if (t.inhook) return; callstack().onReturn(); if (t.hookcall && t.hookfunc != null) @@ -424,7 +424,7 @@ public class DebugLib extends OneArgFunction { } void callHook(LuaValue type, LuaValue arg) { - LuaThread t = globals.running_thread; + LuaThread t = globals.running; t.inhook = true; try { t.hookfunc.call(type, arg); @@ -436,7 +436,7 @@ public class DebugLib extends OneArgFunction { } CallStack callstack() { - return callstack(globals.running_thread); + return callstack(globals.running); } CallStack callstack(LuaThread t) { diff --git a/test/java/org/luaj/luajc/TestLuaJ.java b/test/java/org/luaj/luajc/TestLuaJ.java index 04edb2a9..c72a7c71 100644 --- a/test/java/org/luaj/luajc/TestLuaJ.java +++ b/test/java/org/luaj/luajc/TestLuaJ.java @@ -24,7 +24,6 @@ package org.luaj.luajc; import java.io.ByteArrayInputStream; import java.io.InputStream; -import org.luaj.vm2.LuaClosure; import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaValue; import org.luaj.vm2.Print; @@ -56,12 +55,17 @@ public class TestLuaJ { // compile into a chunk, or load as a class InputStream is = new ByteArrayInputStream( script.getBytes() ); - LuaValue chunk = LuaC.instance.load(is, "script",_G); - chunk.call(); + LuaValue chunk = LuaC.instance.load(is, "script", _G); + + // The loaded chunk should be a closure, which contains the prototype. + print( chunk.checkclosure().p ); + + // The chunk can be called with arguments as desired. + chunk.call(LuaValue.ZERO, LuaValue.ONE); } private static void print(Prototype p) { - System.out.println("--- "+p.is_vararg); + System.out.println("--- "+p); Print.printCode(p); if (p.p!=null) for ( int i=0,n=p.p.length; i