mirror of
https://github.com/rayaman/multi.git
synced 2026-09-05 07:27:35 -04:00
Reworking the networkManager
some new features
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
--[[
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Ryan Ward
|
||||
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
|
||||
|
||||
+76
-135
@@ -1,7 +1,7 @@
|
||||
--[[
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Ryan Ward
|
||||
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
|
||||
@@ -861,9 +861,13 @@ function multi:newConnection(protect,func)
|
||||
self.func={}
|
||||
return self
|
||||
end
|
||||
function c:connect(func,name,num)
|
||||
local function conn_helper(self,func,name,num)
|
||||
self.ID=self.ID+1
|
||||
table.insert(self.func,num or #self.func+1,{func,self.ID})
|
||||
if num then
|
||||
table.insert(self.func,num,{func,self.ID})
|
||||
else
|
||||
table.insert(self.func,1,{func,self.ID})
|
||||
end
|
||||
local temp = {
|
||||
Link=self.func,
|
||||
func=func,
|
||||
@@ -908,6 +912,24 @@ function multi:newConnection(protect,func)
|
||||
end
|
||||
return temp
|
||||
end
|
||||
function c:connect(...)--func,name,num
|
||||
local tab = {...}
|
||||
local funcs={}
|
||||
for i=1,#tab do
|
||||
if type(tab[i])=="function" then
|
||||
funcs[#funcs+1] = tab[i]
|
||||
end
|
||||
end
|
||||
if #funcs>1 then
|
||||
local ret = {}
|
||||
for i=1,#funcs do
|
||||
table.insert(ret,conn_helper(self,funcs[i]))
|
||||
end
|
||||
return ret
|
||||
else
|
||||
conn_helper(self,tab[1],tab[2],tab[3])
|
||||
end
|
||||
end
|
||||
c.Connect=c.connect
|
||||
c.GetConnection=c.getConnection
|
||||
function c:tofile(path)
|
||||
@@ -1489,34 +1511,59 @@ function thread.waitFor(name)
|
||||
thread.hold(function() return thread.get(name)~=nil end)
|
||||
return thread.get(name)
|
||||
end
|
||||
function multi.hold(func)
|
||||
local death = false
|
||||
if type(func)=="function" then
|
||||
local rets
|
||||
multi:newThread("Hold_func",function()
|
||||
rets = {thread.hold(func)}
|
||||
death = true
|
||||
end)
|
||||
while not death do
|
||||
multi.scheduler:Act()
|
||||
end
|
||||
return unpack(rets)
|
||||
elseif type(func)=="number" then
|
||||
multi:newThread("Hold_func",function()
|
||||
thread.sleep(func)
|
||||
death = true
|
||||
end)
|
||||
while not death do
|
||||
multi.scheduler:Act()
|
||||
end
|
||||
end
|
||||
end
|
||||
function thread:newFunction(func)
|
||||
local c = {Type = "tfunc"}
|
||||
c.__call = function(self,...)
|
||||
local rets, err
|
||||
local function wait()
|
||||
return thread.hold(function()
|
||||
if err then
|
||||
return multi.NIL, err
|
||||
elseif rets then
|
||||
return unpack(rets)
|
||||
if thread.isThread() then
|
||||
return thread.hold(function()
|
||||
if err then
|
||||
return multi.NIL, err
|
||||
elseif rets then
|
||||
return unpack(rets)
|
||||
end
|
||||
end)
|
||||
else
|
||||
while not rets do
|
||||
multi.scheduler:Act()
|
||||
end
|
||||
end)
|
||||
return unpack(rets)
|
||||
end
|
||||
end
|
||||
local t = multi:newThread("TempThread",func,...)
|
||||
local t = multi:newThread("TempThread",func,...)
|
||||
t.OnDeath(function(self,status,...) rets = {...} end)
|
||||
t.OnError(function(self,e) err = e end)
|
||||
--if thread.isThread() then
|
||||
-- return wait()
|
||||
--else
|
||||
return {
|
||||
isTFunc = true,
|
||||
wait = wait,
|
||||
connect = function(f)
|
||||
t.OnDeath(function(self,status,...) f(...) end)
|
||||
t.OnError(function(self,err) f(self, err) end)
|
||||
end
|
||||
}
|
||||
--end
|
||||
return {
|
||||
isTFunc = true,
|
||||
wait = wait,
|
||||
connect = function(f)
|
||||
t.OnDeath(function(self,status,...) f(...) end)
|
||||
t.OnError(function(self,err) f(self, err) end)
|
||||
end
|
||||
}
|
||||
end
|
||||
setmetatable(c,c)
|
||||
return c
|
||||
@@ -1648,7 +1695,7 @@ function multi:newThread(name,func,...)
|
||||
threadid = threadid + 1
|
||||
return c
|
||||
end
|
||||
function multi.initThreads()
|
||||
function multi.initThreads(justThreads)
|
||||
initT = true
|
||||
multi.scheduler=multi:newLoop():setName("multi.thread")
|
||||
multi.scheduler.Type="scheduler"
|
||||
@@ -1764,120 +1811,14 @@ function multi.initThreads()
|
||||
helper(i)
|
||||
end
|
||||
end)
|
||||
if justThreads then
|
||||
while true do
|
||||
multi.scheduler:Act()
|
||||
end
|
||||
end
|
||||
end
|
||||
function multi:threadloop()
|
||||
initT = true
|
||||
multi.scheduler=multi:newLoop():setName("multi.thread")
|
||||
multi.scheduler.Type="scheduler"
|
||||
function multi.scheduler:setStep(n)
|
||||
self.skip=tonumber(n) or 24
|
||||
end
|
||||
multi.scheduler.skip=0
|
||||
local t0,t1,t2,t3,t4,t5,t6
|
||||
local r1,r2,r3,r4,r5,r6
|
||||
local ret,_
|
||||
local function helper(i)
|
||||
if ret then
|
||||
if ret[1]=="_kill_" then
|
||||
threads[i].OnDeath:Fire(threads[i],"killed",ret,r1,r2,r3,r4,r5,r6)
|
||||
table.remove(threads,i)
|
||||
ret = nil
|
||||
elseif ret[1]=="_sleep_" then
|
||||
threads[i].sec = ret[2]
|
||||
threads[i].time = clock()
|
||||
threads[i].task = "sleep"
|
||||
threads[i].__ready = false
|
||||
ret = nil
|
||||
elseif ret[1]=="_skip_" then
|
||||
threads[i].count = ret[2]
|
||||
threads[i].pos = 0
|
||||
threads[i].task = "skip"
|
||||
threads[i].__ready = false
|
||||
ret = nil
|
||||
elseif ret[1]=="_hold_" then
|
||||
threads[i].func = ret[2]
|
||||
threads[i].task = "hold"
|
||||
threads[i].__ready = false
|
||||
ret = nil
|
||||
elseif ret[1]=="_holdF_" then
|
||||
threads[i].sec = ret[2]
|
||||
threads[i].func = ret[3]
|
||||
threads[i].task = "holdF"
|
||||
threads[i].time = clock()
|
||||
threads[i].__ready = false
|
||||
ret = nil
|
||||
elseif ret[1]=="_holdW_" then
|
||||
threads[i].count = ret[2]
|
||||
threads[i].pos = 0
|
||||
threads[i].func = ret[3]
|
||||
threads[i].task = "holdW"
|
||||
threads[i].time = clock()
|
||||
threads[i].__ready = false
|
||||
ret = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
while true do
|
||||
for i=#threads,1,-1 do
|
||||
if not threads[i].__started then
|
||||
_,ret,r1,r2,r3,r4,r5,r6=coroutine.resume(threads[i].thread)
|
||||
threads[i].__started = true
|
||||
helper(i)
|
||||
end
|
||||
if not _ then
|
||||
threads[i].OnError:Fire(threads[i],ret)
|
||||
end
|
||||
if coroutine.status(threads[i].thread)=="dead" then
|
||||
threads[i].OnDeath(threads[i],"ended",ret,r1,r2,r3,r4,r5,r6)
|
||||
table.remove(threads,i)
|
||||
elseif threads[i].task == "skip" then
|
||||
threads[i].pos = threads[i].pos + 1
|
||||
if threads[i].count==threads[i].pos then
|
||||
threads[i].task = ""
|
||||
threads[i].__ready = true
|
||||
end
|
||||
elseif threads[i].task == "hold" then
|
||||
t0,t1,t2,t3,t4,t5,t6 = threads[i].func()
|
||||
if t0 then
|
||||
threads[i].task = ""
|
||||
threads[i].__ready = true
|
||||
end
|
||||
elseif threads[i].task == "sleep" then
|
||||
if clock() - threads[i].time>=threads[i].sec then
|
||||
threads[i].task = ""
|
||||
threads[i].__ready = true
|
||||
end
|
||||
elseif threads[i].task == "holdF" then
|
||||
t0,t1,t2,t3,t4,t5,t6 = threads[i].func()
|
||||
if t0 then
|
||||
threads[i].task = ""
|
||||
threads[i].__ready = true
|
||||
elseif clock() - threads[i].time>=threads[i].sec then
|
||||
threads[i].task = ""
|
||||
threads[i].__ready = true
|
||||
t0 = nil
|
||||
t1 = "TIMEOUT"
|
||||
end
|
||||
elseif threads[i].task == "holdW" then
|
||||
threads[i].pos = threads[i].pos + 1
|
||||
t0,t1,t2,t3,t4,t5,t6 = threads[i].func()
|
||||
if t0 then
|
||||
threads[i].task = ""
|
||||
threads[i].__ready = true
|
||||
elseif threads[i].count==threads[i].pos then
|
||||
threads[i].task = ""
|
||||
threads[i].__ready = true
|
||||
t0 = nil
|
||||
t1 = "TIMEOUT"
|
||||
end
|
||||
end
|
||||
if threads[i] and threads[i].__ready then
|
||||
threads[i].__ready = false
|
||||
_,ret,r1,r2,r3,r4,r5,r6=coroutine.resume(threads[i].thread,t0,t1,t2,t3,t4,t5,t6)
|
||||
end
|
||||
helper(i)
|
||||
end
|
||||
end
|
||||
multi.initThreads(true)
|
||||
end
|
||||
multi.OnError=multi:newConnection()
|
||||
function multi:newThreadedProcess(name)
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
--[[
|
||||
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()
|
||||
local GLOBAL, THREAD = multi.integration.GLOBAL,multi.integration.THREAD
|
||||
function multi:newSystemThreadedQueue(name)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
--[[
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Ryan Ward
|
||||
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
|
||||
@@ -30,13 +30,6 @@ if multi.integration then -- This allows us to call the lanes manager from suppo
|
||||
end
|
||||
}
|
||||
end
|
||||
function os.getOS()
|
||||
if package.config:sub(1, 1) == "\\" then
|
||||
return "windows"
|
||||
else
|
||||
return "unix"
|
||||
end
|
||||
end
|
||||
-- Step 1 get lanes
|
||||
lanes = require("lanes").configure()
|
||||
multi.SystemThreads = {}
|
||||
@@ -50,114 +43,11 @@ end
|
||||
-- Step 2 set up the Linda objects
|
||||
local __GlobalLinda = lanes.linda() -- handles global stuff
|
||||
local __SleepingLinda = lanes.linda() -- handles sleeping stuff
|
||||
-- For convenience a GLOBAL table will be constructed to handle requests
|
||||
local GLOBAL = {}
|
||||
setmetatable(
|
||||
GLOBAL,
|
||||
{
|
||||
__index = function(t, k)
|
||||
return __GlobalLinda:get(k)
|
||||
end,
|
||||
__newindex = function(t, k, v)
|
||||
__GlobalLinda:set(k, v)
|
||||
end
|
||||
}
|
||||
)
|
||||
-- Step 3 rewrite the thread methods to use Lindas
|
||||
local THREAD = {}
|
||||
function THREAD.set(name, val)
|
||||
__GlobalLinda:set(name, val)
|
||||
end
|
||||
function THREAD.get(name)
|
||||
__GlobalLinda:get(name)
|
||||
end
|
||||
local function randomString(n)
|
||||
local str = ""
|
||||
local strings = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","1","2","3","4","5","6","7","8","9","0","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"}
|
||||
for i = 1, n do
|
||||
str = str .. "" .. strings[math.random(1, #strings)]
|
||||
end
|
||||
return str
|
||||
end
|
||||
function THREAD.waitFor(name)
|
||||
local function wait()
|
||||
math.randomseed(os.time())
|
||||
__SleepingLinda:receive(.001, randomString(12))
|
||||
end
|
||||
repeat
|
||||
wait()
|
||||
until __GlobalLinda:get(name)
|
||||
return __GlobalLinda:get(name)
|
||||
end
|
||||
function THREAD.testFor(name, val, sym)
|
||||
--
|
||||
end
|
||||
function THREAD.getCores()
|
||||
return THREAD.__CORES
|
||||
end
|
||||
function THREAD.getThreads()
|
||||
return GLOBAL.__THREADS__
|
||||
end
|
||||
if os.getOS() == "windows" then
|
||||
THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
|
||||
else
|
||||
THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n"))
|
||||
end
|
||||
function THREAD.kill() -- trigger the lane destruction
|
||||
error("Thread was killed!")
|
||||
end
|
||||
function THREAD.getName()
|
||||
return THREAD_NAME
|
||||
end
|
||||
function THREAD.getID()
|
||||
return THREAD_ID
|
||||
end
|
||||
_G.THREAD_ID = 0
|
||||
--[[ Step 4 We need to get sleeping working to handle timing... We want idle wait, not busy wait
|
||||
Idle wait keeps the CPU running better where busy wait wastes CPU cycles... Lanes does not have a sleep method
|
||||
however, a linda recieve will in fact be a idle wait! So we use that and wrap it in a nice package]]
|
||||
function THREAD.sleep(n)
|
||||
math.randomseed(os.time())
|
||||
__SleepingLinda:receive(n, randomString(12))
|
||||
end
|
||||
function THREAD.hold(n)
|
||||
local function wait()
|
||||
math.randomseed(os.time())
|
||||
__SleepingLinda:receive(.001, randomString(12))
|
||||
end
|
||||
repeat
|
||||
wait()
|
||||
until n()
|
||||
end
|
||||
local rand = math.random(1, 10000000)
|
||||
-- Step 5 Basic Threads!
|
||||
local GLOBAL,THREAD = require("multi.integration.lanesManager.threads").init(__GlobalLinda,__SleepingLinda)
|
||||
local threads = {}
|
||||
local count = 1
|
||||
local started = false
|
||||
local livingThreads = {}
|
||||
function multi.removeUpvalues(func)
|
||||
if not debug then return end
|
||||
local count=1
|
||||
local dat = true
|
||||
while dat do
|
||||
dat = debug.setupvalue(func, count, nil)
|
||||
count = count+1
|
||||
end
|
||||
end
|
||||
function multi.getUpvalues(func)
|
||||
local count=1
|
||||
local tab = {}
|
||||
local dat = true
|
||||
while dat do
|
||||
dat = debug.getupvalue(func, count)
|
||||
if dat then
|
||||
table.insert(tab,dat)
|
||||
print(dat)
|
||||
end
|
||||
count = count+1
|
||||
end
|
||||
return tab
|
||||
end
|
||||
function multi:newSystemThread(name, func, ...)
|
||||
multi.InitSystemThreadErrorHandler()
|
||||
rand = math.random(1, 10000000)
|
||||
|
||||
@@ -1,3 +1,33 @@
|
||||
--[[
|
||||
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 function getOS()
|
||||
if package.config:sub(1, 1) == "\\" then
|
||||
return "windows"
|
||||
else
|
||||
return "unix"
|
||||
end
|
||||
end
|
||||
local function INIT(__GlobalLinda,__SleepingLinda)
|
||||
local THREAD = {}
|
||||
function THREAD.set(name, val)
|
||||
@@ -16,8 +46,10 @@ local function INIT(__GlobalLinda,__SleepingLinda)
|
||||
until __GlobalLinda:get(name)
|
||||
return __GlobalLinda:get(name)
|
||||
end
|
||||
function THREAD.testFor(name, val, sym)
|
||||
--
|
||||
if getOS() == "windows" then
|
||||
THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
|
||||
else
|
||||
THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n"))
|
||||
end
|
||||
function THREAD.getCores()
|
||||
return THREAD.__CORES
|
||||
@@ -59,9 +91,6 @@ local function INIT(__GlobalLinda,__SleepingLinda)
|
||||
return __GlobalLinda:get(k)
|
||||
end,
|
||||
__newindex = function(t, k, v)
|
||||
for i,v in pairs(__GlobalLinda) do
|
||||
print(i,v)
|
||||
end
|
||||
__GlobalLinda:set(k, v)
|
||||
end
|
||||
})
|
||||
|
||||
@@ -1,5 +1,27 @@
|
||||
--[[
|
||||
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()
|
||||
local status = require("multi.integration.loveManager.status")
|
||||
local pad = require("multi.integration.loveManager.scratchpad")
|
||||
GLOBAL = multi.integration.GLOBAL
|
||||
THREAD = multi.integration.THREAD
|
||||
|
||||
@@ -1,17 +1,37 @@
|
||||
--[[
|
||||
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 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!
|
||||
scratchpad = require("multi.integration.loveManager.scratchpad")
|
||||
STATUS = require("multi.integration.loveManager.status")
|
||||
__IMPORTS = {...}
|
||||
__FUNC__=table.remove(__IMPORTS,1)
|
||||
__THREADID__=table.remove(__IMPORTS,1)
|
||||
__THREADNAME__=table.remove(__IMPORTS,1)
|
||||
pad=table.remove(__IMPORTS,1)
|
||||
globalhpad=table.remove(__IMPORTS,1)
|
||||
GLOBAL = THREAD.getGlobal()
|
||||
multi, thread = require("multi").init()
|
||||
THREAD.loadDump(__FUNC__)(unpack(__IMPORTS))]]
|
||||
@@ -21,21 +41,16 @@ __THREADID__ = 0
|
||||
__THREADNAME__ = "MainThread"
|
||||
multi.integration={}
|
||||
multi.integration.love2d={}
|
||||
multi.integration.love2d.defaultScratchpadSize = 1024
|
||||
multi.integration.love2d.GlobalScratchpad = love.data.newByteData(string.rep("\0",16*multi.integration.love2d.defaultScratchpadSize))
|
||||
local THREAD = require("multi.integration.loveManager.threads")
|
||||
local scratchpad = require("multi.integration.loveManager.scratchpad")
|
||||
local STATUS = require("multi.integration.loveManager.status")
|
||||
local GLOBAL = THREAD.getGlobal()
|
||||
local THREAD_ID = 1 -- The Main thread has ID of 0
|
||||
local THREAD_ID = 1
|
||||
local OBJECT_ID = 0
|
||||
function multi:newSystemThread(name,func,...)
|
||||
local c = {}
|
||||
c.scratchpad = love.data.newByteData(string.rep("\0",multi.integration.love2d.defaultScratchpadSize))
|
||||
c.name = name
|
||||
c.ID=THREAD_ID
|
||||
c.thread=love.thread.newThread(ThreadFileData)
|
||||
c.thread:start(THREAD.dump(func),c.ID,c.name,c.scratchpad,multi.integration.love2d.GlobalScratchpad,...)
|
||||
c.thread:start(THREAD.dump(func),c.ID,c.name,...)
|
||||
GLOBAL["__THREAD_"..c.ID] = {ID=c.ID,Name=c.name,Thread=c.thread}
|
||||
GLOBAL["__THREAD_COUNT"] = THREAD_ID
|
||||
THREAD_ID=THREAD_ID+1
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
local ffi = require("ffi")
|
||||
local scratchpad = {}
|
||||
local mt = {
|
||||
__index = function(t, k)
|
||||
if type(k)=="string" then
|
||||
local a, b = k:match("(%d+):(%d+)")
|
||||
return t:read(tonumber(a),tonumber(b))
|
||||
elseif type(k)=="number" then
|
||||
return t:read(k,1)
|
||||
end
|
||||
end,
|
||||
__newindex = function(t, k, v)
|
||||
t:write(v,k)
|
||||
end
|
||||
}
|
||||
function scratchpad:new(data, size, rep)
|
||||
local c = {}
|
||||
local pad
|
||||
if type(data)=="string" then
|
||||
pad = love.data.newByteData(data or string.rep(rep or "\0",size or 16))
|
||||
elseif data:type()=="ByteData" then
|
||||
pad = data
|
||||
end
|
||||
local ptr = ffi.cast("unsigned char*",pad:getPointer())
|
||||
local size = pad:getSize()
|
||||
function c:write(data, loc, len)
|
||||
if (loc or 0)+(len or #data)>size then
|
||||
error("Attpemting to write data outside the bounds of data byte array!")
|
||||
end
|
||||
ffi.copy(ptr+(loc or 0), data, len or #data)
|
||||
end
|
||||
function c:read(loc, len)
|
||||
if (((loc or 0)+(len or size)) > size) or ((loc or 0)<0) then
|
||||
error("Attempt to read outside the bounds of the scratchpad!")
|
||||
end
|
||||
return ffi.string(ptr+(loc or 0), len or size)
|
||||
end
|
||||
setmetatable(c,mt)
|
||||
return c
|
||||
end
|
||||
return scratchpad
|
||||
@@ -1,13 +0,0 @@
|
||||
--[[
|
||||
global pads allow us to directly write data to threads. Each thread has a unique ID which means we can allocate space in memory for each thread to relay stats
|
||||
Below are codes, If there is more data that needs to be sent we can use byte 0 for that and byte 1,2 and 3 to define a channel
|
||||
]]
|
||||
local char = string.char
|
||||
local cmds = {
|
||||
OK = char(0x00), -- All is good thread is running can recieve and send data
|
||||
ERR = char(0x01), -- This tells the system that an error has occured
|
||||
STOP = char(0x02), -- Thread has finished
|
||||
BUSY = char(0x03), -- Thread is busy and isn't responding to messages right now
|
||||
POST = char(0x04), -- Important message for other threads to see, ChannelData with message MSG_TID
|
||||
}
|
||||
return cmds
|
||||
@@ -1,5 +1,25 @@
|
||||
--[[
|
||||
Shared methods for both the main thread and
|
||||
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.
|
||||
]]
|
||||
require("love.timer")
|
||||
require("love.system")
|
||||
@@ -47,7 +67,6 @@ function threads.get(name)
|
||||
return dat
|
||||
end
|
||||
end
|
||||
|
||||
function threads.waitFor(name)
|
||||
if thread.isThread() then
|
||||
return thread.hold(function()
|
||||
@@ -63,22 +82,17 @@ function threads.waitFor(name)
|
||||
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.testFor(name,val,sym)
|
||||
-- Not yet implemented
|
||||
end
|
||||
function threads.getCores()
|
||||
return love.system.getProcessorCount()
|
||||
end
|
||||
function threads.kill()
|
||||
|
||||
error("Thread Killed!")
|
||||
end
|
||||
function threads.getThreads()
|
||||
local t = {}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
--[[
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Ryan Ward
|
||||
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
|
||||
@@ -21,8 +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.
|
||||
]]
|
||||
-- I DEMAND USAGE FOR LUVIT
|
||||
-- Cannot use discordia without my multitasking library (Which I love more that the luvit platform... then again i'm partial :P)
|
||||
|
||||
-- This module probably will not be maintained any longer!
|
||||
package.path = "?/init.lua;?.lua;" .. package.path
|
||||
local function _INIT(luvitThread, timer)
|
||||
-- lots of this stuff should be able to stay the same
|
||||
@@ -66,70 +66,7 @@ local function _INIT(luvitThread, timer)
|
||||
end
|
||||
local function randomString(n)
|
||||
local str = ""
|
||||
local strings = {
|
||||
"a",
|
||||
"b",
|
||||
"c",
|
||||
"d",
|
||||
"e",
|
||||
"f",
|
||||
"g",
|
||||
"h",
|
||||
"i",
|
||||
"j",
|
||||
"k",
|
||||
"l",
|
||||
"m",
|
||||
"n",
|
||||
"o",
|
||||
"p",
|
||||
"q",
|
||||
"r",
|
||||
"s",
|
||||
"t",
|
||||
"u",
|
||||
"v",
|
||||
"w",
|
||||
"x",
|
||||
"y",
|
||||
"z",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
"0",
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"H",
|
||||
"I",
|
||||
"J",
|
||||
"K",
|
||||
"L",
|
||||
"M",
|
||||
"N",
|
||||
"O",
|
||||
"P",
|
||||
"Q",
|
||||
"R",
|
||||
"S",
|
||||
"T",
|
||||
"U",
|
||||
"V",
|
||||
"W",
|
||||
"X",
|
||||
"Y",
|
||||
"Z"
|
||||
}
|
||||
local strings = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","1","2","3","4","5","6","7","8","9","0","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"}
|
||||
for i = 1, n do
|
||||
str = str .. "" .. strings[math.random(1, #strings)]
|
||||
end
|
||||
@@ -195,6 +132,6 @@ local function _INIT(luvitThread, timer)
|
||||
return multi
|
||||
end
|
||||
return {init = function(threadHandle, timerHandle)
|
||||
local multi = _INIT(threadHandle, timerHandle)
|
||||
return GLOBAL, THREAD
|
||||
end}
|
||||
local multi = _INIT(threadHandle, timerHandle)
|
||||
return GLOBAL, THREAD
|
||||
end}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
--[[
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Ryan Ward
|
||||
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
|
||||
@@ -21,7 +21,7 @@ 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()
|
||||
local multi, thread = require("multi"):init()
|
||||
local net = require("net")
|
||||
local bin = require("bin")
|
||||
bin.setBitsInterface(infinabits) -- the bits interface does not work so well, another bug to fix
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
local cmds = {
|
||||
ERROR = 0x00,
|
||||
PING = 0x01,
|
||||
PONG = 0x02,
|
||||
QUEUE = 0x03,
|
||||
TASK = 0x04,
|
||||
INITNODE = 0x05,
|
||||
INITMASTER = 0x06,
|
||||
GLOBAL = 0x07,
|
||||
LOAD = 0x08,
|
||||
CALL = 0x09,
|
||||
REG = 0x0A,
|
||||
CONSOLE = 0x0B,
|
||||
}
|
||||
return cmds
|
||||
@@ -0,0 +1,23 @@
|
||||
--[[
|
||||
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.
|
||||
]]
|
||||
@@ -0,0 +1,57 @@
|
||||
--[[
|
||||
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()
|
||||
local net = require("net")
|
||||
local bin = require("bin")
|
||||
local char = string.char
|
||||
local byte = string.byte
|
||||
bin.setBitsInterface(infinabits)
|
||||
--[[
|
||||
--[=[ Pre reqs:
|
||||
- Network contains nodes
|
||||
- Network can broadcast/has nodemanager/ is simple and can be scanned
|
||||
|
||||
Outline:
|
||||
- multi:newMasterNode(connectionDetails)
|
||||
-- master:setDefaultNode(nodeName) -- Set default node
|
||||
-- master:newNetworkThread(nodeName,func,...) -- Thread is ran on a random node or the default one if set if nodeName is set to nil
|
||||
-- master:newNetworkChannel(nodeName)
|
||||
-- master:sendTo(nodeName,data)
|
||||
- multi:newNode(connectionDetails)
|
||||
- multi:newNodeManager(connectionDetails) -- This will be incharge of a lot of data handling
|
||||
]=]
|
||||
|
||||
local nGLOBAL, nTHREAD = require("multi.integration.networkManager"):init()
|
||||
local master = multi:newMasterNode()
|
||||
master:newNetworkThread("simpleNode",function(a,b,c)
|
||||
print(a,b,c)
|
||||
end,1,2,3)
|
||||
]]
|
||||
|
||||
-- The init file should provide the structure that all the other modules build off of
|
||||
return {
|
||||
init = function()
|
||||
--
|
||||
end
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
--[[
|
||||
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()
|
||||
local cmd = require("multi.integration.networkManager.cmds")
|
||||
local net = require("net")
|
||||
local bin = require("bin")
|
||||
local master = {}
|
||||
master.__index = master
|
||||
function multi:newMasterNode(connectionDetails)
|
||||
local c = {}
|
||||
c.OnDataRecieved = multi:newConnection()
|
||||
c.defaultNode = ""
|
||||
c.nodes = {}
|
||||
if connectionDetails then
|
||||
-- We do what we do
|
||||
else
|
||||
-- Lets make assumptions
|
||||
end
|
||||
setmetatable(c, master)
|
||||
return c
|
||||
end
|
||||
function master:setDefaultNode(nodeName)
|
||||
-- Verify Node is active
|
||||
if self:nodeExists(nodeName) then
|
||||
self.defaultNode = nodeName
|
||||
end
|
||||
end
|
||||
function master:newNetworkThread(nodeName,func)
|
||||
--
|
||||
end
|
||||
function master:newNetworkChannel(nodeName)
|
||||
--
|
||||
end
|
||||
function master:sendTo(nodeName,data)
|
||||
if self:nodeExists(nodeName):wait() then
|
||||
print("It exists!")
|
||||
end
|
||||
end
|
||||
master.nodeExists = thread:newFunction(function(self,nodeName)
|
||||
if self.nodes[nodeName] then
|
||||
local wait = nodes[nodeName]:ping()
|
||||
local bool = thread.hold(function()
|
||||
return wait()
|
||||
end)
|
||||
return bool
|
||||
else
|
||||
return false
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,23 @@
|
||||
--[[
|
||||
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.
|
||||
]]
|
||||
@@ -0,0 +1,4 @@
|
||||
local bin = require("bin")
|
||||
local utils = {}
|
||||
-- Will contain data that handles sterilizing and managing data
|
||||
return utils
|
||||
@@ -1,7 +1,7 @@
|
||||
--[[
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Ryan Ward
|
||||
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
|
||||
@@ -167,7 +167,6 @@ function multi:newSystemThreadedConnection(name, protect)
|
||||
GLOBAL[c.name] = c
|
||||
return c
|
||||
end
|
||||
|
||||
function multi:SystemThreadedBenchmark(n)
|
||||
n = n or 1
|
||||
local cores = multi.integration.THREAD.getCores()
|
||||
@@ -269,232 +268,6 @@ function multi:newSystemThreadedConsole(name)
|
||||
GLOBAL[c.name] = c
|
||||
return c
|
||||
end
|
||||
-- NEEDS WORK
|
||||
function multi:newSystemThreadedTable(name)
|
||||
local c = {}
|
||||
c.name = name -- set the name this is important for identifying what is what
|
||||
local sThread = multi.integration.THREAD
|
||||
local GLOBAL = multi.integration.GLOBAL
|
||||
function c:init() -- create an init function so we can mimic on both love2d and lanes
|
||||
_G.__Needs_Multi = true
|
||||
local multi = require("multi")
|
||||
if multi:getPlatform() == "love2d" then
|
||||
GLOBAL = _G.GLOBAL
|
||||
sThread = _G.sThread
|
||||
end
|
||||
local cc = {}
|
||||
cc.tab = {}
|
||||
if multi.isMainThread then
|
||||
if not GLOBAL[self.name .. "_Tabled_Connection"] then
|
||||
cc.conn = multi:newSystemThreadedConnection(self.name .. "_Tabled_Connection"):init()
|
||||
end
|
||||
else
|
||||
cc.conn = sThread.waitFor(self.name .. "_Tabled_Connection"):init()
|
||||
end
|
||||
function cc:waitFor(name)
|
||||
repeat
|
||||
multi:uManager()
|
||||
until tab[name] ~= nil
|
||||
return tab[name]
|
||||
end
|
||||
local link = cc
|
||||
cc.conn(
|
||||
function(k, v)
|
||||
link.tab[k] = v
|
||||
end
|
||||
)
|
||||
setmetatable(
|
||||
cc,
|
||||
{
|
||||
__index = function(t, k)
|
||||
return t.tab[k]
|
||||
end,
|
||||
__newindex = function(t, k, v)
|
||||
t.tab[k] = v
|
||||
t.conn:Fire(k, v)
|
||||
end
|
||||
}
|
||||
)
|
||||
return cc
|
||||
end
|
||||
GLOBAL[c.name] = c
|
||||
return c
|
||||
end
|
||||
local jobqueuecount = 0
|
||||
local jqueues = {}
|
||||
function multi:newSystemThreadedJobQueue(a, b)
|
||||
jobqueuecount = jobqueuecount + 1
|
||||
local GLOBAL = multi.integration.GLOBAL
|
||||
local sThread = multi.integration.THREAD
|
||||
local c = {}
|
||||
c.numberofcores = 4
|
||||
c.idle = nil
|
||||
c.name = "SYSTEM_THREADED_JOBQUEUE_" .. jobqueuecount
|
||||
-- This is done to keep backwards compatibility for older code
|
||||
if type(a) == "string" and not (b) then
|
||||
c.name = a
|
||||
elseif type(a) == "number" and not (b) then
|
||||
c.numberofcores = a
|
||||
elseif type(a) == "string" and type(b) == "number" then
|
||||
c.name = a
|
||||
c.numberofcores = b
|
||||
elseif type(a) == "number" and type(b) == "string" then
|
||||
c.name = b
|
||||
c.numberofcores = a
|
||||
end
|
||||
if jqueues[c.name] then
|
||||
error("A job queue by the name: " .. c.name .. " already exists!")
|
||||
end
|
||||
jqueues[c.name] = true
|
||||
c.isReady = false
|
||||
c.jobnum = 1
|
||||
c.OnJobCompleted = multi:newConnection()
|
||||
local queueIN = self:newSystemThreadedQueue("QUEUE_IN_" .. c.name):init()
|
||||
local queueCC = self:newSystemThreadedQueue("QUEUE_CC_" .. c.name):init()
|
||||
local queueREG = self:newSystemThreadedQueue("QUEUE_REG_" .. c.name):init()
|
||||
local queueJD = self:newSystemThreadedQueue("QUEUE_JD_" .. c.name):init()
|
||||
local queueDA = self:newSystemThreadedQueue("QUEUE_DA_" .. c.name):init()
|
||||
c.OnReady = multi:newConnection()
|
||||
function c:registerJob(name, func)
|
||||
for i = 1, self.numberofcores do
|
||||
queueREG:push({name, func})
|
||||
end
|
||||
end
|
||||
c.tempQueue = {}
|
||||
function c:pushJob(name, ...)
|
||||
c.idle = os.clock()
|
||||
if not self.isReady then
|
||||
table.insert(c.tempQueue, {self.jobnum, name, ...})
|
||||
self.jobnum = self.jobnum + 1
|
||||
return self.jobnum - 1
|
||||
else
|
||||
queueIN:push {self.jobnum, name, ...}
|
||||
self.jobnum = self.jobnum + 1
|
||||
return self.jobnum - 1
|
||||
end
|
||||
end
|
||||
function c:doToAll(func)
|
||||
local r = multi.randomString(12)
|
||||
for i = 1, self.numberofcores do
|
||||
queueDA:push {r, func}
|
||||
end
|
||||
end
|
||||
for i = 1, c.numberofcores do
|
||||
multi:newSystemThread(
|
||||
c.name .. " Worker Thread #" .. i,
|
||||
function(name)
|
||||
local multi = require("multi")
|
||||
if love then -- lets make sure we don't reference up-values if using love2d
|
||||
GLOBAL = _G.GLOBAL
|
||||
sThread = _G.sThread
|
||||
end
|
||||
local CC = sThread.waitFor("QUEUE_CC_" .. name):init()
|
||||
CC:push("ready")
|
||||
local FUNCS = {}
|
||||
local ids = {}
|
||||
local JQI = sThread.waitFor("QUEUE_IN_" .. name):init()
|
||||
local JD = sThread.waitFor("QUEUE_JD_" .. name):init()
|
||||
local REG = sThread.waitFor("QUEUE_REG_" .. name):init()
|
||||
local DA = sThread.waitFor("QUEUE_DA_" .. name):init()
|
||||
local lastjob = os.clock()
|
||||
multi:newLoop(
|
||||
function()
|
||||
local job = JQI:pop()
|
||||
local rd = REG:peek()
|
||||
local da = DA:peek()
|
||||
if rd then
|
||||
if not FUNCS[rd[1]] then
|
||||
FUNCS[rd[1]] = rd[2]
|
||||
rd = nil
|
||||
REG:pop()
|
||||
end
|
||||
end
|
||||
if da then
|
||||
if not ids[da[1]] then
|
||||
local meh = da[1]
|
||||
ids[da[1]] = true
|
||||
da[2](multi)
|
||||
da = nil
|
||||
DA:pop()
|
||||
multi:newAlarm(60):OnRing(
|
||||
function(a)
|
||||
ids[meh] = nil
|
||||
a:Destroy()
|
||||
end
|
||||
)
|
||||
end
|
||||
end
|
||||
if job then
|
||||
lastjob = os.clock()
|
||||
local ID = table.remove(job, 1) -- return and remove
|
||||
local _name = table.remove(job, 1) -- return and remove
|
||||
if FUNCS[_name] then
|
||||
JD:push({ID, FUNCS[_name](unpack(job))})
|
||||
else -- making use of that new holding feature
|
||||
JD:push({ID, FUNCS:waitFor(_name)(unpack(job))})
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
multi:newLoop(
|
||||
function()
|
||||
if os.clock() - lastjob > 1 then
|
||||
sThread.sleep(.1)
|
||||
end
|
||||
end
|
||||
)
|
||||
setmetatable(
|
||||
_G,
|
||||
{
|
||||
__index = function(t, k)
|
||||
return FUNCS[k]
|
||||
end
|
||||
}
|
||||
)
|
||||
if not love then
|
||||
multi:mainloop()
|
||||
end
|
||||
end,
|
||||
c.name
|
||||
)
|
||||
end
|
||||
local clock = os.clock
|
||||
multi:newThread(
|
||||
"JQ-" .. c.name .. " Manager",
|
||||
function()
|
||||
local _count = 0
|
||||
while _count < c.numberofcores do
|
||||
thread.skip()
|
||||
if queueCC:pop() then
|
||||
_count = _count + 1
|
||||
end
|
||||
end
|
||||
c.isReady = true
|
||||
for i = 1, #c.tempQueue do
|
||||
queueIN:push(c.tempQueue[i])
|
||||
end
|
||||
c.tempQueue = nil
|
||||
c.OnReady:Fire(c)
|
||||
local dat
|
||||
while true do
|
||||
if not c.idle then
|
||||
thread.sleep(.5)
|
||||
else
|
||||
if clock() - c.idle >= 15 then
|
||||
c.idle = nil
|
||||
end
|
||||
thread.skip()
|
||||
end
|
||||
dat = queueJD:pop()
|
||||
if dat then
|
||||
c.idle = clock()
|
||||
c.OnJobCompleted:Fire(unpack(dat))
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
return c
|
||||
end
|
||||
function multi:newSystemThreadedExecute(cmd)
|
||||
local c = {}
|
||||
local GLOBAL = multi.integration.GLOBAL -- set up locals incase we are using lanes
|
||||
|
||||
Reference in New Issue
Block a user