working on 1.14.4
This commit is contained in:
parent
296d56d233
commit
689133e71f
33
changes.md
33
changes.md
@ -1,5 +1,38 @@
|
|||||||
# Changes
|
# Changes
|
||||||
[TOC]
|
[TOC]
|
||||||
|
Update 14.0.0 Consistency and stability
|
||||||
|
-------------
|
||||||
|
Added:
|
||||||
|
- multi.init() -- Initlizes the library! Must be called for multiple files to have the same handle. Example below
|
||||||
|
- thread.holdFor(NUMBER sec, FUNCTION condition) -- Works like hold, but timesout when a certain amount of time has passed!
|
||||||
|
- thread.holdWithin(NUMBER; cycles,FUNCTION; condition) -- Holds until the condition is met! If the number of cycles passed is equal to cycles, hold will return a timeout error
|
||||||
|
**Note:** when hold has a timeout the first argument will return nil and the second atgument will be TIMEOUT, if not timed out hold will return the values from the conditions
|
||||||
|
|
||||||
|
Fixed:
|
||||||
|
- Connections had a preformance issue where they would create a non function when using connection.getConnection() of a non existing label.
|
||||||
|
- An internal mismanagement of the treads scheduler was fixed. Now it should be quicker and free of bugs
|
||||||
|
- Thread error management is the integrations was not properly implemented. This is now fixed
|
||||||
|
-
|
||||||
|
|
||||||
|
Changed:
|
||||||
|
- Ties in to the new function that has been added multi.init()
|
||||||
|
```lua
|
||||||
|
local multi, thread = require("multi").init() -- The require multi function still returns the multi object like before
|
||||||
|
```
|
||||||
|
Note: Using init allows you to get access to the thread handle. This was done because thread was modifying the global space as well as multi. I wanted to not modify the global space anymore.
|
||||||
|
internally most of your code can stay the same, you only need to change how the library is required. I do toy a bit with the global space, buy I use a variable name that is invalid as a variable name. The variable name is $multi. This is used internally to keep some records and maintain a clean space
|
||||||
|
|
||||||
|
Also when using intergrations things now look more consistant.
|
||||||
|
```lua
|
||||||
|
local multi, thread = require("multi").init()
|
||||||
|
local GLOBSL, THREAD = require("multi.integration.lanesManager").init() -- or whichever manager you are using
|
||||||
|
local nGLOBAL, nTHREAD = require("multi.intergration.networkManager).inti()
|
||||||
|
```
|
||||||
|
Note: You can mix and match integrations together. You can create systemthreads within network threads, and you can also create cotoutine based threads within bothe network and system threads. This gives you quite a bit of flexibility to create something awesome.
|
||||||
|
|
||||||
|
Going forward:
|
||||||
|
- Sterlization is still being worked on. I was planning of having a way to save state of multi objects and such, but that isn't possible without knowing how your code is strutured or if it is even made to handle something like that. So I decided on giving a tostirng/tofile method for each multi object as well as a fromstring/fromfile method for use. This is technically in the code already, but not documented. It has actually been in the code for a while, but its not done just yet and I want to make it perfect before sending it out.
|
||||||
|
|
||||||
Update 13.1.0 Bug fixes and features added
|
Update 13.1.0 Bug fixes and features added
|
||||||
-------------
|
-------------
|
||||||
Added:
|
Added:
|
||||||
|
|||||||
@ -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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
]]
|
]]
|
||||||
local multi = require("multi")
|
local multi, thread = require("multi").init()
|
||||||
os.sleep = love.timer.sleep
|
os.sleep = love.timer.sleep
|
||||||
multi.drawF = {}
|
multi.drawF = {}
|
||||||
function multi:onDraw(func, i)
|
function multi:onDraw(func, i)
|
||||||
@ -38,14 +38,18 @@ multi.OnDraw = multi:newConnection()
|
|||||||
multi.OnTextInput = multi:newConnection()
|
multi.OnTextInput = multi:newConnection()
|
||||||
multi.OnUpdate = multi:newConnection()
|
multi.OnUpdate = multi:newConnection()
|
||||||
multi.OnQuit = multi:newConnection()
|
multi.OnQuit = multi:newConnection()
|
||||||
multi.OnPreLoad(function()
|
multi.OnPreLoad(
|
||||||
|
function()
|
||||||
local function Hook(func, conn)
|
local function Hook(func, conn)
|
||||||
if love[func] ~= nil then
|
if love[func] ~= nil then
|
||||||
love[func] = Library.convert(love[func])
|
love[func] = Library.convert(love[func])
|
||||||
love[func]:inject(function(...)
|
love[func]:inject(
|
||||||
|
function(...)
|
||||||
conn:Fire(...)
|
conn:Fire(...)
|
||||||
return {...}
|
return {...}
|
||||||
end,1)
|
end,
|
||||||
|
1
|
||||||
|
)
|
||||||
elseif love[func] == nil then
|
elseif love[func] == nil then
|
||||||
love[func] = function(...)
|
love[func] = function(...)
|
||||||
conn:Fire(...)
|
conn:Fire(...)
|
||||||
@ -62,15 +66,20 @@ multi.OnPreLoad(function()
|
|||||||
Hook("draw", multi.OnDraw)
|
Hook("draw", multi.OnDraw)
|
||||||
Hook("textinput", multi.OnTextInput)
|
Hook("textinput", multi.OnTextInput)
|
||||||
Hook("update", multi.OnUpdate)
|
Hook("update", multi.OnUpdate)
|
||||||
multi.OnDraw(function()
|
multi.OnDraw(
|
||||||
|
function()
|
||||||
for i = 1, #multi.drawF do
|
for i = 1, #multi.drawF do
|
||||||
love.graphics.setColor(255, 255, 255, 255)
|
love.graphics.setColor(255, 255, 255, 255)
|
||||||
multi.drawF[i]()
|
multi.drawF[i]()
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
end)
|
)
|
||||||
multi.OnQuit(function()
|
end
|
||||||
|
)
|
||||||
|
multi.OnQuit(
|
||||||
|
function()
|
||||||
multi.Stop()
|
multi.Stop()
|
||||||
love.event.quit()
|
love.event.quit()
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
return multi
|
return multi
|
||||||
|
|||||||
@ -25,6 +25,9 @@ local bin = pcall(require,"bin")
|
|||||||
local multi = {}
|
local multi = {}
|
||||||
local clock = os.clock
|
local clock = os.clock
|
||||||
local thread = {}
|
local thread = {}
|
||||||
|
if not _G["$multi"] then
|
||||||
|
_G["$multi"] = {multi=multi,thread=thread}
|
||||||
|
end
|
||||||
multi.Version = "13.1.0"
|
multi.Version = "13.1.0"
|
||||||
multi._VERSION = "13.1.0"
|
multi._VERSION = "13.1.0"
|
||||||
multi.stage = "stable"
|
multi.stage = "stable"
|
||||||
@ -78,6 +81,9 @@ multi.PriorityTick=1 -- Between 1, 2 and 4
|
|||||||
multi.Priority=multi.Priority_High
|
multi.Priority=multi.Priority_High
|
||||||
multi.threshold=256
|
multi.threshold=256
|
||||||
multi.threstimed=.001
|
multi.threstimed=.001
|
||||||
|
function multi.init()
|
||||||
|
return _G["$multi"].multi,_G["$multi"].thread
|
||||||
|
end
|
||||||
function multi.queuefinal(self)
|
function multi.queuefinal(self)
|
||||||
self:Destroy()
|
self:Destroy()
|
||||||
if self.Parent.Mainloop[#self.Parent.Mainloop] then
|
if self.Parent.Mainloop[#self.Parent.Mainloop] then
|
||||||
@ -758,6 +764,9 @@ function multi:newConnector()
|
|||||||
local c = {Type = "connector"}
|
local c = {Type = "connector"}
|
||||||
return c
|
return c
|
||||||
end
|
end
|
||||||
|
local CRef = {
|
||||||
|
Fire = function() end
|
||||||
|
}
|
||||||
function multi:newConnection(protect,func)
|
function multi:newConnection(protect,func)
|
||||||
local c={}
|
local c={}
|
||||||
c.callback = func
|
c.callback = func
|
||||||
@ -802,11 +811,9 @@ function multi:newConnection(protect,func)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
c.FConnect=c.fConnect
|
c.FConnect=c.fConnect
|
||||||
function c:getConnection(name,ingore)
|
function c:getConnection(name,ignore)
|
||||||
if ingore then
|
if ignore then
|
||||||
return self.connections[name] or {
|
return self.connections[name] or CRef
|
||||||
Fire=function() return end -- if the connection doesn't exist lets call all of them or silently ignore
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
return self.connections[name] or self
|
return self.connections[name] or self
|
||||||
end
|
end
|
||||||
@ -1489,6 +1496,10 @@ function thread.hold(n)
|
|||||||
thread._Requests()
|
thread._Requests()
|
||||||
return coroutine.yield({"_hold_",n or function() return true end})
|
return coroutine.yield({"_hold_",n or function() return true end})
|
||||||
end
|
end
|
||||||
|
function thread.holdFor(sec,n)
|
||||||
|
thread._Requests()
|
||||||
|
return coroutine.yield({"_holdF_", sec, n or function() return true end})
|
||||||
|
end
|
||||||
function thread.skip(n)
|
function thread.skip(n)
|
||||||
thread._Requests()
|
thread._Requests()
|
||||||
if not n then n = 1 elseif n<1 then n = 1 end
|
if not n then n = 1 elseif n<1 then n = 1 end
|
||||||
@ -1652,6 +1663,13 @@ function multi.initThreads()
|
|||||||
threads[i].task = "hold"
|
threads[i].task = "hold"
|
||||||
threads[i].__ready = false
|
threads[i].__ready = false
|
||||||
ret = nil
|
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
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1684,8 +1702,19 @@ function multi.initThreads()
|
|||||||
threads[i].task = ""
|
threads[i].task = ""
|
||||||
threads[i].__ready = true
|
threads[i].__ready = true
|
||||||
end
|
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
|
end
|
||||||
if threads[i].__ready then
|
end
|
||||||
|
if threads[i] and threads[i].__ready then
|
||||||
threads[i].__ready = false
|
threads[i].__ready = false
|
||||||
_,ret=coroutine.resume(threads[i].thread,t0,t1,t2,t3,t4,t5,t6)
|
_,ret=coroutine.resume(threads[i].thread,t0,t1,t2,t3,t4,t5,t6)
|
||||||
end
|
end
|
||||||
@ -1724,6 +1753,13 @@ function multi:threadloop()
|
|||||||
threads[i].task = "hold"
|
threads[i].task = "hold"
|
||||||
threads[i].__ready = false
|
threads[i].__ready = false
|
||||||
ret = nil
|
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
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1753,6 +1789,17 @@ function multi:threadloop()
|
|||||||
threads[i].task = ""
|
threads[i].task = ""
|
||||||
threads[i].__ready = true
|
threads[i].__ready = true
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
if threads[i].__ready then
|
if threads[i].__ready then
|
||||||
threads[i].__ready = false
|
threads[i].__ready = false
|
||||||
@ -2550,7 +2597,4 @@ end
|
|||||||
function multi:setDefualtStateFlag(opt)
|
function multi:setDefualtStateFlag(opt)
|
||||||
--
|
--
|
||||||
end
|
end
|
||||||
if not(multi.Version == "13.2.0" or multi.Version == "14.0.0") then
|
return multi
|
||||||
_G.thread = thread
|
|
||||||
end
|
|
||||||
return multi, thread
|
|
||||||
|
|||||||
@ -22,18 +22,24 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
]]
|
]]
|
||||||
package.path = "?/init.lua;?.lua;" .. package.path
|
package.path = "?/init.lua;?.lua;" .. package.path
|
||||||
|
local multi, thread = require("multi").init() -- get it all and have it on all lanes
|
||||||
|
if multi.integration then -- This allows us to call the lanes manager from supporting modules without a hassel
|
||||||
|
return {
|
||||||
|
init = function()
|
||||||
|
return multi.integration.GLOBAL, multi.integration.THREAD
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
function os.getOS()
|
function os.getOS()
|
||||||
if package.config:sub(1,1)=='\\' then
|
if package.config:sub(1, 1) == "\\" then
|
||||||
return 'windows'
|
return "windows"
|
||||||
else
|
else
|
||||||
return 'unix'
|
return "unix"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- Step 1 get lanes
|
-- Step 1 get lanes
|
||||||
lanes = require("lanes").configure()
|
lanes = require("lanes").configure()
|
||||||
local multi, thread = require("multi") -- get it all and have it on all lanes
|
|
||||||
multi.SystemThreads = {}
|
multi.SystemThreads = {}
|
||||||
local thread = thread
|
|
||||||
multi.isMainThread = true
|
multi.isMainThread = true
|
||||||
function multi:canSystemThread()
|
function multi:canSystemThread()
|
||||||
return true
|
return true
|
||||||
@ -46,14 +52,17 @@ local __GlobalLinda = lanes.linda() -- handles global stuff
|
|||||||
local __SleepingLinda = lanes.linda() -- handles sleeping stuff
|
local __SleepingLinda = lanes.linda() -- handles sleeping stuff
|
||||||
-- For convenience a GLOBAL table will be constructed to handle requests
|
-- For convenience a GLOBAL table will be constructed to handle requests
|
||||||
local GLOBAL = {}
|
local GLOBAL = {}
|
||||||
setmetatable(GLOBAL,{
|
setmetatable(
|
||||||
|
GLOBAL,
|
||||||
|
{
|
||||||
__index = function(t, k)
|
__index = function(t, k)
|
||||||
return __GlobalLinda:get(k)
|
return __GlobalLinda:get(k)
|
||||||
end,
|
end,
|
||||||
__newindex = function(t, k, v)
|
__newindex = function(t, k, v)
|
||||||
__GlobalLinda:set(k, v)
|
__GlobalLinda:set(k, v)
|
||||||
end,
|
end
|
||||||
})
|
}
|
||||||
|
)
|
||||||
-- Step 3 rewrite the thread methods to use Lindas
|
-- Step 3 rewrite the thread methods to use Lindas
|
||||||
local THREAD = {}
|
local THREAD = {}
|
||||||
function THREAD.set(name, val)
|
function THREAD.set(name, val)
|
||||||
@ -63,10 +72,10 @@ function THREAD.get(name)
|
|||||||
__GlobalLinda:get(name)
|
__GlobalLinda:get(name)
|
||||||
end
|
end
|
||||||
local function randomString(n)
|
local function randomString(n)
|
||||||
local str = ''
|
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
|
for i = 1, n do
|
||||||
str = str..''..strings[math.random(1,#strings)]
|
str = str .. "" .. strings[math.random(1, #strings)]
|
||||||
end
|
end
|
||||||
return str
|
return str
|
||||||
end
|
end
|
||||||
@ -75,7 +84,9 @@ function THREAD.waitFor(name)
|
|||||||
math.randomseed(os.time())
|
math.randomseed(os.time())
|
||||||
__SleepingLinda:receive(.001, randomString(12))
|
__SleepingLinda:receive(.001, randomString(12))
|
||||||
end
|
end
|
||||||
repeat wait() until __GlobalLinda:get(name)
|
repeat
|
||||||
|
wait()
|
||||||
|
until __GlobalLinda:get(name)
|
||||||
return __GlobalLinda:get(name)
|
return __GlobalLinda:get(name)
|
||||||
end
|
end
|
||||||
function THREAD.testFor(name, val, sym)
|
function THREAD.testFor(name, val, sym)
|
||||||
@ -114,7 +125,9 @@ function THREAD.hold(n)
|
|||||||
math.randomseed(os.time())
|
math.randomseed(os.time())
|
||||||
__SleepingLinda:receive(.001, randomString(12))
|
__SleepingLinda:receive(.001, randomString(12))
|
||||||
end
|
end
|
||||||
repeat wait() until n()
|
repeat
|
||||||
|
wait()
|
||||||
|
until n()
|
||||||
end
|
end
|
||||||
local rand = math.random(1, 10000000)
|
local rand = math.random(1, 10000000)
|
||||||
-- Step 5 Basic Threads!
|
-- Step 5 Basic Threads!
|
||||||
@ -161,9 +174,13 @@ function multi:newSystemThread(name,func,...)
|
|||||||
end
|
end
|
||||||
multi.OnSystemThreadDied = multi:newConnection()
|
multi.OnSystemThreadDied = multi:newConnection()
|
||||||
function multi.InitSystemThreadErrorHandler()
|
function multi.InitSystemThreadErrorHandler()
|
||||||
if started==true then return end
|
if started == true then
|
||||||
|
return
|
||||||
|
end
|
||||||
started = true
|
started = true
|
||||||
multi:newThread("ThreadErrorHandler",function()
|
multi:newThread(
|
||||||
|
"ThreadErrorHandler",
|
||||||
|
function()
|
||||||
local threads = multi.SystemThreads
|
local threads = multi.SystemThreads
|
||||||
while true do
|
while true do
|
||||||
thread.sleep(.5) -- switching states often takes a huge hit on performance. half a second to tell me there is an error is good enough.
|
thread.sleep(.5) -- switching states often takes a huge hit on performance. half a second to tell me there is an error is good enough.
|
||||||
@ -189,11 +206,16 @@ function multi.InitSystemThreadErrorHandler()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
end
|
end
|
||||||
multi.print("Integrated Lanes!")
|
multi.print("Integrated Lanes!")
|
||||||
multi.integration = {} -- for module creators
|
multi.integration = {} -- for module creators
|
||||||
multi.integration.GLOBAL = GLOBAL
|
multi.integration.GLOBAL = GLOBAL
|
||||||
multi.integration.THREAD = THREAD
|
multi.integration.THREAD = THREAD
|
||||||
require("multi.integration.shared")
|
require("multi.integration.shared")
|
||||||
return {init=function() return GLOBAL, THREAD end}
|
return {
|
||||||
|
init = function()
|
||||||
|
return GLOBAL, THREAD
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|||||||
@ -22,6 +22,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
]]
|
]]
|
||||||
local multi = require("multi.compat.love2d")
|
local multi = require("multi.compat.love2d")
|
||||||
|
if multi.integration then -- This allows us to call the lanes manager from supporting modules without a hassel
|
||||||
|
return {
|
||||||
|
init = function()
|
||||||
|
return multi.integration.GLOBAL, multi.integration.THREAD
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
function multi:canSystemThread()
|
function multi:canSystemThread()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@ -30,7 +37,8 @@ function multi:getPlatform()
|
|||||||
end
|
end
|
||||||
multi.integration = {}
|
multi.integration = {}
|
||||||
multi.integration.love2d = {}
|
multi.integration.love2d = {}
|
||||||
multi.integration.love2d.ThreadBase=[[
|
multi.integration.love2d.ThreadBase =
|
||||||
|
[[
|
||||||
tab={...}
|
tab={...}
|
||||||
__THREADID__=table.remove(tab,1)
|
__THREADID__=table.remove(tab,1)
|
||||||
__THREADNAME__=table.remove(tab,1)
|
__THREADNAME__=table.remove(tab,1)
|
||||||
@ -201,7 +209,9 @@ multi:mainloop()
|
|||||||
GLOBAL = {} -- Allow main thread to interact with these objects as well
|
GLOBAL = {} -- Allow main thread to interact with these objects as well
|
||||||
_G.THREAD_ID = 0
|
_G.THREAD_ID = 0
|
||||||
__proxy__ = {}
|
__proxy__ = {}
|
||||||
setmetatable(GLOBAL,{
|
setmetatable(
|
||||||
|
GLOBAL,
|
||||||
|
{
|
||||||
__index = function(t, k)
|
__index = function(t, k)
|
||||||
return __proxy__[k]
|
return __proxy__[k]
|
||||||
end,
|
end,
|
||||||
@ -214,8 +224,9 @@ setmetatable(GLOBAL,{
|
|||||||
__channels__[i]:push("SYNC " .. type(v) .. " " .. k .. " " .. resolveData(v))
|
__channels__[i]:push("SYNC " .. type(v) .. " " .. k .. " " .. resolveData(v))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end,
|
end
|
||||||
})
|
}
|
||||||
|
)
|
||||||
THREAD = {} -- Allow main thread to interact with these objects as well
|
THREAD = {} -- Allow main thread to interact with these objects as well
|
||||||
multi.integration.love2d.mainChannel = love.thread.getChannel("__MainChan__")
|
multi.integration.love2d.mainChannel = love.thread.getChannel("__MainChan__")
|
||||||
isMainThread = true
|
isMainThread = true
|
||||||
@ -232,7 +243,7 @@ function ToStr(val, name, skipnewlines, depth)
|
|||||||
local tmp = string.rep(" ", depth)
|
local tmp = string.rep(" ", depth)
|
||||||
if name then
|
if name then
|
||||||
if type(name) == "string" then
|
if type(name) == "string" then
|
||||||
tmp = tmp .. "[\""..name.."\"] = "
|
tmp = tmp .. '["' .. name .. '"] = '
|
||||||
else
|
else
|
||||||
tmp = tmp .. "[" .. (name or "") .. "] = "
|
tmp = tmp .. "[" .. (name or "") .. "] = "
|
||||||
end
|
end
|
||||||
@ -252,7 +263,7 @@ function ToStr(val, name, skipnewlines, depth)
|
|||||||
elseif type(val) == "function" then
|
elseif type(val) == "function" then
|
||||||
tmp = tmp .. "loadDump([===[" .. dump(val) .. "]===])"
|
tmp = tmp .. "loadDump([===[" .. dump(val) .. "]===])"
|
||||||
else
|
else
|
||||||
tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
|
tmp = tmp .. '"[inserializeable datatype:' .. type(val) .. ']"'
|
||||||
end
|
end
|
||||||
return tmp
|
return tmp
|
||||||
end
|
end
|
||||||
@ -297,10 +308,10 @@ function dump(func)
|
|||||||
return table.concat(code)
|
return table.concat(code)
|
||||||
end
|
end
|
||||||
local function randomString(n)
|
local function randomString(n)
|
||||||
local str = ''
|
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
|
for i = 1, n do
|
||||||
str = str..''..strings[math.random(1,#strings)]
|
str = str .. "" .. strings[math.random(1, #strings)]
|
||||||
end
|
end
|
||||||
return str
|
return str
|
||||||
end
|
end
|
||||||
@ -328,7 +339,11 @@ function multi:newSystemThread(name,func,...) -- the main method
|
|||||||
end
|
end
|
||||||
function love.threaderror(thread, errorstr)
|
function love.threaderror(thread, errorstr)
|
||||||
multi.OnError:Fire(thread, errorstr)
|
multi.OnError:Fire(thread, errorstr)
|
||||||
livingThreads[thread].OnError:Fire(threads[i],err,"Error in systemThread: '"..livingThreads[thread].name.."' <"..errorstr..">")
|
livingThreads[thread].OnError:Fire(
|
||||||
|
threads[i],
|
||||||
|
err,
|
||||||
|
"Error in systemThread: '" .. livingThreads[thread].name .. "' <" .. errorstr .. ">"
|
||||||
|
)
|
||||||
multi.print("Error in systemThread: " .. tostring(thread) .. ": " .. errorstr)
|
multi.print("Error in systemThread: " .. tostring(thread) .. ": " .. errorstr)
|
||||||
end
|
end
|
||||||
local THREAD = {}
|
local THREAD = {}
|
||||||
@ -339,7 +354,9 @@ function THREAD.get(name)
|
|||||||
return GLOBAL[name]
|
return GLOBAL[name]
|
||||||
end
|
end
|
||||||
function THREAD.waitFor(name)
|
function THREAD.waitFor(name)
|
||||||
repeat multi:uManager() until GLOBAL[name]
|
repeat
|
||||||
|
multi:uManager()
|
||||||
|
until GLOBAL[name]
|
||||||
return GLOBAL[name]
|
return GLOBAL[name]
|
||||||
end
|
end
|
||||||
function THREAD.getCores()
|
function THREAD.getCores()
|
||||||
@ -349,12 +366,16 @@ function THREAD.sleep(n)
|
|||||||
love.timer.sleep(n)
|
love.timer.sleep(n)
|
||||||
end
|
end
|
||||||
function THREAD.hold(n)
|
function THREAD.hold(n)
|
||||||
repeat multi:uManager() until n()
|
repeat
|
||||||
|
multi:uManager()
|
||||||
|
until n()
|
||||||
end
|
end
|
||||||
__channels__ = {}
|
__channels__ = {}
|
||||||
multi.integration.GLOBAL = GLOBAL
|
multi.integration.GLOBAL = GLOBAL
|
||||||
multi.integration.THREAD = THREAD
|
multi.integration.THREAD = THREAD
|
||||||
updater=multi:newLoop(function(self)
|
updater =
|
||||||
|
multi:newLoop(
|
||||||
|
function(self)
|
||||||
local data = multi.integration.love2d.mainChannel:pop()
|
local data = multi.integration.love2d.mainChannel:pop()
|
||||||
while data do
|
while data do
|
||||||
if type(data) == "string" then
|
if type(data) == "string" then
|
||||||
@ -384,13 +405,18 @@ updater=multi:newLoop(function(self)
|
|||||||
end
|
end
|
||||||
data = multi.integration.love2d.mainChannel:pop()
|
data = multi.integration.love2d.mainChannel:pop()
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
multi.OnSystemThreadDied = multi:newConnection()
|
multi.OnSystemThreadDied = multi:newConnection()
|
||||||
local started = false
|
local started = false
|
||||||
function multi.InitSystemThreadErrorHandler()
|
function multi.InitSystemThreadErrorHandler()
|
||||||
if started==true then return end
|
if started == true then
|
||||||
|
return
|
||||||
|
end
|
||||||
started = true
|
started = true
|
||||||
multi:newThread("ThreadErrorHandler",function()
|
multi:newThread(
|
||||||
|
"ThreadErrorHandler",
|
||||||
|
function()
|
||||||
local threads = multi.SystemThreads
|
local threads = multi.SystemThreads
|
||||||
while true do
|
while true do
|
||||||
thread.sleep(.5) -- switching states often takes a huge hit on performance. half a second to tell me there is an error is good enough.
|
thread.sleep(.5) -- switching states often takes a huge hit on performance. half a second to tell me there is an error is good enough.
|
||||||
@ -412,7 +438,8 @@ function multi.InitSystemThreadErrorHandler()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
end
|
end
|
||||||
require("multi.integration.shared")
|
require("multi.integration.shared")
|
||||||
multi.print("Integrated Love2d!")
|
multi.print("Integrated Love2d!")
|
||||||
|
|||||||
@ -21,21 +21,20 @@ 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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
-- I DEMAND USAGE FOR LUVIT
|
-- 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)
|
-- Cannot use discordia without my multitasking library (Which I love more that the luvit platform... then again i'm partial :P)
|
||||||
package.path = "?/init.lua;?.lua;" .. package.path
|
package.path = "?/init.lua;?.lua;" .. package.path
|
||||||
local function _INIT(luvitThread, timer)
|
local function _INIT(luvitThread, timer)
|
||||||
-- lots of this stuff should be able to stay the same
|
-- lots of this stuff should be able to stay the same
|
||||||
function os.getOS()
|
function os.getOS()
|
||||||
if package.config:sub(1,1)=='\\' then
|
if package.config:sub(1, 1) == "\\" then
|
||||||
return 'windows'
|
return "windows"
|
||||||
else
|
else
|
||||||
return 'unix'
|
return "unix"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- Step 1 get setup threads on luvit... Sigh how do i even...
|
-- Step 1 get setup threads on luvit... Sigh how do i even...
|
||||||
local multi, thread = require("multi")
|
local multi, thread = require("multi").init()
|
||||||
isMainThread = true
|
isMainThread = true
|
||||||
function multi:canSystemThread()
|
function multi:canSystemThread()
|
||||||
return true
|
return true
|
||||||
@ -46,15 +45,18 @@ local function _INIT(luvitThread,timer)
|
|||||||
local multi = multi
|
local multi = multi
|
||||||
-- Step 2 set up the Global table... is this possible?
|
-- Step 2 set up the Global table... is this possible?
|
||||||
local GLOBAL = {}
|
local GLOBAL = {}
|
||||||
setmetatable(GLOBAL,{
|
setmetatable(
|
||||||
|
GLOBAL,
|
||||||
|
{
|
||||||
__index = function(t, k)
|
__index = function(t, k)
|
||||||
--print("No Global table when using luvit integration!")
|
--print("No Global table when using luvit integration!")
|
||||||
return nil
|
return nil
|
||||||
end,
|
end,
|
||||||
__newindex = function(t, k, v)
|
__newindex = function(t, k, v)
|
||||||
--print("No Global table when using luvit integration!")
|
--print("No Global table when using luvit integration!")
|
||||||
end,
|
end
|
||||||
})
|
}
|
||||||
|
)
|
||||||
local THREAD = {}
|
local THREAD = {}
|
||||||
function THREAD.set(name, val)
|
function THREAD.set(name, val)
|
||||||
--print("No Global table when using luvit integration!")
|
--print("No Global table when using luvit integration!")
|
||||||
@ -63,10 +65,73 @@ local function _INIT(luvitThread,timer)
|
|||||||
--print("No Global table when using luvit integration!")
|
--print("No Global table when using luvit integration!")
|
||||||
end
|
end
|
||||||
local function randomString(n)
|
local function randomString(n)
|
||||||
local str = ''
|
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
|
for i = 1, n do
|
||||||
str = str..''..strings[math.random(1,#strings)]
|
str = str .. "" .. strings[math.random(1, #strings)]
|
||||||
end
|
end
|
||||||
return str
|
return str
|
||||||
end
|
end
|
||||||
@ -96,8 +161,8 @@ local function _INIT(luvitThread,timer)
|
|||||||
end
|
end
|
||||||
-- Step 5 Basic Threads!
|
-- Step 5 Basic Threads!
|
||||||
local function entry(path, name, func, ...)
|
local function entry(path, name, func, ...)
|
||||||
local timer = require'timer'
|
local timer = require "timer"
|
||||||
local luvitThread = require'thread'
|
local luvitThread = require "thread"
|
||||||
package.path = path
|
package.path = path
|
||||||
loadstring(func)(...)
|
loadstring(func)(...)
|
||||||
end
|
end
|
||||||
@ -120,9 +185,16 @@ local function _INIT(luvitThread,timer)
|
|||||||
multi.integration.THREAD = THREAD
|
multi.integration.THREAD = THREAD
|
||||||
require("multi.integration.shared")
|
require("multi.integration.shared")
|
||||||
-- Start the main mainloop... This allows you to process your multi objects, but the engine on the main thread will be limited to .001 or 1 millisecond sigh...
|
-- Start the main mainloop... This allows you to process your multi objects, but the engine on the main thread will be limited to .001 or 1 millisecond sigh...
|
||||||
local interval = timer.setInterval(1, function ()
|
local interval =
|
||||||
|
timer.setInterval(
|
||||||
|
1,
|
||||||
|
function()
|
||||||
multi:uManager()
|
multi:uManager()
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
return multi
|
return multi
|
||||||
end
|
end
|
||||||
return {init=function(threadHandle,timerHandle) local multi = _INIT(threadHandle,timerHandle) return GLOBAL, THREAD end}
|
return {init = function(threadHandle, timerHandle)
|
||||||
|
local multi = _INIT(threadHandle, timerHandle)
|
||||||
|
return GLOBAL, THREAD
|
||||||
|
end}
|
||||||
|
|||||||
@ -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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
]]
|
]]
|
||||||
local multi, thread = require("multi")
|
local multi, thread = require("multi").init()
|
||||||
local net = require("net")
|
local net = require("net")
|
||||||
local bin = require("bin")
|
local bin = require("bin")
|
||||||
bin.setBitsInterface(infinabits) -- the bits interface does not work so well, another bug to fix
|
bin.setBitsInterface(infinabits) -- the bits interface does not work so well, another bug to fix
|
||||||
@ -119,7 +119,9 @@ end
|
|||||||
-- internal global system
|
-- internal global system
|
||||||
local GLOBAL = {}
|
local GLOBAL = {}
|
||||||
local PROXY = {}
|
local PROXY = {}
|
||||||
setmetatable(GLOBAL,{
|
setmetatable(
|
||||||
|
GLOBAL,
|
||||||
|
{
|
||||||
__index = function(t, k)
|
__index = function(t, k)
|
||||||
return PROXY[k]
|
return PROXY[k]
|
||||||
end,
|
end,
|
||||||
@ -128,7 +130,8 @@ setmetatable(GLOBAL,{
|
|||||||
PROXY[k] = v
|
PROXY[k] = v
|
||||||
multi.OnGUpdate:Fire(k, packData(v))
|
multi.OnGUpdate:Fire(k, packData(v))
|
||||||
end
|
end
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
-- In case you are unable to use broadcasting this can be used to help connect to nodes
|
-- In case you are unable to use broadcasting this can be used to help connect to nodes
|
||||||
function multi:nodeManager(port)
|
function multi:nodeManager(port)
|
||||||
@ -140,10 +143,13 @@ function multi:nodeManager(port)
|
|||||||
server.timeouts = {}
|
server.timeouts = {}
|
||||||
server.OnNodeAdded = multi:newConnection()
|
server.OnNodeAdded = multi:newConnection()
|
||||||
server.OnNodeRemoved = multi:newConnection()
|
server.OnNodeRemoved = multi:newConnection()
|
||||||
server.OnDataRecieved(function(server,data,cid,ip,port)
|
server.OnDataRecieved(
|
||||||
|
function(server, data, cid, ip, port)
|
||||||
local cmd = data:sub(1, 1)
|
local cmd = data:sub(1, 1)
|
||||||
if cmd == "R" then
|
if cmd == "R" then
|
||||||
multi:newThread("Node Client Manager",function(loop)
|
multi:newThread(
|
||||||
|
"Node Client Manager",
|
||||||
|
function(loop)
|
||||||
while true do
|
while true do
|
||||||
if server.timeouts[cid] == true then
|
if server.timeouts[cid] == true then
|
||||||
server.OnNodeRemoved:Fire(server.nodes[cid])
|
server.OnNodeRemoved:Fire(server.nodes[cid])
|
||||||
@ -156,23 +162,29 @@ function multi:nodeManager(port)
|
|||||||
end
|
end
|
||||||
thread.sleep(1)
|
thread.sleep(1)
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
server.nodes[cid] = data:sub(2, -1)
|
server.nodes[cid] = data:sub(2, -1)
|
||||||
server.OnNodeAdded:Fire(server.nodes[cid])
|
server.OnNodeAdded:Fire(server.nodes[cid])
|
||||||
elseif cmd == "G" then
|
elseif cmd == "G" then
|
||||||
server.OnNodeAdded(function(node)
|
server.OnNodeAdded(
|
||||||
|
function(node)
|
||||||
server:send(cid, node)
|
server:send(cid, node)
|
||||||
end)
|
end
|
||||||
server.OnNodeRemoved(function(node)
|
)
|
||||||
|
server.OnNodeRemoved(
|
||||||
|
function(node)
|
||||||
server:send(cid, "R" .. node:match("(.-)|"))
|
server:send(cid, "R" .. node:match("(.-)|"))
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
for i, v in pairs(server.nodes) do
|
for i, v in pairs(server.nodes) do
|
||||||
server:send(cid, v)
|
server:send(cid, v)
|
||||||
end
|
end
|
||||||
elseif cmd == "P" then
|
elseif cmd == "P" then
|
||||||
server.timeouts[cid] = nil
|
server.timeouts[cid] = nil
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
end
|
end
|
||||||
-- The main driving force of the network manager: Nodes
|
-- The main driving force of the network manager: Nodes
|
||||||
function multi:newNode(settings)
|
function multi:newNode(settings)
|
||||||
@ -183,9 +195,11 @@ function multi:newNode(settings)
|
|||||||
local name = settings.name or multi.randomString(8)
|
local name = settings.name or multi.randomString(8)
|
||||||
local node = {}
|
local node = {}
|
||||||
node.name = name
|
node.name = name
|
||||||
multi.OnError(function(i,error)
|
multi.OnError(
|
||||||
|
function(i, error)
|
||||||
node.OnError:Fire(node, error, node.server)
|
node.OnError:Fire(node, error, node.server)
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
node.server = net:newUDPServer(0) -- hosts the node using the default port
|
node.server = net:newUDPServer(0) -- hosts the node using the default port
|
||||||
_, node.port = node.server.udp:getsockname()
|
_, node.port = node.server.udp:getsockname()
|
||||||
node.connections = net.ClientCache
|
node.connections = net.ClientCache
|
||||||
@ -193,7 +207,8 @@ function multi:newNode(settings)
|
|||||||
node.functions = bin.stream("RegisteredFunctions.dat", false)
|
node.functions = bin.stream("RegisteredFunctions.dat", false)
|
||||||
node.hasFuncs = {}
|
node.hasFuncs = {}
|
||||||
node.OnError = multi:newConnection()
|
node.OnError = multi:newConnection()
|
||||||
node.OnError(function(node,err,master)
|
node.OnError(
|
||||||
|
function(node, err, master)
|
||||||
multi.print("ERROR", err, node.name)
|
multi.print("ERROR", err, node.name)
|
||||||
local temp = bin.new()
|
local temp = bin.new()
|
||||||
temp:addBlock(#node.name, 2)
|
temp:addBlock(#node.name, 2)
|
||||||
@ -204,17 +219,21 @@ function multi:newNode(settings)
|
|||||||
multi.print(i)
|
multi.print(i)
|
||||||
v[1]:send(v[2], char(CMD_ERROR) .. temp.data, v[3])
|
v[1]:send(v[2], char(CMD_ERROR) .. temp.data, v[3])
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
if settings.managerDetails then
|
if settings.managerDetails then
|
||||||
local c = net:newTCPClient(settings.managerDetails[1], settings.managerDetails[2])
|
local c = net:newTCPClient(settings.managerDetails[1], settings.managerDetails[2])
|
||||||
if not c then
|
if not c then
|
||||||
multi.print("Cannot connect to the node manager! Ensuring broadcast is enabled!") settings.noBroadCast = false
|
multi.print("Cannot connect to the node manager! Ensuring broadcast is enabled!")
|
||||||
|
settings.noBroadCast = false
|
||||||
else
|
else
|
||||||
c.OnDataRecieved(function(self,data)
|
c.OnDataRecieved(
|
||||||
|
function(self, data)
|
||||||
if data == "ping" then
|
if data == "ping" then
|
||||||
self:send("P")
|
self:send("P")
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
c:send("RNODE_" .. name .. "|" .. net.getLocalIP() .. "|" .. node.port)
|
c:send("RNODE_" .. name .. "|" .. net.getLocalIP() .. "|" .. node.port)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -230,7 +249,9 @@ function multi:newNode(settings)
|
|||||||
len = node.functions:read(1)
|
len = node.functions:read(1)
|
||||||
_G[name] = resolveData(func)
|
_G[name] = resolveData(func)
|
||||||
node.hasFuncs[name] = true
|
node.hasFuncs[name] = true
|
||||||
if not len then break end
|
if not len then
|
||||||
|
break
|
||||||
|
end
|
||||||
len = byte(len)
|
len = byte(len)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -261,7 +282,8 @@ function multi:newNode(settings)
|
|||||||
end
|
end
|
||||||
node.loadRate = 1
|
node.loadRate = 1
|
||||||
-- Lets tell the network we are alive!
|
-- Lets tell the network we are alive!
|
||||||
node.server.OnDataRecieved(function(server,data,cid,ip,port)
|
node.server.OnDataRecieved(
|
||||||
|
function(server, data, cid, ip, port)
|
||||||
local cmd = byte(data:sub(1, 1)) -- the first byte is the command
|
local cmd = byte(data:sub(1, 1)) -- the first byte is the command
|
||||||
local dat = data:sub(2, -1) -- the data that you want to read
|
local dat = data:sub(2, -1) -- the data that you want to read
|
||||||
if cmd == CMD_PING then
|
if cmd == CMD_PING then
|
||||||
@ -306,25 +328,35 @@ function multi:newNode(settings)
|
|||||||
elseif cmd == CMD_INITNODE then
|
elseif cmd == CMD_INITNODE then
|
||||||
multi.print("Connected with another node!")
|
multi.print("Connected with another node!")
|
||||||
node.connections[dat] = {server, ip, port}
|
node.connections[dat] = {server, ip, port}
|
||||||
multi.OnGUpdate(function(k,v)
|
multi.OnGUpdate(
|
||||||
|
function(k, v)
|
||||||
server:send(ip, table.concat {char(CMD_GLOBAL), k, "|", v}, port)
|
server:send(ip, table.concat {char(CMD_GLOBAL), k, "|", v}, port)
|
||||||
end)-- set this up
|
end
|
||||||
|
)
|
||||||
|
-- set this up
|
||||||
elseif cmd == CMD_INITMASTER then
|
elseif cmd == CMD_INITMASTER then
|
||||||
multi.print("Connected to the master!", dat)
|
multi.print("Connected to the master!", dat)
|
||||||
node.connections[dat] = {server, ip, port}
|
node.connections[dat] = {server, ip, port}
|
||||||
multi.OnGUpdate(function(k,v)
|
multi.OnGUpdate(
|
||||||
|
function(k, v)
|
||||||
server:send(ip, table.concat {char(CMD_GLOBAL), k, "|", v}, port)
|
server:send(ip, table.concat {char(CMD_GLOBAL), k, "|", v}, port)
|
||||||
end)-- set this up
|
end
|
||||||
multi:newTLoop(function()
|
)
|
||||||
|
-- set this up
|
||||||
|
multi:newTLoop(
|
||||||
|
function()
|
||||||
server:send(ip, char(CMD_LOAD) .. node.name .. "|" .. multi:getLoad(), port)
|
server:send(ip, char(CMD_LOAD) .. node.name .. "|" .. multi:getLoad(), port)
|
||||||
end,node.loadRate)
|
end,
|
||||||
|
node.loadRate
|
||||||
|
)
|
||||||
server:send(ip, char(CMD_LOAD) .. node.name .. "|" .. multi:getLoad(), port)
|
server:send(ip, char(CMD_LOAD) .. node.name .. "|" .. multi:getLoad(), port)
|
||||||
server:send(ip, char(CMD_INITNODE) .. node.name, port)
|
server:send(ip, char(CMD_INITNODE) .. node.name, port)
|
||||||
elseif cmd == CMD_GLOBAL then
|
elseif cmd == CMD_GLOBAL then
|
||||||
local k, v = dat:match("(.-)|(.+)")
|
local k, v = dat:match("(.-)|(.+)")
|
||||||
PROXY[k] = resolveData(v)
|
PROXY[k] = resolveData(v)
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
function node:sendTo(name, data)
|
function node:sendTo(name, data)
|
||||||
local conn = node.connections[name]
|
local conn = node.connections[name]
|
||||||
conn[1]:send(conn[2], data, conn[3])
|
conn[1]:send(conn[2], data, conn[3])
|
||||||
@ -350,27 +382,34 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
|
|||||||
master.connections = net.ClientCache -- Link to the client cache that is created on the net interface
|
master.connections = net.ClientCache -- Link to the client cache that is created on the net interface
|
||||||
master.loads = {}
|
master.loads = {}
|
||||||
master.timeouts = {}
|
master.timeouts = {}
|
||||||
master.trigger = multi:newFunction(function(self,node)
|
master.trigger =
|
||||||
|
multi:newFunction(
|
||||||
|
function(self, node)
|
||||||
master.OnFirstNodeConnected:Fire(node)
|
master.OnFirstNodeConnected:Fire(node)
|
||||||
self:Pause()
|
self:Pause()
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
if settings.managerDetails then
|
if settings.managerDetails then
|
||||||
local client = net:newTCPClient(settings.managerDetails[1], settings.managerDetails[2])
|
local client = net:newTCPClient(settings.managerDetails[1], settings.managerDetails[2])
|
||||||
if not client then
|
if not client then
|
||||||
multi.print("Warning: Cannot connect to the node manager! Ensuring broadcast listening is enabled!") settings.noBroadCast = false
|
multi.print("Warning: Cannot connect to the node manager! Ensuring broadcast listening is enabled!")
|
||||||
|
settings.noBroadCast = false
|
||||||
else
|
else
|
||||||
client.OnDataRecieved(function(client,data)
|
client.OnDataRecieved(
|
||||||
|
function(client, data)
|
||||||
local cmd = data:sub(1, 1)
|
local cmd = data:sub(1, 1)
|
||||||
if cmd == "N" then
|
if cmd == "N" then
|
||||||
print(data)
|
print(data)
|
||||||
local name, ip, port = data:match("(.-)|(.-)|(.+)")
|
local name, ip, port = data:match("(.-)|(.-)|(.+)")
|
||||||
local c = net:newUDPClient(ip, port)
|
local c = net:newUDPClient(ip, port)
|
||||||
net.OnCastedClientInfo:Fire(c,name,ip,port)master.connections[name]=c
|
net.OnCastedClientInfo:Fire(c, name, ip, port)
|
||||||
|
master.connections[name] = c
|
||||||
elseif cmd == "R" then
|
elseif cmd == "R" then
|
||||||
local name = data:sub(2, -1)
|
local name = data:sub(2, -1)
|
||||||
master.connections[name] = nil
|
master.connections[name] = nil
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
client:send("G") -- init your connection as a master
|
client:send("G") -- init your connection as a master
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -441,12 +480,20 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
|
|||||||
name = self:getRandomNode()
|
name = self:getRandomNode()
|
||||||
end
|
end
|
||||||
if name == nil then
|
if name == nil then
|
||||||
multi:newEvent(function() return name~=nil end):OnEvent(function(evnt)
|
multi:newEvent(
|
||||||
|
function()
|
||||||
|
return name ~= nil
|
||||||
|
end
|
||||||
|
):OnEvent(
|
||||||
|
function(evnt)
|
||||||
self:sendTo(name, char(CMD_TASK) .. len .. aData .. len2 .. fData)
|
self:sendTo(name, char(CMD_TASK) .. len .. aData .. len2 .. fData)
|
||||||
evnt:Destroy()
|
evnt:Destroy()
|
||||||
end):SetName("DelayedSendTask"):SetName("DelayedSendTask"):SetTime(8):OnTimedOut(function(self)
|
end
|
||||||
|
):SetName("DelayedSendTask"):SetName("DelayedSendTask"):SetTime(8):OnTimedOut(
|
||||||
|
function(self)
|
||||||
self:Destroy()
|
self:Destroy()
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
else
|
else
|
||||||
self:sendTo(name, char(CMD_TASK) .. len .. aData .. len2 .. fData)
|
self:sendTo(name, char(CMD_TASK) .. len .. aData .. len2 .. fData)
|
||||||
end
|
end
|
||||||
@ -460,12 +507,20 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
|
|||||||
name = "NODE_" .. name
|
name = "NODE_" .. name
|
||||||
end
|
end
|
||||||
if self.connections[name] == nil then
|
if self.connections[name] == nil then
|
||||||
multi:newEvent(function() return self.connections[name]~=nil end):OnEvent(function(evnt)
|
multi:newEvent(
|
||||||
|
function()
|
||||||
|
return self.connections[name] ~= nil
|
||||||
|
end
|
||||||
|
):OnEvent(
|
||||||
|
function(evnt)
|
||||||
self.connections[name]:send(data)
|
self.connections[name]:send(data)
|
||||||
evnt:Destroy()
|
evnt:Destroy()
|
||||||
end):SetName("DelayedSendTask"):SetTime(8):OnTimedOut(function(self)
|
end
|
||||||
|
):SetName("DelayedSendTask"):SetTime(8):OnTimedOut(
|
||||||
|
function(self)
|
||||||
self:Destroy()
|
self:Destroy()
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
else
|
else
|
||||||
self.connections[name]:send(data)
|
self.connections[name]:send(data)
|
||||||
end
|
end
|
||||||
@ -489,18 +544,24 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
|
|||||||
end
|
end
|
||||||
return list[math.random(1, #list)]
|
return list[math.random(1, #list)]
|
||||||
end
|
end
|
||||||
net.OnCastedClientInfo(function(client,name,ip,port)
|
net.OnCastedClientInfo(
|
||||||
multi.OnGUpdate(function(k,v)
|
function(client, name, ip, port)
|
||||||
|
multi.OnGUpdate(
|
||||||
|
function(k, v)
|
||||||
client:send(table.concat {char(CMD_GLOBAL), k, "|", v})
|
client:send(table.concat {char(CMD_GLOBAL), k, "|", v})
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
local nodename
|
local nodename
|
||||||
for i, v in pairs(master.connections) do
|
for i, v in pairs(master.connections) do
|
||||||
nodename = i
|
nodename = i
|
||||||
end
|
end
|
||||||
client.OnClientReady(function()
|
client.OnClientReady(
|
||||||
|
function()
|
||||||
client:send(char(CMD_INITMASTER) .. master.name) -- Tell the node that you are a master trying to connect
|
client:send(char(CMD_INITMASTER) .. master.name) -- Tell the node that you are a master trying to connect
|
||||||
if not settings.managerDetails then
|
if not settings.managerDetails then
|
||||||
multi:newThread("Node Data Link Controller",function(loop)
|
multi:newThread(
|
||||||
|
"Node Data Link Controller",
|
||||||
|
function(loop)
|
||||||
while true do
|
while true do
|
||||||
if master.timeouts[name] == true then
|
if master.timeouts[name] == true then
|
||||||
master.timeouts[name] = nil
|
master.timeouts[name] = nil
|
||||||
@ -512,10 +573,12 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
|
|||||||
end
|
end
|
||||||
thread.sleep(1)
|
thread.sleep(1)
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
end
|
end
|
||||||
client.name = name
|
client.name = name
|
||||||
client.OnDataRecieved(function(client,data)
|
client.OnDataRecieved(
|
||||||
|
function(client, data)
|
||||||
local cmd = byte(data:sub(1, 1)) -- the first byte is the command
|
local cmd = byte(data:sub(1, 1)) -- the first byte is the command
|
||||||
local dat = data:sub(2, -1) -- the data that you want to read
|
local dat = data:sub(2, -1) -- the data that you want to read
|
||||||
master.trigger(nodename)
|
master.trigger(nodename)
|
||||||
@ -541,9 +604,12 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
|
|||||||
local name, load = dat:match("(.-)|(.+)")
|
local name, load = dat:match("(.-)|(.+)")
|
||||||
master.loads[name] = tonumber(load)
|
master.loads[name] = tonumber(load)
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
end)
|
)
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
|
end
|
||||||
|
)
|
||||||
if not settings.noBroadCast then
|
if not settings.noBroadCast then
|
||||||
net:newCastedClients("NODE_(.+)") -- Searches for nodes and connects to them, the master.clients table will contain them by name
|
net:newCastedClients("NODE_(.+)") -- Searches for nodes and connects to them, the master.clients table will contain them by name
|
||||||
end
|
end
|
||||||
@ -551,6 +617,8 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
|
|||||||
end
|
end
|
||||||
-- The init function that gets returned
|
-- The init function that gets returned
|
||||||
multi.print("Integrated Network Parallelism")
|
multi.print("Integrated Network Parallelism")
|
||||||
return {init = function()
|
return {
|
||||||
|
init = function()
|
||||||
return GLOBAL
|
return GLOBAL
|
||||||
end}
|
end
|
||||||
|
}
|
||||||
|
|||||||
@ -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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
]]
|
]]
|
||||||
multi, thread = require("multi")
|
local multi, thread = require("multi").init()
|
||||||
function multi:newSystemThreadedQueue(name) -- in love2d this will spawn a channel on both ends
|
function multi:newSystemThreadedQueue(name) -- in love2d this will spawn a channel on both ends
|
||||||
local c = {} -- where we will store our object
|
local c = {} -- where we will store our object
|
||||||
c.name = name -- set the name this is important for the love2d side
|
c.name = name -- set the name this is important for the love2d side
|
||||||
@ -47,7 +47,9 @@ function multi:newSystemThreadedQueue(name) -- in love2d this will spawn a chann
|
|||||||
end
|
end
|
||||||
function self:pop() -- pop from the channel
|
function self:pop() -- pop from the channel
|
||||||
local v = self.chan:pop()
|
local v = self.chan:pop()
|
||||||
if not v then return end
|
if not v then
|
||||||
|
return
|
||||||
|
end
|
||||||
if type(v) == "table" then
|
if type(v) == "table" then
|
||||||
tab = {}
|
tab = {}
|
||||||
for i, c in pairs(v) do
|
for i, c in pairs(v) do
|
||||||
@ -68,7 +70,9 @@ function multi:newSystemThreadedQueue(name) -- in love2d this will spawn a chann
|
|||||||
end
|
end
|
||||||
function self:peek()
|
function self:peek()
|
||||||
local v = self.chan:peek()
|
local v = self.chan:peek()
|
||||||
if not v then return end
|
if not v then
|
||||||
|
return
|
||||||
|
end
|
||||||
if type(v) == "table" then
|
if type(v) == "table" then
|
||||||
tab = {}
|
tab = {}
|
||||||
for i, c in pairs(v) do
|
for i, c in pairs(v) do
|
||||||
@ -130,11 +134,14 @@ function multi:newSystemThreadedConnection(name,protect)
|
|||||||
end
|
end
|
||||||
local conn = {}
|
local conn = {}
|
||||||
conn.obj = multi:newConnection()
|
conn.obj = multi:newConnection()
|
||||||
setmetatable(conn,{
|
setmetatable(
|
||||||
|
conn,
|
||||||
|
{
|
||||||
__call = function(self, ...)
|
__call = function(self, ...)
|
||||||
return self:connect(...)
|
return self:connect(...)
|
||||||
end
|
end
|
||||||
})
|
}
|
||||||
|
)
|
||||||
local ID = sThread.getID()
|
local ID = sThread.getID()
|
||||||
local sync = sThread.waitFor(self.name .. "_CONN_SYNC"):init()
|
local sync = sThread.waitFor(self.name .. "_CONN_SYNC"):init()
|
||||||
local fire = sThread.waitFor(self.name .. "_CONN_FIRE"):init()
|
local fire = sThread.waitFor(self.name .. "_CONN_FIRE"):init()
|
||||||
@ -165,14 +172,17 @@ function multi:newSystemThreadedConnection(name,protect)
|
|||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not good then return multi.print("NonExisting Connection!") end
|
if not good then
|
||||||
|
return multi.print("NonExisting Connection!")
|
||||||
|
end
|
||||||
fire:push {to, ID, {...}}
|
fire:push {to, ID, {...}}
|
||||||
end
|
end
|
||||||
-- FIRE {TO,FROM,{ARGS}}
|
-- FIRE {TO,FROM,{ARGS}}
|
||||||
local data
|
local data
|
||||||
local clock = os.clock
|
local clock = os.clock
|
||||||
conn.OnConnectionAdded = multi:newConnection()
|
conn.OnConnectionAdded = multi:newConnection()
|
||||||
multi:newLoop(function()
|
multi:newLoop(
|
||||||
|
function()
|
||||||
data = fire:peek()
|
data = fire:peek()
|
||||||
if type(data) == "table" and data[1] == ID then
|
if type(data) == "table" and data[1] == ID then
|
||||||
if data[2] == ID and conn.IgnoreSelf then
|
if data[2] == ID and conn.IgnoreSelf then
|
||||||
@ -185,9 +195,11 @@ function multi:newSystemThreadedConnection(name,protect)
|
|||||||
data = sync:peek()
|
data = sync:peek()
|
||||||
if data ~= nil and data[1] == "SYNCA" and data[2] == ID then
|
if data ~= nil and data[1] == "SYNCA" and data[2] == ID then
|
||||||
sync:pop()
|
sync:pop()
|
||||||
multi.nextStep(function()
|
multi.nextStep(
|
||||||
|
function()
|
||||||
conn.OnConnectionAdded:Fire(data[3])
|
conn.OnConnectionAdded:Fire(data[3])
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
table.insert(connections, data[3])
|
table.insert(connections, data[3])
|
||||||
end
|
end
|
||||||
if type(data) == "table" and data[1] == "SYNCR" and data[2] == ID then
|
if type(data) == "table" and data[1] == "SYNCR" and data[2] == ID then
|
||||||
@ -198,17 +210,22 @@ function multi:newSystemThreadedConnection(name,protect)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end):setName("STConn.syncer")
|
end
|
||||||
|
):setName("STConn.syncer")
|
||||||
return conn
|
return conn
|
||||||
end
|
end
|
||||||
local cleanUp = {}
|
local cleanUp = {}
|
||||||
multi.OnSystemThreadDied(function(ThreadID)
|
multi.OnSystemThreadDied(
|
||||||
|
function(ThreadID)
|
||||||
for i = 1, #syncs do
|
for i = 1, #syncs do
|
||||||
connSync:push {"SYNCR", syncs[i], ThreadID}
|
connSync:push {"SYNCR", syncs[i], ThreadID}
|
||||||
end
|
end
|
||||||
cleanUp[ThreadID] = true
|
cleanUp[ThreadID] = true
|
||||||
end)
|
end
|
||||||
multi:newThread(c.name.." Connection-Handler",function()
|
)
|
||||||
|
multi:newThread(
|
||||||
|
c.name .. " Connection-Handler",
|
||||||
|
function()
|
||||||
local data
|
local data
|
||||||
local clock = os.clock
|
local clock = os.clock
|
||||||
local syncs = {}
|
local syncs = {}
|
||||||
@ -234,12 +251,15 @@ function multi:newSystemThreadedConnection(name,protect)
|
|||||||
if data ~= nil and cleanUp[data[1]] then
|
if data ~= nil and cleanUp[data[1]] then
|
||||||
local meh = data[1]
|
local meh = data[1]
|
||||||
connFire:pop() -- lets remove dead thread stuff
|
connFire:pop() -- lets remove dead thread stuff
|
||||||
multi:newAlarm(15):OnRing(function(a)
|
multi:newAlarm(15):OnRing(
|
||||||
|
function(a)
|
||||||
cleanUp[meh] = nil
|
cleanUp[meh] = nil
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
GLOBAL[c.name] = c
|
GLOBAL[c.name] = c
|
||||||
return c
|
return c
|
||||||
end
|
end
|
||||||
@ -252,22 +272,30 @@ function multi:SystemThreadedBenchmark(n)
|
|||||||
local GLOBAL = multi.integration.GLOBAL
|
local GLOBAL = multi.integration.GLOBAL
|
||||||
local c = {}
|
local c = {}
|
||||||
for i = 1, cores do
|
for i = 1, cores do
|
||||||
multi:newSystemThread("STHREAD_BENCH",function(n)
|
multi:newSystemThread(
|
||||||
|
"STHREAD_BENCH",
|
||||||
|
function(n)
|
||||||
local multi = require("multi")
|
local multi = require("multi")
|
||||||
if multi:getPlatform() == "love2d" then
|
if multi:getPlatform() == "love2d" then
|
||||||
GLOBAL = _G.GLOBAL
|
GLOBAL = _G.GLOBAL
|
||||||
sThread = _G.sThread
|
sThread = _G.sThread
|
||||||
end -- we cannot have upvalues... in love2d globals, not locals must be used
|
end -- we cannot have upvalues... in love2d globals, not locals must be used
|
||||||
queue = sThread.waitFor("THREAD_BENCH_QUEUE"):init() -- always wait for when looking for a variable at the start of the thread!
|
queue = sThread.waitFor("THREAD_BENCH_QUEUE"):init() -- always wait for when looking for a variable at the start of the thread!
|
||||||
multi:benchMark(n):OnBench(function(self,count)
|
multi:benchMark(n):OnBench(
|
||||||
|
function(self, count)
|
||||||
queue:push(count)
|
queue:push(count)
|
||||||
sThread.kill()
|
sThread.kill()
|
||||||
error("Thread was killed!")
|
error("Thread was killed!")
|
||||||
end)
|
|
||||||
multi:mainloop()
|
|
||||||
end,n)
|
|
||||||
end
|
end
|
||||||
multi:newThread("THREAD_BENCH",function()
|
)
|
||||||
|
multi:mainloop()
|
||||||
|
end,
|
||||||
|
n
|
||||||
|
)
|
||||||
|
end
|
||||||
|
multi:newThread(
|
||||||
|
"THREAD_BENCH",
|
||||||
|
function()
|
||||||
local count = 0
|
local count = 0
|
||||||
local cc = 0
|
local cc = 0
|
||||||
while true do
|
while true do
|
||||||
@ -282,7 +310,8 @@ function multi:SystemThreadedBenchmark(n)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
c.OnBench = multi:newConnection()
|
c.OnBench = multi:newConnection()
|
||||||
return c
|
return c
|
||||||
end
|
end
|
||||||
@ -304,7 +333,8 @@ function multi:newSystemThreadedConsole(name)
|
|||||||
cc.stream = sThread.waitFor("__SYSTEM_CONSOLE__"):init()
|
cc.stream = sThread.waitFor("__SYSTEM_CONSOLE__"):init()
|
||||||
else
|
else
|
||||||
cc.stream = multi:newSystemThreadedQueue("__SYSTEM_CONSOLE__"):init()
|
cc.stream = multi:newSystemThreadedQueue("__SYSTEM_CONSOLE__"):init()
|
||||||
multi:newLoop(function()
|
multi:newLoop(
|
||||||
|
function()
|
||||||
local data = cc.stream:pop()
|
local data = cc.stream:pop()
|
||||||
if data then
|
if data then
|
||||||
local dat = table.remove(data, 1)
|
local dat = table.remove(data, 1)
|
||||||
@ -314,7 +344,8 @@ function multi:newSystemThreadedConsole(name)
|
|||||||
print(unpack(data))
|
print(unpack(data))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end):setName("ST.consoleSyncer")
|
end
|
||||||
|
):setName("ST.consoleSyncer")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
cc.stream = sThread.waitFor("__SYSTEM_CONSOLE__"):init()
|
cc.stream = sThread.waitFor("__SYSTEM_CONSOLE__"):init()
|
||||||
@ -357,14 +388,20 @@ function multi:newSystemThreadedTable(name)
|
|||||||
cc.conn = sThread.waitFor(self.name .. "_Tabled_Connection"):init()
|
cc.conn = sThread.waitFor(self.name .. "_Tabled_Connection"):init()
|
||||||
end
|
end
|
||||||
function cc:waitFor(name)
|
function cc:waitFor(name)
|
||||||
repeat multi:uManager() until tab[name]~=nil
|
repeat
|
||||||
|
multi:uManager()
|
||||||
|
until tab[name] ~= nil
|
||||||
return tab[name]
|
return tab[name]
|
||||||
end
|
end
|
||||||
local link = cc
|
local link = cc
|
||||||
cc.conn(function(k,v)
|
cc.conn(
|
||||||
|
function(k, v)
|
||||||
link.tab[k] = v
|
link.tab[k] = v
|
||||||
end)
|
end
|
||||||
setmetatable(cc,{
|
)
|
||||||
|
setmetatable(
|
||||||
|
cc,
|
||||||
|
{
|
||||||
__index = function(t, k)
|
__index = function(t, k)
|
||||||
return t.tab[k]
|
return t.tab[k]
|
||||||
end,
|
end,
|
||||||
@ -372,7 +409,8 @@ function multi:newSystemThreadedTable(name)
|
|||||||
t.tab[k] = v
|
t.tab[k] = v
|
||||||
t.conn:Fire(k, v)
|
t.conn:Fire(k, v)
|
||||||
end
|
end
|
||||||
})
|
}
|
||||||
|
)
|
||||||
return cc
|
return cc
|
||||||
end
|
end
|
||||||
GLOBAL[c.name] = c
|
GLOBAL[c.name] = c
|
||||||
@ -438,7 +476,9 @@ function multi:newSystemThreadedJobQueue(a,b)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
for i = 1, c.numberofcores do
|
for i = 1, c.numberofcores do
|
||||||
multi:newSystemThread(c.name.." Worker Thread #"..i,function(name)
|
multi:newSystemThread(
|
||||||
|
c.name .. " Worker Thread #" .. i,
|
||||||
|
function(name)
|
||||||
local multi = require("multi")
|
local multi = require("multi")
|
||||||
if love then -- lets make sure we don't reference up-values if using love2d
|
if love then -- lets make sure we don't reference up-values if using love2d
|
||||||
GLOBAL = _G.GLOBAL
|
GLOBAL = _G.GLOBAL
|
||||||
@ -453,7 +493,8 @@ function multi:newSystemThreadedJobQueue(a,b)
|
|||||||
local REG = sThread.waitFor("QUEUE_REG_" .. name):init()
|
local REG = sThread.waitFor("QUEUE_REG_" .. name):init()
|
||||||
local DA = sThread.waitFor("QUEUE_DA_" .. name):init()
|
local DA = sThread.waitFor("QUEUE_DA_" .. name):init()
|
||||||
local lastjob = os.clock()
|
local lastjob = os.clock()
|
||||||
multi:newLoop(function()
|
multi:newLoop(
|
||||||
|
function()
|
||||||
local job = JQI:pop()
|
local job = JQI:pop()
|
||||||
local rd = REG:peek()
|
local rd = REG:peek()
|
||||||
local da = DA:peek()
|
local da = DA:peek()
|
||||||
@ -471,10 +512,12 @@ function multi:newSystemThreadedJobQueue(a,b)
|
|||||||
da[2](multi)
|
da[2](multi)
|
||||||
da = nil
|
da = nil
|
||||||
DA:pop()
|
DA:pop()
|
||||||
multi:newAlarm(60):OnRing(function(a)
|
multi:newAlarm(60):OnRing(
|
||||||
|
function(a)
|
||||||
ids[meh] = nil
|
ids[meh] = nil
|
||||||
a:Destroy()
|
a:Destroy()
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if job then
|
if job then
|
||||||
@ -487,24 +530,34 @@ function multi:newSystemThreadedJobQueue(a,b)
|
|||||||
JD:push({ID, FUNCS:waitFor(_name)(unpack(job))})
|
JD:push({ID, FUNCS:waitFor(_name)(unpack(job))})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
multi:newLoop(function()
|
)
|
||||||
|
multi:newLoop(
|
||||||
|
function()
|
||||||
if os.clock() - lastjob > 1 then
|
if os.clock() - lastjob > 1 then
|
||||||
sThread.sleep(.1)
|
sThread.sleep(.1)
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
setmetatable(_G,{
|
)
|
||||||
|
setmetatable(
|
||||||
|
_G,
|
||||||
|
{
|
||||||
__index = function(t, k)
|
__index = function(t, k)
|
||||||
return FUNCS[k]
|
return FUNCS[k]
|
||||||
end
|
end
|
||||||
})
|
}
|
||||||
|
)
|
||||||
if not love then
|
if not love then
|
||||||
multi:mainloop()
|
multi:mainloop()
|
||||||
end
|
end
|
||||||
end,c.name)
|
end,
|
||||||
|
c.name
|
||||||
|
)
|
||||||
end
|
end
|
||||||
local clock = os.clock
|
local clock = os.clock
|
||||||
multi:newThread("JQ-"..c.name.." Manager",function()
|
multi:newThread(
|
||||||
|
"JQ-" .. c.name .. " Manager",
|
||||||
|
function()
|
||||||
local _count = 0
|
local _count = 0
|
||||||
while _count < c.numberofcores do
|
while _count < c.numberofcores do
|
||||||
thread.skip()
|
thread.skip()
|
||||||
@ -534,7 +587,8 @@ function multi:newSystemThreadedJobQueue(a,b)
|
|||||||
c.OnJobCompleted:Fire(unpack(dat))
|
c.OnJobCompleted:Fire(unpack(dat))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
return c
|
return c
|
||||||
end
|
end
|
||||||
function multi:newSystemThreadedExecute(cmd)
|
function multi:newSystemThreadedExecute(cmd)
|
||||||
@ -544,7 +598,9 @@ function multi:newSystemThreadedExecute(cmd)
|
|||||||
local name = "Execute_Thread" .. multi.randomString(16)
|
local name = "Execute_Thread" .. multi.randomString(16)
|
||||||
c.name = name
|
c.name = name
|
||||||
GLOBAL[name .. "CMD"] = cmd
|
GLOBAL[name .. "CMD"] = cmd
|
||||||
multi:newSystemThread(name,function()
|
multi:newSystemThread(
|
||||||
|
name,
|
||||||
|
function()
|
||||||
if love then -- lets make sure we don't reference upvalues if using love2d
|
if love then -- lets make sure we don't reference upvalues if using love2d
|
||||||
GLOBAL = _G.GLOBAL
|
GLOBAL = _G.GLOBAL
|
||||||
sThread = _G.sThread
|
sThread = _G.sThread
|
||||||
@ -553,15 +609,19 @@ function multi:newSystemThreadedExecute(cmd)
|
|||||||
cmd = sThread.waitFor(name .. "CMD")
|
cmd = sThread.waitFor(name .. "CMD")
|
||||||
local ret = os.execute(cmd)
|
local ret = os.execute(cmd)
|
||||||
GLOBAL[name .. "R"] = ret
|
GLOBAL[name .. "R"] = ret
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
c.OnCMDFinished = multi:newConnection()
|
c.OnCMDFinished = multi:newConnection()
|
||||||
c.looper=multi:newLoop(function(self)
|
c.looper =
|
||||||
|
multi:newLoop(
|
||||||
|
function(self)
|
||||||
local ret = GLOBAL[self.link.name .. "R"]
|
local ret = GLOBAL[self.link.name .. "R"]
|
||||||
if ret then
|
if ret then
|
||||||
self.link.OnCMDFinished:Fire(ret)
|
self.link.OnCMDFinished:Fire(ret)
|
||||||
self:Destroy()
|
self:Destroy()
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
c.looper.link = c
|
c.looper.link = c
|
||||||
return c
|
return c
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user