public static void resume(LuaInterop lua) { LuaThread co = lua.Argument <LuaThread>(0); co.BeginResume(lua.ArgumentCount - 1); for (int argument = 0; argument < lua.ArgumentCount - 1; ++argument) { co.ResumeArgument(argument, lua.Argument(argument)); } int resultCount; try { resultCount = co.Resume(LuaThread.VarResult); } catch (Exception e) { lua.BeginReturn(2); lua.ReturnResult(0, false); lua.ReturnResult(1, e.Message); lua.EndReturn(); return; } lua.BeginReturn(resultCount + 1); lua.ReturnResult(0, true); for (int result = 0; result < resultCount; ++result) { lua.ReturnResult(result + 1, co.ResumeResult(result)); } co.EndResume(); lua.EndReturn(); }
internal override void Call(LuaThread thread, int frameBase, int argumentCount, int resultCount) { LuaInterop lua = new LuaInterop(thread, frameBase, argumentCount, resultCount); action(); lua.Return(); }
internal override void Resume(LuaThread thread) { // We should be the last function in the stack (at index 0). Frame frame = thread.UnwoundFrames[thread.UnwoundFrames.Count - 1]; thread.UnwoundFrames.RemoveAt(thread.UnwoundFrames.Count - 1); // The resume code will have altered our arguments to correspond to the // arguments of the resume call (always the correct number of results). // The resume code can't simulate a return directly because that would // overwrite the value at the frame base, which references the yeild // function. // Find number of arguments/results. int resultCount; if (frame.ResultCount != -1) { resultCount = frame.ResultCount; } else { resultCount = thread.Top - frame.FrameBase; thread.Top = -1; thread.Top = frame.FrameBase + resultCount - 1; } // Copy down. for (int result = 0; result < resultCount; ++result) { thread.Stack[frame.FrameBase + result] = thread.Stack[frame.FrameBase + 1 + result]; } }
internal LuaInterop(LuaThread thread, int frameBase, int argumentCount, int resultCount) { this.thread = thread; this.frameBase = frameBase; this.argumentCount = argumentCount; this.resultCount = resultCount; }
public static bool GetResult(out LuaThread res) { bool ret = false; if (s_ResIndex > s_ResNum) { res = null; return(ret); } int from = s_From + s_ResIndex; ++s_ResIndex; var L = s_Func.L; LuaTypes type = LuaDLL.lua_type(L, from); switch (type) { case LuaTypes.LUA_TTHREAD: { LuaThread lt; LuaObject.checkType(L, from, out lt); res = lt; ret = true; break; } default: res = null; break; } return(ret); }
[TestMethod] public void Native() { using (var lua = new Lua()) { var calls = new List <string>(4); LuaThread thread = null; lua.RegisterFunction("callback", new Action <string>(s => { calls.Add(s); Assert.AreEqual(LuaCoStatus.Running, thread.Status); })); using (var body = lua.LoadString(@" assert(... == 'start') callback('B') assert(coroutine.yield('yield') == 'resume') callback('D') return 'return' " )) thread = lua.NewThread(body); using (thread) { Assert.AreEqual(LuaCoStatus.Suspended, thread.Status); calls.Add("A"); CollectionAssert.AreEqual(new object[] { "yield" }, thread.Resume("start")); Assert.AreEqual(LuaCoStatus.Suspended, thread.Status); calls.Add("C"); CollectionAssert.AreEqual(new object[] { "return" }, thread.Resume("resume")); Assert.AreEqual(LuaCoStatus.Dead, thread.Status); calls.Add("E"); } Assert.AreEqual("ABCDE", string.Concat(calls.ToArray())); } }
private void CloseThread() { if (thread != null) { thread.Dispose(); thread = null; } }
public static void Spawn(MulticastDelegate f) { var sw = Stopwatch.StartNew(); var e = new WaitExecution(CurrentScript, (LuaThread)LuaThread.running().Values[0], 0, () => f.FastDynamicInvoke(sw.Elapsed.TotalSeconds, Game.Workspace.DistributedGameTime)); ExecutionQueue.Enqueue(e); }
static int TimeoutAsync(IntPtr state) { IntPtr co = LuaStack.GetThread(state, 1); float time = (float)LuaStack.GetNumber(state, 2); Observable.Timer(TimeSpan.FromSeconds(time)).Subscribe(x => { LuaThread.ResumeSubthread(co, state, 0, out _); }); return(0); }
private void OnDestroy() { if (this.thread != null) { this.thread.Dispose(); this.thread = null; } this.state.Dispose(); this.state = null; }
// Lifetime. public void Close() { if (thread == null) { throw new InvalidOperationException(); } value = thread.Stack[stackIndex]; thread = null; stackIndex = -1; }
void OnDestroy() { if (thread != null) { thread.Dispose(); thread = null; } state.Dispose(); state = null; }
void OnApplicationQuit() { if (thread != null) { thread.Dispose(); thread = null; } state.Dispose(); state = null; Application.logMessageReceived -= ShowTips; }
public static IEnumerator EnumLuaCoroutine(LuaFunc lfunc) { if (lfunc != null) { LuaThread lthd = new LuaThread(lfunc); return(EnumLuaCoroutine(lthd)); } else { return(GetEmptyEnumerator()); } }
public void printidentity() { var identity = GetIdentity(LuaThread.running()); if (identity.HasValue) { OnPrint($"Current identity is {(byte)identity.Value} ({identity})"); } else { OnPrint("This thread has no identity."); } }
// Update is called once per frame void Update() { if (!co.IsDead()) { co.Resume(); } else { print("Coroutine has exited."); // In order to destroy a coroutine (but not the function in lua, just the coroutine stack instance) simply allow C# to clean up the wrapped object co = null; } }
// Update is called once per frame void Update() { if( !co.IsDead() ) { co.Resume(); } else { print("Coroutine has exited."); // In order to destroy a coroutine (but not the function in lua, just the coroutine stack instance) simply allow C# to clean up the wrapped object co = null; } }
public static double Wait(double seconds) { seconds = Math.Max(seconds, LuaSettings.DefaultWaitTime); var sw = Stopwatch.StartNew(); var e = new WaitExecution(CurrentScript, (LuaThread)LuaThread.running().Values[0], seconds); ExecutionQueue.Enqueue(e); YieldThread(); return(sw.Elapsed.TotalSeconds); }
public static string status(LuaThread co) { switch (co.Status) { case LuaThreadStatus.Running: return("running"); case LuaThreadStatus.Suspended: return("suspended"); case LuaThreadStatus.Normal: return("normal"); case LuaThreadStatus.Dead: return("dead"); } throw new ArgumentException(); }
private void OnApplicationQuit() { if (thread != null) { thread.Dispose(); thread = null; } state.Dispose(); state = null; #if UNITY_5 || UNITY_2017 || UNITY_2018 Application.logMessageReceived -= ShowTips; #else Application.RegisterLogCallback(null); #endif }
void Start() { LuaState l = new LuaState(); // First run the script so the function is created l.DoString(Encoding.UTF8.GetBytes(script)); // Get the function object LuaFunction f = l.GetFunction("myFunc"); // Create a paused lua coroutine object from the parent state and a function co = new LuaThread(l, f); // The coroutine needs to be resumed each frame, since it is yielding each frame, alternatively you could only resume it on conditions in C# instead co.Start(); }
void Start () { state = new LuaState(); state.Start(); state.DoString(script); LuaFunction func = state.GetFunction("Test"); func.BeginPCall(); func.PCall(); thread = func.CheckLuaThread(); func.EndPCall(); func.Dispose(); func = null; thread.Resume(10); }
// Use this for initialization void Start() { LuaState l = new LuaState(); LuaScriptMgr._translator = l.GetTranslator(); // First run the script so the function is created l.DoString(script); // Get the function object LuaFunction f = l.GetFunction("myFunc"); // Create a paused lua coroutine object from the parent state and a function co = new LuaThread(l, f); // The coroutine needs to be resumed each frame, since it is yielding each frame, alternatively you could only resume it on conditions in C# instead co.Start(); }
void Start() { state = new LuaState(); state.Start(); state.DoString(script); LuaFunction func = state.GetFunction("Test"); func.BeginPCall(); func.PCall(); thread = func.CheckLuaThread(); func.EndPCall(); func.Dispose(); func = null; thread.Resume(10); }
public double wait() { var thread = (LuaThread)LuaThread.running().Values[0]; var sw = Stopwatch.StartNew(); Action callback = null; callback = () => { ScriptService.ResumeThread(thread); Disconnect(callback); }; Connect(callback); ScriptService.YieldThread(); return(sw.Elapsed.TotalSeconds); }
private void OnGUI() { if (GUI.Button(new Rect(10f, 10f, 120f, 40f), "Resume Thead")) { if (this.thread != null && this.thread.Resume(new object[] { true }) == 1) { object[] result = this.thread.GetResult(); Debugger.Log("lua yield: " + result[0]); } } else if (GUI.Button(new Rect(10f, 60f, 120f, 40f), "Close Thread") && this.thread != null) { this.thread.Dispose(); this.thread = null; } }
private void Start() { this.state = new LuaState(); this.state.Start(); this.state.LogGC = true; this.state.DoString(this.script, "LuaState.cs"); LuaFunction function = this.state.GetFunction("Test", true); function.BeginPCall(); function.PCall(); this.thread = function.CheckLuaThread(); this.thread.name = "LuaThread"; function.EndPCall(); function.Dispose(); this.thread.Resume(new object[] { 10 }); }
void OnGUI() { if (GUI.Button(new Rect(10, 10, 120, 40), "Resume Thead")) { if (thread != null && thread.Resume(true) == (int)LuaThreadStatus.LUA_YIELD) { object[] objs = thread.GetResult(); Debugger.Log("lua yield: " + objs[0]); } } else if (GUI.Button(new Rect(10, 60, 120, 40), "Close Thread")) { if (thread != null) { thread.Dispose(); thread = null; } } }
/// <summary> /// Asserts that the calling thread has the required identity. /// </summary> /// <param name="target">The required identity.</param> /// <param name="condition"> /// If true, an exception is thrown when the thread does not meet target identity. /// If false, an exception is thrown when the thread does the target identity. /// </param> internal static void AssertIdentity(ScriptIdentity target, bool condition = true) { var thread = LuaThread.running(); var identity = GetIdentity(thread); if (identity == null || (target.HasFlag(identity) == condition)) { return; // threads with no identity are unrestricted } #if DEBUG var frame = new StackFrame(1); var method = frame.GetMethod(); var type = method.DeclaringType; var name = method.Name; throw new SecurityException($"Method {type}.{name} requires identity level {target}. (Current: {identity})"); #else throw new SecurityException(); #endif }
public Instance WaitForChild(string name, double?timeout = null) { if (string.IsNullOrEmpty(name)) { throw new ArgumentException("Name parameter cannot be empty."); } foreach (var c in Children) { if (c.Name == name) { return(c); } } var thread = (LuaThread)LuaThread.running().Values[0]; lock (Locker) { List <LuaThread> threads; if (_waitForChildList.TryGetValue(name, out threads)) { threads.Add(thread); } else { _waitForChildList.Add(name, new List <LuaThread>(new[] { thread })); } } Timer timer = null; var timerAction = new TimerCallback(obj => { ScriptService.ResumeThread(thread); timer?.Dispose(); }); timer = timeout == null ? new Timer(timerAction) : new Timer(timerAction, null, (int)(timeout * 1000), -1); ScriptService.YieldThread(); return(FindFirstChild(name)); }
void OnGUI() { GUI.Label(new Rect(Screen.width / 2 - 300, Screen.height / 2 - 200, 600, 400), tips); if (GUI.Button(new Rect(10, 50, 120, 40), "Resume Thread")) { int ret = -1; if (thread != null && thread.Resume(true, out ret) == (int)LuaThreadStatus.LUA_YIELD) { Debugger.Log("lua yield:" + ret); } } else if (GUI.Button(new Rect(10, 150, 120, 40), "Close thread ")) { if (thread != null) { thread.Dispose(); thread = null; } } }
void OnGUI() { GUI.Label(new Rect(Screen.width / 2 - 300, Screen.height / 2 - 200, 600, 400), tips); if (GUI.Button(new Rect(10, 50, 120, 40), "Resume Thead")) { if (thread != null && thread.Resume(true) == (int)LuaThreadStatus.LUA_YIELD) { object[] objs = thread.GetResult(); Debugger.Log("lua yield: " + objs[0]); } } else if (GUI.Button(new Rect(10, 150, 120, 40), "Close Thread")) { if (thread != null) { thread.Dispose(); thread = null; } } }
void Start() { Application.logMessageReceived += ShowTips; new LuaResLoader(); state = new LuaState(); state.Start(); state.LogGC = true; state.DoString(script); LuaFunction func = state.GetFunction("Test"); func.BeginPCall(); func.PCall(); thread = func.CheckLuaThread(); thread.name = "LuaThread"; func.EndPCall(); func.Dispose(); func = null; thread.Resume(10); }
private object[] Run(LuaThread mainThread) { LuaThread thread = currentThread = mainThread; thread.Status = Thread.StatusType.Running; List<object> result = new List<object>(); ThreadResult tResult; Dictionary<LuaThread, LuaThread> calledBy = new Dictionary<LuaThread, LuaThread>(); do { EmptyFunc pushResults = delegate() { if (thread.func.returnsSaved >= 1) { thread.func.Top = thread.func.returnRegister + thread.func.returnsSaved - 1; for (int i = 0; i < thread.func.returnsSaved-1; ++i) { thread.func.stack[thread.func.returnRegister+i] = i < result.Count ? result[i] : Nil.Value; } } else { thread.func.Top = thread.func.returnRegister + result.Count; for (int i = 0; i < result.Count; ++i) { thread.func.stack[thread.func.returnRegister+i] = result[i]; } } }; do { try { tResult = thread.Run(); } catch(Exception ex) { tResult = new ThreadResult { Type = ThreadResult.ResultType.Error, Data = ex.ToString(), }; } if (tResult.Type == ThreadResult.ResultType.FunctionCall || tResult.Type == ThreadResult.ResultType.Error) { if (tResult.Type == ThreadResult.ResultType.FunctionCall) { try { var tResultF = (InternalClosure)tResult.Data; tResultF.Run(); currentThread = thread; //Pop results result = tResultF.GetResults(); } catch (Exception ex) { result = new List<object> { VMCommand.ERROR, ex.ToString() /*Error msg*/ }; } } else { //It was an error result = new List<object> { VMCommand.ERROR, tResult.Data /*Error msg*/ }; } if (result.Count != 0) { if (result[0] is System.Enum) { switch((VMCommand)result[0]) { //1: The closure case VMCommand.CO_CREATE: var newFunction = (FunctionClosure)((FunctionClosure)result[1]).CreateCallableInstance(); LuaThread newThread = new LuaThread(thread.func.env, newFunction, this); result.Clear(); result.Add(newThread); break; //1: the thread to resume //2+: args to the thread case VMCommand.CO_RESUME: calledBy.Add((LuaThread)result[1], thread); thread.Status = Thread.StatusType.Normal; thread = currentThread = (LuaThread)result[1]; thread.Status = Thread.StatusType.Running; if (!thread.Running) { for (int i = 2; i < result.Count; ++i) { thread.func.AddParam(result[i]); } continue; } //Else just pass them as return values to yield result.RemoveRange(0, 2); // Remove the command and the thread break; case VMCommand.CO_RUNNING: result.Clear(); if (calledBy.ContainsKey(thread)) { result.Add(thread); } else { result.Add(Nil.Value); } break; //1+: return values to resume case VMCommand.CO_YIELD: var caller = calledBy[thread]; calledBy.Remove(thread); thread.Status = Thread.StatusType.Suspended; thread = currentThread = caller; thread.Status = Thread.StatusType.Running; result.RemoveAt(0); // Remove command break; case VMCommand.PCALL: thread.func.errorHandler = true; break; //1: error msg case VMCommand.ERROR: //Pop all stacks until an error handler is found var stackTrace = new List<string>(); string errorMsg = string.Intern(thread.ErrorString + ": " + (string)result[1]); result[1] = errorMsg; FunctionClosure fc; do { fc = thread.PopFrame(); if (fc == null) { //Thread finished without handling the error, start unwinding the calling thread if (calledBy.Count == 0) { stackTrace.Add("\t" + thread.ErrorString + ": in main chunk"); //Last thread finished without handling the error, bailing out throw new LuaScriptException(errorMsg, stackTrace.ToArray()); } var callerThread = calledBy[thread]; calledBy.Remove(thread); thread = currentThread = callerThread; stackTrace.Add("\t" + thread.ErrorString + ": in lua thread"); continue; } else if (fc.errorHandler == true) break; stackTrace.Add("\t"+ thread.ErrorString +": in lua function"); } while (true); result[0] = false; break; } } } pushResults(); } } while(tResult.Type != ThreadResult.ResultType.Dead); thread.Status = Thread.StatusType.Dead; if (calledBy.Count == 0) break; result = thread.func.GetResults(); var prevThread = calledBy[thread]; calledBy.Remove(thread); thread = currentThread = prevThread; pushResults(); } while(true); return thread.func.stack.ToArray(); }