Fix tasks crashing memory and stuff

This commit is contained in:
Alessandro Proto 2023-03-07 22:09:05 +01:00
parent d137c46ed9
commit 9aadc35329
5 changed files with 74 additions and 68 deletions

View file

@ -24,6 +24,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml.Linq;
namespace Capy64.Runtime.Libraries; namespace Capy64.Runtime.Libraries;
@ -527,7 +528,12 @@ public class GPU : IComponent
Height = texture.Height, Height = texture.Height,
Width = texture.Width, Width = texture.Width,
}; };
task.Fulfill(buffer);
task.Fulfill(lk =>
{
ObjectManager.PushObject(lk, buffer);
lk.SetMetaTable(GPUBufferMeta.ObjectType);
});
texture.Dispose(); texture.Dispose();
}); });

View file

@ -25,6 +25,7 @@ using System.Net.Http;
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
namespace Capy64.Runtime.Libraries; namespace Capy64.Runtime.Libraries;
#nullable enable #nullable enable
@ -198,19 +199,15 @@ public class HTTP : IComponent
var requestId = _requestId++; var requestId = _requestId++;
var luaTask = TaskMeta.Push(L, "HTTPRequest");
var reqTask = _httpClient.SendAsync(request); var reqTask = _httpClient.SendAsync(request);
reqTask.ContinueWith(async (task) => reqTask.ContinueWith(async (task) =>
{ {
if (task.IsFaulted || task.IsCanceled) if (task.IsFaulted || task.IsCanceled)
{ {
_game.LuaRuntime.QueueEvent("http_failure", LK => luaTask.Reject(task.Exception?.Message);
{
LK.PushInteger(requestId);
LK.PushString(task.Exception?.Message);
return 2;
});
return; return;
} }
@ -218,23 +215,15 @@ public class HTTP : IComponent
var stream = await response.Content.ReadAsStreamAsync(); 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.NewTable();
LK.PushString("content");
ObjectManager.PushObject(LK, stream);
LK.SetMetaTable(FileHandle.ObjectType);
LK.SetTable(-3);
LK.PushString("success"); LK.PushString("success");
LK.PushBoolean(response.IsSuccessStatusCode); LK.PushBoolean(response.IsSuccessStatusCode);
LK.SetTable(-3); LK.SetTable(-3);
@ -258,15 +247,9 @@ public class HTTP : IComponent
} }
LK.SetTable(-3); LK.SetTable(-3);
return 3;
}); });
}); });
L.PushInteger(requestId);
return 1; return 1;
} }

View file

@ -26,7 +26,7 @@ namespace Capy64.Runtime;
public class LuaState : IDisposable public class LuaState : IDisposable
{ {
public Lua Thread; public Lua Thread;
private readonly Lua _parent; public readonly Lua Parent;
private readonly ConcurrentQueue<LuaEvent> _queue = new(); private readonly ConcurrentQueue<LuaEvent> _queue = new();
@ -36,25 +36,21 @@ public class LuaState : IDisposable
public LuaState() public LuaState()
{ {
_parent = new Lua(false) Parent = new Lua(false)
{ {
Encoding = Encoding.UTF8, Encoding = Encoding.UTF8,
}; };
Sandbox.OpenLibraries(_parent); Sandbox.OpenLibraries(Parent);
Sandbox.Patch(_parent); Sandbox.Patch(Parent);
Thread = _parent.NewThread(); Thread = Parent.NewThread();
Thread.SetHook(LH_YieldTimeout, LuaHookMask.Count, 7000); Thread.SetHook(LH_YieldTimeout, LuaHookMask.Count, 7000);
yieldTimeoutTimer.Elapsed += (sender, ev) => yieldTimeoutTimer.Elapsed += (sender, ev) =>
{ {
yieldTimedOut = true; yieldTimedOut = true;
}; };
InitPlugins();
Thread.SetTop(0);
} }
private static void LH_YieldTimeout(IntPtr state, IntPtr ar) 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() private void InitPlugins()
{ {
var allPlugins = new List<IComponent>(Capy64.Instance.NativePlugins); var allPlugins = new List<IComponent>(Capy64.Instance.NativePlugins);
@ -192,6 +195,6 @@ public class LuaState : IDisposable
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
_queue.Clear(); _queue.Clear();
Thread.Close(); Thread.Close();
_parent.Close(); Parent.Close();
} }
} }

View file

@ -44,19 +44,23 @@ public class TaskMeta : IComponent
} }
public class RuntimeTask 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 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 TaskStatus Status { get; set; } = TaskStatus.Running;
public object Result { get; private set; } public object Result { get; private set; }
public string Error { get; private set; } public string Error { get; private set; }
public int DataIndex { get; private set; } = 0;
public void Fulfill<T>(T obj) public void Fulfill<T>(T obj)
{ {
Status = TaskStatus.Succeeded; /*Status = TaskStatus.Succeeded;
Result = obj; Result = obj;
@ -65,32 +69,30 @@ public class TaskMeta : IComponent
LK.PushString(Guid.ToString()); LK.PushString(Guid.ToString());
ObjectManager.PushObject(LK, obj); ObjectManager.PushObject(LK, obj);
LK.SetMetaTable(TypeName); LK.SetMetaTable(Name);
LK.PushNil(); LK.PushNil();
return 3; return 3;
}); });*/
} }
public void Fulfill(Action<Lua> lk) public void Fulfill(Action<Lua> lk)
{ {
Status = TaskStatus.Succeeded; 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 => _game.LuaRuntime.QueueEvent("task_finish", LK =>
{ {
LK.PushString(Guid.ToString()); LK.PushString(Guid.ToString());
// Create Lua thread to store Lua native result data tasks.PushCopy(DataIndex);
Result = LK.NewThread(); tasks.XMove(LK, 1);
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);
LK.PushNil(); LK.PushNil();
@ -176,8 +178,11 @@ public class TaskMeta : IComponent
new(), new(),
}; };
private static Lua tasks;
public void LuaInit(Lua L) public void LuaInit(Lua L)
{ {
tasks = _game.LuaRuntime.Parent.NewThread();
CreateMeta(L); CreateMeta(L);
} }
@ -211,7 +216,7 @@ public class TaskMeta : IComponent
var obj = ObjectManager.CheckObject<RuntimeTask>(L, 1, ObjectType, gc); var obj = ObjectManager.CheckObject<RuntimeTask>(L, 1, ObjectType, gc);
if (obj is null) if (obj is null)
{ {
L.Error("attempt to use a closed file"); L.Error("attempt to use a closed task");
return null; return null;
} }
return obj; return obj;
@ -265,7 +270,7 @@ public class TaskMeta : IComponent
var task = CheckTask(L, false); var task = CheckTask(L, false);
L.PushString(task.TypeName); L.PushString(task.Name);
return 1; return 1;
} }
@ -289,17 +294,9 @@ public class TaskMeta : IComponent
if (task.Status == TaskStatus.Succeeded) if (task.Status == TaskStatus.Succeeded)
{ {
if (task.Result is Lua thread) // Push copy of value on top and move it to L
{ tasks.PushCopy(task.DataIndex);
// Push copy of value on top and move it to LK tasks.XMove(L, 1);
thread.PushCopy(-1);
thread.XMove(L, 1);
}
else
{
ObjectManager.PushObject(L, task.Result);
L.SetMetaTable(task.TypeName);
}
} }
else else
{ {
@ -329,6 +326,21 @@ public class TaskMeta : IComponent
private static int LM_GC(IntPtr state) 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; return 0;
} }
@ -336,7 +348,7 @@ public class TaskMeta : IComponent
{ {
var L = Lua.FromIntPtr(state); var L = Lua.FromIntPtr(state);
var task = ToTask(L); 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; return 1;
} }

View file

@ -100,6 +100,7 @@ internal class RuntimeManager : IComponent
luaState = new LuaState(); luaState = new LuaState();
_game.LuaRuntime = luaState; _game.LuaRuntime = luaState;
luaState.Init();
emitter = new(_game.EventEmitter, luaState); emitter = new(_game.EventEmitter, luaState);
@ -136,6 +137,7 @@ internal class RuntimeManager : IComponent
luaState = new LuaState(); luaState = new LuaState();
_game.LuaRuntime = luaState; _game.LuaRuntime = luaState;
luaState.Init();
emitter = new(_game.EventEmitter, luaState); emitter = new(_game.EventEmitter, luaState);