diff --git a/multi/compat/lovr.lua b/multi/compat/lovr.lua new file mode 100644 index 0000000..c37906d --- /dev/null +++ b/multi/compat/lovr.lua @@ -0,0 +1,281 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +if table.unpack then + unpack=table.unpack +end +function table.val_to_str ( v ) + if "string" == type( v ) then + v = string.gsub( v, "\n", "\\n" ) + if string.match( string.gsub(v,"[^'\"]",""), '^"+$' ) then + return "'" .. v .. "'" + end + return '"' .. string.gsub(v,'"', '\\"' ) .. '"' + else + return "table" == type( v ) and table.tostring( v ) or + tostring( v ) + end +end + +function table.key_to_str ( k ) + if "string" == type( k ) and string.match( k, "^[_%a][_%a%d]*$" ) then + return k + else + return "[" .. table.val_to_str( k ) .. "]" + end +end + +function table.tostring( tbl ) + local result, done = {}, {} + for k, v in ipairs( tbl ) do + table.insert( result, table.val_to_str( v ) ) + done[ k ] = true + end + for k, v in pairs( tbl ) do + if not done[ k ] then + table.insert( result, + table.key_to_str( k ) .. "=" .. table.val_to_str( v ) ) + end + end + return "{" .. table.concat( result, "," ) .. "}" +end +function table.merge(t1, t2) + t1,t2= t1 or {},t2 or {} + for k,v in pairs(t2) do + if type(v) == "table" then + if type(t1[k] or false) == "table" then + table.merge(t1[k] or {}, t2[k] or {}) + else + t1[k] = v + end + else + t1[k] = v + end + end + return t1 +end +Library={} +function Library.inject(lib,dat,arg) + if type(lib)=="table" then + if type(dat)=="table" then + table.merge(lib,dat) + elseif type(dat)=="string" then + if lib.Version and dat:match("(%d-)%.(%d-)%.(%d-)") then + lib.Version={dat:match("(%d+)%.(%d+)%.(%d+)")} + elseif dat=="meta" and type(arg)=="table" then + local _mt=getmetatable(lib) or {} + local mt={} + table.merge(mt,arg) + table.merge(_mt,mt) + setmetatable(lib,_mt) + elseif dat=="compat" then + lib["getVersion"]=function(self) return self.Version[1].."."..self.Version[2].."."..self.Version[3] end + if not lib.Version then + lib.Version={1,0,0} + end + elseif dat=="inhert" then + if not(lib["!%"..arg.."%!"]) then print("Wrong Password!!") return end + lib["!%"..arg.."%!"].__index=lib["!!%"..arg.."%!!"] + end + elseif type(dat)=="function" then + for i,v in pairs(lib) do + dat(lib,i,v) + end + end + elseif type(lib)=="function" or type(lib)=="userdata" then + if lib==unpack then + print("function unpack cannot yet be injected!") + return unpack + elseif lib==pairs then + print("function pairs cannot yet be injected!") + return lib + elseif lib==ipairs then + print("function ipairs cannot yet be injected!") + return lib + elseif lib==type then + print("function type cannot yet be injected!") + return lib + end + temp={} + local mt={ + __call=function(t,...) + local consume,MainRet,init={},{},{...} + local tt={} + for i=1,#t.__Link do + tt={} + if t.__Link[i]==t.__Main then + if #consume~=0 then + MainRet={t.__Link[i](unpack(consume))} + else + MainRet={t.__Link[i](unpack(init))} + end + else + if i==1 then + consume=(t.__Link[i](unpack(init))) + else + if type(MainRet)=="table" then + table.merge(tt,MainRet) + end + if type(consume)=="table" then + table.merge(tt,consume) + end + consume={t.__Link[i](unpack(tt))} + end + if i==#t.__Link then + return unpack(consume) + end + if consume then if consume[0]=="\1\7\6\3\2\99\125" then consume[0]=nil return unpack(consume) end end + end + end + if type(MainRet)=="table" then + table.merge(tt,MainRet) + end + if type(consume)=="table" then + table.merge(tt,consume) + end + return unpack(tt) + end, + } + temp.__Link={lib} + temp.__Main=lib + temp.__self=temp + function temp:inject(func,i) + if i then + table.insert(self.__Link,i,func) + else + table.insert(self.__Link,func) + end + end + function temp:consume(func) + for i=1,#self.__Link do + if self.__Link[i]==self.__Main then + self.__Link[i]=func + self.__self.__Main=func + return true + end + end + return false + end + setmetatable(temp,mt) + return temp + else + return "arg1 must be a table or a function" + end +end +function Library.convert(...) + local temp,rets={...},{} + for i=1,#temp do + if type(temp[i])=="function" then + table.insert(rets,Library.inject(temp[i])) + else + error("Takes only functions and returns in order from functions given. arg # "..i.." is not a function!!! It is a "..type(temp[i])) + end + end + return unpack(rets) +end + +local link={MainLibrary=Library} +Library.inject(Library,"meta",{ + __Link=link, + __call=function(self,func) func(link) end, +}) +local multi, thread = require("multi").init() +os.sleep = lovr.timer.sleep +multi.drawF = {} +function multi:onDraw(func, i) + i = i or 1 + table.insert(self.drawF, i, func) +end +multi.OnKeyPressed = multi:newConnection() +multi.OnKeyReleased = multi:newConnection() +multi.OnErrHand = multi:newConnection() +multi.OnFocus = multi:newConnection() +multi.OnLoad = multi:newConnection() +multi.OnLog = multi:newConnection() +multi.OnPermission = multi:newConnection() +multi.OnResize = multi:newConnection() +multi.OnRestart = multi:newConnection() +multi.OnThreadError = multi:newConnection() +multi.OnDraw = multi:newConnection() +multi.OnTextInput = multi:newConnection() +multi.OnUpdate = multi:newConnection() +multi.OnQuit = multi:newConnection() +multi.OnPreLoad(function() + local function Hook(func, conn) + if lovr[func] ~= nil then + lovr[func] = Library.convert(lovr[func]) + lovr[func]:inject(function(...) + conn:Fire(...) + return {...} + end,1) + elseif lovr[func] == nil then + lovr[func] = function(...) + conn:Fire(...) + end + end + end + Hook("quit", multi.OnQuit) + Hook("keypressed", multi.OnKeyPressed) + Hook("keyreleased", multi.OnKeyReleased) + Hook("focus", multi.OnFocus) + Hook("log", multi.OnLog) + Hook("errhand", multi.OnErrHand) + Hook("load", multi.OnLoad) + Hook("draw", multi.OnDraw) + Hook("textinput", multi.OnTextInput) + Hook("update", multi.OnUpdate) + Hook("permission", multi.OnPermission) + Hook("resize", multi.OnResize) + Hook("restart", multi.OnRestart) + Hook("threaderror", multi.OnThreadError) + multi.OnDraw(function() + for i = 1, #multi.drawF do + lovr.graphics.setColor(255, 255, 255, 255) + multi.drawF[i]() + end + end) +end) + +function multi:lovrloop(light) + local link + link = multi:newThread(function() + local mainloop = lovr.run() + while true do + thread.yield() + pcall(mainloop) + end + end).OnError(function(...) + print(...) + end) + if light==false then + multi:mainloop() + else + multi:lightloop() + end +end + +multi.OnQuit(function() + multi.Stop() + lovr.event.quit() +end) +return multi diff --git a/multi/integration/loveManager/extensions.lua b/multi/integration/loveManager/extensions.lua index cbeecf3..805e185 100644 --- a/multi/integration/loveManager/extensions.lua +++ b/multi/integration/loveManager/extensions.lua @@ -21,6 +21,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] + +-- TODO make compatible with lovr local multi, thread = require("multi").init() GLOBAL = multi.integration.GLOBAL THREAD = multi.integration.THREAD diff --git a/multi/integration/lovr/extensions.lua b/multi/integration/lovr/extensions.lua new file mode 100644 index 0000000..cbeecf3 --- /dev/null +++ b/multi/integration/lovr/extensions.lua @@ -0,0 +1,200 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +local multi, thread = require("multi").init() +GLOBAL = multi.integration.GLOBAL +THREAD = multi.integration.THREAD +function multi:newSystemThreadedQueue(name) + local c = {} + c.Name = name + local fRef = {"func",nil} + function c:init() + local q = {} + q.chan = love.thread.getChannel(self.Name) + function q:push(dat) + if type(dat) == "function" then + fRef[2] = THREAD.dump(dat) + self.chan:push(fRef) + return + else + self.chan:push(dat) + end + end + function q:pop() + local dat = self.chan:pop() + if type(dat)=="table" and dat[1]=="func" then + return THREAD.loadDump(dat[2]) + else + return dat + end + end + function q:peek() + local dat = self.chan:peek() + if type(dat)=="table" and dat[1]=="func" then + return THREAD.loadDump(dat[2]) + else + return dat + end + end + return q + end + THREAD.package(name,c) + return c +end +function multi:newSystemThreadedTable(name) + local c = {} + c.name = name + function c:init() + return THREAD.createTable(self.name) + end + THREAD.package(name,c) + return c +end +local jqc = 1 +function multi:newSystemThreadedJobQueue(n) + local c = {} + c.cores = n or THREAD.getCores() + c.registerQueue = {} + c.funcs = THREAD.createStaticTable("__JobQueue_"..jqc.."_table") + c.queue = love.thread.getChannel("__JobQueue_"..jqc.."_queue") + c.queueReturn = love.thread.getChannel("__JobQueue_"..jqc.."_queueReturn") + c.queueAll = love.thread.getChannel("__JobQueue_"..jqc.."_queueAll") + c.id = 0 + c.OnJobCompleted = multi:newConnection() + local allfunc = 0 + function c:doToAll(func) + local f = THREAD.dump(func) + for i = 1, self.cores do + self.queueAll:push({allfunc,f}) + end + allfunc = allfunc + 1 + end + function c:registerFunction(name,func) + if self.funcs[name] then + error("A function by the name "..name.." has already been registered!") + end + self.funcs[name] = func + end + function c:pushJob(name,...) + self.id = self.id + 1 + self.queue:push{name,self.id,...} + return self.id + end + local nFunc = 0 + function c:newFunction(name,func,holup) -- This registers with the queue + if type(name)=="function" then + holup = func + func = name + name = "JQ_Function_"..nFunc + end + nFunc = nFunc + 1 + c:registerFunction(name,func) + return thread:newFunction(function(...) + local id = c:pushJob(name,...) + local link + local rets + link = c.OnJobCompleted(function(jid,...) + if id==jid then + rets = {...} + link:Destroy() + end + end) + return thread.hold(function() + if rets then + return unpack(rets) or multi.NIL + end + end) + end,holup),name + end + multi:newThread("jobManager",function() + while true do + thread.yield() + local dat = c.queueReturn:pop() + if dat then + c.OnJobCompleted:Fire(unpack(dat)) + end + end + end) + for i=1,c.cores do + multi:newSystemThread("JobQueue_"..jqc.."_worker_"..i,function(jqc) + local multi, thread = require("multi"):init() + require("love.timer") + local function atomic(channel) + return channel:pop() + end + local clock = os.clock + local funcs = THREAD.createStaticTable("__JobQueue_"..jqc.."_table") + local queue = love.thread.getChannel("__JobQueue_"..jqc.."_queue") + local queueReturn = love.thread.getChannel("__JobQueue_"..jqc.."_queueReturn") + local lastProc = clock() + local queueAll = love.thread.getChannel("__JobQueue_"..jqc.."_queueAll") + local registry = {} + setmetatable(_G,{__index = funcs}) + multi:newThread("startUp",function() + while true do + thread.yield() + local all = queueAll:peek() + if all and not registry[all[1]] then + lastProc = os.clock() + THREAD.loadDump(queueAll:pop()[2])() + end + end + end) + multi:newThread("runner",function() + thread.sleep(.1) + while true do + thread.yield() + local all = queueAll:peek() + if all and not registry[all[1]] then + lastProc = os.clock() + THREAD.loadDump(queueAll:pop()[2])() + end + local dat = queue:performAtomic(atomic) + if dat then + lastProc = os.clock() + local name = table.remove(dat,1) + local id = table.remove(dat,1) + local tab = {funcs[name](unpack(dat))} + table.insert(tab,1,id) + queueReturn:push(tab) + end + end + end):OnError(function(...) + error(...) + end) + multi:newThread("Idler",function() + while true do + thread.yield() + if clock()-lastProc> 2 then + THREAD.sleep(.05) + else + THREAD.sleep(.001) + end + end + end) + multi:mainloop() + end,jqc) + end + jqc = jqc + 1 + return c +end \ No newline at end of file diff --git a/multi/integration/lovr/init.lua b/multi/integration/lovr/init.lua new file mode 100644 index 0000000..7db8e47 --- /dev/null +++ b/multi/integration/lovr/init.lua @@ -0,0 +1,88 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +-- TODO make compatible with lovr +if ISTHREAD then + error("You cannot require the loveManager from within a thread!") +end +local ThreadFileData = [[ +ISTHREAD = true +THREAD = require("multi.integration.loveManager.threads") -- order is important! +sThread = THREAD +__IMPORTS = {...} +__FUNC__=table.remove(__IMPORTS,1) +__THREADID__=table.remove(__IMPORTS,1) +__THREADNAME__=table.remove(__IMPORTS,1) +stab = THREAD.createStaticTable(__THREADNAME__) +GLOBAL = THREAD.getGlobal() +multi, thread = require("multi").init() +stab["returns"] = {THREAD.loadDump(__FUNC__)(unpack(__IMPORTS))} +]] +local multi, thread = require("multi.compat.love2d"):init() +local THREAD = {} +__THREADID__ = 0 +__THREADNAME__ = "MainThread" +multi.integration={} +multi.integration.love2d={} +local THREAD = require("multi.integration.loveManager.threads") +local GLOBAL = THREAD.getGlobal() +local THREAD_ID = 1 +local OBJECT_ID = 0 +local stf = 0 +function THREAD:newFunction(func,holup) + stf = stf + 1 + return function(...) + local t = multi:newSystemThread("STF"..stf,func,...) + return thread:newFunction(function() + return thread.hold(function() + if t.stab["returns"] then + local dat = t.stab.returns + t.stab.returns = nil + return unpack(dat) + end + end) + end,holup)() + end +end +function multi:newSystemThread(name,func,...) + local c = {} + c.name = name + c.ID=THREAD_ID + c.thread=love.thread.newThread(ThreadFileData) + c.thread:start(THREAD.dump(func),c.ID,c.name,...) + c.stab = THREAD.createStaticTable(name) + GLOBAL["__THREAD_"..c.ID] = {ID=c.ID,Name=c.name,Thread=c.thread} + GLOBAL["__THREAD_COUNT"] = THREAD_ID + THREAD_ID=THREAD_ID+1 + return c +end +function love.threaderror(thread, errorstr) + print("Thread error!\n"..errorstr) +end +multi.integration.GLOBAL = GLOBAL +multi.integration.THREAD = THREAD +require("multi.integration.loveManager.extensions") +print("Integrated Love Threading!") +return {init=function() + return GLOBAL,THREAD +end} \ No newline at end of file diff --git a/multi/integration/lovr/threads.lua b/multi/integration/lovr/threads.lua new file mode 100644 index 0000000..e133f31 --- /dev/null +++ b/multi/integration/lovr/threads.lua @@ -0,0 +1,222 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +-- TODO make compatible with lovr +require("love.timer") +require("love.system") +require("love.data") +local socket = require("socket") +local multi, thread = require("multi").init() +local threads = {} +function threads.loadDump(d) + return loadstring(d:getString()) +end +function threads.dump(func) + return love.data.newByteData(string.dump(func)) +end +local fRef = {"func",nil} +local function manage(channel, value) + channel:clear() + if type(value) == "function" then + fRef[2] = THREAD.dump(value) + channel:push(fRef) + return + else + channel:push(value) + end +end +local function RandomVariable(length) + local res = {} + math.randomseed(socket.gettime()*10000) + for i = 1, length do + res[#res+1] = string.char(math.random(97, 122)) + end + return table.concat(res) +end +local GNAME = "__GLOBAL_" +local proxy = {} +function threads.set(name,val) + if not proxy[name] then proxy[name] = love.thread.getChannel(GNAME..name) end + proxy[name]:performAtomic(manage, val) +end +function threads.get(name) + if not proxy[name] then proxy[name] = love.thread.getChannel(GNAME..name) end + local dat = proxy[name]:peek() + if type(dat)=="table" and dat[1]=="func" then + return THREAD.loadDump(dat[2]) + else + return dat + end +end +function threads.waitFor(name) + if thread.isThread() then + return thread.hold(function() + return threads.get(name) + end) + end + while threads.get(name)==nil do + love.timer.sleep(.001) + end + local dat = threads.get(name) + if type(dat) == "table" and dat.init then + dat.init = threads.loadDump(dat.init) + end + return dat +end +function threads.package(name,val) + local init = val.init + val.init=threads.dump(val.init) + GLOBAL[name]=val + val.init=init +end +function threads.getCores() + return love.system.getProcessorCount() +end +function threads.kill() + error("Thread Killed!") +end +function threads.getThreads() + local t = {} + for i=1,GLOBAL["__THREAD_COUNT"] do + t[#t+1]=GLOBAL["__THREAD_"..i] + end + return t +end +function threads.getThread(n) + return GLOBAL["__THREAD_"..n] +end +function threads.getName() + return __THREADNAME__ +end +function threads.getID() + return __THREADID__ +end +function threads.sleep(n) + love.timer.sleep(n) +end +function threads.getGlobal() + return setmetatable({}, + { + __index = function(t, k) + return THREAD.get(k) + end, + __newindex = function(t, k, v) + THREAD.set(k,v) + end + } + ) +end +function threads.createTable(n) + local _proxy = {} + local function set(name,val) + if not _proxy[name] then _proxy[name] = love.thread.getChannel(n..name) end + _proxy[name]:performAtomic(manage, val) + end + local function get(name) + if not _proxy[name] then _proxy[name] = love.thread.getChannel(n..name) end + local dat = _proxy[name]:peek() + if type(dat)=="table" and dat[1]=="func" then + return THREAD.loadDump(dat[2]) + else + return dat + end + end + return setmetatable({}, + { + __index = function(t, k) + return get(k) + end, + __newindex = function(t, k, v) + set(k,v) + end + } + ) +end +function threads.getConsole() + local c = {} + c.queue = love.thread.getChannel("__CONSOLE__") + function c.print(...) + c.queue:push{...} + end + function c.error(err) + c.queue:push{"ERROR in <"..__THREADNAME__..">: "..err,__THREADID__} + error(err) + end + return c +end +if not ISTHREAD then + local clock = os.clock + local lastproc = clock() + local queue = love.thread.getChannel("__CONSOLE__") + multi:newThread("consoleManager",function() + while true do + thread.yield() + dat = queue:pop() + if dat then + lastproc = clock() + print(unpack(dat)) + end + if clock()-lastproc>2 then + thread.sleep(.1) + end + end + end) +end +function threads.createStaticTable(n) + local __proxy = {} + local function set(name,val) + if __proxy[name] then return end + local chan = love.thread.getChannel(n..name) + if chan:getCount()>0 then return end + chan:performAtomic(manage, val) + __proxy[name] = val + end + local function get(name) + if __proxy[name] then return __proxy[name] end + local dat = love.thread.getChannel(n..name):peek() + if type(dat)=="table" and dat[1]=="func" then + __proxy[name] = THREAD.loadDump(dat[2]) + return __proxy[name] + else + __proxy[name] = dat + return __proxy[name] + end + end + return setmetatable({}, + { + __index = function(t, k) + return get(k) + end, + __newindex = function(t, k, v) + set(k,v) + end + } + ) +end +function threads.hold(n) + local dat + while not(dat) do + dat = n() + end +end +return threads \ No newline at end of file diff --git a/rockspecs/multi-15.1-0.rockspec b/rockspecs/multi-15.1-0.rockspec new file mode 100644 index 0000000..b3d9cca --- /dev/null +++ b/rockspecs/multi-15.1-0.rockspec @@ -0,0 +1,42 @@ +package = "multi" +version = "15.1-0" +source = { + url = "git://github.com/rayaman/multi.git", + tag = "v15.1.0", +} +description = { + summary = "Lua Multi tasking library", + detailed = [[ + This library contains many methods for multi tasking. Features non coroutine based multi-tasking, coroutine based multi-tasking, and system threading (Requires use of an integration). + Check github for how to use. + ]], + homepage = "https://github.com/rayaman/multi", + license = "MIT" +} +dependencies = { + "lua >= 5.1", + "lanes", +} +build = { + type = "builtin", + modules = { + ["multi"] = "multi/init.lua", + ["multi.compat.love2d"] = "multi/compat/love2d.lua", + ["multi.compat.lovr"] = "multi/compat/lovr.lua", + ["multi.integration"] = "multi/integration/threading.lua", + ["multi.integration.lanesManager"] = "multi/integration/lanesManager/init.lua", + ["multi.integration.lanesManager.extensions"] = "multi/integration/lanesManager/extensions.lua", + ["multi.integration.lanesManager.threads"] = "multi/integration/lanesManager/threads.lua", + ["multi.integration.loveManager"] = "multi/integration/loveManager/init.lua", + ["multi.integration.loveManager.extensions"] = "multi/integration/loveManager/extensions.lua", + ["multi.integration.loveManager.threads"] = "multi/integration/loveManager/threads.lua", + ["multi.integration.lovrManager"] = "multi/integration/lovrManager/init.lua", + ["multi.integration.lovrManager.extensions"] = "multi/integration/lovrManager/extensions.lua", + ["multi.integration.lovrManager.threads"] = "multi/integration/lovrManager/threads.lua", + ["multi.integration.pesudoManager"] = "multi/integration/pesudoManager/init.lua", + ["multi.integration.pesudoManager.extensions"] = "multi/integration/pesudoManager/extensions.lua", + ["multi.integration.pesudoManager.threads"] = "multi/integration/pesudoManager/threads.lua", + ["multi.integration.luvitManager"] = "multi/integration/luvitManager.lua", + --["multi.integration.networkManager"] = "multi/integration/networkManager.lua", + } +} \ No newline at end of file