Threading working in love2d

This commit is contained in:
2024-02-24 23:05:05 -05:00
parent 42b4e0fcf4
commit e3ac0951ab
18 changed files with 210 additions and 999 deletions
+6 -3
View File
@@ -11,25 +11,27 @@ function multi:newSystemThreadedQueue(name)
c.Name = name
c.Type = multi.registerType("s_queue")
c.chan = love.thread.newChannel()
c.chan = love.thread.getChannel(name)
function c:push(dat)
self.chan:push(THREAD.packValue(dat))
end
function c:pop()
return THREAD.unpackValue(self.chan:pop())
return THREAD.unpackValue(self.chan:pop())
end
function c:peek()
return THREAD.unpackValue(self.chan:peek())
return THREAD.unpackValue(self.chan:peek())
end
function c:init()
self.chan = love.thread.getChannel(self.Name)
return self
end
function c:Hold(opt)
local multi, thread = require("multi"):init()
if opt.peek then
return thread.hold(function()
return self:peek()
@@ -73,6 +75,7 @@ function multi:newSystemThreadedTable(name)
c.__init = c.init
function c:Hold(opt)
local multi, thread = require("multi"):init()
if opt.key then
return thread.hold(function()
return self.tab[opt.key]
+16 -8
View File
@@ -5,11 +5,13 @@ end
local ThreadFileData = [[
ISTHREAD = true
args = {...}
THREAD_ID = table.remove(args, 1)
THREAD_NAME = table.remove(args, 1)
GLOBAL, THREAD = require("multi.integration.loveManager.threads"):init()
__FUNC = THREAD.unpackValue(table.remove(args, 1))
ARGS = THREAD.unpackValue(table.remove(args, 1))
THREAD_ID = args[1]
THREAD_NAME = args[2]
GLOBAL, THREAD, DEFER = require("multi.integration.loveManager.threads"):init()
__FUNC = THREAD.unpackValue(args[3])
ARGS = THREAD.unpackValue(args[4])
settings = args[5]
if ARGS == nil then ARGS = {} end
math.randomseed(THREAD_ID)
math.random()
math.random()
@@ -21,10 +23,16 @@ if GLOBAL["__env"] then
_G[i] = v
end
end
multi, thread = require("multi"):init()
multi, thread = require("multi"):init{error=true, warning=true, print=true, priority=true}
multi.defaultSettings.print = true
require("multi.integration.loveManager.extensions")
require("multi.integration.sharedExtensions")
stab["returns"] = {__FUNC(multi.unpack(ARGS))}
local returns = {pcall(__FUNC, multi.unpack(ARGS))}
table.remove(returns,1)
stab["returns"] = returns
for i,v in pairs(DEFER) do
pcall(v)
end
]]
_G.THREAD_NAME = "MAIN_THREAD"
@@ -49,7 +57,7 @@ function multi:newSystemThread(name, func, ...)
c.Name = name
c.ID = tid
c.thread = love.thread.newThread(ThreadFileData)
c.thread:start(c.ID, c.Name, THREAD.packValue(func), THREAD.packValue({...}))
c.thread:start(c.ID, c.Name, THREAD.packValue(func), THREAD.packValue({...}), multi.defaultSettings)
c.stab = THREAD.createTable(name .. c.ID)
c.creationTime = os.clock()
c.OnDeath = multi:newConnection()
+79 -17
View File
@@ -25,19 +25,76 @@ require("love.timer")
require("love.system")
require("love.data")
require("love.thread")
local utils = require("multi.integration.loveManager.utils")
local multi, thread = require("multi"):init()
local NIL = love.data.newByteData("\3")
-- If a non table/function is supplied we just return it
local function packValue(t)
return utils.pack(t)
-- Checks if the given value is a LOVE2D object (i.e. has metatable with __index field) and if that __index field contains functions typical of LOVE2D objects
function isLoveObject(value)
-- Check if the value has metatable
if type(value) == "userdata" and getmetatable(value) then
-- Check if the metatable has the __index field
local index = getmetatable(value).__index
if type(index) == "table" then
-- Check if the metatable's __index table contains functions typical of LOVE2D objects
if index.draw or index.update or index.getWidth or index.getHeight or index.getString or index.getPointer then
return true
end
end
end
return false
end
-- If a non table/function is supplied we just return it
local function unpackValue(d)
return utils.unpack(d)
-- Converts any function values in a table to a string with the value "\1\2:func:<function_string>" where <function_string> is the Lua stringified version of the function
function tableToFunctionString(t)
if type(t) == "nil" then return "\1\2:nil:" end
if type(t) == "function" then return "\1\2:func:"..string.dump(t) end
if type(t) ~= "table" then return t end
local newtable = {}
for k, v in pairs(t) do
if type(v) == "function" then
newtable[k] = "\1\2:func:"..string.dump(v)
elseif type(v) == "table" then
newtable[k] = tableToFunctionString(v)
elseif isLoveObject(v) then
newtable[k] = v
elseif type(v) == "userdata" then
newtable[k] = tostring(v)
else
newtable[k] = v
end
end
return newtable
end
-- Converts strings with the value "\1\2:func:<function_string>" back to functions
function functionStringToTable(t)
if type(t) == "string" and t:sub(1, 8) == "\1\2:func:" then return loadstring(t:sub(9, -1)) end
if type(t) == "string" and t:sub(1, 7) == "\1\2:nil:" then return nil end
if type(t) ~= "table" then return t end
for k, v in pairs(t) do
if type(v) == "string" then
if v:sub(1, 8) == "\1\2:func:" then
t[k] = loadstring(v:sub(9, -1))
else
t[k] = v
end
elseif type(v) == "table" then
t[k] = functionStringToTable(v)
else
t[k] = v
end
end
if t.init then
t:init()
end
return t
end
local function packValue(t)
return tableToFunctionString(t)
end
local function unpackValue(t)
return functionStringToTable(t)
end
local function createTable(n)
@@ -53,6 +110,11 @@ local function createTable(n)
end
local function get(name)
return unpackValue(love.thread.getChannel(n .. name):peek())
-- if type(data) == "table" and data.init then
-- return data:init()
-- else
-- return data
-- end
end
return setmetatable({},
{
@@ -67,7 +129,7 @@ local function createTable(n)
end
function INIT()
local GLOBAL, THREAD = createTable("__GLOBAL__"), {}
local GLOBAL, THREAD, DEFER = createTable("__GLOBAL__"), {}, {}
local status_channel, console_channel = love.thread.getChannel("__status_channel__" .. THREAD_ID),
love.thread.getChannel("__console_channel__")
@@ -92,11 +154,7 @@ function INIT()
repeat
wait()
until GLOBAL[name] ~= nil
if type(GLOBAL[name].__init) == "function" then
return GLOBAL[name]:__init()
else
return GLOBAL[name]
end
return GLOBAL[name]
end, true)
function THREAD.getCores()
@@ -153,10 +211,14 @@ function INIT()
end
function THREAD.defer(func)
multi.OnExit(func)
table.insert(DEFER, func)
end
return GLOBAL, THREAD
function THREAD.sync()
-- Maybe do something...
end
return GLOBAL, THREAD, DEFER
end
return {
-58
View File
@@ -1,58 +0,0 @@
require("love.data")
local utils = {}
local NIL = {Type="nil"}
--love.data.newByteData("\2"..serpent.dump({t,true},{safe = true}))
local ltype = function(v) return v:type() end
local t = function(value)
local v = type(value)
if v == "userdata" then
local status, return_or_err = pcall(ltype, value)
if status then return return_or_err else return "userdata" end
else return v end
end
function utils.pack(tbl, seen)
if type(tbl) == "function" then return {["__$FUNC$__"] = love.data.newByteData(string.dump(tbl))} end
if type(tbl) ~= "table" then return tbl end
local seen = seen or {}
local result = {}
result.__isPacked = true
for i,v in pairs(tbl) do
if seen[v] then
result[i] = v
elseif t(v) == "table" then
seen[v] = true
result[i] = utils.pack(v, seen)
elseif t(v) == "function" then
result["$F"..i] = love.data.newByteData(string.dump(v))
elseif t{v} == "userdata" then
result[i] = "userdata"
else -- Handle what we need to and pass the rest along as a value
result[i] = v
end
end
return result
end
function utils.unpack(tbl)
if not tbl then return nil end
if type(tbl) ~= "table" then return tbl end
if tbl["__$FUNC$__"] then return loadstring(tbl["__$FUNC$__"]:getString()) end
for i,v in pairs(tbl) do
if type(i) == "string" and i:sub(1,2) == "$F" then
local rawfunc = v:getString()
v:release()
tbl[i] = nil
tbl[i:sub(3,-1)] = loadstring(rawfunc)
end
if type(v) == "table" then
utils.unpack(v)
end
end
tbl.__isPacked = nil
return tbl
end
return utils