From 9aadc35329977fb1b57ad518c2130fffc8645a70 Mon Sep 17 00:00:00 2001 From: Alessandro Proto Date: Tue, 7 Mar 2023 22:09:05 +0100 Subject: [PATCH] Fix tasks crashing memory and stuff --- Capy64/Runtime/Libraries/GPU.cs | 8 +++- Capy64/Runtime/Libraries/HTTP.cs | 37 +++++----------- Capy64/Runtime/LuaState.cs | 23 +++++----- Capy64/Runtime/Objects/Task.cs | 72 +++++++++++++++++++------------- Capy64/Runtime/RuntimeManager.cs | 2 + 5 files changed, 74 insertions(+), 68 deletions(-) diff --git a/Capy64/Runtime/Libraries/GPU.cs b/Capy64/Runtime/Libraries/GPU.cs index 0d6117e..37de717 100644 --- a/Capy64/Runtime/Libraries/GPU.cs +++ b/Capy64/Runtime/Libraries/GPU.cs @@ -24,6 +24,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; +using System.Xml.Linq; namespace Capy64.Runtime.Libraries; @@ -527,7 +528,12 @@ public class GPU : IComponent Height = texture.Height, Width = texture.Width, }; - task.Fulfill(buffer); + + task.Fulfill(lk => + { + ObjectManager.PushObject(lk, buffer); + lk.SetMetaTable(GPUBufferMeta.ObjectType); + }); texture.Dispose(); }); diff --git a/Capy64/Runtime/Libraries/HTTP.cs b/Capy64/Runtime/Libraries/HTTP.cs index c45575c..3fefe02 100644 --- a/Capy64/Runtime/Libraries/HTTP.cs +++ b/Capy64/Runtime/Libraries/HTTP.cs @@ -25,6 +25,7 @@ using System.Net.Http; using System.Net.WebSockets; using System.Text; using System.Threading; +using System.Threading.Tasks; namespace Capy64.Runtime.Libraries; #nullable enable @@ -198,19 +199,15 @@ public class HTTP : IComponent var requestId = _requestId++; + var luaTask = TaskMeta.Push(L, "HTTPRequest"); + var reqTask = _httpClient.SendAsync(request); reqTask.ContinueWith(async (task) => { if (task.IsFaulted || task.IsCanceled) { - _game.LuaRuntime.QueueEvent("http_failure", LK => - { - LK.PushInteger(requestId); - LK.PushString(task.Exception?.Message); - - return 2; - }); + luaTask.Reject(task.Exception?.Message); return; } @@ -218,23 +215,15 @@ public class HTTP : IComponent var stream = await response.Content.ReadAsStreamAsync(); - _game.LuaRuntime.QueueEvent("http_response", LK => + luaTask.Fulfill(LK => { - // arg 1, request id - LK.PushInteger(requestId); - - // arg 2, response data - ObjectManager.PushObject(L, stream); - //L.PushObject(stream); - L.SetMetaTable(FileHandle.ObjectType); - /*if ((bool)options["binary"]) - BinaryReadHandle.Push(LK, new(stream)); - else - ReadHandle.Push(LK, new(stream));*/ - - // arg 3, response info LK.NewTable(); + LK.PushString("content"); + ObjectManager.PushObject(LK, stream); + LK.SetMetaTable(FileHandle.ObjectType); + LK.SetTable(-3); + LK.PushString("success"); LK.PushBoolean(response.IsSuccessStatusCode); LK.SetTable(-3); @@ -258,15 +247,9 @@ public class HTTP : IComponent } LK.SetTable(-3); - - return 3; - }); - }); - L.PushInteger(requestId); - return 1; } diff --git a/Capy64/Runtime/LuaState.cs b/Capy64/Runtime/LuaState.cs index e2b603d..c9750a8 100644 --- a/Capy64/Runtime/LuaState.cs +++ b/Capy64/Runtime/LuaState.cs @@ -26,7 +26,7 @@ namespace Capy64.Runtime; public class LuaState : IDisposable { public Lua Thread; - private readonly Lua _parent; + public readonly Lua Parent; private readonly ConcurrentQueue _queue = new(); @@ -36,25 +36,21 @@ public class LuaState : IDisposable public LuaState() { - _parent = new Lua(false) + Parent = new Lua(false) { Encoding = Encoding.UTF8, }; - Sandbox.OpenLibraries(_parent); - Sandbox.Patch(_parent); + Sandbox.OpenLibraries(Parent); + Sandbox.Patch(Parent); - Thread = _parent.NewThread(); + Thread = Parent.NewThread(); Thread.SetHook(LH_YieldTimeout, LuaHookMask.Count, 7000); yieldTimeoutTimer.Elapsed += (sender, ev) => { yieldTimedOut = true; }; - - InitPlugins(); - - Thread.SetTop(0); } private static void LH_YieldTimeout(IntPtr state, IntPtr ar) @@ -68,6 +64,13 @@ public class LuaState : IDisposable } } + public void Init() + { + InitPlugins(); + + Thread.SetTop(0); + } + private void InitPlugins() { var allPlugins = new List(Capy64.Instance.NativePlugins); @@ -192,6 +195,6 @@ public class LuaState : IDisposable GC.SuppressFinalize(this); _queue.Clear(); Thread.Close(); - _parent.Close(); + Parent.Close(); } } diff --git a/Capy64/Runtime/Objects/Task.cs b/Capy64/Runtime/Objects/Task.cs index 4f8110a..d4300be 100644 --- a/Capy64/Runtime/Objects/Task.cs +++ b/Capy64/Runtime/Objects/Task.cs @@ -44,19 +44,23 @@ public class TaskMeta : IComponent } public class RuntimeTask { - public RuntimeTask(string typeName) + public RuntimeTask(string name) { - TypeName = typeName; + Name = name; } + + public RuntimeTask() { } + public Guid Guid { get; set; } = Guid.NewGuid(); - public string TypeName { get; set; } + public string Name { get; set; } = "object"; public TaskStatus Status { get; set; } = TaskStatus.Running; public object Result { get; private set; } public string Error { get; private set; } + public int DataIndex { get; private set; } = 0; public void Fulfill(T obj) { - Status = TaskStatus.Succeeded; + /*Status = TaskStatus.Succeeded; Result = obj; @@ -65,32 +69,30 @@ public class TaskMeta : IComponent LK.PushString(Guid.ToString()); ObjectManager.PushObject(LK, obj); - LK.SetMetaTable(TypeName); + LK.SetMetaTable(Name); LK.PushNil(); return 3; - }); + });*/ } public void Fulfill(Action lk) { Status = TaskStatus.Succeeded; + var container = tasks.NewThread(); + lk(container); + container.XMove(tasks, 1); + tasks.Replace(-2); + DataIndex = tasks.GetTop(); + _game.LuaRuntime.QueueEvent("task_finish", LK => { LK.PushString(Guid.ToString()); - // Create Lua thread to store Lua native result data - Result = LK.NewThread(); - var thread = (Lua)Result; - LK.Pop(1); - - lk(thread); - - // Push copy of value on top and move it to LK - thread.PushCopy(-1); - thread.XMove(LK, 1); + tasks.PushCopy(DataIndex); + tasks.XMove(LK, 1); LK.PushNil(); @@ -176,8 +178,11 @@ public class TaskMeta : IComponent new(), }; + private static Lua tasks; public void LuaInit(Lua L) { + tasks = _game.LuaRuntime.Parent.NewThread(); + CreateMeta(L); } @@ -211,7 +216,7 @@ public class TaskMeta : IComponent var obj = ObjectManager.CheckObject(L, 1, ObjectType, gc); if (obj is null) { - L.Error("attempt to use a closed file"); + L.Error("attempt to use a closed task"); return null; } return obj; @@ -265,7 +270,7 @@ public class TaskMeta : IComponent var task = CheckTask(L, false); - L.PushString(task.TypeName); + L.PushString(task.Name); return 1; } @@ -289,17 +294,9 @@ public class TaskMeta : IComponent if (task.Status == TaskStatus.Succeeded) { - if (task.Result is Lua thread) - { - // Push copy of value on top and move it to LK - thread.PushCopy(-1); - thread.XMove(L, 1); - } - else - { - ObjectManager.PushObject(L, task.Result); - L.SetMetaTable(task.TypeName); - } + // Push copy of value on top and move it to L + tasks.PushCopy(task.DataIndex); + tasks.XMove(L, 1); } else { @@ -329,6 +326,21 @@ public class TaskMeta : IComponent private static int LM_GC(IntPtr state) { + var L = Lua.FromIntPtr(state); + + var task = ToTask(L, true); + if (task is null) + return 0; + + // todo: add cleanup to remove nil values at top of stack + + if (tasks.GetTop() == task.DataIndex) + tasks.SetTop(task.DataIndex - 1); + else + { + tasks.PushNil(); + tasks.Replace(task.DataIndex); + } return 0; } @@ -336,7 +348,7 @@ public class TaskMeta : IComponent { var L = Lua.FromIntPtr(state); var task = ToTask(L); - L.PushString("Task<{0}>: {1} ({2})", task?.TypeName, task?.Guid, task?.Status); + L.PushString("Task<{0}>: {1} ({2})", task?.Name, task?.Guid, task?.Status); return 1; } diff --git a/Capy64/Runtime/RuntimeManager.cs b/Capy64/Runtime/RuntimeManager.cs index cf150d7..55bf974 100644 --- a/Capy64/Runtime/RuntimeManager.cs +++ b/Capy64/Runtime/RuntimeManager.cs @@ -100,6 +100,7 @@ internal class RuntimeManager : IComponent luaState = new LuaState(); _game.LuaRuntime = luaState; + luaState.Init(); emitter = new(_game.EventEmitter, luaState); @@ -136,6 +137,7 @@ internal class RuntimeManager : IComponent luaState = new LuaState(); _game.LuaRuntime = luaState; + luaState.Init(); emitter = new(_game.EventEmitter, luaState);